gremlin 3.5.0 → 3.5.3

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 (91) hide show
  1. package/.eslintrc.js +154 -0
  2. package/.prettierrc.js +29 -0
  3. package/Gruntfile.js +15 -16
  4. package/NOTICE +1 -1
  5. package/doc/AnonymousTraversalSource.html +7 -7
  6. package/doc/Authenticator.html +3 -3
  7. package/doc/Bytecode.html +249 -5
  8. package/doc/Client.html +139 -65
  9. package/doc/Connection.html +90 -6
  10. package/doc/DriverRemoteConnection.html +380 -8
  11. package/doc/EdgeLabelVerificationStrategy.html +3 -3
  12. package/doc/Graph.html +2 -2
  13. package/doc/GraphSON2Reader.html +4 -4
  14. package/doc/GraphSON2Writer.html +3 -3
  15. package/doc/GraphSON3Reader.html +3 -3
  16. package/doc/GraphSON3Writer.html +3 -3
  17. package/doc/GraphTraversal.html +107 -107
  18. package/doc/GraphTraversalSource.html +130 -19
  19. package/doc/HaltedTraverserStrategy.html +3 -3
  20. package/doc/MatchAlgorithmStrategy.html +3 -3
  21. package/doc/P.html +13 -13
  22. package/doc/PartitionStrategy.html +3 -3
  23. package/doc/Path.html +2 -2
  24. package/doc/PlainTextSaslAuthenticator.html +2 -2
  25. package/doc/ProductiveByStrategy.html +288 -0
  26. package/doc/RemoteConnection.html +484 -10
  27. package/doc/RemoteStrategy.html +4 -4
  28. package/doc/RemoteTraversal.html +3 -3
  29. package/doc/ReservedKeysVerificationStrategy.html +3 -3
  30. package/doc/ResponseError.html +3 -3
  31. package/doc/ResultSet.html +8 -8
  32. package/doc/SaslAuthenticator.html +2 -2
  33. package/doc/SaslMechanismBase.html +3 -3
  34. package/doc/SaslMechanismPlain.html +6 -6
  35. package/doc/{GraphSONReader.html → SeedStrategy.html} +12 -15
  36. package/doc/SubgraphStrategy.html +3 -3
  37. package/doc/TextP.html +10 -10
  38. package/doc/Transaction.html +655 -0
  39. package/doc/Translator.html +200 -6
  40. package/doc/TraversalStrategies.html +137 -4
  41. package/doc/TraversalStrategy.html +4 -4
  42. package/doc/TypeSerializer.html +2 -2
  43. package/doc/driver_auth_authenticator.js.html +4 -4
  44. package/doc/driver_auth_mechanisms_sasl-mechanism-base.js.html +3 -3
  45. package/doc/driver_auth_mechanisms_sasl-mechanism-plain.js.html +26 -17
  46. package/doc/driver_auth_plain-text-sasl-authenticator.js.html +7 -7
  47. package/doc/driver_auth_sasl-authenticator.js.html +3 -3
  48. package/doc/driver_client.js.html +75 -25
  49. package/doc/driver_connection.js.html +108 -89
  50. package/doc/driver_driver-remote-connection.js.html +40 -9
  51. package/doc/driver_remote-connection.js.html +47 -6
  52. package/doc/driver_response-error.js.html +5 -4
  53. package/doc/driver_result-set.js.html +4 -4
  54. package/doc/global.html +200 -3
  55. package/doc/index.html +2 -2
  56. package/doc/process_anonymous-traversal.js.html +5 -5
  57. package/doc/process_bytecode.js.html +32 -7
  58. package/doc/process_graph-traversal.js.html +213 -143
  59. package/doc/process_transaction.js.html +143 -0
  60. package/doc/process_translator.js.html +58 -39
  61. package/doc/process_traversal-strategy.js.html +79 -52
  62. package/doc/process_traversal.js.html +101 -108
  63. package/doc/structure_graph.js.html +7 -7
  64. package/doc/structure_io_graph-serializer.js.html +65 -18
  65. package/doc/structure_io_type-serializers.js.html +86 -89
  66. package/index.js +5 -5
  67. package/lib/driver/auth/authenticator.js +2 -2
  68. package/lib/driver/auth/mechanisms/sasl-mechanism-base.js +1 -1
  69. package/lib/driver/auth/mechanisms/sasl-mechanism-plain.js +24 -15
  70. package/lib/driver/auth/plain-text-sasl-authenticator.js +5 -5
  71. package/lib/driver/auth/sasl-authenticator.js +1 -1
  72. package/lib/driver/client.js +73 -23
  73. package/lib/driver/connection.js +106 -87
  74. package/lib/driver/driver-remote-connection.js +38 -7
  75. package/lib/driver/remote-connection.js +45 -4
  76. package/lib/driver/response-error.js +2 -2
  77. package/lib/driver/result-set.js +1 -2
  78. package/lib/process/anonymous-traversal.js +2 -3
  79. package/lib/process/bytecode.js +30 -5
  80. package/lib/process/graph-traversal.js +210 -141
  81. package/lib/process/transaction.js +92 -0
  82. package/lib/process/translator.js +55 -37
  83. package/lib/process/traversal-strategy.js +76 -50
  84. package/lib/process/traversal.js +99 -106
  85. package/lib/structure/graph.js +5 -5
  86. package/lib/structure/io/graph-serializer.js +62 -16
  87. package/lib/structure/io/type-serializers.js +84 -87
  88. package/lib/utils.js +15 -10
  89. package/package.json +11 -5
  90. package/doc/GraphSONWriter.html +0 -436
  91. package/gremlin-javascript.iml +0 -9
