gremlin 3.5.1 → 3.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/.eslintrc.js +155 -0
  2. package/.prettierrc.js +29 -0
  3. package/Gruntfile.js +15 -16
  4. package/doc/AnonymousTraversalSource.html +5 -5
  5. package/doc/Authenticator.html +2 -2
  6. package/doc/Bytecode.html +7 -7
  7. package/doc/Client.html +138 -64
  8. package/doc/Connection.html +93 -9
  9. package/doc/DriverRemoteConnection.html +11 -11
  10. package/doc/EdgeLabelVerificationStrategy.html +3 -3
  11. package/doc/Graph.html +2 -2
  12. package/doc/GraphSON2Reader.html +4 -4
  13. package/doc/GraphSON2Writer.html +3 -3
  14. package/doc/GraphSON3Reader.html +3 -3
  15. package/doc/GraphSON3Writer.html +3 -3
  16. package/doc/GraphTraversal.html +107 -107
  17. package/doc/GraphTraversalSource.html +19 -19
  18. package/doc/HaltedTraverserStrategy.html +3 -3
  19. package/doc/MatchAlgorithmStrategy.html +3 -3
  20. package/doc/P.html +13 -13
  21. package/doc/PartitionStrategy.html +3 -3
  22. package/doc/Path.html +2 -2
  23. package/doc/PlainTextSaslAuthenticator.html +2 -2
  24. package/doc/ProductiveByStrategy.html +288 -0
  25. package/doc/RemoteConnection.html +10 -10
  26. package/doc/RemoteStrategy.html +4 -4
  27. package/doc/RemoteTraversal.html +3 -3
  28. package/doc/ReservedKeysVerificationStrategy.html +3 -3
  29. package/doc/ResponseError.html +2 -2
  30. package/doc/ResultSet.html +7 -7
  31. package/doc/SaslAuthenticator.html +2 -2
  32. package/doc/SaslMechanismBase.html +2 -2
  33. package/doc/SaslMechanismPlain.html +6 -6
  34. package/doc/SeedStrategy.html +288 -0
  35. package/doc/SubgraphStrategy.html +3 -3
  36. package/doc/TextP.html +10 -10
  37. package/doc/Transaction.html +6 -6
  38. package/doc/Translator.html +198 -4
  39. package/doc/TraversalStrategies.html +5 -5
  40. package/doc/TraversalStrategy.html +3 -3
  41. package/doc/TypeSerializer.html +2 -2
  42. package/doc/driver_auth_authenticator.js.html +4 -4
  43. package/doc/driver_auth_mechanisms_sasl-mechanism-base.js.html +3 -3
  44. package/doc/driver_auth_mechanisms_sasl-mechanism-plain.js.html +26 -17
  45. package/doc/driver_auth_plain-text-sasl-authenticator.js.html +7 -7
  46. package/doc/driver_auth_sasl-authenticator.js.html +3 -3
  47. package/doc/driver_client.js.html +73 -23
  48. package/doc/driver_connection.js.html +134 -92
  49. package/doc/driver_driver-remote-connection.js.html +12 -11
  50. package/doc/driver_remote-connection.js.html +4 -5
  51. package/doc/driver_response-error.js.html +5 -4
  52. package/doc/driver_result-set.js.html +4 -4
  53. package/doc/global.html +264 -3
  54. package/doc/index.html +2 -2
  55. package/doc/module.exports.html +301 -0
  56. package/doc/process_anonymous-traversal.js.html +4 -4
  57. package/doc/process_bytecode.js.html +11 -9
  58. package/doc/process_graph-traversal.js.html +194 -143
  59. package/doc/process_transaction.js.html +16 -9
  60. package/doc/process_translator.js.html +53 -37
  61. package/doc/process_traversal-strategy.js.html +70 -53
  62. package/doc/process_traversal.js.html +101 -108
  63. package/doc/structure_graph.js.html +7 -7
  64. package/doc/structure_io_binary_internals_DataType.js.html +148 -0
  65. package/doc/structure_io_binary_internals_GraphBinaryReader.js.html +131 -0
  66. package/doc/structure_io_binary_internals_GraphBinaryWriter.js.html +134 -0
  67. package/doc/structure_io_graph-serializer.js.html +65 -18
  68. package/doc/structure_io_type-serializers.js.html +86 -89
  69. package/index.js +5 -5
  70. package/lib/driver/auth/authenticator.js +2 -2
  71. package/lib/driver/auth/mechanisms/sasl-mechanism-base.js +1 -1
  72. package/lib/driver/auth/mechanisms/sasl-mechanism-plain.js +24 -15
  73. package/lib/driver/auth/plain-text-sasl-authenticator.js +5 -5
  74. package/lib/driver/auth/sasl-authenticator.js +1 -1
  75. package/lib/driver/client.js +71 -21
  76. package/lib/driver/connection.js +132 -90
  77. package/lib/driver/driver-remote-connection.js +10 -9
  78. package/lib/driver/remote-connection.js +2 -3
  79. package/lib/driver/response-error.js +2 -2
  80. package/lib/driver/result-set.js +1 -2
  81. package/lib/process/anonymous-traversal.js +1 -2
  82. package/lib/process/bytecode.js +9 -7
  83. package/lib/process/graph-traversal.js +191 -141
  84. package/lib/process/transaction.js +13 -7
  85. package/lib/process/translator.js +50 -35
  86. package/lib/process/traversal-strategy.js +67 -51
  87. package/lib/process/traversal.js +99 -106
  88. package/lib/structure/graph.js +5 -5
  89. package/lib/structure/io/binary/GraphBinary.js +109 -0
  90. package/lib/structure/io/binary/internals/AnySerializer.js +95 -0
  91. package/lib/structure/io/binary/internals/ArraySerializer.js +135 -0
  92. package/lib/structure/io/binary/internals/BigIntegerSerializer.js +151 -0
  93. package/lib/structure/io/binary/internals/BooleanSerializer.js +103 -0
  94. package/lib/structure/io/binary/internals/BulkSetSerializer.js +124 -0
  95. package/lib/structure/io/binary/internals/ByteBufferSerializer.js +124 -0
  96. package/lib/structure/io/binary/internals/ByteSerializer.js +95 -0
  97. package/lib/structure/io/binary/internals/BytecodeSerializer.js +249 -0
  98. package/lib/structure/io/binary/internals/DataType.js +97 -0
  99. package/lib/structure/io/binary/internals/DateSerializer.js +103 -0
  100. package/lib/structure/io/binary/internals/DoubleSerializer.js +99 -0
  101. package/lib/structure/io/binary/internals/EdgeSerializer.js +215 -0
  102. package/lib/structure/io/binary/internals/EnumSerializer.js +148 -0
  103. package/lib/structure/io/binary/internals/FloatSerializer.js +99 -0
  104. package/lib/structure/io/binary/internals/GraphBinaryReader.js +80 -0
  105. package/lib/structure/io/binary/internals/GraphBinaryWriter.js +83 -0
  106. package/lib/structure/io/binary/internals/IntSerializer.js +112 -0
  107. package/lib/structure/io/binary/internals/LambdaSerializer.js +70 -0
  108. package/lib/structure/io/binary/internals/LongSerializer.js +107 -0
  109. package/lib/structure/io/binary/internals/LongSerializerNg.js +102 -0
  110. package/lib/structure/io/binary/internals/MapSerializer.js +153 -0
  111. package/lib/structure/io/binary/internals/NumberSerializationStrategy.js +68 -0
  112. package/lib/structure/io/binary/internals/PSerializer.js +151 -0
  113. package/lib/structure/io/binary/internals/PathSerializer.js +123 -0
  114. package/lib/structure/io/binary/internals/PropertySerializer.js +141 -0
  115. package/lib/structure/io/binary/internals/ShortSerializer.js +99 -0
  116. package/lib/structure/io/binary/internals/StringSerializer.js +114 -0
  117. package/lib/structure/io/binary/internals/TextPSerializer.js +145 -0
  118. package/lib/structure/io/binary/internals/TraversalStrategySerializer.js +72 -0
  119. package/lib/structure/io/binary/internals/TraverserSerializer.js +123 -0
  120. package/lib/structure/io/binary/internals/UnspecifiedNullSerializer.js +75 -0
  121. package/lib/structure/io/binary/internals/UuidSerializer.js +119 -0
  122. package/lib/structure/io/binary/internals/VertexPropertySerializer.js +172 -0
  123. package/lib/structure/io/binary/internals/VertexSerializer.js +135 -0
  124. package/lib/structure/io/binary/internals/utils.js +59 -0
  125. package/lib/structure/io/graph-serializer.js +62 -16
  126. package/lib/structure/io/type-serializers.js +84 -87
  127. package/lib/utils.js +15 -10
  128. package/package.json +21 -8
