|
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