package/index.js CHANGED
@@ -50,8 +50,8 @@ module.exports = {
50
50
  ResultSet,
51
51
  auth: {
52
52
  Authenticator,
53
- PlainTextSaslAuthenticator
54
- }
53
+ PlainTextSaslAuthenticator,
54
+ },
55
55
  },
56
56
  process: {
57
57
  Bytecode,
@@ -79,7 +79,7 @@ module.exports = {
79
79
  Translator,
80
80
  traversal: AnonymousTraversalSource.traversal,
81
81
  AnonymousTraversalSource,
82
- withOptions: t.withOptions
82
+ withOptions: t.withOptions,
83
83
  },
84
84
  structure: {
85
85
  io: gs,
@@ -89,6 +89,6 @@ module.exports = {
89
89
  Property: graph.Property,
90
90
  Vertex: graph.Vertex,
91
91
  VertexProperty: graph.VertexProperty,
92
- toLong: utils.toLong
93
- }
92
+ toLong: utils.toLong,
93
+ },
94
94
  };
@@ -24,14 +24,14 @@ class Authenticator {
24
24
  constructor(options) {
25
25
  this._options = options;
26
26
  }
27
-
27
+
28
28
  /**
29
29
  * @abstract
30
30
  * Evaluates the challenge from the server and returns appropriate response.
31
31
  * @param {String} challenge Challenge string presented by the server.
32
32
  */
33
33
  evaluateChallenge(challenge) {
34
- throw new Error("evaluateChallenge should be implemented");
34
+ throw new Error('evaluateChallenge should be implemented');
35
35
  }
36
36
  }
37
37
 
@@ -45,7 +45,7 @@ class SaslMechanismBase {
45
45
  * @param {String} challenge Challenge string presented by the server
46
46
  */
47
47
  evaluateChallenge(challenge) {
48
- throw new Error("evaluateChallenge should be implemented");
48
+ throw new Error('evaluateChallenge should be implemented');
49
49
  }
50
50
  }
51
51
 
