|
22 | 22 |
|
23 | 23 | var MAX_CHUNK_SIZE = 16383,
|
24 | 24 |
|
25 |
| - // Signature bytes for each message type |
| 25 | + // Signature bytes for each message type |
26 | 26 | INIT = 0x01, // 0000 0001 // INIT <user_agent>
|
27 | 27 | ACK_FAILURE = 0x0F, // 0000 1111 // ACK_FAILURE
|
28 | 28 | RUN = 0x10, // 0001 0000 // RUN <statement> <parameters>
|
|
61 | 61 | MAP_32 = 0xDA,
|
62 | 62 | STRUCT_8 = 0xDC,
|
63 | 63 | STRUCT_16 = 0xDD,
|
64 |
| - |
| 64 | + |
65 | 65 | USER_AGENT = "neo4j-javascript/0.0";
|
66 | 66 |
|
67 | 67 | function Structure(signature, fields) {
|
68 | 68 | this.signature = signature;
|
69 | 69 | this.fields = fields;
|
70 | 70 | }
|
71 |
| - |
| 71 | + |
72 | 72 | function Node(identity, labels, properties) {
|
73 | 73 | this.identity = identity;
|
74 | 74 | this.labels = labels;
|
75 | 75 | this.properties = properties;
|
76 |
| - |
| 76 | + |
77 | 77 | this.toString = function toString() {
|
78 | 78 | var s = "(" + this.identity.split('/')[1];
|
79 | 79 | for (var i = 0; i < this.labels.length; i++) {
|
|
99 | 99 | this.end = end;
|
100 | 100 | this.type = type;
|
101 | 101 | this.properties = properties;
|
102 |
| - |
| 102 | + |
103 | 103 | this.toString = function toString() {
|
104 | 104 | var s = "(" + this.start.split('/')[1] + ")-[:" + this.type;
|
105 | 105 | var keys = Object.keys(this.properties);
|
|
115 | 115 | return s;
|
116 | 116 | }
|
117 | 117 | }
|
118 |
| - |
| 118 | + |
119 | 119 | function UnboundRelationship(identity, type, properties) {
|
120 | 120 | this.identity = identity;
|
121 | 121 | this.type = type;
|
122 | 122 | this.properties = properties;
|
123 |
| - |
| 123 | + |
124 | 124 | this.bind = function bind(start, end) {
|
125 | 125 | return new Relationship(identity, start, end, type, properties);
|
126 | 126 | }
|
127 |
| - |
| 127 | + |
128 | 128 | this.toString = function toString() {
|
129 | 129 | var s = "-[:" + this.type;
|
130 | 130 | var keys = Object.keys(this.properties);
|
|
140 | 140 | return s;
|
141 | 141 | }
|
142 | 142 | }
|
143 |
| - |
| 143 | + |
144 | 144 | function Path(nodes, rels, sequence) {
|
| 145 | + for(var i = 0; i < nodes.length; i++) { |
| 146 | + nodes[i] = hydrate(nodes[i]); |
| 147 | + } |
145 | 148 | var last_node = nodes[0],
|
146 | 149 | entities = [last_node];
|
147 | 150 | for (var i = 0; i < sequence.length; i += 2) {
|
148 | 151 | var rel_index = sequence[i],
|
149 |
| - next_node = nodes[sequence[2 * i + 1]], |
| 152 | + next_node = nodes[sequence[i + 1]], |
150 | 153 | rel;
|
151 | 154 | if (rel_index > 0) {
|
152 | 155 | rel = hydrate(rels[rel_index - 1]);
|
| 156 | + entities.push(rel.bind(last_node.identity, next_node.identity)); |
153 | 157 | } else {
|
154 | 158 | rel = hydrate(rels[-rel_index - 1]);
|
| 159 | + entities.push(rel.bind(next_node.identity, last_node.identity)); |
155 | 160 | }
|
156 |
| - entities.push(rel.bind(next_node, last_node)) |
157 |
| - entities.push(next_node) |
| 161 | + entities.push(next_node); |
| 162 | + last_node = next_node; |
158 | 163 | }
|
159 |
| - |
| 164 | + |
160 | 165 | this.nodes = [entities[0]];
|
161 | 166 | this.relationships = [];
|
162 | 167 | for (var i = 1; i < entities.length; i++) {
|
163 |
| - if (i % 2 == 1) { |
| 168 | + if (i % 2 == 0) { |
164 | 169 | this.nodes.push(entities[i]);
|
165 | 170 | } else {
|
166 | 171 | this.relationships.push(entities[i]);
|
167 | 172 | }
|
168 | 173 | }
|
169 |
| - |
| 174 | + |
170 | 175 | this.toString = function toString() {
|
171 | 176 | return "<Path>";
|
172 | 177 | }
|
|
180 | 185 | } else if (x instanceof Structure) {
|
181 | 186 | fields = x.fields;
|
182 | 187 | switch(x.signature) {
|
183 |
| - case NODE: |
184 |
| - x = new Node(fields[0], fields[1], fields[2]); |
185 |
| - break; |
186 |
| - case RELATIONSHIP: |
187 |
| - x = new Relationship(fields[0], fields[1], fields[2], fields[3], fields[4]); |
188 |
| - break; |
189 |
| - case UNBOUND_RELATIONSHIP: |
190 |
| - x = new UnboundRelationship(fields[0], fields[1], fields[2]); |
191 |
| - break; |
192 |
| - case PATH: |
193 |
| - x = new Path(fields[0], fields[1], fields[2]); |
194 |
| - break; |
| 188 | + case NODE: |
| 189 | + x = new Node(fields[0], fields[1], fields[2]); |
| 190 | + break; |
| 191 | + case RELATIONSHIP: |
| 192 | + x = new Relationship(fields[0], fields[1], fields[2], fields[3], fields[4]); |
| 193 | + break; |
| 194 | + case UNBOUND_RELATIONSHIP: |
| 195 | + x = new UnboundRelationship(fields[0], fields[1], fields[2]); |
| 196 | + break; |
| 197 | + case PATH: |
| 198 | + x = new Path(fields[0], fields[1], fields[2]); |
| 199 | + break; |
195 | 200 | }
|
196 | 201 | }
|
197 | 202 | return x;
|
|
213 | 218 | this.summaryHandler = summaryHandler;
|
214 | 219 | this.detailHandler = detailHandler;
|
215 | 220 | }
|
216 |
| - |
| 221 | + |
217 | 222 | function Message(ws) {
|
218 | 223 | var data = [],
|
219 | 224 | size = 0;
|
220 |
| - |
| 225 | + |
221 | 226 | function flush() {
|
222 | 227 | var header = new Uint8Array([size/256>>0, size%256]);
|
223 | 228 | ws.send(header);
|
|
227 | 232 | data = [];
|
228 | 233 | size = 0;
|
229 | 234 | }
|
230 |
| - |
| 235 | + |
231 | 236 | this.write = function write(b) {
|
232 | 237 | // TODO: when b > MAX_CHUNK_SIZE
|
233 | 238 | var newSize = size + b.length;
|
|
243 | 248 | var zero = new Uint8Array([0, 0]);
|
244 | 249 | ws.send(zero);
|
245 | 250 | }
|
246 |
| - |
| 251 | + |
247 | 252 | }
|
248 | 253 |
|
249 | 254 | function Packer(msg) {
|
|
282 | 287 | console.log(x);
|
283 | 288 | }
|
284 | 289 | }
|
285 |
| - |
| 290 | + |
286 | 291 | function packNull() {
|
287 | 292 | msg.write(new Uint8Array([NULL]));
|
288 | 293 | }
|
289 |
| - |
| 294 | + |
290 | 295 | function packTrue() {
|
291 | 296 | msg.write(new Uint8Array([TRUE]));
|
292 | 297 | }
|
293 |
| - |
| 298 | + |
294 | 299 | function packFalse() {
|
295 | 300 | msg.write(new Uint8Array([FALSE]));
|
296 | 301 | }
|
297 |
| - |
| 302 | + |
298 | 303 | function packNumber(x) {
|
299 | 304 | if (x == x>>0)
|
300 | 305 | packInteger(x);
|
301 | 306 | else
|
302 | 307 | packFloat(x);
|
303 | 308 | }
|
304 |
| - |
| 309 | + |
305 | 310 | function packInteger(x) {
|
306 | 311 | if (-0x10 <= x && x < 0x80) {
|
307 | 312 | var a = new Uint8Array(1);
|
|
331 | 336 | packFloat(x);
|
332 | 337 | }
|
333 | 338 | }
|
334 |
| - |
| 339 | + |
335 | 340 | function packFloat(x) {
|
336 | 341 | var a = new Uint8Array(9);
|
337 | 342 | a[0] = FLOAT_64;
|
338 | 343 | new DataView(a.buffer).setFloat64(1, x);
|
339 | 344 | msg.write(a);
|
340 | 345 | }
|
341 |
| - |
| 346 | + |
342 | 347 | function packText(x) {
|
343 | 348 | var bytes = encoder.encode(x);
|
344 | 349 | var size = bytes.length;
|
|
358 | 363 | throw new ProtocolError("UTF-8 strings of size " + size + " are not supported");
|
359 | 364 | }
|
360 | 365 | }
|
361 |
| - |
| 366 | + |
362 | 367 | function packListHeader(size) {
|
363 | 368 | if (size < 0x10) {
|
364 | 369 | msg.write(new Uint8Array([TINY_LIST | size]));
|
|
372 | 377 | throw new ProtocolError("Lists of size " + size + " are not supported");
|
373 | 378 | }
|
374 | 379 | }
|
375 |
| - |
| 380 | + |
376 | 381 | function packMapHeader(size) {
|
377 | 382 | if (size < 0x10) {
|
378 | 383 | msg.write(new Uint8Array([TINY_MAP | size]));
|
|
386 | 391 | throw new ProtocolError("Maps of size " + size + " are not supported");
|
387 | 392 | }
|
388 | 393 | }
|
389 |
| - |
| 394 | + |
390 | 395 | function packStructHeader(size, signature) {
|
391 | 396 | if (size < 0x10) {
|
392 | 397 | msg.write(new Uint8Array([TINY_STRUCT | size, signature]));
|
|
398 | 403 | throw new ProtocolError("Structures of size " + size + " are not supported");
|
399 | 404 | }
|
400 | 405 | }
|
401 |
| - |
| 406 | + |
402 | 407 | var bytes = function bytes() {
|
403 | 408 | return Uint8Array(data);
|
404 | 409 | }
|
|
409 | 414 | var p = 0,
|
410 | 415 | view = new DataView(data.buffer),
|
411 | 416 | decoder = new TextDecoder();
|
412 |
| - |
| 417 | + |
413 | 418 | function read() {
|
414 | 419 | var ch = data[p];
|
415 | 420 | p += 1;
|
416 | 421 | return ch;
|
417 | 422 | }
|
418 |
| - |
| 423 | + |
419 | 424 | function readUint16() {
|
420 | 425 | var q = p;
|
421 | 426 | readBytes(2);
|
422 | 427 | return view.getUint16(q);
|
423 | 428 | }
|
424 |
| - |
| 429 | + |
425 | 430 | function readUint32() {
|
426 | 431 | var q = p;
|
427 | 432 | readBytes(4);
|
428 | 433 | return view.getUint32(q);
|
429 | 434 | }
|
430 |
| - |
| 435 | + |
431 | 436 | function readUint64() {
|
432 | 437 | var q = p;
|
433 | 438 | readBytes(8);
|
434 | 439 | return view.getUint64(q);
|
435 | 440 | }
|
436 |
| - |
| 441 | + |
437 | 442 | function readBytes(n) {
|
438 | 443 | var q = p + n,
|
439 | 444 | s = data.subarray(p, q);
|
|
558 | 563 | packer.pack(new Structure(signature, fields));
|
559 | 564 | msg.end();
|
560 | 565 | }
|
561 |
| - |
| 566 | + |
562 | 567 | function recv(data) {
|
563 | 568 | var b = new Uint8Array(data), h = [];
|
564 | 569 | for(var i = 0; i < b.length; i++) {
|
|
572 | 577 | var unpacker = new Unpacker(data),
|
573 | 578 | message = unpacker.unpack();
|
574 | 579 | switch(message.signature) {
|
575 |
| - case SUCCESS: |
576 |
| - debug("S: SUCCESS " + JSON.stringify(message.fields[0])); |
577 |
| - var handler = responseHandlers.shift().summaryHandler; |
578 |
| - if(handler) handler(true, message.fields[0]); |
579 |
| - break; |
580 |
| - case FAILURE: |
581 |
| - debug("S: FAILURE " + JSON.stringify(message.fields[0])); |
582 |
| - console.log(message.fields[0]); |
583 |
| - var handler = responseHandlers.shift().summaryHandler; |
584 |
| - if(handler) handler(false, message.fields[0]); |
585 |
| - debug("C: ACK_FAILURE"); |
586 |
| - responseHandlers.unshift(new ResponseHandler()); |
587 |
| - packer.pack(new Structure(ACK_FAILURE, [])); |
588 |
| - msg.end(); |
589 |
| - break; |
590 |
| - case IGNORED: |
591 |
| - debug("S: IGNORED"); |
592 |
| - responseHandlers.shift(); |
593 |
| - break; |
594 |
| - case RECORD: |
595 |
| - debug("S: RECORD " + JSON.stringify(message.fields[0])); |
596 |
| - var handler = responseHandlers[0].detailHandler; |
597 |
| - if(handler) handler(hydrate(message.fields[0])); |
598 |
| - break; |
599 |
| - default: |
600 |
| - debug("WTF"); |
| 580 | + case SUCCESS: |
| 581 | + debug("S: SUCCESS " + JSON.stringify(message.fields[0])); |
| 582 | + var handler = responseHandlers.shift().summaryHandler; |
| 583 | + if(handler) handler(true, message.fields[0]); |
| 584 | + break; |
| 585 | + case FAILURE: |
| 586 | + debug("S: FAILURE " + JSON.stringify(message.fields[0])); |
| 587 | + console.log(message.fields[0]); |
| 588 | + var handler = responseHandlers.shift().summaryHandler; |
| 589 | + if(handler) handler(false, message.fields[0]); |
| 590 | + debug("C: ACK_FAILURE"); |
| 591 | + responseHandlers.unshift(new ResponseHandler()); |
| 592 | + packer.pack(new Structure(ACK_FAILURE, [])); |
| 593 | + msg.end(); |
| 594 | + break; |
| 595 | + case IGNORED: |
| 596 | + debug("S: IGNORED"); |
| 597 | + responseHandlers.shift(); |
| 598 | + break; |
| 599 | + case RECORD: |
| 600 | + debug("S: RECORD " + JSON.stringify(message.fields[0])); |
| 601 | + var handler = responseHandlers[0].detailHandler; |
| 602 | + if(handler) handler(hydrate(message.fields[0])); |
| 603 | + break; |
| 604 | + default: |
| 605 | + debug("WTF"); |
601 | 606 | }
|
602 | 607 | }
|
603 | 608 |
|
|
613 | 618 | messageData = newData;
|
614 | 619 | }
|
615 | 620 | }
|
616 |
| - |
| 621 | + |
617 | 622 | function receiverV1(data) {
|
618 | 623 | var p = 0;
|
619 | 624 | while (p < data.byteLength) {
|
|
622 | 627 | p = q + chunkSize;
|
623 | 628 | onChunk(new Uint8Array(data.slice(q, p)));
|
624 | 629 | }
|
625 |
| - |
| 630 | + |
626 | 631 | }
|
627 | 632 |
|
628 | 633 | function init() {
|
|
639 | 644 | requests.push(new RunRequest(statement, parameters, onHeader, onRecord, onFooter));
|
640 | 645 | runNext();
|
641 | 646 | }
|
642 |
| - |
| 647 | + |
643 | 648 | function runNext() {
|
644 | 649 | if (ready) {
|
645 | 650 | while (requests.length > 0) {
|
|
691 | 696 | window.Path = Path;
|
692 | 697 |
|
693 | 698 | }());
|
694 |
| - |
|
0 commit comments