knex 3.2.2 → 3.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2447 -2441
- package/CONTRIBUTING.md +190 -190
- package/LICENSE +22 -22
- package/README.md +156 -156
- package/UPGRADING.md +245 -245
- package/bin/cli.js +516 -516
- package/bin/knexfile-runtime-error.js +27 -27
- package/bin/utils/cli-config-utils.js +217 -217
- package/bin/utils/constants.js +7 -7
- package/bin/utils/migrationsLister.js +37 -37
- package/knex.js +23 -23
- package/knex.mjs +11 -11
- package/lib/builder-interface-augmenter.js +120 -120
- package/lib/client.js +585 -585
- package/lib/constants.js +61 -61
- package/lib/dialects/better-sqlite3/index.js +101 -101
- package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -14
- package/lib/dialects/cockroachdb/crdb-querybuilder.js +11 -11
- package/lib/dialects/cockroachdb/crdb-querycompiler.js +122 -122
- package/lib/dialects/cockroachdb/crdb-tablecompiler.js +46 -46
- package/lib/dialects/cockroachdb/crdb-viewcompiler.js +15 -15
- package/lib/dialects/cockroachdb/index.js +86 -86
- package/lib/dialects/index.js +34 -34
- package/lib/dialects/mssql/index.js +498 -498
- package/lib/dialects/mssql/mssql-formatter.js +34 -34
- package/lib/dialects/mssql/query/mssql-querycompiler.js +601 -601
- package/lib/dialects/mssql/schema/mssql-columncompiler.js +185 -185
- package/lib/dialects/mssql/schema/mssql-compiler.js +91 -91
- package/lib/dialects/mssql/schema/mssql-tablecompiler.js +393 -393
- package/lib/dialects/mssql/schema/mssql-viewcompiler.js +55 -55
- package/lib/dialects/mssql/transaction.js +176 -176
- package/lib/dialects/mysql/index.js +317 -317
- package/lib/dialects/mysql/query/mysql-querybuilder.js +14 -14
- package/lib/dialects/mysql/query/mysql-querycompiler.js +292 -292
- package/lib/dialects/mysql/schema/mysql-columncompiler.js +193 -193
- package/lib/dialects/mysql/schema/mysql-compiler.js +60 -60
- package/lib/dialects/mysql/schema/mysql-tablecompiler.js +426 -426
- package/lib/dialects/mysql/schema/mysql-viewbuilder.js +21 -21
- package/lib/dialects/mysql/schema/mysql-viewcompiler.js +15 -15
- package/lib/dialects/mysql/transaction.js +46 -46
- package/lib/dialects/mysql2/index.js +53 -53
- package/lib/dialects/mysql2/transaction.js +44 -44
- package/lib/dialects/oracle/DEAD_CODE.md +5 -5
- package/lib/dialects/oracle/index.js +92 -92
- package/lib/dialects/oracle/query/oracle-querycompiler.js +343 -343
- package/lib/dialects/oracle/schema/internal/incrementUtils.js +22 -22
- package/lib/dialects/oracle/schema/internal/trigger.js +155 -155
- package/lib/dialects/oracle/schema/oracle-columnbuilder.js +17 -17
- package/lib/dialects/oracle/schema/oracle-columncompiler.js +126 -126
- package/lib/dialects/oracle/schema/oracle-compiler.js +124 -124
- package/lib/dialects/oracle/schema/oracle-tablecompiler.js +210 -210
- package/lib/dialects/oracle/utils.js +107 -107
- package/lib/dialects/oracledb/index.js +381 -381
- package/lib/dialects/oracledb/query/oracledb-querycompiler.js +481 -481
- package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +61 -61
- package/lib/dialects/oracledb/schema/oracledb-tablecompiler.js +19 -19
- package/lib/dialects/oracledb/schema/oracledb-viewbuilder.js +13 -13
- package/lib/dialects/oracledb/schema/oracledb-viewcompiler.js +19 -19
- package/lib/dialects/oracledb/transaction.js +98 -98
- package/lib/dialects/oracledb/utils.js +208 -208
- package/lib/dialects/pgnative/index.js +60 -60
- package/lib/dialects/postgres/execution/pg-transaction.js +19 -19
- package/lib/dialects/postgres/index.js +373 -373
- package/lib/dialects/postgres/query/pg-querybuilder.js +43 -43
- package/lib/dialects/postgres/query/pg-querycompiler.js +400 -400
- package/lib/dialects/postgres/schema/pg-columncompiler.js +162 -162
- package/lib/dialects/postgres/schema/pg-compiler.js +138 -138
- package/lib/dialects/postgres/schema/pg-tablecompiler.js +331 -331
- package/lib/dialects/postgres/schema/pg-viewbuilder.js +21 -21
- package/lib/dialects/postgres/schema/pg-viewcompiler.js +35 -35
- package/lib/dialects/redshift/index.js +86 -86
- package/lib/dialects/redshift/query/redshift-querycompiler.js +163 -163
- package/lib/dialects/redshift/schema/redshift-columnbuilder.js +22 -22
- package/lib/dialects/redshift/schema/redshift-columncompiler.js +67 -67
- package/lib/dialects/redshift/schema/redshift-compiler.js +14 -14
- package/lib/dialects/redshift/schema/redshift-tablecompiler.js +134 -134
- package/lib/dialects/redshift/schema/redshift-viewcompiler.js +11 -11
- package/lib/dialects/redshift/transaction.js +32 -32
- package/lib/dialects/sqlite3/execution/sqlite-transaction.js +172 -172
- package/lib/dialects/sqlite3/index.js +263 -263
- package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -33
- package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +341 -341
- package/lib/dialects/sqlite3/schema/ddl.js +380 -380
- package/lib/dialects/sqlite3/schema/internal/compiler.js +327 -327
- package/lib/dialects/sqlite3/schema/internal/parser-combinator.js +161 -161
- package/lib/dialects/sqlite3/schema/internal/parser.js +638 -638
- package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +41 -41
- package/lib/dialects/sqlite3/schema/internal/tokenizer.js +38 -38
- package/lib/dialects/sqlite3/schema/internal/utils.js +12 -12
- package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +50 -50
- package/lib/dialects/sqlite3/schema/sqlite-compiler.js +80 -80
- package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +364 -364
- package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +40 -40
- package/lib/execution/batch-insert.js +51 -51
- package/lib/execution/internal/delay.js +6 -6
- package/lib/execution/internal/ensure-connection-callback.js +41 -41
- package/lib/execution/internal/query-executioner.js +62 -62
- package/lib/execution/runner.js +325 -325
- package/lib/execution/transaction.js +417 -417
- package/lib/formatter/formatterUtils.js +42 -42
- package/lib/formatter/rawFormatter.js +84 -84
- package/lib/formatter/wrappingFormatter.js +253 -253
- package/lib/formatter.js +25 -25
- package/lib/index.js +3 -3
- package/lib/knex-builder/FunctionHelper.js +80 -80
- package/lib/knex-builder/Knex.js +59 -59
- package/lib/knex-builder/internal/config-resolver.js +57 -57
- package/lib/knex-builder/internal/parse-connection.js +87 -87
- package/lib/knex-builder/make-knex.js +345 -345
- package/lib/logger.js +76 -76
- package/lib/migrations/common/MigrationsLoader.js +36 -36
- package/lib/migrations/migrate/MigrationGenerator.js +84 -84
- package/lib/migrations/migrate/Migrator.js +632 -632
- package/lib/migrations/migrate/migrate-stub.js +17 -17
- package/lib/migrations/migrate/migration-list-resolver.js +33 -33
- package/lib/migrations/migrate/migrator-configuration-merger.js +58 -58
- package/lib/migrations/migrate/sources/fs-migrations.js +74 -74
- package/lib/migrations/migrate/stub/cjs.stub +15 -15
- package/lib/migrations/migrate/stub/coffee.stub +13 -13
- package/lib/migrations/migrate/stub/eg.stub +14 -14
- package/lib/migrations/migrate/stub/js-schema.stub +22 -22
- package/lib/migrations/migrate/stub/js.stub +22 -22
- package/lib/migrations/migrate/stub/knexfile-coffee.stub +34 -34
- package/lib/migrations/migrate/stub/knexfile-eg.stub +43 -43
- package/lib/migrations/migrate/stub/knexfile-js.stub +47 -47
- package/lib/migrations/migrate/stub/knexfile-ls.stub +35 -35
- package/lib/migrations/migrate/stub/knexfile-ts.stub +47 -47
- package/lib/migrations/migrate/stub/ls.stub +14 -14
- package/lib/migrations/migrate/stub/mjs.stub +23 -23
- package/lib/migrations/migrate/stub/ts-schema.stub +21 -21
- package/lib/migrations/migrate/stub/ts.stub +21 -21
- package/lib/migrations/migrate/table-creator.js +77 -77
- package/lib/migrations/migrate/table-resolver.js +27 -27
- package/lib/migrations/seed/Seeder.js +137 -137
- package/lib/migrations/seed/seed-stub.js +13 -13
- package/lib/migrations/seed/seeder-configuration-merger.js +60 -60
- package/lib/migrations/seed/sources/fs-seeds.js +65 -65
- package/lib/migrations/seed/stub/coffee.stub +9 -9
- package/lib/migrations/seed/stub/eg.stub +11 -11
- package/lib/migrations/seed/stub/js.stub +13 -13
- package/lib/migrations/seed/stub/ls.stub +11 -11
- package/lib/migrations/seed/stub/mjs.stub +12 -12
- package/lib/migrations/seed/stub/ts.stub +13 -13
- package/lib/migrations/util/fs.js +86 -86
- package/lib/migrations/util/import-file.js +12 -12
- package/lib/migrations/util/is-module-type.js +9 -9
- package/lib/migrations/util/template.js +52 -52
- package/lib/migrations/util/timestamp.js +14 -14
- package/lib/query/analytic.js +52 -52
- package/lib/query/constants.js +15 -15
- package/lib/query/joinclause.js +270 -270
- package/lib/query/method-constants.js +136 -136
- package/lib/query/querybuilder.js +1793 -1793
- package/lib/query/querycompiler.js +1634 -1634
- package/lib/raw.js +139 -139
- package/lib/ref.js +39 -39
- package/lib/schema/builder.js +115 -115
- package/lib/schema/columnbuilder.js +146 -146
- package/lib/schema/columncompiler.js +307 -307
- package/lib/schema/compiler.js +187 -187
- package/lib/schema/internal/helpers.js +55 -55
- package/lib/schema/tablebuilder.js +379 -379
- package/lib/schema/tablecompiler.js +450 -450
- package/lib/schema/viewbuilder.js +92 -92
- package/lib/schema/viewcompiler.js +138 -138
- package/lib/util/finally-mixin.js +13 -13
- package/lib/util/helpers.js +95 -95
- package/lib/util/is.js +32 -32
- package/lib/util/nanoid.js +40 -40
- package/lib/util/noop.js +1 -1
- package/lib/util/save-async-stack.js +14 -14
- package/lib/util/security.js +32 -32
- package/lib/util/string.js +190 -190
- package/lib/util/timeout.js +29 -29
- package/package.json +294 -296
- package/scripts/act-testing/act.sh +19 -19
- package/scripts/act-testing/merged-no-label.json +11 -11
- package/scripts/act-testing/merged-patch-labeled.json +12 -12
- package/scripts/act-testing/merged-skip-labeled.json +12 -12
- package/scripts/act-testing/not-merged-patch-labeled.json +12 -12
- package/scripts/build-for-release.sh +121 -121
- package/scripts/build.js +125 -125
- package/scripts/clean.js +31 -31
- package/scripts/docker-compose.yml +150 -150
- package/scripts/format-changelog.js +55 -55
- package/scripts/next-release-howto.md +24 -24
- package/scripts/oracledb-install-driver-libs.sh +82 -82
- package/scripts/release.sh +36 -36
- package/scripts/runkit-example.js +35 -35
- package/scripts/stress-test/README.txt +18 -18
- package/scripts/stress-test/docker-compose.yml +55 -55
- package/scripts/stress-test/knex-stress-test.js +212 -212
- package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +149 -149
- package/scripts/stress-test/mysql2-sudden-exit-without-error.js +101 -101
- package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +188 -188
- package/types/index.d.mts +11 -0
- package/types/index.d.ts +3321 -3321
- package/types/result.d.ts +27 -27
- package/types/tables.d.ts +4 -4
package/lib/execution/runner.js
CHANGED
|
@@ -1,325 +1,325 @@
|
|
|
1
|
-
const { KnexTimeoutError } = require('../util/timeout');
|
|
2
|
-
const { timeout } = require('../util/timeout');
|
|
3
|
-
const {
|
|
4
|
-
ensureConnectionCallback,
|
|
5
|
-
ensureConnectionStreamCallback,
|
|
6
|
-
} = require('./internal/ensure-connection-callback');
|
|
7
|
-
|
|
8
|
-
let Transform;
|
|
9
|
-
|
|
10
|
-
// The "Runner" constructor takes a "builder" (query, schema, or raw)
|
|
11
|
-
// and runs through each of the query statements, calling any additional
|
|
12
|
-
// "output" method provided alongside the query and bindings.
|
|
13
|
-
class Runner {
|
|
14
|
-
constructor(client, builder) {
|
|
15
|
-
this.client = client;
|
|
16
|
-
this.builder = builder;
|
|
17
|
-
this.queries = [];
|
|
18
|
-
|
|
19
|
-
// The "connection" object is set on the runner when
|
|
20
|
-
// "run" is called.
|
|
21
|
-
this.connection = undefined;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// "Run" the target, calling "toSQL" on the builder, returning
|
|
25
|
-
// an object or array of queries to run, each of which are run on
|
|
26
|
-
// a single connection.
|
|
27
|
-
async run() {
|
|
28
|
-
const runner = this;
|
|
29
|
-
try {
|
|
30
|
-
const res = await this.ensureConnection(ensureConnectionCallback);
|
|
31
|
-
|
|
32
|
-
// Fire a single "end" event on the builder when
|
|
33
|
-
// all queries have successfully completed.
|
|
34
|
-
runner.builder.emit('end');
|
|
35
|
-
return res;
|
|
36
|
-
|
|
37
|
-
// If there are any "error" listeners, we fire an error event
|
|
38
|
-
// and then re-throw the error to be eventually handled by
|
|
39
|
-
// the promise chain. Useful if you're wrapping in a custom `Promise`.
|
|
40
|
-
} catch (err) {
|
|
41
|
-
if (runner.builder._events && runner.builder._events.error) {
|
|
42
|
-
runner.builder.emit('error', err);
|
|
43
|
-
}
|
|
44
|
-
throw err;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Stream the result set, by passing through to the dialect's streaming
|
|
49
|
-
// capabilities. If the options are
|
|
50
|
-
stream(optionsOrHandler, handlerOrNil) {
|
|
51
|
-
const firstOptionIsHandler =
|
|
52
|
-
typeof optionsOrHandler === 'function' && arguments.length === 1;
|
|
53
|
-
|
|
54
|
-
const options = firstOptionIsHandler ? {} : optionsOrHandler;
|
|
55
|
-
const handler = firstOptionIsHandler ? optionsOrHandler : handlerOrNil;
|
|
56
|
-
|
|
57
|
-
// Determines whether we emit an error or throw here.
|
|
58
|
-
const hasHandler = typeof handler === 'function';
|
|
59
|
-
|
|
60
|
-
// Lazy-load the "Transform" dependency.
|
|
61
|
-
Transform = Transform || require('stream').Transform;
|
|
62
|
-
|
|
63
|
-
const queryContext = this.builder.queryContext();
|
|
64
|
-
|
|
65
|
-
const stream = new Transform({
|
|
66
|
-
objectMode: true,
|
|
67
|
-
transform: (chunk, _, callback) => {
|
|
68
|
-
callback(null, this.client.postProcessResponse(chunk, queryContext));
|
|
69
|
-
},
|
|
70
|
-
});
|
|
71
|
-
stream.on('close', () => {
|
|
72
|
-
this.client.releaseConnection(this.connection);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// If the stream is manually destroyed, the close event is not
|
|
76
|
-
// propagated to the top of the pipe chain. We need to manually verify
|
|
77
|
-
// that the source stream is closed and if not, manually destroy it.
|
|
78
|
-
stream.on('pipe', (sourceStream) => {
|
|
79
|
-
const cleanSourceStream = () => {
|
|
80
|
-
if (!sourceStream.closed) {
|
|
81
|
-
sourceStream.destroy();
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
// Stream already closed, cleanup immediately
|
|
86
|
-
if (stream.closed) {
|
|
87
|
-
cleanSourceStream();
|
|
88
|
-
} else {
|
|
89
|
-
stream.on('close', cleanSourceStream);
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
const connectionAcquirePromise = this.ensureConnection(
|
|
94
|
-
ensureConnectionStreamCallback,
|
|
95
|
-
{
|
|
96
|
-
options,
|
|
97
|
-
hasHandler,
|
|
98
|
-
stream,
|
|
99
|
-
}
|
|
100
|
-
)
|
|
101
|
-
// Emit errors on the stream if the error occurred before a connection
|
|
102
|
-
// could be acquired.
|
|
103
|
-
// If the connection was acquired, assume the error occurred in the client
|
|
104
|
-
// code and has already been emitted on the stream. Don't emit it twice.
|
|
105
|
-
.catch((err) => {
|
|
106
|
-
if (!this.connection) {
|
|
107
|
-
stream.emit('error', err);
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// If a function is passed to handle the stream, send the stream
|
|
112
|
-
// there and return the promise, otherwise just return the stream
|
|
113
|
-
// and the promise will take care of itself.
|
|
114
|
-
if (hasHandler) {
|
|
115
|
-
handler(stream);
|
|
116
|
-
return connectionAcquirePromise;
|
|
117
|
-
}
|
|
118
|
-
return stream;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Allow you to pipe the stream to a writable stream.
|
|
122
|
-
pipe(writable, options) {
|
|
123
|
-
return this.stream(options).pipe(writable);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// "Runs" a query, returning a promise. All queries specified by the builder are guaranteed
|
|
127
|
-
// to run in sequence, and on the same connection, especially helpful when schema building
|
|
128
|
-
// and dealing with foreign key constraints, etc.
|
|
129
|
-
async query(obj) {
|
|
130
|
-
const { __knexUid, __knexTxId } = this.connection;
|
|
131
|
-
|
|
132
|
-
this.builder.emit('query', Object.assign({ __knexUid, __knexTxId }, obj));
|
|
133
|
-
|
|
134
|
-
const runner = this;
|
|
135
|
-
const queryContext = this.builder.queryContext();
|
|
136
|
-
// query-error events are emitted before the queryPromise continuations.
|
|
137
|
-
// pass queryContext into client.query so it can be raised properly.
|
|
138
|
-
if (obj !== null && typeof obj === 'object') {
|
|
139
|
-
obj.queryContext = queryContext;
|
|
140
|
-
}
|
|
141
|
-
let queryPromise = this.client.query(this.connection, obj);
|
|
142
|
-
|
|
143
|
-
if (obj.timeout) {
|
|
144
|
-
queryPromise = timeout(queryPromise, obj.timeout);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Await the return value of client.processResponse; in the case of sqlite3's
|
|
148
|
-
// dropColumn()/renameColumn(), it will be a Promise for the transaction
|
|
149
|
-
// containing the complete rename procedure.
|
|
150
|
-
return queryPromise
|
|
151
|
-
.then((resp) => this.client.processResponse(resp, runner))
|
|
152
|
-
.then((processedResponse) => {
|
|
153
|
-
const postProcessedResponse = this.client.postProcessResponse(
|
|
154
|
-
processedResponse,
|
|
155
|
-
queryContext
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
this.builder.emit(
|
|
159
|
-
'query-response',
|
|
160
|
-
postProcessedResponse,
|
|
161
|
-
Object.assign({ __knexUid, __knexTxId }, obj),
|
|
162
|
-
this.builder
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
this.client.emit(
|
|
166
|
-
'query-response',
|
|
167
|
-
postProcessedResponse,
|
|
168
|
-
Object.assign({ __knexUid, __knexTxId }, obj),
|
|
169
|
-
this.builder
|
|
170
|
-
);
|
|
171
|
-
|
|
172
|
-
return postProcessedResponse;
|
|
173
|
-
})
|
|
174
|
-
.catch((error) => {
|
|
175
|
-
if (!(error instanceof KnexTimeoutError)) {
|
|
176
|
-
return Promise.reject(error);
|
|
177
|
-
}
|
|
178
|
-
const { timeout, sql, bindings } = obj;
|
|
179
|
-
|
|
180
|
-
let cancelQuery;
|
|
181
|
-
if (obj.cancelOnTimeout) {
|
|
182
|
-
cancelQuery = this.client.cancelQuery(this.connection);
|
|
183
|
-
} else {
|
|
184
|
-
// If we don't cancel the query, we need to mark the connection as disposed so that
|
|
185
|
-
// it gets destroyed by the pool and is never used again. If we don't do this and
|
|
186
|
-
// return the connection to the pool, it will be useless until the current operation
|
|
187
|
-
// that timed out, finally finishes.
|
|
188
|
-
this.connection.__knex__disposed = error;
|
|
189
|
-
cancelQuery = Promise.resolve();
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return cancelQuery
|
|
193
|
-
.catch((cancelError) => {
|
|
194
|
-
// If the cancellation failed, we need to mark the connection as disposed so that
|
|
195
|
-
// it gets destroyed by the pool and is never used again. If we don't do this and
|
|
196
|
-
// return the connection to the pool, it will be useless until the current operation
|
|
197
|
-
// that timed out, finally finishes.
|
|
198
|
-
this.connection.__knex__disposed = error;
|
|
199
|
-
|
|
200
|
-
// cancellation failed
|
|
201
|
-
throw Object.assign(cancelError, {
|
|
202
|
-
message: `After query timeout of ${timeout}ms exceeded, cancelling of query failed.`,
|
|
203
|
-
sql,
|
|
204
|
-
bindings,
|
|
205
|
-
timeout,
|
|
206
|
-
});
|
|
207
|
-
})
|
|
208
|
-
.then(() => {
|
|
209
|
-
// cancellation succeeded, rethrow timeout error
|
|
210
|
-
throw Object.assign(error, {
|
|
211
|
-
message: `Defined query timeout of ${timeout}ms exceeded when running query.`,
|
|
212
|
-
sql,
|
|
213
|
-
bindings,
|
|
214
|
-
timeout,
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
})
|
|
218
|
-
.catch((error) => {
|
|
219
|
-
this.builder.emit(
|
|
220
|
-
'query-error',
|
|
221
|
-
error,
|
|
222
|
-
Object.assign({ __knexUid, __knexTxId, queryContext }, obj)
|
|
223
|
-
);
|
|
224
|
-
throw error;
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// In the case of the "schema builder" we call `queryArray`, which runs each
|
|
229
|
-
// of the queries in sequence.
|
|
230
|
-
async queryArray(queries) {
|
|
231
|
-
if (queries.length === 1) {
|
|
232
|
-
const query = queries[0];
|
|
233
|
-
|
|
234
|
-
if (!query.statementsProducer) {
|
|
235
|
-
return this.query(query);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const statements = await query.statementsProducer(
|
|
239
|
-
undefined,
|
|
240
|
-
this.connection
|
|
241
|
-
);
|
|
242
|
-
|
|
243
|
-
const sqlQueryObjects = statements.sql.map((statement) => ({
|
|
244
|
-
sql: statement,
|
|
245
|
-
bindings: query.bindings,
|
|
246
|
-
}));
|
|
247
|
-
const preQueryObjects = statements.pre.map((statement) => ({
|
|
248
|
-
sql: statement,
|
|
249
|
-
bindings: query.bindings,
|
|
250
|
-
}));
|
|
251
|
-
const postQueryObjects = statements.post.map((statement) => ({
|
|
252
|
-
sql: statement,
|
|
253
|
-
bindings: query.bindings,
|
|
254
|
-
}));
|
|
255
|
-
|
|
256
|
-
let results = [];
|
|
257
|
-
|
|
258
|
-
await this.queryArray(preQueryObjects);
|
|
259
|
-
|
|
260
|
-
try {
|
|
261
|
-
await this.client.transaction(
|
|
262
|
-
async (trx) => {
|
|
263
|
-
const transactionRunner = new Runner(trx.client, this.builder);
|
|
264
|
-
transactionRunner.connection = this.connection;
|
|
265
|
-
|
|
266
|
-
results = await transactionRunner.queryArray(sqlQueryObjects);
|
|
267
|
-
|
|
268
|
-
if (statements.check) {
|
|
269
|
-
const foreignViolations = await trx.raw(statements.check);
|
|
270
|
-
|
|
271
|
-
if (foreignViolations.length > 0) {
|
|
272
|
-
throw new Error('FOREIGN KEY constraint failed');
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
},
|
|
276
|
-
{ connection: this.connection }
|
|
277
|
-
);
|
|
278
|
-
} finally {
|
|
279
|
-
await this.queryArray(postQueryObjects);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
return results;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
const results = [];
|
|
286
|
-
for (const query of queries) {
|
|
287
|
-
results.push(await this.queryArray([query]));
|
|
288
|
-
}
|
|
289
|
-
return results;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// Check whether there's a transaction flag, and that it has a connection.
|
|
293
|
-
async ensureConnection(cb, cbParams) {
|
|
294
|
-
// Use override from a builder if passed
|
|
295
|
-
if (this.builder._connection) {
|
|
296
|
-
this.connection = this.builder._connection;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (this.connection) {
|
|
300
|
-
return cb(this, cbParams);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
let acquiredConnection;
|
|
304
|
-
try {
|
|
305
|
-
acquiredConnection = await this.client.acquireConnection();
|
|
306
|
-
} catch (error) {
|
|
307
|
-
if (!(error instanceof KnexTimeoutError)) {
|
|
308
|
-
return Promise.reject(error);
|
|
309
|
-
}
|
|
310
|
-
if (this.builder) {
|
|
311
|
-
error.sql = this.builder.sql;
|
|
312
|
-
error.bindings = this.builder.bindings;
|
|
313
|
-
}
|
|
314
|
-
throw error;
|
|
315
|
-
}
|
|
316
|
-
try {
|
|
317
|
-
this.connection = acquiredConnection;
|
|
318
|
-
return await cb(this, cbParams);
|
|
319
|
-
} finally {
|
|
320
|
-
await this.client.releaseConnection(acquiredConnection);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
module.exports = Runner;
|
|
1
|
+
const { KnexTimeoutError } = require('../util/timeout');
|
|
2
|
+
const { timeout } = require('../util/timeout');
|
|
3
|
+
const {
|
|
4
|
+
ensureConnectionCallback,
|
|
5
|
+
ensureConnectionStreamCallback,
|
|
6
|
+
} = require('./internal/ensure-connection-callback');
|
|
7
|
+
|
|
8
|
+
let Transform;
|
|
9
|
+
|
|
10
|
+
// The "Runner" constructor takes a "builder" (query, schema, or raw)
|
|
11
|
+
// and runs through each of the query statements, calling any additional
|
|
12
|
+
// "output" method provided alongside the query and bindings.
|
|
13
|
+
class Runner {
|
|
14
|
+
constructor(client, builder) {
|
|
15
|
+
this.client = client;
|
|
16
|
+
this.builder = builder;
|
|
17
|
+
this.queries = [];
|
|
18
|
+
|
|
19
|
+
// The "connection" object is set on the runner when
|
|
20
|
+
// "run" is called.
|
|
21
|
+
this.connection = undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// "Run" the target, calling "toSQL" on the builder, returning
|
|
25
|
+
// an object or array of queries to run, each of which are run on
|
|
26
|
+
// a single connection.
|
|
27
|
+
async run() {
|
|
28
|
+
const runner = this;
|
|
29
|
+
try {
|
|
30
|
+
const res = await this.ensureConnection(ensureConnectionCallback);
|
|
31
|
+
|
|
32
|
+
// Fire a single "end" event on the builder when
|
|
33
|
+
// all queries have successfully completed.
|
|
34
|
+
runner.builder.emit('end');
|
|
35
|
+
return res;
|
|
36
|
+
|
|
37
|
+
// If there are any "error" listeners, we fire an error event
|
|
38
|
+
// and then re-throw the error to be eventually handled by
|
|
39
|
+
// the promise chain. Useful if you're wrapping in a custom `Promise`.
|
|
40
|
+
} catch (err) {
|
|
41
|
+
if (runner.builder._events && runner.builder._events.error) {
|
|
42
|
+
runner.builder.emit('error', err);
|
|
43
|
+
}
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Stream the result set, by passing through to the dialect's streaming
|
|
49
|
+
// capabilities. If the options are
|
|
50
|
+
stream(optionsOrHandler, handlerOrNil) {
|
|
51
|
+
const firstOptionIsHandler =
|
|
52
|
+
typeof optionsOrHandler === 'function' && arguments.length === 1;
|
|
53
|
+
|
|
54
|
+
const options = firstOptionIsHandler ? {} : optionsOrHandler;
|
|
55
|
+
const handler = firstOptionIsHandler ? optionsOrHandler : handlerOrNil;
|
|
56
|
+
|
|
57
|
+
// Determines whether we emit an error or throw here.
|
|
58
|
+
const hasHandler = typeof handler === 'function';
|
|
59
|
+
|
|
60
|
+
// Lazy-load the "Transform" dependency.
|
|
61
|
+
Transform = Transform || require('stream').Transform;
|
|
62
|
+
|
|
63
|
+
const queryContext = this.builder.queryContext();
|
|
64
|
+
|
|
65
|
+
const stream = new Transform({
|
|
66
|
+
objectMode: true,
|
|
67
|
+
transform: (chunk, _, callback) => {
|
|
68
|
+
callback(null, this.client.postProcessResponse(chunk, queryContext));
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
stream.on('close', () => {
|
|
72
|
+
this.client.releaseConnection(this.connection);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// If the stream is manually destroyed, the close event is not
|
|
76
|
+
// propagated to the top of the pipe chain. We need to manually verify
|
|
77
|
+
// that the source stream is closed and if not, manually destroy it.
|
|
78
|
+
stream.on('pipe', (sourceStream) => {
|
|
79
|
+
const cleanSourceStream = () => {
|
|
80
|
+
if (!sourceStream.closed) {
|
|
81
|
+
sourceStream.destroy();
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// Stream already closed, cleanup immediately
|
|
86
|
+
if (stream.closed) {
|
|
87
|
+
cleanSourceStream();
|
|
88
|
+
} else {
|
|
89
|
+
stream.on('close', cleanSourceStream);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const connectionAcquirePromise = this.ensureConnection(
|
|
94
|
+
ensureConnectionStreamCallback,
|
|
95
|
+
{
|
|
96
|
+
options,
|
|
97
|
+
hasHandler,
|
|
98
|
+
stream,
|
|
99
|
+
}
|
|
100
|
+
)
|
|
101
|
+
// Emit errors on the stream if the error occurred before a connection
|
|
102
|
+
// could be acquired.
|
|
103
|
+
// If the connection was acquired, assume the error occurred in the client
|
|
104
|
+
// code and has already been emitted on the stream. Don't emit it twice.
|
|
105
|
+
.catch((err) => {
|
|
106
|
+
if (!this.connection) {
|
|
107
|
+
stream.emit('error', err);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// If a function is passed to handle the stream, send the stream
|
|
112
|
+
// there and return the promise, otherwise just return the stream
|
|
113
|
+
// and the promise will take care of itself.
|
|
114
|
+
if (hasHandler) {
|
|
115
|
+
handler(stream);
|
|
116
|
+
return connectionAcquirePromise;
|
|
117
|
+
}
|
|
118
|
+
return stream;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Allow you to pipe the stream to a writable stream.
|
|
122
|
+
pipe(writable, options) {
|
|
123
|
+
return this.stream(options).pipe(writable);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// "Runs" a query, returning a promise. All queries specified by the builder are guaranteed
|
|
127
|
+
// to run in sequence, and on the same connection, especially helpful when schema building
|
|
128
|
+
// and dealing with foreign key constraints, etc.
|
|
129
|
+
async query(obj) {
|
|
130
|
+
const { __knexUid, __knexTxId } = this.connection;
|
|
131
|
+
|
|
132
|
+
this.builder.emit('query', Object.assign({ __knexUid, __knexTxId }, obj));
|
|
133
|
+
|
|
134
|
+
const runner = this;
|
|
135
|
+
const queryContext = this.builder.queryContext();
|
|
136
|
+
// query-error events are emitted before the queryPromise continuations.
|
|
137
|
+
// pass queryContext into client.query so it can be raised properly.
|
|
138
|
+
if (obj !== null && typeof obj === 'object') {
|
|
139
|
+
obj.queryContext = queryContext;
|
|
140
|
+
}
|
|
141
|
+
let queryPromise = this.client.query(this.connection, obj);
|
|
142
|
+
|
|
143
|
+
if (obj.timeout) {
|
|
144
|
+
queryPromise = timeout(queryPromise, obj.timeout);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Await the return value of client.processResponse; in the case of sqlite3's
|
|
148
|
+
// dropColumn()/renameColumn(), it will be a Promise for the transaction
|
|
149
|
+
// containing the complete rename procedure.
|
|
150
|
+
return queryPromise
|
|
151
|
+
.then((resp) => this.client.processResponse(resp, runner))
|
|
152
|
+
.then((processedResponse) => {
|
|
153
|
+
const postProcessedResponse = this.client.postProcessResponse(
|
|
154
|
+
processedResponse,
|
|
155
|
+
queryContext
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
this.builder.emit(
|
|
159
|
+
'query-response',
|
|
160
|
+
postProcessedResponse,
|
|
161
|
+
Object.assign({ __knexUid, __knexTxId }, obj),
|
|
162
|
+
this.builder
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
this.client.emit(
|
|
166
|
+
'query-response',
|
|
167
|
+
postProcessedResponse,
|
|
168
|
+
Object.assign({ __knexUid, __knexTxId }, obj),
|
|
169
|
+
this.builder
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
return postProcessedResponse;
|
|
173
|
+
})
|
|
174
|
+
.catch((error) => {
|
|
175
|
+
if (!(error instanceof KnexTimeoutError)) {
|
|
176
|
+
return Promise.reject(error);
|
|
177
|
+
}
|
|
178
|
+
const { timeout, sql, bindings } = obj;
|
|
179
|
+
|
|
180
|
+
let cancelQuery;
|
|
181
|
+
if (obj.cancelOnTimeout) {
|
|
182
|
+
cancelQuery = this.client.cancelQuery(this.connection);
|
|
183
|
+
} else {
|
|
184
|
+
// If we don't cancel the query, we need to mark the connection as disposed so that
|
|
185
|
+
// it gets destroyed by the pool and is never used again. If we don't do this and
|
|
186
|
+
// return the connection to the pool, it will be useless until the current operation
|
|
187
|
+
// that timed out, finally finishes.
|
|
188
|
+
this.connection.__knex__disposed = error;
|
|
189
|
+
cancelQuery = Promise.resolve();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return cancelQuery
|
|
193
|
+
.catch((cancelError) => {
|
|
194
|
+
// If the cancellation failed, we need to mark the connection as disposed so that
|
|
195
|
+
// it gets destroyed by the pool and is never used again. If we don't do this and
|
|
196
|
+
// return the connection to the pool, it will be useless until the current operation
|
|
197
|
+
// that timed out, finally finishes.
|
|
198
|
+
this.connection.__knex__disposed = error;
|
|
199
|
+
|
|
200
|
+
// cancellation failed
|
|
201
|
+
throw Object.assign(cancelError, {
|
|
202
|
+
message: `After query timeout of ${timeout}ms exceeded, cancelling of query failed.`,
|
|
203
|
+
sql,
|
|
204
|
+
bindings,
|
|
205
|
+
timeout,
|
|
206
|
+
});
|
|
207
|
+
})
|
|
208
|
+
.then(() => {
|
|
209
|
+
// cancellation succeeded, rethrow timeout error
|
|
210
|
+
throw Object.assign(error, {
|
|
211
|
+
message: `Defined query timeout of ${timeout}ms exceeded when running query.`,
|
|
212
|
+
sql,
|
|
213
|
+
bindings,
|
|
214
|
+
timeout,
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
})
|
|
218
|
+
.catch((error) => {
|
|
219
|
+
this.builder.emit(
|
|
220
|
+
'query-error',
|
|
221
|
+
error,
|
|
222
|
+
Object.assign({ __knexUid, __knexTxId, queryContext }, obj)
|
|
223
|
+
);
|
|
224
|
+
throw error;
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// In the case of the "schema builder" we call `queryArray`, which runs each
|
|
229
|
+
// of the queries in sequence.
|
|
230
|
+
async queryArray(queries) {
|
|
231
|
+
if (queries.length === 1) {
|
|
232
|
+
const query = queries[0];
|
|
233
|
+
|
|
234
|
+
if (!query.statementsProducer) {
|
|
235
|
+
return this.query(query);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const statements = await query.statementsProducer(
|
|
239
|
+
undefined,
|
|
240
|
+
this.connection
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
const sqlQueryObjects = statements.sql.map((statement) => ({
|
|
244
|
+
sql: statement,
|
|
245
|
+
bindings: query.bindings,
|
|
246
|
+
}));
|
|
247
|
+
const preQueryObjects = statements.pre.map((statement) => ({
|
|
248
|
+
sql: statement,
|
|
249
|
+
bindings: query.bindings,
|
|
250
|
+
}));
|
|
251
|
+
const postQueryObjects = statements.post.map((statement) => ({
|
|
252
|
+
sql: statement,
|
|
253
|
+
bindings: query.bindings,
|
|
254
|
+
}));
|
|
255
|
+
|
|
256
|
+
let results = [];
|
|
257
|
+
|
|
258
|
+
await this.queryArray(preQueryObjects);
|
|
259
|
+
|
|
260
|
+
try {
|
|
261
|
+
await this.client.transaction(
|
|
262
|
+
async (trx) => {
|
|
263
|
+
const transactionRunner = new Runner(trx.client, this.builder);
|
|
264
|
+
transactionRunner.connection = this.connection;
|
|
265
|
+
|
|
266
|
+
results = await transactionRunner.queryArray(sqlQueryObjects);
|
|
267
|
+
|
|
268
|
+
if (statements.check) {
|
|
269
|
+
const foreignViolations = await trx.raw(statements.check);
|
|
270
|
+
|
|
271
|
+
if (foreignViolations.length > 0) {
|
|
272
|
+
throw new Error('FOREIGN KEY constraint failed');
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
{ connection: this.connection }
|
|
277
|
+
);
|
|
278
|
+
} finally {
|
|
279
|
+
await this.queryArray(postQueryObjects);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return results;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const results = [];
|
|
286
|
+
for (const query of queries) {
|
|
287
|
+
results.push(await this.queryArray([query]));
|
|
288
|
+
}
|
|
289
|
+
return results;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Check whether there's a transaction flag, and that it has a connection.
|
|
293
|
+
async ensureConnection(cb, cbParams) {
|
|
294
|
+
// Use override from a builder if passed
|
|
295
|
+
if (this.builder._connection) {
|
|
296
|
+
this.connection = this.builder._connection;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (this.connection) {
|
|
300
|
+
return cb(this, cbParams);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
let acquiredConnection;
|
|
304
|
+
try {
|
|
305
|
+
acquiredConnection = await this.client.acquireConnection();
|
|
306
|
+
} catch (error) {
|
|
307
|
+
if (!(error instanceof KnexTimeoutError)) {
|
|
308
|
+
return Promise.reject(error);
|
|
309
|
+
}
|
|
310
|
+
if (this.builder) {
|
|
311
|
+
error.sql = this.builder.sql;
|
|
312
|
+
error.bindings = this.builder.bindings;
|
|
313
|
+
}
|
|
314
|
+
throw error;
|
|
315
|
+
}
|
|
316
|
+
try {
|
|
317
|
+
this.connection = acquiredConnection;
|
|
318
|
+
return await cb(this, cbParams);
|
|
319
|
+
} finally {
|
|
320
|
+
await this.client.releaseConnection(acquiredConnection);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
module.exports = Runner;
|