@@ -32,12 +32,13 @@ class SaslMechanismPlain extends SaslMechanismBase {
32
32
  constructor(options) {
33
33
  super(options);
34
34
 
35
- if (this._options.username === undefined
36
- || this._options.username === null
37
- || this._options.username.length == 0
38
- || this._options.password === undefined
39
- || this._options.password === null
40
- || this._options.password.length == 0
35
+ if (
36
+ this._options.username === undefined ||
37
+ this._options.username === null ||
38
+ this._options.username.length === 0 ||
39
+ this._options.password === undefined ||
40
+ this._options.password === null ||
41
+ this._options.password.length === 0
41
42
  ) {
42
43
  throw new Error('Missing credentials for SASL PLAIN mechanism');
43
44
  }
@@ -49,7 +50,7 @@ class SaslMechanismPlain extends SaslMechanismBase {
49
50
  get name() {
50
51
  return 'PLAIN';
51
52
  }
52
-
53
+
53
54
  /**
54
55
  * Evaluates the challenge from the server and returns appropriate response.
55
56
  * @param {String} challenge Challenge string presented by the server.
@@ -58,12 +59,14 @@ class SaslMechanismPlain extends SaslMechanismBase {
58
59
  evaluateChallenge(challenge) {
59
60
  if (this._hasInitialResponse(challenge)) {
60
61
  return Promise.resolve({
61
- 'saslMechanism': this.name,
62
- 'sasl': this._saslArgument(this._options.authzid, this._options.username, this._options.password)
62
+ saslMechanism: this.name,
63
+ sasl: this._saslArgument(this._options.authzid, this._options.username, this._options.password),
63
64
  });
64
65
  }
65
-
66
- return Promise.resolve({ 'sasl': this._saslArgument(this._options.authzid, this._options.username, this._options.password) });
66
+
67
+ return Promise.resolve({
68
+ sasl: this._saslArgument(this._options.authzid, this._options.username, this._options.password),
69
+ });
67
70
  }
68
71
 
69
72
  /**
@@ -73,11 +76,17 @@ class SaslMechanismPlain extends SaslMechanismBase {
73
76
  * @param {String} password The password of user with access to server.
74
77
  */
75
78
  _saslArgument(authzid, username, password) {
76
- if (authzid === undefined || authzid === null) authzid = '';
77
- if (username === undefined || username === null) username = '';
78
- if (password === undefined || password.length === null) password = '';
79
+ if (authzid === undefined || authzid === null) {
80
+ authzid = '';
81
+ }
82
+ if (username === undefined || username === null) {
83
+ username = '';
84
+ }
85
+ if (password === undefined || password.length === null) {
86
+ password = '';
87
+ }
79
88
 
80
- return new Buffer(`${authzid}\0${username}\0${password}`).toString('base64');
89
+ return Buffer.from(`${authzid}\0${username}\0${password}`).toString('base64');
81
90
  }
82
91
 
83
92
  /**
@@ -33,15 +33,15 @@ class PlainTextSaslAuthenticator extends Authenticator {
33
33
  constructor(username, password, authzid) {
34
34
  const options = {
35
35
  mechanism: new SaslMechanismPlain({
36
- 'username': username,
37
- 'password': password,
38
- 'authzid': authzid
39
- })
36
+ username: username,
37
+ password: password,
38
+ authzid: authzid,
39
+ }),
40
40
  };
41
41
 
42
42
  super(options);
43
43
  }
44
-
44
+
45
45
  /**
46
46
  * Evaluates the challenge from the server and returns appropriate response.
47
47
  * @param {String} challenge Challenge string presented by the server.
@@ -35,7 +35,7 @@ class SaslAuthenticator extends Authenticator {
35
35
  throw new Error('No Sasl Mechanism Specified');
36
36
  }
37
37
  }
38
-
38
+
39
39
  /**
40
40
  * Evaluates the challenge from the server and returns appropriate response.
41
41
  * @param {String} challenge Challenge string presented by the server.
@@ -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.
@@ -48,7 +47,7 @@ class Client {
48
47
  this._options = options;
49
48
  if (this._options.processor === 'session') {
50
49
  // compatibility with old 'session' processor setting
51
- this._options.session = options.session || utils.getUuid()
50
+ this._options.session = options.session || utils.getUuid();
52
51
  }
53
52
  if (this._options.session) {
54
53
  // re-assign processor to 'session' when in session mode
@@ -73,40 +72,91 @@ 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
+ }
96
+
97
+ const args = Object.assign(
98
+ {
99
+ gremlin: message,
100
+ aliases: { g: this._options.traversalSource || 'g' },
101
+ },
102
+ requestOptions,
103
+ );
90
104
 
91
- const args = Object.assign({
92
- gremlin: message,
93
- aliases: { 'g': this._options.traversalSource || 'g' }
94
- }, requestOptions)
105
+ if (this._options.session && this._options.processor === 'session') {
106
+ args['session'] = this._options.session;
107
+ }
95
108
 
96
109
  if (message instanceof Bytecode) {
97
- return this._connection.submit('traversal','bytecode', args, requestIdOverride);
110
+ if (this._options.session && this._options.processor === 'session') {
111
+ return this._connection.submit('session', 'bytecode', args, requestIdOverride);
112
+ }
113
+ return this._connection.submit('traversal', 'bytecode', args, requestIdOverride);
98
114
  } else if (typeof message === 'string') {
99
115
  args['bindings'] = bindings;
100
116
  args['language'] = 'gremlin-groovy';
101
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
+ }
102
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) {
103
149
  if (this._options.session && this._options.processor === 'session') {
104
- args['session'] = this._options.session;
150
+ return this._connection.stream('session', 'bytecode', args, requestIdOverride);
105
151
  }
106
- return this._connection.submit(this._options.processor || '','eval', args, requestIdOverride);
107
- } else {
108
- throw new TypeError("message must be of type Bytecode or string");
152
+ return this._connection.stream('traversal', 'bytecode', args, requestIdOverride);
153
+ } else if (typeof message === 'string') {
154
+ args['bindings'] = bindings;
155
+ args['language'] = 'gremlin-groovy';
156
+ args['accept'] = this._connection.mimeType;
157
+ return this._connection.stream(this._options.processor || '', 'eval', args, requestIdOverride);
109
158
  }
159
+ throw new TypeError('message must be of type Bytecode or string');
110
160
  }
111
161
 
112
162
  /**
@@ -116,7 +166,7 @@ class Client {
116
166
  */
117
167
  close() {
118
168
  if (this._options.session && this._options.processor === 'session') {
119
- const args = {'session': this._options.session};
169
+ const args = { session: this._options.session };
120
170
  return this._connection.submit(this._options.processor, 'close', args, null).then(() => this._connection.close());
121
171
  }
122
172
  return this._connection.close();
@@ -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,19 +23,19 @@
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');
30
31
  const ResultSet = require('./result-set');
31
32
  const ResponseError = require('./response-error');
32
- const Bytecode = require('../process/bytecode');
33
33
 
34
34
  const responseStatusCode = {
35
35
  success: 200,
36
36
  noContent: 204,
37
37
  partialContent: 206,
38
- authenticationChallenge: 407,
38
+ authenticationChallenge: 407,
39
39
  };
40
40
 
41
41
  const defaultMimeType = 'application/vnd.gremlin-v3.0+json';
@@ -48,7 +48,6 @@ const pongTimeoutDelay = 30 * 1000;
48
48
  * Represents a single connection to a Gremlin Server.
49
49
  */
50
50
  class Connection extends EventEmitter {
51
-
52
51
  /**
53
52
  * Creates a new instance of {@link Connection}.
54
53
  * @param {String} url The resource uri.
@@ -92,7 +91,8 @@ class Connection extends EventEmitter {
92
91
  this._pingInterval = null;
93
92
  this._pongTimeout = null;
94
93
 
95
- this._header = String.fromCharCode(this.mimeType.length) + this.mimeType;
94
+ this._header = String.fromCharCode(this.mimeType.length) + this.mimeType; // TODO: what if mimeType.length > 255
95
+ this._header_buf = Buffer.from(this._header);
96
96
  this.isOpen = false;
97
97
  this.traversalSource = options.traversalSource || 'g';
98
98
  this._authenticator = options.authenticator;
@@ -118,14 +118,14 @@ class Connection extends EventEmitter {
118
118
  return this._openPromise;
119
119
  }
120
120
 
121
- this.emit('log', `ws open`);
121
+ this.emit('log', 'ws open');
122
122
 
123
123
  this._ws = new WebSocket(this.url, {
124
124
  headers: this.options.headers,
125
125
  ca: this.options.ca,
126
126
  cert: this.options.cert,
127
127
  pfx: this.options.pfx,
128
- rejectUnauthorized: this.options.rejectUnauthorized
128
+ rejectUnauthorized: this.options.rejectUnauthorized,
129
129
  });
130
130
 
131
131
  this._ws.on('message', (data) => this._handleMessage(data));
@@ -143,7 +143,7 @@ class Connection extends EventEmitter {
143
143
  this._ws.pong();
144
144
  });
145
145
 
146
- return this._openPromise = new Promise((resolve, reject) => {
146
+ return (this._openPromise = new Promise((resolve, reject) => {
147
147
  this._ws.on('open', () => {
148
148
  this.isOpen = true;
149
149
  if (this._pingEnabled) {
@@ -155,59 +155,79 @@ class Connection extends EventEmitter {
155
155
  this._handleError(err);
156
156
  reject(err);
157
157
  });
158
- });
158
+ }));
159
159
  }
160
160
 
161
161
  /** @override */
162
162
  submit(processor, op, args, requestId) {
163
163
  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
164
+ return this.open().then(
165
+ () =>
166
+ new Promise((resolve, reject) => {
167
+ if (op !== 'authentication') {
168
+ this._responseHandlers[rid] = {
169
+ callback: (err, result) => (err ? reject(err) : resolve(result)),
170
+ result: null,
171
+ };
172
+ }
173
+
174
+ const request = {
175
+ requestId: rid,
176
+ op: op || 'bytecode',
177
+ // if using op eval need to ensure processor stays unset if caller didn't set it.
178
+ processor: !processor && op !== 'eval' ? 'traversal' : processor,
179
+ args: args || {},
180
+ };
181
+
182
+ const request_buf = this._writer.writeRequest(request);
183
+ const message = Buffer.concat([this._header_buf, request_buf], this._header_buf.length + request_buf.length);
184
+ this._ws.send(message);
185
+ }),
186
+ );
187
+ }
188
+
189
+ /** @override */
190
+ stream(processor, op, args, requestId) {
191
+ const rid = requestId || utils.getUuid();
192
+
193
+ const readableStream = new Stream.Readable({
194
+ objectMode: true,
195
+ read() {},
196
+ });
197
+
198
+ this._responseHandlers[rid] = {
199
+ callback: (err) => (err ? readableStream.destroy(err) : readableStream.push(null)),
200
+ result: readableStream,
201
+ };
202
+
203
+ this.open()
204
+ .then(() => {
205
+ const request = {
206
+ requestId: rid,
207
+ op: op || 'bytecode',
208
+ // if using op eval need to ensure processor stays unset if caller didn't set it.
209
+ processor: !processor && op !== 'eval' ? 'traversal' : processor,
210
+ args: args || {},
169
211
  };
170
- }
171
212
 
172
- const message = Buffer.from(this._header + JSON.stringify(this._getRequest(rid, op, args, processor)));
173
- this._ws.send(message);
174
- }));
213
+ const request_buf = this._writer.writeRequest(request);
214
+ const message = Buffer.concat([this._header_buf, request_buf], this._header_buf.length + request_buf.length);
215
+ this._ws.send(message);
216
+ })
217
+ .catch((err) => readableStream.destroy(err));
218
+
219
+ return readableStream;
175
220
  }
176
221
 
177
222
  _getDefaultReader(mimeType) {
178
- return mimeType === graphSON2MimeType
179
- ? new serializer.GraphSON2Reader()
180
- : new serializer.GraphSONReader();
223
+ return mimeType === graphSON2MimeType ? new serializer.GraphSON2Reader() : new serializer.GraphSONReader();
181
224
  }
182
225
 
183
226
  _getDefaultWriter(mimeType) {
184
- return mimeType === graphSON2MimeType
185
- ? new serializer.GraphSON2Writer()
186
- : new serializer.GraphSONWriter();
187
- }
188
-
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']);
198
- }
199
-
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
- });
227
+ return mimeType === graphSON2MimeType ? new serializer.GraphSON2Writer() : new serializer.GraphSONWriter();
207
228
  }