@@ -4,14 +4,14 @@
4
4
  * distributed with this work for additional information
5
5
  * regarding copyright ownership. The ASF licenses this file
6
6
  * to you under the Apache License, Version 2.0 (the
7
- * "License"); you may not use this file except in compliance
7
+ * 'License'); you may not use this file except in compliance
8
8
  * with the License. You may obtain a copy of the License at
9
9
  *
10
10
  * http://www.apache.org/licenses/LICENSE-2.0
11
11
  *
12
12
  * Unless required by applicable law or agreed to in writing,
13
13
  * software distributed under the License is distributed on an
14
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
15
  * KIND, either express or implied. See the License for the
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
@@ -26,7 +26,6 @@ const Bytecode = require('../process/bytecode');
26
26
  * A {@link Client} contains methods to send messages to a Gremlin Server.
27
27
  */
28
28
  class Client {
29
-
30
29
  /**
31
30
  * Creates a new instance of {@link Client}.
32
31
  * @param {String} url The resource uri.
@@ -73,25 +72,35 @@ class Client {
73
72
  return this._connection.isOpen;
74
73
  }
75
74
 
75
+ /**
76
+ * Configuration specific to the current request.
77
+ * @typedef {Object} RequestOptions
78
+ * @property {String} requestId - User specified request identifier which must be a UUID.
79
+ * @property {Number} batchSize - Indicates whether the Power component is present.
80
+ * @property {String} userAgent - The size in which the result of a request is to be 'batched' back to the client
81
+ * @property {Number} evaluationTimeout - The timeout for the evaluation of the request.
82
+ */
83
+
76
84
  /**
77
85
  * Send a request to the Gremlin Server, can send a script or bytecode steps.
78
86
  * @param {Bytecode|string} message The bytecode or script to send
79
87
  * @param {Object} [bindings] The script bindings, if any.
80
- * @param {Object} [requestOptions] Configuration specific to the current request.
81
- * @param {String} [requestOptions.requestId] User specified request identifier which must be a UUID.
82
- * @param {Number} [requestOptions.batchSize] The size in which the result of a request is to be "batched" back to the client
83
- * @param {String} [requestOptions.userAgent] A custom string that specifies to the server where the request came from.
84
- * @param {Number} [requestOptions.evaluationTimeout] The timeout for the evaluation of the request.
88
+ * @param {RequestOptions} [requestOptions] Configuration specific to the current request.
85
89
  * @returns {Promise}
86
90
  */
87
91
  submit(message, bindings, requestOptions) {
88
- const requestIdOverride = requestOptions && requestOptions.requestId
89
- if (requestIdOverride) delete requestOptions['requestId'];
92
+ const requestIdOverride = requestOptions && requestOptions.requestId;
93
+ if (requestIdOverride) {
94
+ delete requestOptions['requestId'];
95
+ }
90
96
 
91
- const args = Object.assign({
92
- gremlin: message,
93
- aliases: { 'g': this._options.traversalSource || 'g' }
94
- }, requestOptions)
97
+ const args = Object.assign(
98
+ {
99
+ gremlin: message,
100
+ aliases: { g: this._options.traversalSource || 'g' },
101
+ },
102
+ requestOptions,
103
+ );
95
104
 
96
105
  if (this._options.session && this._options.processor === 'session') {
97
106
  args['session'] = this._options.session;
@@ -100,17 +109,54 @@ class Client {
100
109
  if (message instanceof Bytecode) {
101
110
  if (this._options.session && this._options.processor === 'session') {
102
111
  return this._connection.submit('session', 'bytecode', args, requestIdOverride);
103
- } else {
104
- return this._connection.submit('traversal', 'bytecode', args, requestIdOverride);
105
112
  }
113
+ return this._connection.submit('traversal', 'bytecode', args, requestIdOverride);
114
+ } else if (typeof message === 'string') {
115
+ args['bindings'] = bindings;
116
+ args['language'] = 'gremlin-groovy';
117
+ args['accept'] = this._connection.mimeType;
118
+ return this._connection.submit(this._options.processor || '', 'eval', args, requestIdOverride);
119
+ }
120
+ throw new TypeError('message must be of type Bytecode or string');
121
+ }
122
+
123
+ /**
124
+ * Send a request to the Gremlin Server and receive a stream for the results, can send a script or bytecode steps.
125
+ * @param {Bytecode|string} message The bytecode or script to send
126
+ * @param {Object} [bindings] The script bindings, if any.
127
+ * @param {RequestOptions} [requestOptions] Configuration specific to the current request.
128
+ * @returns {ReadableStream}
129
+ */
130
+ stream(message, bindings, requestOptions) {
131
+ const requestIdOverride = requestOptions && requestOptions.requestId;
132
+ if (requestIdOverride) {
133
+ delete requestOptions['requestId'];
134
+ }
135
+
136
+ const args = Object.assign(
137
+ {
138
+ gremlin: message,
139
+ aliases: { g: this._options.traversalSource || 'g' },
140
+ },
141
+ requestOptions,
142
+ );
143
+
144
+ if (this._options.session && this._options.processor === 'session') {
145
+ args['session'] = this._options.session;
146
+ }
147
+
148
+ if (message instanceof Bytecode) {
149
+ if (this._options.session && this._options.processor === 'session') {
150
+ return this._connection.stream('session', 'bytecode', args, requestIdOverride);
151
+ }
152
+ return this._connection.stream('traversal', 'bytecode', args, requestIdOverride);
106
153
  } else if (typeof message === 'string') {
107
154
  args['bindings'] = bindings;
108
155
  args['language'] = 'gremlin-groovy';
109
156
  args['accept'] = this._connection.mimeType;
110
- return this._connection.submit(this._options.processor || '','eval', args, requestIdOverride);
111
- } else {
112
- throw new TypeError("message must be of type Bytecode or string");
157
+ return this._connection.stream(this._options.processor || '', 'eval', args, requestIdOverride);
113
158
  }
159
+ throw new TypeError('message must be of type Bytecode or string');
114
160
  }
115
161
 
116
162
  /**
@@ -119,6 +165,10 @@ class Client {
119
165
  * @returns {Promise}
120
166
  */
121
167
  close() {
168
+ if (this._options.session && this._options.processor === 'session') {
169
+ const args = { session: this._options.session };
170
+ return this._connection.submit(this._options.processor, 'close', args, null).then(() => this._connection.close());
171
+ }
122
172
  return this._connection.close();
123
173
  }
124
174
 
@@ -128,7 +178,7 @@ class Client {
128
178
  * @param {Function} handler The callback to be called when the event occurs.
129
179
  */
130
180
  addListener(event, handler) {
131
- this._connection.on(event, handler)
181
+ this._connection.on(event, handler);
132
182
  }
133
183
 
134
184
  /**
@@ -137,7 +187,7 @@ class Client {
137
187
  * @param {Function} handler The event handler to be removed.
138
188
  */
139
189
  removeListener(event, handler) {
140
- this._connection.removeListener(event, handler)
190
+ this._connection.removeListener(event, handler);
141
191
  }
142
192
  }
143
193
 
@@ -23,23 +23,25 @@
23
23
  'use strict';
24
24
 
25
25
  const EventEmitter = require('events');
26
+ const Stream = require('stream');
26
27
  const WebSocket = require('ws');
27
28
  const util = require('util');
28
29
  const utils = require('../utils');
29
30
  const serializer = require('../structure/io/graph-serializer');
31
+ const { graphBinaryReader, graphBinaryWriter } = require('../structure/io/binary/GraphBinary');
30
32
  const ResultSet = require('./result-set');
31
33
  const ResponseError = require('./response-error');
32
- const Bytecode = require('../process/bytecode');
33
34
 
34
35
  const responseStatusCode = {
35
36
  success: 200,
36
37
  noContent: 204,
37
38
  partialContent: 206,
38
- authenticationChallenge: 407,
39
+ authenticationChallenge: 407,
39
40
  };
40
41
 
41
42
  const defaultMimeType = 'application/vnd.gremlin-v3.0+json';
42
43
  const graphSON2MimeType = 'application/vnd.gremlin-v2.0+json';
44
+ const graphBinaryMimeType = 'application/vnd.graphbinary-v1.0';
43
45
 
44
46
  const pingIntervalDelay = 60 * 1000;
45
47
  const pongTimeoutDelay = 30 * 1000;
@@ -48,7 +50,6 @@ const pongTimeoutDelay = 30 * 1000;
48
50
  * Represents a single connection to a Gremlin Server.
49
51
  */
50
52
  class Connection extends EventEmitter {
51
-
52
53
  /**
53
54
  * Creates a new instance of {@link Connection}.
54
55
  * @param {String} url The resource uri.
@@ -66,7 +67,7 @@ class Connection extends EventEmitter {
66
67
  * @param {Boolean} [options.pingEnabled] Setup ping interval. Defaults to: true.
67
68
  * @param {Number} [options.pingInterval] Ping request interval in ms if ping enabled. Defaults to: 60000.
68
69
  * @param {Number} [options.pongTimeout] Timeout of pong response in ms after sending a ping. Defaults to: 30000.
69
- * @param {Boolean} [options.connectOnStartup] Open websocket on startup. Defaults to: true.
70
+ * @param {Boolean} [options.connectOnStartup] Deprecated and non-functional. Open websocket on startup.
70
71
  * @constructor
71
72
  */
72
73
  constructor(url, options) {
@@ -92,7 +93,8 @@ class Connection extends EventEmitter {
92
93
  this._pingInterval = null;
93
94
  this._pongTimeout = null;
94
95
 
95
- this._header = String.fromCharCode(this.mimeType.length) + this.mimeType;
96
+ this._header = String.fromCharCode(this.mimeType.length) + this.mimeType; // TODO: what if mimeType.length > 255
97
+ this._header_buf = Buffer.from(this._header);
96
98
  this.isOpen = false;
97
99
  this.traversalSource = options.traversalSource || 'g';
98
100
  this._authenticator = options.authenticator;
@@ -101,8 +103,10 @@ class Connection extends EventEmitter {
101
103
  this._pingIntervalDelay = this.options.pingInterval || pingIntervalDelay;
102
104
  this._pongTimeoutDelay = this.options.pongTimeout || pongTimeoutDelay;
103
105
 
104
- if (this.options.connectOnStartup !== false) {
105
- this.open();
106
+ if (this.options.connectOnStartup) {
107
+ console.warn(
108
+ 'connectOnStartup is now deprecated and non-functional. To open a connection, please call open() after instantiating connection object.',
109
+ );
106
110
  }
107
111
  }
108
112
 
@@ -118,14 +122,14 @@ class Connection extends EventEmitter {
118
122
  return this._openPromise;
119
123
  }
120
124
 
121
- this.emit('log', `ws open`);
125
+ this.emit('log', 'ws open');
122
126
 
123
127
  this._ws = new WebSocket(this.url, {
124
128
  headers: this.options.headers,
125
129
  ca: this.options.ca,
126
130
  cert: this.options.cert,
127
131
  pfx: this.options.pfx,
128
- rejectUnauthorized: this.options.rejectUnauthorized
132
+ rejectUnauthorized: this.options.rejectUnauthorized,
129
133
  });
130
134
 
131
135
  this._ws.on('message', (data) => this._handleMessage(data));
@@ -143,7 +147,7 @@ class Connection extends EventEmitter {
143
147
  this._ws.pong();
144
148
  });
145
149
 
146
- return this._openPromise = new Promise((resolve, reject) => {
150
+ return (this._openPromise = new Promise((resolve, reject) => {
147
151
  this._ws.on('open', () => {
148
152
  this.isOpen = true;
149
153
  if (this._pingEnabled) {
@@ -155,59 +159,87 @@ class Connection extends EventEmitter {
155
159
  this._handleError(err);
156
160
  reject(err);
157
161
  });
158
- });
162
+ }));
159
163
  }
160
164
 
161
165
  /** @override */
162
166
  submit(processor, op, args, requestId) {
163
167
  const rid = requestId || utils.getUuid();
164
- return this.open().then(() => new Promise((resolve, reject) => {
165
- if (op !== 'authentication') {
166
- this._responseHandlers[rid] = {
167
- callback: (err, result) => err ? reject(err) : resolve(result),
168
- result: null
168
+ return this.open().then(
169
+ () =>
170
+ new Promise((resolve, reject) => {
171
+ if (op !== 'authentication') {
172
+ this._responseHandlers[rid] = {
173
+ callback: (err, result) => (err ? reject(err) : resolve(result)),
174
+ result: null,
175
+ };
176
+ }
177
+
178
+ const request = {
179
+ requestId: rid,
180
+ op: op || 'bytecode',
181
+ // if using op eval need to ensure processor stays unset if caller didn't set it.
182
+ processor: !processor && op !== 'eval' ? 'traversal' : processor,
183
+ args: args || {},
184
+ };
185
+
186
+ const request_buf = this._writer.writeRequest(request);
187
+ const message = Buffer.concat([this._header_buf, request_buf]);
188
+ this._ws.send(message);
189
+ }),
190
+ );
191
+ }
192
+
193
+ /** @override */
194
+ stream(processor, op, args, requestId) {
195
+ const rid = requestId || utils.getUuid();
196
+
197
+ const readableStream = new Stream.Readable({
198
+ objectMode: true,
199
+ read() {},
200
+ });
201
+
202
+ this._responseHandlers[rid] = {
203
+ callback: (err) => (err ? readableStream.destroy(err) : readableStream.push(null)),
204
+ result: readableStream,
205
+ };
206
+
207
+ this.open()
208
+ .then(() => {
209
+ const request = {
210
+ requestId: rid,
211
+ op: op || 'bytecode',
212
+ // if using op eval need to ensure processor stays unset if caller didn't set it.
213
+ processor: !processor && op !== 'eval' ? 'traversal' : processor,
214
+ args: args || {},
169
215
  };
170
- }
171
216
 
172
- const message = Buffer.from(this._header + JSON.stringify(this._getRequest(rid, op, args, processor)));
173
- this._ws.send(message);
174
- }));
217
+ const request_buf = this._writer.writeRequest(request);
218
+ const message = Buffer.concat([this._header_buf, request_buf]);
219
+ this._ws.send(message);
220
+ })
221
+ .catch((err) => readableStream.destroy(err));
222
+
223
+ return readableStream;
175
224
  }
176
225
 
177
226
  _getDefaultReader(mimeType) {
178
- return mimeType === graphSON2MimeType
179
- ? new serializer.GraphSON2Reader()
180
- : new serializer.GraphSONReader();
181
- }
227
+ if (mimeType === graphBinaryMimeType) {
228
+ return graphBinaryReader;
229
+ }
182
230
 
183
- _getDefaultWriter(mimeType) {
184
- return mimeType === graphSON2MimeType
185
- ? new serializer.GraphSON2Writer()
186
- : new serializer.GraphSONWriter();
231
+ return mimeType === graphSON2MimeType ? new serializer.GraphSON2Reader() : new serializer.GraphSONReader();
187
232
  }
188
233
 
189
- _getRequest(id, op, args, processor) {
190
- if (args) {
191
- args = this._adaptArgs(args, true);
192
- } else {
193
- args = {};
194
- }
195
-
196
- if (args['gremlin'] instanceof Bytecode) {
197
- args['gremlin'] = this._writer.adaptObject(args['gremlin']);
234
+ _getDefaultWriter(mimeType) {
235
+ if (mimeType === graphBinaryMimeType) {
236
+ return graphBinaryWriter;
198
237
  }
199
238
 
200
- return ({
201
- 'requestId': { '@type': 'g:UUID', '@value': id },
202
- 'op': op || 'bytecode',
203
- // if using op eval need to ensure processor stays unset if caller didn't set it.
204
- 'processor': (!processor && op !== 'eval') ? 'traversal' : processor,
205
- 'args': args
206
- });
239
+ return mimeType === graphSON2MimeType ? new serializer.GraphSON2Writer() : new serializer.GraphSONWriter();
207
240
  }
208
241
 
209
242
  _pingHeartbeat() {
210
-
211
243
  if (this._pingInterval) {
212
244
  clearInterval(this._pingInterval);
213
245
  this._pingInterval = null;
@@ -227,13 +259,12 @@ class Connection extends EventEmitter {
227
259
  }, this._pongTimeoutDelay);
228
260
 
229
261
  this._ws.ping();
230
-
231
262
  }, this._pingIntervalDelay);
232
263
  }
233
264
 
234
265
  _handleError(err) {
235
266
  this.emit('log', `ws error ${err}`);
236
- this._cleanupWebsocket();
267
+ this._cleanupWebsocket(err);
237
268
  this.emit('socketError', err);
238
269
  }
239
270
 
@@ -247,22 +278,30 @@ class Connection extends EventEmitter {
247
278
  }
248
279
 
249
280
  _handleMessage(data) {
250
- const response = this._reader.read(JSON.parse(data.toString()));
281
+ const response = this._reader.readResponse(data);
251
282
  if (response.requestId === null || response.requestId === undefined) {
252
283
  // There was a serialization issue on the server that prevented the parsing of the request id
253
284
  // We invoke any of the pending handlers with an error
254
- Object.keys(this._responseHandlers).forEach(requestId => {
285
+ Object.keys(this._responseHandlers).forEach((requestId) => {
255
286
  const handler = this._responseHandlers[requestId];
256
287
  this._clearHandler(requestId);
257
288
  if (response.status !== undefined && response.status.message) {
258
289
  return handler.callback(
259
290
  // TINKERPOP-2285: keep the old server error message in case folks are parsing that - fix in a future breaking version
260
- new ResponseError(util.format(
261
- 'Server error (no request information): %s (%d)', response.status.message, response.status.code), response.status));
262
- } else {
263
- // TINKERPOP-2285: keep the old server error message in case folks are parsing that - fix in a future breaking version
264
- return handler.callback(new ResponseError(util.format('Server error (no request information): %j', response), response.status));
291
+ new ResponseError(
292
+ util.format(
293
+ 'Server error (no request information): %s (%d)',
294
+ response.status.message,
295
+ response.status.code,
296
+ ),
297
+ response.status,
298
+ ),
299
+ );
265
300
  }
301
+ // TINKERPOP-2285: keep the old server error message in case folks are parsing that - fix in a future breaking version
302
+ return handler.callback(
303
+ new ResponseError(util.format('Server error (no request information): %j', response), response.status),
304
+ );
266
305
  });
267
306
  return;
268
307
  }
@@ -276,31 +315,49 @@ class Connection extends EventEmitter {
276
315
  }
277
316
 
278
317
  if (response.status.code === responseStatusCode.authenticationChallenge && this._authenticator) {
279
- this._authenticator.evaluateChallenge(response.result.data).then(res => {
280
- return this.submit(undefined, 'authentication', res, response.requestId);
281
- }).catch(handler.callback);
318
+ this._authenticator
319
+ .evaluateChallenge(response.result.data)
320
+ .then((res) => this.submit(undefined, 'authentication', res, response.requestId))
321
+ .catch(handler.callback);
282
322
 
283
323
  return;
284
- }
285
- else if (response.status.code >= 400) {
324
+ } else if (response.status.code >= 400) {
286
325
  // callback in error
287
326
  return handler.callback(
288
327
  // TINKERPOP-2285: keep the old server error message in case folks are parsing that - fix in a future breaking version
289
- new ResponseError(util.format('Server error: %s (%d)', response.status.message, response.status.code), response.status));
328
+ new ResponseError(
329
+ util.format('Server error: %s (%d)', response.status.message, response.status.code),
330
+ response.status,
331
+ ),
332
+ );
290
333
  }
334
+
335
+ const isStreamingResponse = handler.result instanceof Stream.Readable;
336
+
291
337
  switch (response.status.code) {
292
338
  case responseStatusCode.noContent:
293
339
  this._clearHandler(response.requestId);
340
+ if (isStreamingResponse) {
341
+ handler.result.push(new ResultSet(utils.emptyArray, response.status.attributes));
342
+ return handler.callback(null);
343
+ }
294
344
  return handler.callback(null, new ResultSet(utils.emptyArray, response.status.attributes));
295
345
  case responseStatusCode.partialContent:
346
+ if (isStreamingResponse) {
347
+ handler.result.push(new ResultSet(response.result.data, response.status.attributes));
348
+ break;
349
+ }
296
350
  handler.result = handler.result || [];
297
351
  handler.result.push.apply(handler.result, response.result.data);
298
352
  break;
299
353
  default:
354
+ if (isStreamingResponse) {
355
+ handler.result.push(new ResultSet(response.result.data, response.status.attributes));
356
+ return handler.callback(null);
357
+ }
300
358
  if (handler.result) {
301
359
  handler.result.push.apply(handler.result, response.result.data);
302
- }
303
- else {
360
+ } else {
304
361
  handler.result = response.result.data;
305
362
  }
306
363
  this._clearHandler(response.requestId);
@@ -311,7 +368,7 @@ class Connection extends EventEmitter {
311
368
  /**
312
369
  * clean websocket context
313
370
  */
314
- _cleanupWebsocket() {
371
+ _cleanupWebsocket(err) {
315
372
  if (this._pingInterval) {
316
373
  clearInterval(this._pingInterval);
317
374
  }
@@ -321,6 +378,17 @@ class Connection extends EventEmitter {
321
378
  }
322
379
  this._pongTimeout = null;
323
380
 
381
+ // Invoke waiting callbacks to complete Promises when closing the websocket
382
+ Object.keys(this._responseHandlers).forEach((requestId) => {
383
+ const handler = this._responseHandlers[requestId];
384
+ const isStreamingResponse = handler.result instanceof Stream.Readable;
385
+ if (isStreamingResponse) {
386
+ handler.callback(null);
387
+ } else {
388
+ const cause = err ? err : new Error('Connection has been closed.');
389
+ handler.callback(cause);
390
+ }
391
+ });
324
392
  this._ws.removeAllListeners();
325
393
  this._openPromise = null;
326
394
  this._closePromise = null;
@@ -336,32 +404,6 @@ class Connection extends EventEmitter {
336
404
  delete this._responseHandlers[requestId];
337
405
  }
338
406
 
339
- /**
340
- * Takes the given args map and ensures all arguments are passed through to _write.adaptObject
341
- * @param {Object} args Map of arguments to process.
342
- * @param {Boolean} protocolLevel Determines whether it's a protocol level binding.
343
- * @returns {Object}
344
- * @private
345
- */
346
- _adaptArgs(args, protocolLevel) {
347
- if (args instanceof Object) {
348
- let newObj = {};
349
- Object.keys(args).forEach((key) => {
350
- // bindings key (at the protocol-level needs special handling. without this, it wraps the generated Map
351
- // in another map for types like EnumValue. Could be a nicer way to do this but for now it's solving the
352
- // problem with script submission of non JSON native types
353
- if (protocolLevel && key === 'bindings')
354
- newObj[key] = this._adaptArgs(args[key], false);
355
- else
356
- newObj[key] = this._writer.adaptObject(args[key]);
357
- });
358
-
359
- return newObj;
360
- }
361
-
362
- return args;
363
- }
364
-
365
407
  /**
366
408
  * Closes the Connection.
367
409
  * @return {Promise}
@@ -371,7 +413,7 @@ class Connection extends EventEmitter {
371
413
  return Promise.resolve();
372
414
  }
373
415
  if (!this._closePromise) {
374
- this._closePromise = new Promise(resolve => {
416
+ this._closePromise = new Promise((resolve) => {
375
417
  this._closeCallback = resolve;
376
418
  this._ws.close();
377
419
  });
@@ -34,7 +34,6 @@ const OptionsStrategy = require('../process/traversal-strategy').OptionsStrategy
34
34
  * Represents the default {@link RemoteConnection} implementation.
35
35
  */
36
36
  class DriverRemoteConnection extends RemoteConnection {
37
-
38
37
  /**
39
38
  * Creates a new instance of {@link DriverRemoteConnection}.
40
39
  * @param {String} url The resource uri.
@@ -68,28 +67,30 @@ class DriverRemoteConnection extends RemoteConnection {
68
67
 
69
68
  /** @override */
70
69
  submit(bytecode) {
71
- let optionsStrategy = bytecode.sourceInstructions.find(
72
- i => i[0] === "withStrategies" && i[1] instanceof OptionsStrategy);
70
+ const optionsStrategy = bytecode.sourceInstructions.find(
71
+ (i) => i[0] === 'withStrategies' && i[1] instanceof OptionsStrategy,
72
+ );
73
73
  const allowedKeys = ['evaluationTimeout', 'scriptEvaluationTimeout', 'batchSize', 'requestId', 'userAgent'];
74
74
 
75
75
  let requestOptions = undefined;
76
76
  if (optionsStrategy !== undefined) {
77
77
  requestOptions = {};
78
78
  const conf = optionsStrategy[1].configuration;
79
- for (let key in conf) {
79
+ for (const key in conf) {
80
80
  if (conf.hasOwnProperty(key) && allowedKeys.indexOf(key) > -1) {
81
81
  requestOptions[key] = conf[key];
82
82
  }
83
83
  }
84
84
  }
85
85
 
86
- return this._client.submit(bytecode, null, requestOptions).then(result => new RemoteTraversal(result.toArray()));
86
+ return this._client.submit(bytecode, null, requestOptions).then((result) => new RemoteTraversal(result.toArray()));
87
87
  }
88
88
 
89
89
  /** @override */
90
90
  createSession() {
91
- if (this.isSessionBound)
92
- throw new Error("Connection is already bound to a session - child sessions are not allowed");
91
+ if (this.isSessionBound) {
92
+ throw new Error('Connection is already bound to a session - child sessions are not allowed');
93
+ }
93
94
 
94
95
  // make sure a fresh session is used when starting a new transaction
95
96
  const copiedOptions = Object.assign({}, this.options);
@@ -104,12 +105,12 @@ class DriverRemoteConnection extends RemoteConnection {
104
105
 
105
106
  /** @override */
106
107
  commit() {
107
- return this._client.submit(Bytecode.GraphOp.commit, null)
108
+ return this._client.submit(Bytecode.GraphOp.commit, null);
108
109
  }
109
110
 
110
111
  /** @override */
111
112
  rollback() {
112
- return this._client.submit(Bytecode.GraphOp.rollback, null)
113
+ return this._client.submit(Bytecode.GraphOp.rollback, null);
113
114
  }
114
115
 
115
116
  /** @override */
@@ -30,7 +30,6 @@ const TraversalStrategy = require('../process/traversal-strategy').TraversalStra
30
30
  * returning results.
31
31
  */
32
32
  class RemoteConnection {
33
-
34
33
  /**
35
34
  * @param {String} url The resource uri.
36
35
  * @param {Object} [options] The connection options.
@@ -73,7 +72,7 @@ class RemoteConnection {
73
72
  */
74
73
  submit(bytecode) {
75
74
  throw new Error('submit() must be implemented');
76
- };
75
+ }
77
76
 
78
77
  /**
79
78
  * Create a new <code>RemoteConnection</code> that is bound to a session using the configuration from this one.
@@ -128,7 +127,7 @@ class RemoteStrategy extends TraversalStrategy {
128
127
  // gave this a fqcn that has a local "js:" prefix since this strategy isn't sent as bytecode to the server.
129
128
  // this is a sort of local-only strategy that actually executes client side. not sure if this prefix is the
130
129
  // right way to name this or not, but it should have a name to identify it.
131
- super("js:RemoteStrategy");
130
+ super('js:RemoteStrategy');
132
131
  this.connection = connection;
133
132
  }
134
133
 
@@ -25,7 +25,7 @@
25
25
  class ResponseError extends Error {
26
26
  constructor(message, responseStatus) {
27
27
  super(message);
28
- this.name = "ResponseError";
28
+ this.name = 'ResponseError';
29
29
 
30
30
  /**
31
31
  * Gets the server status code.
@@ -44,4 +44,4 @@ class ResponseError extends Error {
44
44
  }
45
45
  }
46
46
 
47
- module.exports = ResponseError;
47
+ module.exports = ResponseError;
@@ -31,7 +31,6 @@ const emptyMap = Object.freeze(new utils.ImmutableMap());
31
31
  * Represents the response returned from the execution of a Gremlin traversal or script.
32
32
  */
33
33
  class ResultSet {
34
-
35
34
  /**
36
35
  * Creates a new instance of {@link ResultSet}.
37
36
  * @param {Array} items
@@ -90,4 +89,4 @@ class ResultSet {
90
89
  }
91
90
  }
92
91
 
93
- module.exports = ResultSet;
92
+ module.exports = ResultSet;
@@ -30,7 +30,6 @@ const Graph = require('../structure/graph').Graph;
30
30
  * instance or a <code>RemoteConnection</code>.
31
31
  */
32
32
  class AnonymousTraversalSource {
33
-
34
33
  /**
35
34
  * Creates a new instance of {@code AnonymousTraversalSource}.
36
35
  * @param {Function} [traversalSourceClass] Optional {@code GraphTraversalSource} constructor.
@@ -75,4 +74,4 @@ class AnonymousTraversalSource {
75
74
  }
76
75
  }
77
76
 
78
- module.exports = AnonymousTraversalSource;
77
+ module.exports = AnonymousTraversalSource;