@neo4j-labs/experimental-query-api-wrapper 0.0.1-alpha05 → 0.0.1-alpha06
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/lib/http-connection/codec.js +43 -0
- package/lib/http-connection/connection.http.js +193 -37
- package/lib/http-connection/lang/pipe.js +17 -0
- package/lib/http-connection/query.codec.js +4 -22
- package/lib/http-connection/transaction.codec.js +255 -0
- package/lib/index.js +5 -2
- package/lib/wrapper-session.impl.js +9 -0
- package/lib/wrapper.impl.js +9 -2
- package/package.json +2 -2
- package/types/http-connection/codec.d.ts +21 -0
- package/types/http-connection/connection.http.d.ts +16 -4
- package/types/http-connection/lang/pipe.d.ts +24 -0
- package/types/http-connection/transaction.codec.d.ts +94 -0
- package/types/index.d.ts +7 -4
- package/types/types.d.ts +5 -3
- package/types/wrapper-session.impl.d.ts +4 -1
- package/types/wrapper.impl.d.ts +3 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) "Neo4j"
|
|
3
|
+
* Neo4j Sweden AB [https://neo4j.com]
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
export const NEO4J_QUERY_CONTENT_TYPE = 'application/vnd.neo4j.query';
|
|
18
|
+
export function encodeAuthToken(auth) {
|
|
19
|
+
switch (auth.scheme) {
|
|
20
|
+
case 'bearer':
|
|
21
|
+
return `Bearer ${btoa(auth.credentials)}`;
|
|
22
|
+
case 'basic':
|
|
23
|
+
return `Basic ${btoa(`${auth.principal}:${auth.credentials}`)}`;
|
|
24
|
+
default:
|
|
25
|
+
throw new Error(`Authorization scheme "${auth.scheme}" is not supported.`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function encodeTransactionBody(config) {
|
|
29
|
+
const body = {};
|
|
30
|
+
if (config?.bookmarks != null && !config.bookmarks.isEmpty()) {
|
|
31
|
+
body.bookmarks = config?.bookmarks?.values();
|
|
32
|
+
}
|
|
33
|
+
if (config?.txConfig.timeout != null) {
|
|
34
|
+
body.maxExecutionTime = config?.txConfig.timeout.toInt();
|
|
35
|
+
}
|
|
36
|
+
if (config?.impersonatedUser != null) {
|
|
37
|
+
body.impersonatedUser = config?.impersonatedUser;
|
|
38
|
+
}
|
|
39
|
+
if (config?.mode) {
|
|
40
|
+
body.accessMode = config.mode.toUpperCase();
|
|
41
|
+
}
|
|
42
|
+
return body;
|
|
43
|
+
}
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
import { Connection, newError } from "neo4j-driver-core";
|
|
18
18
|
import { ResultStreamObserver } from "./stream-observers";
|
|
19
19
|
import { QueryRequestCodec, QueryResponseCodec } from "./query.codec";
|
|
20
|
+
import { BeginTransactionRequestCodec, BeginTransactionResponseCodec, CommitTransactionRequestCodec, CommitTransactionResponseCodec, RollbackTransactionRequestCodec, RollbackTransactionResponseCodec } from "./transaction.codec";
|
|
21
|
+
import Pipe from "./lang/pipe";
|
|
20
22
|
let currentId = 0;
|
|
21
23
|
export default class HttpConnection extends Connection {
|
|
22
24
|
constructor(config) {
|
|
@@ -29,43 +31,36 @@ export default class HttpConnection extends Connection {
|
|
|
29
31
|
this._log = config.logger;
|
|
30
32
|
this._errorHandler = config.errorHandler;
|
|
31
33
|
this._open = true;
|
|
34
|
+
this._currentTx = undefined;
|
|
35
|
+
this._workPipe = new Pipe(config.logger);
|
|
36
|
+
this._abortControllers = [];
|
|
37
|
+
this._sessionAffinityHeader = config.config.httpSessionAffinityHeader ?? 'neo4j-cluster-affinity';
|
|
32
38
|
}
|
|
33
39
|
run(query, parameters, config) {
|
|
34
40
|
const observer = new ResultStreamObserver({
|
|
35
41
|
highRecordWatermark: config?.highRecordWatermark ?? Number.MAX_SAFE_INTEGER,
|
|
36
42
|
lowRecordWatermark: config?.lowRecordWatermark ?? Number.MIN_SAFE_INTEGER,
|
|
37
43
|
afterComplete: config?.afterComplete,
|
|
44
|
+
beforeError: config?.beforeError,
|
|
38
45
|
server: this._address,
|
|
39
46
|
});
|
|
40
47
|
const requestCodec = QueryRequestCodec.of(this._auth, query, parameters, config);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
this._log?.debug(`${this} REQUEST: ${JSON.stringify(request)} `);
|
|
55
|
-
fetch(request.url, request).
|
|
56
|
-
then(async (res) => {
|
|
57
|
-
return [res.headers.get('content-type'), (await res.json())];
|
|
58
|
-
})
|
|
59
|
-
.catch((error) => this._handleAndReThrown(newError(`Failure accessing "${request.url}"`, 'SERVICE_UNAVAILABLE', error)))
|
|
60
|
-
.catch((error) => observer.onError(error))
|
|
61
|
-
.then(async ([contentType, rawQueryResponse]) => {
|
|
62
|
-
if (rawQueryResponse == null) {
|
|
63
|
-
// is already dead
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
48
|
+
const abortController = this._newAbortController();
|
|
49
|
+
this._workPipe.attach(async () => {
|
|
50
|
+
const request = {
|
|
51
|
+
url: this._getTransactionApi(config?.database),
|
|
52
|
+
method: 'POST',
|
|
53
|
+
mode: 'cors',
|
|
54
|
+
headers: this._headers(requestCodec),
|
|
55
|
+
signal: abortController.signal,
|
|
56
|
+
body: JSON.stringify(requestCodec.body)
|
|
57
|
+
};
|
|
58
|
+
this._log?.debug(`${this} REQUEST: ${JSON.stringify(request)}`);
|
|
59
|
+
const res = await fetch(request.url, request);
|
|
60
|
+
const { body: rawQueryResponse, headers: [contentType] } = await readBodyAndReaders(request.url, res, 'content-type');
|
|
66
61
|
this._log?.debug(`${this} ${JSON.stringify(rawQueryResponse)}`);
|
|
67
62
|
const batchSize = config?.fetchSize ?? Number.MAX_SAFE_INTEGER;
|
|
68
|
-
const codec = QueryResponseCodec.of(this._config, contentType, rawQueryResponse);
|
|
63
|
+
const codec = QueryResponseCodec.of(this._config, contentType ?? '', rawQueryResponse);
|
|
69
64
|
if (codec.error) {
|
|
70
65
|
throw codec.error;
|
|
71
66
|
}
|
|
@@ -88,18 +83,145 @@ export default class HttpConnection extends Connection {
|
|
|
88
83
|
}
|
|
89
84
|
observer.onCompleted(codec.meta);
|
|
90
85
|
})
|
|
91
|
-
.catch(this.
|
|
92
|
-
.
|
|
93
|
-
|
|
94
|
-
|
|
86
|
+
.catch(this._catch(observer))
|
|
87
|
+
.finally(this._finally(abortController));
|
|
88
|
+
return observer;
|
|
89
|
+
}
|
|
90
|
+
_headers(requestCodec) {
|
|
91
|
+
const headers = {
|
|
92
|
+
'Content-Type': requestCodec.contentType,
|
|
93
|
+
Accept: requestCodec.accept,
|
|
94
|
+
Authorization: requestCodec.authorization,
|
|
95
|
+
};
|
|
96
|
+
if (this._currentTx?.affinity != null) {
|
|
97
|
+
headers[this._sessionAffinityHeader] = this._currentTx.affinity;
|
|
98
|
+
}
|
|
99
|
+
return headers;
|
|
100
|
+
}
|
|
101
|
+
beginTransaction(config) {
|
|
102
|
+
const observer = new ResultStreamObserver({
|
|
103
|
+
server: this._address,
|
|
104
|
+
afterComplete: config?.afterComplete,
|
|
105
|
+
beforeError: config.beforeError,
|
|
106
|
+
highRecordWatermark: Number.MAX_SAFE_INTEGER,
|
|
107
|
+
lowRecordWatermark: Number.MIN_SAFE_INTEGER,
|
|
95
108
|
});
|
|
109
|
+
observer.prepareToHandleSingleResponse();
|
|
110
|
+
const requestCodec = BeginTransactionRequestCodec.of(this._auth, config);
|
|
111
|
+
const abortController = this._newAbortController();
|
|
112
|
+
this._workPipe.attach(async () => {
|
|
113
|
+
const request = {
|
|
114
|
+
url: this._getExplicityTransactionApi(config?.database),
|
|
115
|
+
method: 'POST',
|
|
116
|
+
mode: 'cors',
|
|
117
|
+
headers: this._headers(requestCodec),
|
|
118
|
+
signal: abortController.signal,
|
|
119
|
+
body: JSON.stringify(requestCodec.body)
|
|
120
|
+
};
|
|
121
|
+
this._log?.debug(`${this} REQUEST: ${JSON.stringify(request)} `);
|
|
122
|
+
const res = await fetch(request.url, request);
|
|
123
|
+
const { body: rawBeginTransactionResponse, headers: [contentType, affinity] } = await readBodyAndReaders(request.url, res, 'content-type', this._sessionAffinityHeader);
|
|
124
|
+
this._log?.debug(`${this} ${JSON.stringify(rawBeginTransactionResponse)}`);
|
|
125
|
+
const codec = BeginTransactionResponseCodec.of(this._config, contentType ?? '', rawBeginTransactionResponse);
|
|
126
|
+
if (codec.error != null) {
|
|
127
|
+
throw codec.error;
|
|
128
|
+
}
|
|
129
|
+
this._currentTx = {
|
|
130
|
+
id: codec.id,
|
|
131
|
+
host: codec.host,
|
|
132
|
+
expires: codec.expires,
|
|
133
|
+
database: config?.database,
|
|
134
|
+
};
|
|
135
|
+
if (affinity != null) {
|
|
136
|
+
this._currentTx.affinity = affinity;
|
|
137
|
+
}
|
|
138
|
+
observer.onCompleted({});
|
|
139
|
+
})
|
|
140
|
+
.catch(this._catch(observer))
|
|
141
|
+
.finally(this._finally(abortController));
|
|
142
|
+
return observer;
|
|
143
|
+
}
|
|
144
|
+
commitTransaction(config) {
|
|
145
|
+
const observer = new ResultStreamObserver({
|
|
146
|
+
server: this._address,
|
|
147
|
+
afterComplete: config?.afterComplete,
|
|
148
|
+
beforeError: config.beforeError,
|
|
149
|
+
highRecordWatermark: Number.MAX_SAFE_INTEGER,
|
|
150
|
+
lowRecordWatermark: Number.MIN_SAFE_INTEGER,
|
|
151
|
+
});
|
|
152
|
+
observer.prepareToHandleSingleResponse();
|
|
153
|
+
const requestCodec = CommitTransactionRequestCodec.of(this._auth, config);
|
|
154
|
+
const abortController = this._newAbortController();
|
|
155
|
+
this._workPipe.attach(async () => {
|
|
156
|
+
const request = {
|
|
157
|
+
url: this._getTransactionCommitApi(),
|
|
158
|
+
method: 'POST',
|
|
159
|
+
mode: 'cors',
|
|
160
|
+
headers: this._headers(requestCodec),
|
|
161
|
+
signal: abortController.signal,
|
|
162
|
+
body: JSON.stringify(requestCodec.body)
|
|
163
|
+
};
|
|
164
|
+
this._log?.debug(`${this} REQUEST: ${JSON.stringify(request)} `);
|
|
165
|
+
const res = await fetch(request.url, request);
|
|
166
|
+
const { body: rawCommitTransactionResponse, headers: [contentType] } = await readBodyAndReaders(request.url, res, 'contentType');
|
|
167
|
+
this._log?.debug(`${this} ${JSON.stringify(rawCommitTransactionResponse)}`);
|
|
168
|
+
const codec = CommitTransactionResponseCodec.of(this._config, contentType ?? '', rawCommitTransactionResponse);
|
|
169
|
+
if (codec.error) {
|
|
170
|
+
throw codec.error;
|
|
171
|
+
}
|
|
172
|
+
this._currentTx = undefined;
|
|
173
|
+
observer.onCompleted(codec.meta);
|
|
174
|
+
})
|
|
175
|
+
.catch(this._catch(observer))
|
|
176
|
+
.finally(this._finally(abortController));
|
|
96
177
|
return observer;
|
|
97
178
|
}
|
|
98
|
-
|
|
99
|
-
|
|
179
|
+
rollbackTransaction(config) {
|
|
180
|
+
const observer = new ResultStreamObserver({
|
|
181
|
+
server: this._address,
|
|
182
|
+
afterComplete: config?.afterComplete,
|
|
183
|
+
beforeError: config.beforeError,
|
|
184
|
+
highRecordWatermark: Number.MAX_SAFE_INTEGER,
|
|
185
|
+
lowRecordWatermark: Number.MIN_SAFE_INTEGER,
|
|
186
|
+
});
|
|
187
|
+
observer.prepareToHandleSingleResponse();
|
|
188
|
+
const requestCodec = RollbackTransactionRequestCodec.of(this._auth, config);
|
|
189
|
+
const abortController = this._newAbortController();
|
|
190
|
+
this._workPipe.attach(async () => {
|
|
191
|
+
const request = {
|
|
192
|
+
url: this._getTransactionApi(this._currentTx?.database),
|
|
193
|
+
method: 'DELETE',
|
|
194
|
+
mode: 'cors',
|
|
195
|
+
headers: this._headers(requestCodec),
|
|
196
|
+
signal: abortController.signal,
|
|
197
|
+
body: JSON.stringify(requestCodec.body)
|
|
198
|
+
};
|
|
199
|
+
this._log?.debug(`${this} REQUEST: ${JSON.stringify(request)} `);
|
|
200
|
+
const res = await fetch(request.url, request);
|
|
201
|
+
const { body: rawRollbackTransactionResponse, headers: [contentType] } = await readBodyAndReaders(request.url, res, 'content-type');
|
|
202
|
+
this._log?.debug(`${this} ${JSON.stringify(rawRollbackTransactionResponse)}`);
|
|
203
|
+
const codec = RollbackTransactionResponseCodec.of(this._config, contentType ?? '', rawRollbackTransactionResponse);
|
|
204
|
+
if (codec.error) {
|
|
205
|
+
throw codec.error;
|
|
206
|
+
}
|
|
207
|
+
this._currentTx = undefined;
|
|
208
|
+
observer.onCompleted(codec.meta);
|
|
209
|
+
})
|
|
210
|
+
.catch(this._catch(observer))
|
|
211
|
+
.finally(this._finally(abortController));
|
|
212
|
+
return observer;
|
|
100
213
|
}
|
|
101
214
|
_getTransactionApi(database) {
|
|
102
|
-
|
|
215
|
+
if (this._currentTx === undefined) {
|
|
216
|
+
return this._queryEndpoint.replace('{databaseName}', database);
|
|
217
|
+
}
|
|
218
|
+
return this._queryEndpoint.replace('{databaseName}', this._currentTx.database) + `/tx/${this._currentTx.id}`;
|
|
219
|
+
}
|
|
220
|
+
_getTransactionCommitApi() {
|
|
221
|
+
return this._queryEndpoint.replace('{databaseName}', this._currentTx?.database) + `/tx/${this._currentTx?.id}/commit`;
|
|
222
|
+
}
|
|
223
|
+
_getExplicityTransactionApi(database) {
|
|
224
|
+
return this._queryEndpoint.replace('{databaseName}', database) + '/tx';
|
|
103
225
|
}
|
|
104
226
|
static async discover({ scheme, address }) {
|
|
105
227
|
return await fetch(`${scheme}://${address.asHostPort()}`, {
|
|
@@ -112,7 +234,8 @@ export default class HttpConnection extends Connection {
|
|
|
112
234
|
if (typeof json.query !== 'string') {
|
|
113
235
|
throw new Error('Query API is not available');
|
|
114
236
|
}
|
|
115
|
-
|
|
237
|
+
const query = json.query.endsWith('/') ? json.query.substring(0, json.query.length - 1) : json.query;
|
|
238
|
+
return { query, version: json.neo4j_version, edition: json.neo4j_edition };
|
|
116
239
|
})
|
|
117
240
|
.catch(e => {
|
|
118
241
|
throw newError(`Failure discovering endpoints. Caused by: ${e.message}`, 'SERVICE_UNAVAILABLE', e);
|
|
@@ -140,19 +263,52 @@ export default class HttpConnection extends Connection {
|
|
|
140
263
|
return this._open;
|
|
141
264
|
}
|
|
142
265
|
hasOngoingObservableRequests() {
|
|
143
|
-
return this.
|
|
266
|
+
return this._abortControllers.length > 0;
|
|
144
267
|
}
|
|
145
268
|
async resetAndFlush() {
|
|
146
|
-
this.
|
|
269
|
+
this._abortControllers.forEach((controller) => controller.abort(newError('User aborted operation.')));
|
|
270
|
+
this._abortControllers = [];
|
|
271
|
+
this._currentTx = undefined;
|
|
272
|
+
this._workPipe.recover();
|
|
147
273
|
}
|
|
148
274
|
release() {
|
|
275
|
+
this._workPipe.recover();
|
|
149
276
|
return this._release();
|
|
150
277
|
}
|
|
151
278
|
async close() {
|
|
152
|
-
this.
|
|
279
|
+
this._abortControllers.forEach((controller) => controller.abort(newError('Aborted since connection is being closed.')));
|
|
280
|
+
this._abortControllers = [];
|
|
153
281
|
this._open = false;
|
|
154
282
|
}
|
|
155
283
|
toString() {
|
|
156
284
|
return `HttpConnection [${this._id}]`;
|
|
157
285
|
}
|
|
286
|
+
_catch(observer) {
|
|
287
|
+
return error => {
|
|
288
|
+
this._currentTx = undefined;
|
|
289
|
+
const newError = this._errorHandler(error);
|
|
290
|
+
observer.onError(newError);
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
_finally(abortController) {
|
|
294
|
+
this._abortControllers = this._abortControllers.filter(ac => ac !== abortController);
|
|
295
|
+
return undefined;
|
|
296
|
+
}
|
|
297
|
+
_newAbortController() {
|
|
298
|
+
const abortController = new AbortController();
|
|
299
|
+
this._abortControllers.push(abortController);
|
|
300
|
+
return abortController;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
async function readBodyAndReaders(url, response, ...headers) {
|
|
304
|
+
try {
|
|
305
|
+
const text = await response.text();
|
|
306
|
+
return {
|
|
307
|
+
body: text !== '' ? JSON.parse(text) : {},
|
|
308
|
+
headers: headers.map(header => response.headers.get(header))
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
throw newError(`Failure accessing "${url}"`, 'SERVICE_UNAVAILABLE', error);
|
|
313
|
+
}
|
|
158
314
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export default class Pipe {
|
|
2
|
+
constructor(logger) {
|
|
3
|
+
this.logger = logger;
|
|
4
|
+
this.promise = Promise.resolve();
|
|
5
|
+
}
|
|
6
|
+
attach(work) {
|
|
7
|
+
this.promise = this.promise.then(work);
|
|
8
|
+
return this.promise;
|
|
9
|
+
}
|
|
10
|
+
recover() {
|
|
11
|
+
this.promise = this.promise.catch(error => {
|
|
12
|
+
if (this.logger?.isDebugEnabled() === true) {
|
|
13
|
+
this.logger?.debug(`Recovering from ${error}`);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
import { newError, Node, Relationship, int, error, Time, Date, LocalTime, Point, DateTime, LocalDateTime, Duration, isInt, isPoint, isDuration, isLocalTime, isTime, isDate, isLocalDateTime, isDateTime, isRelationship, isPath, isNode, isPathSegment, Path, PathSegment, internal, isUnboundRelationship } from "neo4j-driver-core";
|
|
18
|
-
|
|
18
|
+
import { NEO4J_QUERY_CONTENT_TYPE, encodeAuthToken, encodeTransactionBody } from "./codec";
|
|
19
19
|
export class QueryResponseCodec {
|
|
20
20
|
static of(config, contentType, response) {
|
|
21
21
|
if (isSuccess(response)) {
|
|
@@ -415,14 +415,7 @@ export class QueryRequestCodec {
|
|
|
415
415
|
return `${NEO4J_QUERY_CONTENT_TYPE}, application/json`;
|
|
416
416
|
}
|
|
417
417
|
get authorization() {
|
|
418
|
-
|
|
419
|
-
case 'bearer':
|
|
420
|
-
return `Bearer ${btoa(this._auth.credentials)}`;
|
|
421
|
-
case 'basic':
|
|
422
|
-
return `Basic ${btoa(`${this._auth.principal}:${this._auth.credentials}`)}`;
|
|
423
|
-
default:
|
|
424
|
-
throw new Error(`Authorization scheme "${this._auth.scheme}" is not supported.`);
|
|
425
|
-
}
|
|
418
|
+
return encodeAuthToken(this._auth);
|
|
426
419
|
}
|
|
427
420
|
get body() {
|
|
428
421
|
if (this._body != null) {
|
|
@@ -430,23 +423,12 @@ export class QueryRequestCodec {
|
|
|
430
423
|
}
|
|
431
424
|
this._body = {
|
|
432
425
|
statement: this._query,
|
|
433
|
-
includeCounters: true
|
|
426
|
+
includeCounters: true,
|
|
427
|
+
...encodeTransactionBody(this._config)
|
|
434
428
|
};
|
|
435
429
|
if (this._parameters != null && Object.getOwnPropertyNames(this._parameters).length !== 0) {
|
|
436
430
|
this._body.parameters = this._encodeParameters(this._parameters);
|
|
437
431
|
}
|
|
438
|
-
if (this._config?.bookmarks != null && !this._config.bookmarks.isEmpty()) {
|
|
439
|
-
this._body.bookmarks = this._config?.bookmarks?.values();
|
|
440
|
-
}
|
|
441
|
-
if (this._config?.txConfig.timeout != null) {
|
|
442
|
-
this._body.maxExecutionTime = this._config?.txConfig.timeout.toInt();
|
|
443
|
-
}
|
|
444
|
-
if (this._config?.impersonatedUser != null) {
|
|
445
|
-
this._body.impersonatedUser = this._config?.impersonatedUser;
|
|
446
|
-
}
|
|
447
|
-
if (this._config?.mode) {
|
|
448
|
-
this._body.accessMode = this._config.mode.toUpperCase();
|
|
449
|
-
}
|
|
450
432
|
return this._body;
|
|
451
433
|
}
|
|
452
434
|
_encodeParameters(parameters) {
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) "Neo4j"
|
|
3
|
+
* Neo4j Sweden AB [https://neo4j.com]
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { error, newError } from "neo4j-driver-core";
|
|
18
|
+
import { NEO4J_QUERY_CONTENT_TYPE, encodeAuthToken, encodeTransactionBody } from "./codec";
|
|
19
|
+
export class BeginTransactionRequestCodec {
|
|
20
|
+
static of(auth, config) {
|
|
21
|
+
return new BeginTransactionRequestCodec(auth, config);
|
|
22
|
+
}
|
|
23
|
+
constructor(_auth, _config) {
|
|
24
|
+
this._auth = _auth;
|
|
25
|
+
this._config = _config;
|
|
26
|
+
}
|
|
27
|
+
get contentType() {
|
|
28
|
+
return 'application/json';
|
|
29
|
+
}
|
|
30
|
+
get accept() {
|
|
31
|
+
return `${NEO4J_QUERY_CONTENT_TYPE}, application/json`;
|
|
32
|
+
}
|
|
33
|
+
get authorization() {
|
|
34
|
+
return encodeAuthToken(this._auth);
|
|
35
|
+
}
|
|
36
|
+
get body() {
|
|
37
|
+
if (this._body != null) {
|
|
38
|
+
return this._body;
|
|
39
|
+
}
|
|
40
|
+
this._body = encodeTransactionBody(this._config);
|
|
41
|
+
return this._body;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export class BeginTransactionResponseCodec {
|
|
45
|
+
static of(config, contentType, response) {
|
|
46
|
+
if (isSuccess(response)) {
|
|
47
|
+
return new BeginTransactionSuccessResponseCodec(config, response);
|
|
48
|
+
}
|
|
49
|
+
return new BeginTransactionFailureResponseCodec(response.errors?.length > 0 ?
|
|
50
|
+
newError(response.errors[0].message,
|
|
51
|
+
// TODO: REMOVE THE ?? AND .ERROR WHEN SERVER IS FIXED
|
|
52
|
+
response.errors[0].code ?? response.errors[0].error) :
|
|
53
|
+
newError('Server replied an empty error response', error.PROTOCOL_ERROR));
|
|
54
|
+
}
|
|
55
|
+
get error() {
|
|
56
|
+
throw new Error('Not implemented');
|
|
57
|
+
}
|
|
58
|
+
get id() {
|
|
59
|
+
throw new Error('Not implemented');
|
|
60
|
+
}
|
|
61
|
+
get expires() {
|
|
62
|
+
throw new Error('Not implemented');
|
|
63
|
+
}
|
|
64
|
+
get host() {
|
|
65
|
+
throw new Error('Not implemented');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
class BeginTransactionSuccessResponseCodec extends BeginTransactionResponseCodec {
|
|
69
|
+
constructor(_config, _response) {
|
|
70
|
+
super();
|
|
71
|
+
this._config = _config;
|
|
72
|
+
this._response = _response;
|
|
73
|
+
}
|
|
74
|
+
get error() {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
get id() {
|
|
78
|
+
return this._response.transaction.id;
|
|
79
|
+
}
|
|
80
|
+
get expires() {
|
|
81
|
+
return new Date(this._response.transaction.expires);
|
|
82
|
+
}
|
|
83
|
+
get host() {
|
|
84
|
+
return this._response.transaction.tx_host;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
class BeginTransactionFailureResponseCodec extends BeginTransactionResponseCodec {
|
|
88
|
+
constructor(_error) {
|
|
89
|
+
super();
|
|
90
|
+
this._error = _error;
|
|
91
|
+
}
|
|
92
|
+
get error() {
|
|
93
|
+
return this._error;
|
|
94
|
+
}
|
|
95
|
+
get id() {
|
|
96
|
+
throw this._error;
|
|
97
|
+
}
|
|
98
|
+
get expires() {
|
|
99
|
+
throw this._error;
|
|
100
|
+
}
|
|
101
|
+
get host() {
|
|
102
|
+
throw this._error;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export class CommitTransactionRequestCodec {
|
|
106
|
+
static of(auth, config) {
|
|
107
|
+
return new CommitTransactionRequestCodec(auth, config);
|
|
108
|
+
}
|
|
109
|
+
constructor(_auth, _config) {
|
|
110
|
+
this._auth = _auth;
|
|
111
|
+
this._config = _config;
|
|
112
|
+
}
|
|
113
|
+
get contentType() {
|
|
114
|
+
return 'application/json';
|
|
115
|
+
}
|
|
116
|
+
get accept() {
|
|
117
|
+
return `${NEO4J_QUERY_CONTENT_TYPE}, application/json`;
|
|
118
|
+
}
|
|
119
|
+
get body() {
|
|
120
|
+
return {};
|
|
121
|
+
}
|
|
122
|
+
get authorization() {
|
|
123
|
+
return encodeAuthToken(this._auth);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
export class CommitTransactionResponseCodec {
|
|
127
|
+
static of(config, contentType, response) {
|
|
128
|
+
if (isCommitSuccess(response)) {
|
|
129
|
+
return new CommitTransactionSuccessResponseCodec(config, response);
|
|
130
|
+
}
|
|
131
|
+
return new CommitTransactionFailureResponseCodec(response.errors?.length > 0 ?
|
|
132
|
+
newError(response.errors[0].message,
|
|
133
|
+
// TODO: REMOVE THE ?? AND .ERROR WHEN SERVER IS FIXED
|
|
134
|
+
response.errors[0].code ?? response.errors[0].error) :
|
|
135
|
+
newError('Server replied an empty error response', error.PROTOCOL_ERROR));
|
|
136
|
+
}
|
|
137
|
+
get error() {
|
|
138
|
+
throw new Error('Not implemented');
|
|
139
|
+
}
|
|
140
|
+
get meta() {
|
|
141
|
+
throw new Error('Not implemented');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
class CommitTransactionSuccessResponseCodec extends CommitTransactionResponseCodec {
|
|
145
|
+
constructor(_config, _response) {
|
|
146
|
+
super();
|
|
147
|
+
this._config = _config;
|
|
148
|
+
this._response = _response;
|
|
149
|
+
}
|
|
150
|
+
get error() {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
get meta() {
|
|
154
|
+
return {
|
|
155
|
+
bookmark: this._response.bookmarks
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
class CommitTransactionFailureResponseCodec extends CommitTransactionResponseCodec {
|
|
160
|
+
constructor(_error) {
|
|
161
|
+
super();
|
|
162
|
+
this._error = _error;
|
|
163
|
+
}
|
|
164
|
+
get error() {
|
|
165
|
+
return this._error;
|
|
166
|
+
}
|
|
167
|
+
get meta() {
|
|
168
|
+
throw this._error;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
export class RollbackTransactionRequestCodec {
|
|
172
|
+
static of(auth, config) {
|
|
173
|
+
return new RollbackTransactionRequestCodec(auth, config);
|
|
174
|
+
}
|
|
175
|
+
constructor(_auth, _config) {
|
|
176
|
+
this._auth = _auth;
|
|
177
|
+
this._config = _config;
|
|
178
|
+
}
|
|
179
|
+
get body() {
|
|
180
|
+
return {};
|
|
181
|
+
}
|
|
182
|
+
get contentType() {
|
|
183
|
+
return 'application/json';
|
|
184
|
+
}
|
|
185
|
+
get accept() {
|
|
186
|
+
return `${NEO4J_QUERY_CONTENT_TYPE}, application/json`;
|
|
187
|
+
}
|
|
188
|
+
get authorization() {
|
|
189
|
+
return encodeAuthToken(this._auth);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
export class RollbackTransactionResponseCodec {
|
|
193
|
+
static of(config, contentType, response) {
|
|
194
|
+
if (isRollbackSuccess(response)) {
|
|
195
|
+
return new RollbackTransactionSuccessResponseCodec(config, response);
|
|
196
|
+
}
|
|
197
|
+
return new RollbackTransactionFailureResponseCodec(response.errors?.length > 0 ?
|
|
198
|
+
newError(response.errors[0].message,
|
|
199
|
+
// TODO: REMOVE THE ?? AND .ERROR WHEN SERVER IS FIXED
|
|
200
|
+
response.errors[0].code ?? response.errors[0].error) :
|
|
201
|
+
newError('Server replied an empty error response', error.PROTOCOL_ERROR));
|
|
202
|
+
}
|
|
203
|
+
get error() {
|
|
204
|
+
throw new Error('Not implemented');
|
|
205
|
+
}
|
|
206
|
+
get meta() {
|
|
207
|
+
throw new Error('Not implemented');
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
class RollbackTransactionSuccessResponseCodec extends RollbackTransactionResponseCodec {
|
|
211
|
+
constructor(_config, _response) {
|
|
212
|
+
super();
|
|
213
|
+
this._config = _config;
|
|
214
|
+
this._response = _response;
|
|
215
|
+
}
|
|
216
|
+
get error() {
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
get meta() {
|
|
220
|
+
return {};
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
class RollbackTransactionFailureResponseCodec extends RollbackTransactionResponseCodec {
|
|
224
|
+
constructor(_error) {
|
|
225
|
+
super();
|
|
226
|
+
this._error = _error;
|
|
227
|
+
}
|
|
228
|
+
get error() {
|
|
229
|
+
return this._error;
|
|
230
|
+
}
|
|
231
|
+
get meta() {
|
|
232
|
+
throw this._error;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function isSuccess(obj) {
|
|
236
|
+
// @ts-expect-error
|
|
237
|
+
if (obj.errors != null) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
function isCommitSuccess(obj) {
|
|
243
|
+
// @ts-expect-error
|
|
244
|
+
if (obj.errors != null) {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
function isRollbackSuccess(obj) {
|
|
250
|
+
// @ts-expect-error
|
|
251
|
+
if (obj.errors != null) {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
return true;
|
|
255
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
-
import { auth, bookmarkManager, authTokenManagers, staticAuthTokenManager, Connection, ConnectionProvider, Date, DateTime, Driver, Duration, error, inSafeRange, int, Integer, internal, isDate, isDateTime, isDuration, isInt, isLocalDateTime, isLocalTime, isNode, isPath, isPathSegment, isPoint, isRelationship, isRetriableError, isTime, isUnboundRelationship, LocalDateTime, LocalTime, Neo4jError, Node, Notification, notificationCategory, notificationSeverityLevel, Path, PathSegment, Plan, Point, ProfiledPlan, QueryStatistics, Record, Relationship, Result, ResultSummary, resultTransformers, ServerInfo, Session, Time, toNumber, toString, UnboundRelationship, driver as coreDriver, } from 'neo4j-driver-core';
|
|
17
|
+
import { auth, bookmarkManager, authTokenManagers, staticAuthTokenManager, Connection, ConnectionProvider, Date, DateTime, Driver, Duration, error, inSafeRange, int, Integer, internal, isDate, isDateTime, isDuration, isInt, isLocalDateTime, isLocalTime, isNode, isPath, isPathSegment, isPoint, isRelationship, isRetriableError, isTime, isUnboundRelationship, LocalDateTime, LocalTime, Neo4jError, Node, Notification, notificationCategory, notificationSeverityLevel, Path, PathSegment, Plan, Point, ProfiledPlan, QueryStatistics, Record, Relationship, Result, ResultSummary, resultTransformers, ServerInfo, Session, Time, toNumber, toString, UnboundRelationship, driver as coreDriver, Transaction, TransactionPromise, ManagedTransaction } from 'neo4j-driver-core';
|
|
18
18
|
import { logging } from './logging';
|
|
19
19
|
import { WrapperImpl } from './wrapper.impl';
|
|
20
20
|
import { HttpConnectionProvider } from './http-connection';
|
|
@@ -186,6 +186,9 @@ const forExport = {
|
|
|
186
186
|
Result,
|
|
187
187
|
Record,
|
|
188
188
|
ResultSummary,
|
|
189
|
+
Transaction,
|
|
190
|
+
TransactionPromise,
|
|
191
|
+
ManagedTransaction,
|
|
189
192
|
Node,
|
|
190
193
|
Relationship,
|
|
191
194
|
UnboundRelationship,
|
|
@@ -213,5 +216,5 @@ const forExport = {
|
|
|
213
216
|
notificationSeverityLevel,
|
|
214
217
|
wrapper
|
|
215
218
|
};
|
|
216
|
-
export { authTokenManagers, int, isInt, isPoint, isDuration, isLocalTime, isTime, isDate, isLocalDateTime, isDateTime, isNode, isPath, isPathSegment, isRelationship, isUnboundRelationship, integer, Neo4jError, isRetriableError, auth, logging, types, session, error, graph, spatial, temporal, Driver, Result, Record, ResultSummary, Node, Relationship, UnboundRelationship, PathSegment, Path, Integer, Plan, ProfiledPlan, QueryStatistics, Notification, ServerInfo, Session, Point, Duration, LocalTime, Time, Date, LocalDateTime, DateTime, ConnectionProvider, Connection, bookmarkManager, resultTransformers, notificationCategory, notificationSeverityLevel, wrapper };
|
|
219
|
+
export { authTokenManagers, int, isInt, isPoint, isDuration, isLocalTime, isTime, isDate, isLocalDateTime, isDateTime, isNode, isPath, isPathSegment, isRelationship, isUnboundRelationship, integer, Neo4jError, isRetriableError, auth, logging, types, session, error, graph, spatial, temporal, Driver, Result, Record, ResultSummary, Node, Relationship, UnboundRelationship, PathSegment, Path, Integer, Plan, ProfiledPlan, QueryStatistics, Notification, ServerInfo, Session, Transaction, TransactionPromise, ManagedTransaction, Point, Duration, LocalTime, Time, Date, LocalDateTime, DateTime, ConnectionProvider, Connection, bookmarkManager, resultTransformers, notificationCategory, notificationSeverityLevel, wrapper };
|
|
217
220
|
export default forExport;
|
|
@@ -8,6 +8,15 @@ export default class WrapperSessionImpl {
|
|
|
8
8
|
run(query, parameters, transactionConfig) {
|
|
9
9
|
return this.session.run(query, parameters, transactionConfig);
|
|
10
10
|
}
|
|
11
|
+
beginTransaction(transactionConfig) {
|
|
12
|
+
return this.session.beginTransaction(transactionConfig);
|
|
13
|
+
}
|
|
14
|
+
executeRead(transactionWork, transactionConfig) {
|
|
15
|
+
return this.session.executeRead(transactionWork, transactionConfig);
|
|
16
|
+
}
|
|
17
|
+
executeWrite(transactionWork, transactionConfig) {
|
|
18
|
+
return this.session.executeWrite(transactionWork, transactionConfig);
|
|
19
|
+
}
|
|
11
20
|
lastBookmarks() {
|
|
12
21
|
return this.session.lastBookmarks();
|
|
13
22
|
}
|
package/lib/wrapper.impl.js
CHANGED
|
@@ -6,6 +6,13 @@ export class WrapperImpl {
|
|
|
6
6
|
close() {
|
|
7
7
|
return this.driver.close();
|
|
8
8
|
}
|
|
9
|
+
executeQuery(query, parameters, config) {
|
|
10
|
+
validateDatabase(config);
|
|
11
|
+
return this.driver.executeQuery(query, parameters, config);
|
|
12
|
+
}
|
|
13
|
+
get executeQueryBookmarkManager() {
|
|
14
|
+
return this.driver.executeQueryBookmarkManager;
|
|
15
|
+
}
|
|
9
16
|
verifyConnectivity(config) {
|
|
10
17
|
validateDatabase(config);
|
|
11
18
|
return this.driver.verifyConnectivity(config);
|
|
@@ -33,7 +40,7 @@ export class WrapperImpl {
|
|
|
33
40
|
}
|
|
34
41
|
}
|
|
35
42
|
function validateDatabase(config) {
|
|
36
|
-
if (config.database == null || config.database === '') {
|
|
37
|
-
throw new TypeError(`database must be a non-empty string, but got ${config
|
|
43
|
+
if (config == null || config.database == null || config.database === '') {
|
|
44
|
+
throw new TypeError(`database must be a non-empty string, but got ${config?.database}`);
|
|
38
45
|
}
|
|
39
46
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neo4j-labs/experimental-query-api-wrapper",
|
|
3
|
-
"version": "0.0.1-
|
|
3
|
+
"version": "0.0.1-alpha06",
|
|
4
4
|
"description": "Experimental wrapper library to access Neo4j Database using Query API with a neo4j-driver-like interface.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"typescript": "^4.9.5"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"neo4j-driver-core": "^5.
|
|
45
|
+
"neo4j-driver-core": "^5.26.0"
|
|
46
46
|
},
|
|
47
47
|
"engines": {
|
|
48
48
|
"node": ">=18.0.0"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) "Neo4j"
|
|
3
|
+
* Neo4j Sweden AB [https://neo4j.com]
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { types } from "neo4j-driver-core";
|
|
18
|
+
import { BeginTransactionConfig } from "neo4j-driver-core/types/connection";
|
|
19
|
+
export declare const NEO4J_QUERY_CONTENT_TYPE = "application/vnd.neo4j.query";
|
|
20
|
+
export declare function encodeAuthToken(auth: types.AuthToken): string;
|
|
21
|
+
export declare function encodeTransactionBody(config?: Pick<BeginTransactionConfig, 'bookmarks' | 'txConfig' | 'mode' | 'impersonatedUser'>): Record<string, unknown>;
|
|
@@ -15,14 +15,15 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
import { Connection, types, internal } from "neo4j-driver-core";
|
|
18
|
-
import { RunQueryConfig } from "neo4j-driver-core/types/connection";
|
|
18
|
+
import { BeginTransactionConfig, CommitTransactionConfig, RunQueryConfig } from "neo4j-driver-core/types/connection";
|
|
19
|
+
import { WrapperConfig } from "../types";
|
|
19
20
|
export type HttpScheme = 'http' | 'https';
|
|
20
21
|
export interface HttpConnectionConfig {
|
|
21
22
|
release: () => Promise<void>;
|
|
22
23
|
auth: types.AuthToken;
|
|
23
24
|
queryEndpoint: string;
|
|
24
25
|
address: internal.serverAddress.ServerAddress;
|
|
25
|
-
config:
|
|
26
|
+
config: WrapperConfig;
|
|
26
27
|
logger: internal.logger.Logger;
|
|
27
28
|
errorHandler: (error: Error & {
|
|
28
29
|
code: string;
|
|
@@ -35,15 +36,23 @@ export default class HttpConnection extends Connection {
|
|
|
35
36
|
private _queryEndpoint;
|
|
36
37
|
private _address;
|
|
37
38
|
private _config;
|
|
38
|
-
private
|
|
39
|
+
private _abortControllers;
|
|
39
40
|
private _log?;
|
|
41
|
+
private _sessionAffinityHeader;
|
|
40
42
|
private _id;
|
|
41
43
|
private _errorHandler;
|
|
42
44
|
private _open;
|
|
45
|
+
private _currentTx;
|
|
46
|
+
private _workPipe;
|
|
43
47
|
constructor(config: HttpConnectionConfig);
|
|
44
48
|
run(query: string, parameters?: Record<string, unknown> | undefined, config?: RunQueryConfig | undefined): internal.observer.ResultStreamObserver;
|
|
45
|
-
private
|
|
49
|
+
private _headers;
|
|
50
|
+
beginTransaction(config: BeginTransactionConfig): internal.observer.ResultStreamObserver;
|
|
51
|
+
commitTransaction(config: CommitTransactionConfig): internal.observer.ResultStreamObserver;
|
|
52
|
+
rollbackTransaction(config: CommitTransactionConfig): internal.observer.ResultStreamObserver;
|
|
46
53
|
private _getTransactionApi;
|
|
54
|
+
private _getTransactionCommitApi;
|
|
55
|
+
private _getExplicityTransactionApi;
|
|
47
56
|
static discover({ scheme, address }: {
|
|
48
57
|
scheme: HttpScheme;
|
|
49
58
|
address: internal.serverAddress.ServerAddress;
|
|
@@ -64,4 +73,7 @@ export default class HttpConnection extends Connection {
|
|
|
64
73
|
release(): Promise<void>;
|
|
65
74
|
close(): Promise<void>;
|
|
66
75
|
toString(): string;
|
|
76
|
+
private _catch;
|
|
77
|
+
private _finally;
|
|
78
|
+
private _newAbortController;
|
|
67
79
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) "Neo4j"
|
|
3
|
+
* Neo4j Sweden AB [https://neo4j.com]
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { internal } from "neo4j-driver-core";
|
|
18
|
+
export default class Pipe {
|
|
19
|
+
private logger?;
|
|
20
|
+
private promise;
|
|
21
|
+
constructor(logger?: internal.logger.Logger | undefined);
|
|
22
|
+
attach(work: () => Promise<void> | void): Promise<void>;
|
|
23
|
+
recover(): void;
|
|
24
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) "Neo4j"
|
|
3
|
+
* Neo4j Sweden AB [https://neo4j.com]
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { types } from "neo4j-driver-core";
|
|
18
|
+
import { BeginTransactionConfig } from "neo4j-driver-core/types/connection";
|
|
19
|
+
export type BeginTransactionRequestCodecConfig = Pick<BeginTransactionConfig, 'bookmarks' | 'txConfig' | 'mode' | 'impersonatedUser'>;
|
|
20
|
+
export type CommitTransactionRequestCodecConfig = {};
|
|
21
|
+
export type RollbackTransactionRequestCodecConfig = {};
|
|
22
|
+
export type RawTransaction = {
|
|
23
|
+
id: string;
|
|
24
|
+
expires: string;
|
|
25
|
+
tx_host?: string;
|
|
26
|
+
};
|
|
27
|
+
export type RawBeginTransactionSuccessResponse = {
|
|
28
|
+
transaction: RawTransaction;
|
|
29
|
+
};
|
|
30
|
+
export type RawTransactionError = {
|
|
31
|
+
code: string;
|
|
32
|
+
message: string;
|
|
33
|
+
error?: string;
|
|
34
|
+
};
|
|
35
|
+
export type RawTransactionFailuresResponse = {
|
|
36
|
+
errors: RawTransactionError[];
|
|
37
|
+
};
|
|
38
|
+
export type RawBeginTransactionResponse = RawBeginTransactionSuccessResponse | RawTransactionFailuresResponse;
|
|
39
|
+
export declare class BeginTransactionRequestCodec {
|
|
40
|
+
private _auth;
|
|
41
|
+
private _config?;
|
|
42
|
+
private _body?;
|
|
43
|
+
static of(auth: types.AuthToken, config?: BeginTransactionRequestCodecConfig | undefined): BeginTransactionRequestCodec;
|
|
44
|
+
private constructor();
|
|
45
|
+
get contentType(): string;
|
|
46
|
+
get accept(): string;
|
|
47
|
+
get authorization(): string;
|
|
48
|
+
get body(): Record<string, unknown>;
|
|
49
|
+
}
|
|
50
|
+
export declare class BeginTransactionResponseCodec {
|
|
51
|
+
static of(config: types.InternalConfig, contentType: string, response: RawBeginTransactionResponse): BeginTransactionResponseCodec;
|
|
52
|
+
get error(): Error | undefined;
|
|
53
|
+
get id(): string;
|
|
54
|
+
get expires(): Date;
|
|
55
|
+
get host(): string | undefined;
|
|
56
|
+
}
|
|
57
|
+
export type RawCommitTransactionSuccessResponse = {
|
|
58
|
+
bookmarks: string[] | undefined;
|
|
59
|
+
};
|
|
60
|
+
export type RawCommitTransactionResponse = RawCommitTransactionSuccessResponse | RawTransactionFailuresResponse;
|
|
61
|
+
export declare class CommitTransactionRequestCodec {
|
|
62
|
+
private _auth;
|
|
63
|
+
private _config?;
|
|
64
|
+
static of(auth: types.AuthToken, config?: CommitTransactionRequestCodecConfig | undefined): CommitTransactionRequestCodec;
|
|
65
|
+
private constructor();
|
|
66
|
+
get contentType(): string;
|
|
67
|
+
get accept(): string;
|
|
68
|
+
get body(): Record<string, unknown>;
|
|
69
|
+
get authorization(): string;
|
|
70
|
+
}
|
|
71
|
+
export declare class CommitTransactionResponseCodec {
|
|
72
|
+
static of(config: types.InternalConfig, contentType: string, response: RawCommitTransactionResponse): CommitTransactionResponseCodec;
|
|
73
|
+
get error(): Error | undefined;
|
|
74
|
+
get meta(): Record<string, unknown>;
|
|
75
|
+
}
|
|
76
|
+
export type RawRollbackTransactionSuccessResponse = {
|
|
77
|
+
e?: any;
|
|
78
|
+
};
|
|
79
|
+
export type RawRollbackTransactionResponse = RawRollbackTransactionSuccessResponse | RawTransactionFailuresResponse;
|
|
80
|
+
export declare class RollbackTransactionRequestCodec {
|
|
81
|
+
private _auth;
|
|
82
|
+
private _config?;
|
|
83
|
+
static of(auth: types.AuthToken, config?: RollbackTransactionRequestCodecConfig | undefined): RollbackTransactionRequestCodec;
|
|
84
|
+
private constructor();
|
|
85
|
+
get body(): Record<string, unknown>;
|
|
86
|
+
get contentType(): string;
|
|
87
|
+
get accept(): string;
|
|
88
|
+
get authorization(): string;
|
|
89
|
+
}
|
|
90
|
+
export declare class RollbackTransactionResponseCodec {
|
|
91
|
+
static of(config: types.InternalConfig, contentType: string, response: RawRollbackTransactionResponse): RollbackTransactionResponseCodec;
|
|
92
|
+
get error(): Error | undefined;
|
|
93
|
+
get meta(): Record<string, unknown>;
|
|
94
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
-
import { auth, BookmarkManager, bookmarkManager, BookmarkManagerConfig, authTokenManagers, AuthTokenManager, AuthTokenManagers, AuthTokenAndExpiration, Connection, ConnectionProvider, Date, DateTime, Driver, Duration, error, int, Integer, internal, isDate, isDateTime, isDuration, isInt, isLocalDateTime, isLocalTime, isNode, isPath, isPathSegment, isPoint, isRelationship, isRetriableError, isTime, isUnboundRelationship, LocalDateTime, LocalTime, Neo4jError, Node, Notification, notificationCategory, NotificationCategory, NotificationPosition, notificationSeverityLevel, NotificationSeverityLevel, Path, PathSegment, Plan, Point, ProfiledPlan, QueryConfig, QueryResult, QueryStatistics, Record, RecordShape, Relationship, Result, ResultObserver, ResultSummary, ResultTransformer, resultTransformers, ServerInfo, Session, SessionConfig, Time, types as coreTypes, UnboundRelationship } from 'neo4j-driver-core';
|
|
17
|
+
import { auth, BookmarkManager, bookmarkManager, BookmarkManagerConfig, authTokenManagers, AuthTokenManager, AuthTokenManagers, AuthTokenAndExpiration, Connection, ConnectionProvider, Date, DateTime, Driver, Duration, error, int, Integer, internal, isDate, isDateTime, isDuration, isInt, isLocalDateTime, isLocalTime, isNode, isPath, isPathSegment, isPoint, isRelationship, isRetriableError, isTime, isUnboundRelationship, LocalDateTime, LocalTime, Neo4jError, Node, Notification, notificationCategory, NotificationCategory, NotificationPosition, notificationSeverityLevel, NotificationSeverityLevel, Path, PathSegment, Plan, Point, ProfiledPlan, QueryConfig, QueryResult, QueryStatistics, Record, RecordShape, Relationship, Result, ResultObserver, ResultSummary, ResultTransformer, resultTransformers, ServerInfo, Session, SessionConfig, Time, types as coreTypes, UnboundRelationship, Transaction, TransactionConfig, TransactionPromise, ManagedTransaction } from 'neo4j-driver-core';
|
|
18
18
|
import { logging } from './logging';
|
|
19
19
|
import { HttpUrl, Wrapper, WrapperSession, WrapperConfig, WrapperSessionConfig } from './types';
|
|
20
20
|
type AuthToken = coreTypes.AuthToken;
|
|
@@ -191,6 +191,9 @@ declare const forExport: {
|
|
|
191
191
|
Result: typeof Result;
|
|
192
192
|
Record: typeof Record;
|
|
193
193
|
ResultSummary: typeof ResultSummary;
|
|
194
|
+
Transaction: typeof Transaction;
|
|
195
|
+
TransactionPromise: typeof TransactionPromise;
|
|
196
|
+
ManagedTransaction: typeof ManagedTransaction;
|
|
194
197
|
Node: typeof Node;
|
|
195
198
|
Relationship: typeof Relationship;
|
|
196
199
|
UnboundRelationship: typeof UnboundRelationship;
|
|
@@ -248,12 +251,12 @@ declare const forExport: {
|
|
|
248
251
|
SCHEMA: "SCHEMA";
|
|
249
252
|
};
|
|
250
253
|
notificationSeverityLevel: {
|
|
254
|
+
UNKNOWN: "UNKNOWN";
|
|
251
255
|
WARNING: "WARNING";
|
|
252
256
|
INFORMATION: "INFORMATION";
|
|
253
|
-
UNKNOWN: "UNKNOWN";
|
|
254
257
|
};
|
|
255
258
|
wrapper: typeof wrapper;
|
|
256
259
|
};
|
|
257
|
-
export { authTokenManagers, int, isInt, isPoint, isDuration, isLocalTime, isTime, isDate, isLocalDateTime, isDateTime, isNode, isPath, isPathSegment, isRelationship, isUnboundRelationship, integer, Neo4jError, isRetriableError, auth, logging, types, session, error, graph, spatial, temporal, Driver, Result, Record, ResultSummary, Node, Relationship, UnboundRelationship, PathSegment, Path, Integer, Plan, ProfiledPlan, QueryStatistics, Notification, ServerInfo, Session, Point, Duration, LocalTime, Time, Date, LocalDateTime, DateTime, ConnectionProvider, Connection, bookmarkManager, resultTransformers, notificationCategory, notificationSeverityLevel, wrapper };
|
|
258
|
-
export type { QueryResult, AuthToken, AuthTokenManager, AuthTokenManagers, AuthTokenAndExpiration, Config, EncryptionLevel, TrustStrategy, SessionMode, ResultObserver, NotificationPosition, BookmarkManager, BookmarkManagerConfig, SessionConfig, QueryConfig, RecordShape, ResultTransformer, NotificationCategory, NotificationSeverityLevel, Logger, HttpUrl, Wrapper, WrapperConfig, WrapperSession, WrapperSessionConfig };
|
|
260
|
+
export { authTokenManagers, int, isInt, isPoint, isDuration, isLocalTime, isTime, isDate, isLocalDateTime, isDateTime, isNode, isPath, isPathSegment, isRelationship, isUnboundRelationship, integer, Neo4jError, isRetriableError, auth, logging, types, session, error, graph, spatial, temporal, Driver, Result, Record, ResultSummary, Node, Relationship, UnboundRelationship, PathSegment, Path, Integer, Plan, ProfiledPlan, QueryStatistics, Notification, ServerInfo, Session, Transaction, TransactionPromise, ManagedTransaction, Point, Duration, LocalTime, Time, Date, LocalDateTime, DateTime, ConnectionProvider, Connection, bookmarkManager, resultTransformers, notificationCategory, notificationSeverityLevel, wrapper };
|
|
261
|
+
export type { QueryResult, AuthToken, AuthTokenManager, AuthTokenManagers, AuthTokenAndExpiration, Config, EncryptionLevel, TrustStrategy, SessionMode, ResultObserver, NotificationPosition, BookmarkManager, BookmarkManagerConfig, SessionConfig, QueryConfig, RecordShape, ResultTransformer, TransactionConfig, NotificationCategory, NotificationSeverityLevel, Logger, HttpUrl, Wrapper, WrapperConfig, WrapperSession, WrapperSessionConfig };
|
|
259
262
|
export default forExport;
|
package/types/types.d.ts
CHANGED
|
@@ -30,12 +30,14 @@ type VerifyAuthentication = {
|
|
|
30
30
|
}): Promise<boolean>;
|
|
31
31
|
};
|
|
32
32
|
type HttpUrl = `http://${string}` | `https://${string}`;
|
|
33
|
-
type WrapperSession = Pick<Session, 'run' | 'lastBookmarks' | 'close'> & Disposable;
|
|
33
|
+
type WrapperSession = Pick<Session, 'run' | 'beginTransaction' | 'executeRead' | 'executeWrite' | 'lastBookmarks' | 'close'> & Disposable;
|
|
34
34
|
type WrapperSessionConfig = Pick<SessionConfig, 'bookmarks' | 'impersonatedUser' | 'bookmarkManager' | 'defaultAccessMode' | 'auth'> & {
|
|
35
35
|
database: string;
|
|
36
36
|
};
|
|
37
|
-
type Wrapper = Pick<Driver, 'close' | 'supportsMultiDb' | 'supportsSessionAuth' | 'supportsUserImpersonation'> & Disposable & VerifyConnectivity & VerifyAuthentication & {
|
|
37
|
+
type Wrapper = Pick<Driver, 'close' | 'executeQuery' | 'executeQueryBookmarkManager' | 'supportsMultiDb' | 'supportsSessionAuth' | 'supportsUserImpersonation'> & Disposable & VerifyConnectivity & VerifyAuthentication & {
|
|
38
38
|
session(config: WrapperSessionConfig): WrapperSession;
|
|
39
39
|
};
|
|
40
|
-
type WrapperConfig = Pick<Config, 'encrypted' | 'useBigInt' | 'disableLosslessIntegers' | 'maxConnectionPoolSize' | 'connectionAcquisitionTimeout'
|
|
40
|
+
type WrapperConfig = Pick<Config, 'encrypted' | 'useBigInt' | 'disableLosslessIntegers' | 'maxConnectionPoolSize' | 'connectionAcquisitionTimeout'> & {
|
|
41
|
+
httpSessionAffinityHeader?: string;
|
|
42
|
+
};
|
|
41
43
|
export type { HttpUrl, WrapperSession, WrapperSessionConfig, Wrapper, WrapperConfig };
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
-
import { RecordShape, TransactionConfig, Result, Session } from "neo4j-driver-core";
|
|
17
|
+
import { RecordShape, TransactionConfig, Result, Session, TransactionPromise, ManagedTransaction } from "neo4j-driver-core";
|
|
18
18
|
import { Query } from "neo4j-driver-core/types/types";
|
|
19
19
|
import { WrapperSession } from "./types";
|
|
20
20
|
export default class WrapperSessionImpl implements WrapperSession {
|
|
@@ -22,6 +22,9 @@ export default class WrapperSessionImpl implements WrapperSession {
|
|
|
22
22
|
constructor(session: Session);
|
|
23
23
|
[Symbol.asyncDispose](): Promise<void>;
|
|
24
24
|
run<R extends RecordShape = RecordShape>(query: Query, parameters?: any, transactionConfig?: TransactionConfig | undefined): Result<R>;
|
|
25
|
+
beginTransaction(transactionConfig?: TransactionConfig | undefined): TransactionPromise;
|
|
26
|
+
executeRead<T>(transactionWork: (tx: ManagedTransaction) => T | Promise<T>, transactionConfig?: TransactionConfig | undefined): Promise<T>;
|
|
27
|
+
executeWrite<T>(transactionWork: (tx: ManagedTransaction) => T | Promise<T>, transactionConfig?: TransactionConfig | undefined): Promise<T>;
|
|
25
28
|
lastBookmarks(): string[];
|
|
26
29
|
close(): Promise<void>;
|
|
27
30
|
}
|
package/types/wrapper.impl.d.ts
CHANGED
|
@@ -14,12 +14,14 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
-
import { Driver, ServerInfo, types } from "neo4j-driver-core";
|
|
17
|
+
import { BookmarkManager, Driver, EagerResult, QueryConfig, RecordShape, ServerInfo, types } from "neo4j-driver-core";
|
|
18
18
|
import { Wrapper, WrapperSession, WrapperSessionConfig } from "./types";
|
|
19
19
|
export declare class WrapperImpl implements Wrapper {
|
|
20
20
|
private readonly driver;
|
|
21
21
|
constructor(driver: Driver);
|
|
22
22
|
close(): Promise<void>;
|
|
23
|
+
executeQuery<T = EagerResult<RecordShape>>(query: types.Query, parameters?: any, config?: QueryConfig<T> | undefined): Promise<T>;
|
|
24
|
+
get executeQueryBookmarkManager(): BookmarkManager;
|
|
23
25
|
verifyConnectivity(config: {
|
|
24
26
|
database: string;
|
|
25
27
|
}): Promise<ServerInfo>;
|