208
229
 
209
230
  _pingHeartbeat() {
210
-
211
231
  if (this._pingInterval) {
212
232
  clearInterval(this._pingInterval);
213
233
  this._pingInterval = null;
@@ -227,7 +247,6 @@ class Connection extends EventEmitter {
227
247
  }, this._pongTimeoutDelay);
228
248
 
229
249
  this._ws.ping();
230
-
231
250
  }, this._pingIntervalDelay);
232
251
  }
233
252
 
@@ -247,22 +266,30 @@ class Connection extends EventEmitter {
247
266
  }
248
267
 
249
268
  _handleMessage(data) {
250
- const response = this._reader.read(JSON.parse(data.toString()));
269
+ const response = this._reader.readResponse(data);
251
270
  if (response.requestId === null || response.requestId === undefined) {
252
271
  // There was a serialization issue on the server that prevented the parsing of the request id
253
272
  // We invoke any of the pending handlers with an error
254
- Object.keys(this._responseHandlers).forEach(requestId => {
273
+ Object.keys(this._responseHandlers).forEach((requestId) => {
255
274
  const handler = this._responseHandlers[requestId];
256
275
  this._clearHandler(requestId);
257
276
  if (response.status !== undefined && response.status.message) {
258
277
  return handler.callback(
259
278
  // 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));
279
+ new ResponseError(
280
+ util.format(
281
+ 'Server error (no request information): %s (%d)',
282
+ response.status.message,
283
+ response.status.code,
284
+ ),
285
+ response.status,
286
+ ),
287
+ );
265
288
  }
289
+ // TINKERPOP-2285: keep the old server error message in case folks are parsing that - fix in a future breaking version
290
+ return handler.callback(
291
+ new ResponseError(util.format('Server error (no request information): %j', response), response.status),
292
+ );
266
293
  });
267
294
  return;
268
295
  }
@@ -276,31 +303,49 @@ class Connection extends EventEmitter {
276
303
  }
277
304
 
278
305
  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);
306
+ this._authenticator
307
+ .evaluateChallenge(response.result.data)
308
+ .then((res) => this.submit(undefined, 'authentication', res, response.requestId))
309
+ .catch(handler.callback);
282
310
 
283
311
  return;
284
- }
285
- else if (response.status.code >= 400) {
312
+ } else if (response.status.code >= 400) {
286
313
  // callback in error
287
314
  return handler.callback(
288
315
  // 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));
316
+ new ResponseError(
317
+ util.format('Server error: %s (%d)', response.status.message, response.status.code),
318
+ response.status,
319
+ ),
320
+ );
290
321
  }
322
+
323
+ const isStreamingResponse = handler.result instanceof Stream.Readable;
324
+
291
325
  switch (response.status.code) {
292
326
  case responseStatusCode.noContent:
293
327
  this._clearHandler(response.requestId);
328
+ if (isStreamingResponse) {
329
+ handler.result.push(new ResultSet(utils.emptyArray, response.status.attributes));
330
+ return handler.callback(null);
331
+ }
294
332
  return handler.callback(null, new ResultSet(utils.emptyArray, response.status.attributes));
295
333
  case responseStatusCode.partialContent:
334
+ if (isStreamingResponse) {
335
+ handler.result.push(new ResultSet(response.result.data, response.status.attributes));
336
+ break;
337
+ }
296
338
  handler.result = handler.result || [];
297
339
  handler.result.push.apply(handler.result, response.result.data);
298
340
  break;
299
341
  default:
342
+ if (isStreamingResponse) {
343
+ handler.result.push(new ResultSet(response.result.data, response.status.attributes));
344
+ return handler.callback(null);
345
+ }
300
346
  if (handler.result) {
301
347
  handler.result.push.apply(handler.result, response.result.data);
302
- }
303
- else {
348
+ } else {
304
349
  handler.result = response.result.data;
305
350
  }
306
351
  this._clearHandler(response.requestId);
@@ -336,32 +381,6 @@ class Connection extends EventEmitter {
336
381
  delete this._responseHandlers[requestId];
337
382
  }
338
383
 
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
384
  /**
366
385
  * Closes the Connection.
367
386
  * @return {Promise}
@@ -371,7 +390,7 @@ class Connection extends EventEmitter {
371
390
  return Promise.resolve();
372
391
  }
373
392
  if (!this._closePromise) {
374
- this._closePromise = new Promise(resolve => {
393
+ this._closePromise = new Promise((resolve) => {
375
394
  this._closeCallback = resolve;
376
395
  this._ws.close();
377
396
  });