gremlin 3.5.2 → 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.
- package/.eslintrc.js +154 -0
- package/.prettierrc.js +29 -0
- package/Gruntfile.js +15 -16
- package/doc/AnonymousTraversalSource.html +4 -4
- package/doc/Authenticator.html +1 -1
- package/doc/Bytecode.html +6 -6
- package/doc/Client.html +137 -63
- package/doc/Connection.html +88 -4
- package/doc/DriverRemoteConnection.html +10 -10
- package/doc/EdgeLabelVerificationStrategy.html +1 -1
- package/doc/Graph.html +1 -1
- package/doc/GraphSON2Reader.html +3 -3
- package/doc/GraphSON2Writer.html +2 -2
- package/doc/GraphSON3Reader.html +2 -2
- package/doc/GraphSON3Writer.html +2 -2
- package/doc/GraphTraversal.html +106 -106
- package/doc/GraphTraversalSource.html +18 -18
- package/doc/HaltedTraverserStrategy.html +2 -2
- package/doc/MatchAlgorithmStrategy.html +2 -2
- package/doc/P.html +12 -12
- package/doc/PartitionStrategy.html +2 -2
- package/doc/Path.html +1 -1
- package/doc/PlainTextSaslAuthenticator.html +1 -1
- package/doc/ProductiveByStrategy.html +1 -1
- package/doc/RemoteConnection.html +9 -9
- package/doc/RemoteStrategy.html +3 -3
- package/doc/RemoteTraversal.html +2 -2
- package/doc/ReservedKeysVerificationStrategy.html +2 -2
- package/doc/ResponseError.html +1 -1
- package/doc/ResultSet.html +6 -6
- package/doc/SaslAuthenticator.html +1 -1
- package/doc/SaslMechanismBase.html +1 -1
- package/doc/SaslMechanismPlain.html +5 -5
- package/doc/SeedStrategy.html +2 -2
- package/doc/SubgraphStrategy.html +2 -2
- package/doc/TextP.html +9 -9
- package/doc/Transaction.html +5 -5
- package/doc/Translator.html +1 -1
- package/doc/TraversalStrategies.html +4 -4
- package/doc/TraversalStrategy.html +2 -2
- package/doc/TypeSerializer.html +1 -1
- package/doc/driver_auth_authenticator.js.html +3 -3
- package/doc/driver_auth_mechanisms_sasl-mechanism-base.js.html +2 -2
- package/doc/driver_auth_mechanisms_sasl-mechanism-plain.js.html +25 -16
- package/doc/driver_auth_plain-text-sasl-authenticator.js.html +6 -6
- package/doc/driver_auth_sasl-authenticator.js.html +2 -2
- package/doc/driver_client.js.html +69 -23
- package/doc/driver_connection.js.html +107 -88
- package/doc/driver_driver-remote-connection.js.html +11 -10
- package/doc/driver_remote-connection.js.html +3 -4
- package/doc/driver_response-error.js.html +4 -3
- package/doc/driver_result-set.js.html +3 -3
- package/doc/global.html +199 -2
- package/doc/index.html +1 -1
- package/doc/process_anonymous-traversal.js.html +3 -3
- package/doc/process_bytecode.js.html +10 -8
- package/doc/process_graph-traversal.js.html +193 -142
- package/doc/process_transaction.js.html +15 -8
- package/doc/process_translator.js.html +13 -10
- package/doc/process_traversal-strategy.js.html +59 -53
- package/doc/process_traversal.js.html +100 -107
- package/doc/structure_graph.js.html +6 -6
- package/doc/structure_io_graph-serializer.js.html +64 -17
- package/doc/structure_io_type-serializers.js.html +85 -88
- package/index.js +5 -5
- package/lib/driver/auth/authenticator.js +2 -2
- package/lib/driver/auth/mechanisms/sasl-mechanism-base.js +1 -1
- package/lib/driver/auth/mechanisms/sasl-mechanism-plain.js +24 -15
- package/lib/driver/auth/plain-text-sasl-authenticator.js +5 -5
- package/lib/driver/auth/sasl-authenticator.js +1 -1
- package/lib/driver/client.js +68 -22
- package/lib/driver/connection.js +106 -87
- package/lib/driver/driver-remote-connection.js +10 -9
- package/lib/driver/remote-connection.js +2 -3
- package/lib/driver/response-error.js +2 -2
- package/lib/driver/result-set.js +1 -2
- package/lib/process/anonymous-traversal.js +1 -2
- package/lib/process/bytecode.js +9 -7
- package/lib/process/graph-traversal.js +191 -141
- package/lib/process/transaction.js +13 -7
- package/lib/process/translator.js +11 -9
- package/lib/process/traversal-strategy.js +57 -52
- package/lib/process/traversal.js +99 -106
- package/lib/structure/graph.js +5 -5
- package/lib/structure/io/graph-serializer.js +62 -16
- package/lib/structure/io/type-serializers.js +84 -87
- package/lib/utils.js +15 -10
- package/package.json +10 -5
package/lib/driver/client.js
CHANGED
|
@@ -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
|
-
*
|
|
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
|
-
*
|
|
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 {
|
|
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)
|
|
92
|
+
const requestIdOverride = requestOptions && requestOptions.requestId;
|
|
93
|
+
if (requestIdOverride) {
|
|
94
|
+
delete requestOptions['requestId'];
|
|
95
|
+
}
|
|
90
96
|
|
|
91
|
-
const args = Object.assign(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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.
|
|
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
|
/**
|
|
@@ -120,7 +166,7 @@ class Client {
|
|
|
120
166
|
*/
|
|
121
167
|
close() {
|
|
122
168
|
if (this._options.session && this._options.processor === 'session') {
|
|
123
|
-
const args = {
|
|
169
|
+
const args = { session: this._options.session };
|
|
124
170
|
return this._connection.submit(this._options.processor, 'close', args, null).then(() => this._connection.close());
|
|
125
171
|
}
|
|
126
172
|
return this._connection.close();
|
|
@@ -132,7 +178,7 @@ class Client {
|
|
|
132
178
|
* @param {Function} handler The callback to be called when the event occurs.
|
|
133
179
|
*/
|
|
134
180
|
addListener(event, handler) {
|
|
135
|
-
this._connection.on(event, handler)
|
|
181
|
+
this._connection.on(event, handler);
|
|
136
182
|
}
|
|
137
183
|
|
|
138
184
|
/**
|
|
@@ -141,7 +187,7 @@ class Client {
|
|
|
141
187
|
* @param {Function} handler The event handler to be removed.
|
|
142
188
|
*/
|
|
143
189
|
removeListener(event, handler) {
|
|
144
|
-
this._connection.removeListener(event, handler)
|
|
190
|
+
this._connection.removeListener(event, handler);
|
|
145
191
|
}
|
|
146
192
|
}
|
|
147
193
|
|
package/lib/driver/connection.js
CHANGED
|
@@ -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:
|
|
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',
|
|
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(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
173
|
-
|
|
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.
|
|
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(
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
|
|
280
|
-
|
|
281
|
-
|
|
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(
|
|
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
|
});
|
|
@@ -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
|
-
|
|
72
|
-
|
|
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 (
|
|
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(
|
|
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(
|
|
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 =
|
|
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;
|
package/lib/driver/result-set.js
CHANGED
|
@@ -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;
|
package/lib/process/bytecode.js
CHANGED
|
@@ -33,8 +33,7 @@ class Bytecode {
|
|
|
33
33
|
if (!toClone) {
|
|
34
34
|
this.sourceInstructions = [];
|
|
35
35
|
this.stepInstructions = [];
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
36
|
+
} else {
|
|
38
37
|
this.sourceInstructions = [...toClone.sourceInstructions];
|
|
39
38
|
this.stepInstructions = [...toClone.stepInstructions];
|
|
40
39
|
}
|
|
@@ -79,9 +78,12 @@ class Bytecode {
|
|
|
79
78
|
instruction[0] = name;
|
|
80
79
|
for (let i = 1; i < length; i++) {
|
|
81
80
|
const val = values[i - 1];
|
|
82
|
-
if (val instanceof Traversal && val.graph != null)
|
|
83
|
-
throw new Error(
|
|
84
|
-
|
|
81
|
+
if (val instanceof Traversal && val.graph != null) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`The child traversal of ${val} was not spawned anonymously - use ` +
|
|
84
|
+
'the __ class rather than a TraversalSource to construct the child traversal',
|
|
85
|
+
);
|
|
86
|
+
}
|
|
85
87
|
instruction[i] = val;
|
|
86
88
|
}
|
|
87
89
|
return instruction;
|
|
@@ -113,8 +115,8 @@ class Bytecode {
|
|
|
113
115
|
*/
|
|
114
116
|
static get GraphOp() {
|
|
115
117
|
return {
|
|
116
|
-
commit: Bytecode._createGraphOp(
|
|
117
|
-
rollback: Bytecode._createGraphOp(
|
|
118
|
+
commit: Bytecode._createGraphOp('tx', ['commit']),
|
|
119
|
+
rollback: Bytecode._createGraphOp('tx', ['rollback']),
|
|
118
120
|
};
|
|
119
121
|
}
|
|
120
122
|
}
|