-
Notifications
You must be signed in to change notification settings - Fork 154
Expand file tree
/
Copy pathquery-executor.ts
More file actions
98 lines (83 loc) · 3.38 KB
/
query-executor.ts
File metadata and controls
98 lines (83 loc) · 3.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/**
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [https://neo4j.com]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import BookmarkManager from '../bookmark-manager'
import Session, { TransactionConfig } from '../session'
import Result from '../result'
import ManagedTransaction from '../transaction-managed'
import { AuthToken, Query } from '../types'
import { TELEMETRY_APIS } from './constants'
import { Rules } from '../mapping.highlevel'
type SessionFactory = (config: { database?: string, bookmarkManager?: BookmarkManager, impersonatedUser?: string, auth?: AuthToken }) => Session
type TransactionFunction<T> = (transactionWork: (tx: ManagedTransaction) => Promise<T>, transactionConfig?: TransactionConfig) => Promise<T>
interface ExecutionConfig<T> {
routing: 'WRITE' | 'READ'
database?: string
impersonatedUser?: string
bookmarkManager?: BookmarkManager
transactionConfig?: TransactionConfig
auth?: AuthToken
signal?: AbortSignal
resultTransformer: (result: Result) => Promise<T>
}
export default class QueryExecutor {
constructor (private readonly _createSession: SessionFactory) {
}
public async execute<T>(config: ExecutionConfig<T>, query: Query, parameters?: any, parameterRules?: Rules): Promise<T> {
const session = this._createSession({
database: config.database,
bookmarkManager: config.bookmarkManager,
impersonatedUser: config.impersonatedUser,
auth: config.auth
})
const listenerHandle = installEventListenerWhenPossible(
// Solving linter and types definitions issue
config.signal as unknown as EventTarget,
'abort',
async () => await session.close())
// @ts-expect-error The method is private for external users
session._configureTransactionExecutor(true, TELEMETRY_APIS.EXECUTE_QUERY)
try {
const executeInTransaction: TransactionFunction<T> = config.routing === 'READ'
? session.executeRead.bind(session)
: session.executeWrite.bind(session)
return await executeInTransaction(async (tx: ManagedTransaction) => {
const result = tx.run(query, parameters, parameterRules)
return await config.resultTransformer(result)
}, config.transactionConfig)
} finally {
listenerHandle.uninstall()
await session.close()
}
}
}
type Listener = (event: unknown) => unknown
interface EventTarget {
addEventListener?: (type: string, listener: Listener) => unknown
removeEventListener?: (type: string, listener: Listener) => unknown
}
function installEventListenerWhenPossible (target: EventTarget | undefined, event: string, listener: () => unknown): { uninstall: () => void } {
if (typeof target?.addEventListener === 'function') {
target.addEventListener(event, listener)
}
return {
uninstall: () => {
if (typeof target?.removeEventListener === 'function') {
target.removeEventListener(event, listener)
}
}
}
}