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.
Files changed (199) hide show
  1. package/CHANGELOG.md +2447 -2441
  2. package/CONTRIBUTING.md +190 -190
  3. package/LICENSE +22 -22
  4. package/README.md +156 -156
  5. package/UPGRADING.md +245 -245
  6. package/bin/cli.js +516 -516
  7. package/bin/knexfile-runtime-error.js +27 -27
  8. package/bin/utils/cli-config-utils.js +217 -217
  9. package/bin/utils/constants.js +7 -7
  10. package/bin/utils/migrationsLister.js +37 -37
  11. package/knex.js +23 -23
  12. package/knex.mjs +11 -11
  13. package/lib/builder-interface-augmenter.js +120 -120
  14. package/lib/client.js +585 -585
  15. package/lib/constants.js +61 -61
  16. package/lib/dialects/better-sqlite3/index.js +101 -101
  17. package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -14
  18. package/lib/dialects/cockroachdb/crdb-querybuilder.js +11 -11
  19. package/lib/dialects/cockroachdb/crdb-querycompiler.js +122 -122
  20. package/lib/dialects/cockroachdb/crdb-tablecompiler.js +46 -46
  21. package/lib/dialects/cockroachdb/crdb-viewcompiler.js +15 -15
  22. package/lib/dialects/cockroachdb/index.js +86 -86
  23. package/lib/dialects/index.js +34 -34
  24. package/lib/dialects/mssql/index.js +498 -498
  25. package/lib/dialects/mssql/mssql-formatter.js +34 -34
  26. package/lib/dialects/mssql/query/mssql-querycompiler.js +601 -601
  27. package/lib/dialects/mssql/schema/mssql-columncompiler.js +185 -185
  28. package/lib/dialects/mssql/schema/mssql-compiler.js +91 -91
  29. package/lib/dialects/mssql/schema/mssql-tablecompiler.js +393 -393
  30. package/lib/dialects/mssql/schema/mssql-viewcompiler.js +55 -55
  31. package/lib/dialects/mssql/transaction.js +176 -176
  32. package/lib/dialects/mysql/index.js +317 -317
  33. package/lib/dialects/mysql/query/mysql-querybuilder.js +14 -14
  34. package/lib/dialects/mysql/query/mysql-querycompiler.js +292 -292
  35. package/lib/dialects/mysql/schema/mysql-columncompiler.js +193 -193
  36. package/lib/dialects/mysql/schema/mysql-compiler.js +60 -60
  37. package/lib/dialects/mysql/schema/mysql-tablecompiler.js +426 -426
  38. package/lib/dialects/mysql/schema/mysql-viewbuilder.js +21 -21
  39. package/lib/dialects/mysql/schema/mysql-viewcompiler.js +15 -15
  40. package/lib/dialects/mysql/transaction.js +46 -46
  41. package/lib/dialects/mysql2/index.js +53 -53
  42. package/lib/dialects/mysql2/transaction.js +44 -44
  43. package/lib/dialects/oracle/DEAD_CODE.md +5 -5
  44. package/lib/dialects/oracle/index.js +92 -92
  45. package/lib/dialects/oracle/query/oracle-querycompiler.js +343 -343
  46. package/lib/dialects/oracle/schema/internal/incrementUtils.js +22 -22
  47. package/lib/dialects/oracle/schema/internal/trigger.js +155 -155
  48. package/lib/dialects/oracle/schema/oracle-columnbuilder.js +17 -17
  49. package/lib/dialects/oracle/schema/oracle-columncompiler.js +126 -126
  50. package/lib/dialects/oracle/schema/oracle-compiler.js +124 -124
  51. package/lib/dialects/oracle/schema/oracle-tablecompiler.js +210 -210
  52. package/lib/dialects/oracle/utils.js +107 -107
  53. package/lib/dialects/oracledb/index.js +381 -381
  54. package/lib/dialects/oracledb/query/oracledb-querycompiler.js +481 -481
  55. package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +61 -61
  56. package/lib/dialects/oracledb/schema/oracledb-tablecompiler.js +19 -19
  57. package/lib/dialects/oracledb/schema/oracledb-viewbuilder.js +13 -13
  58. package/lib/dialects/oracledb/schema/oracledb-viewcompiler.js +19 -19
  59. package/lib/dialects/oracledb/transaction.js +98 -98
  60. package/lib/dialects/oracledb/utils.js +208 -208
  61. package/lib/dialects/pgnative/index.js +60 -60
  62. package/lib/dialects/postgres/execution/pg-transaction.js +19 -19
  63. package/lib/dialects/postgres/index.js +373 -373
  64. package/lib/dialects/postgres/query/pg-querybuilder.js +43 -43
  65. package/lib/dialects/postgres/query/pg-querycompiler.js +400 -400
  66. package/lib/dialects/postgres/schema/pg-columncompiler.js +162 -162
  67. package/lib/dialects/postgres/schema/pg-compiler.js +138 -138
  68. package/lib/dialects/postgres/schema/pg-tablecompiler.js +331 -331
  69. package/lib/dialects/postgres/schema/pg-viewbuilder.js +21 -21
  70. package/lib/dialects/postgres/schema/pg-viewcompiler.js +35 -35
  71. package/lib/dialects/redshift/index.js +86 -86
  72. package/lib/dialects/redshift/query/redshift-querycompiler.js +163 -163
  73. package/lib/dialects/redshift/schema/redshift-columnbuilder.js +22 -22
  74. package/lib/dialects/redshift/schema/redshift-columncompiler.js +67 -67
  75. package/lib/dialects/redshift/schema/redshift-compiler.js +14 -14
  76. package/lib/dialects/redshift/schema/redshift-tablecompiler.js +134 -134
  77. package/lib/dialects/redshift/schema/redshift-viewcompiler.js +11 -11
  78. package/lib/dialects/redshift/transaction.js +32 -32
  79. package/lib/dialects/sqlite3/execution/sqlite-transaction.js +172 -172
  80. package/lib/dialects/sqlite3/index.js +263 -263
  81. package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -33
  82. package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +341 -341
  83. package/lib/dialects/sqlite3/schema/ddl.js +380 -380
  84. package/lib/dialects/sqlite3/schema/internal/compiler.js +327 -327
  85. package/lib/dialects/sqlite3/schema/internal/parser-combinator.js +161 -161
  86. package/lib/dialects/sqlite3/schema/internal/parser.js +638 -638
  87. package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +41 -41
  88. package/lib/dialects/sqlite3/schema/internal/tokenizer.js +38 -38
  89. package/lib/dialects/sqlite3/schema/internal/utils.js +12 -12
  90. package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +50 -50
  91. package/lib/dialects/sqlite3/schema/sqlite-compiler.js +80 -80
  92. package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +364 -364
  93. package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +40 -40
  94. package/lib/execution/batch-insert.js +51 -51
  95. package/lib/execution/internal/delay.js +6 -6
  96. package/lib/execution/internal/ensure-connection-callback.js +41 -41
  97. package/lib/execution/internal/query-executioner.js +62 -62
  98. package/lib/execution/runner.js +325 -325
  99. package/lib/execution/transaction.js +417 -417
  100. package/lib/formatter/formatterUtils.js +42 -42
  101. package/lib/formatter/rawFormatter.js +84 -84
  102. package/lib/formatter/wrappingFormatter.js +253 -253
  103. package/lib/formatter.js +25 -25
  104. package/lib/index.js +3 -3
  105. package/lib/knex-builder/FunctionHelper.js +80 -80
  106. package/lib/knex-builder/Knex.js +59 -59
  107. package/lib/knex-builder/internal/config-resolver.js +57 -57
  108. package/lib/knex-builder/internal/parse-connection.js +87 -87
  109. package/lib/knex-builder/make-knex.js +345 -345
  110. package/lib/logger.js +76 -76
  111. package/lib/migrations/common/MigrationsLoader.js +36 -36
  112. package/lib/migrations/migrate/MigrationGenerator.js +84 -84
  113. package/lib/migrations/migrate/Migrator.js +632 -632
  114. package/lib/migrations/migrate/migrate-stub.js +17 -17
  115. package/lib/migrations/migrate/migration-list-resolver.js +33 -33
  116. package/lib/migrations/migrate/migrator-configuration-merger.js +58 -58
  117. package/lib/migrations/migrate/sources/fs-migrations.js +74 -74
  118. package/lib/migrations/migrate/stub/cjs.stub +15 -15
  119. package/lib/migrations/migrate/stub/coffee.stub +13 -13
  120. package/lib/migrations/migrate/stub/eg.stub +14 -14
  121. package/lib/migrations/migrate/stub/js-schema.stub +22 -22
  122. package/lib/migrations/migrate/stub/js.stub +22 -22
  123. package/lib/migrations/migrate/stub/knexfile-coffee.stub +34 -34
  124. package/lib/migrations/migrate/stub/knexfile-eg.stub +43 -43
  125. package/lib/migrations/migrate/stub/knexfile-js.stub +47 -47
  126. package/lib/migrations/migrate/stub/knexfile-ls.stub +35 -35
  127. package/lib/migrations/migrate/stub/knexfile-ts.stub +47 -47
  128. package/lib/migrations/migrate/stub/ls.stub +14 -14
  129. package/lib/migrations/migrate/stub/mjs.stub +23 -23
  130. package/lib/migrations/migrate/stub/ts-schema.stub +21 -21
  131. package/lib/migrations/migrate/stub/ts.stub +21 -21
  132. package/lib/migrations/migrate/table-creator.js +77 -77
  133. package/lib/migrations/migrate/table-resolver.js +27 -27
  134. package/lib/migrations/seed/Seeder.js +137 -137
  135. package/lib/migrations/seed/seed-stub.js +13 -13
  136. package/lib/migrations/seed/seeder-configuration-merger.js +60 -60
  137. package/lib/migrations/seed/sources/fs-seeds.js +65 -65
  138. package/lib/migrations/seed/stub/coffee.stub +9 -9
  139. package/lib/migrations/seed/stub/eg.stub +11 -11
  140. package/lib/migrations/seed/stub/js.stub +13 -13
  141. package/lib/migrations/seed/stub/ls.stub +11 -11
  142. package/lib/migrations/seed/stub/mjs.stub +12 -12
  143. package/lib/migrations/seed/stub/ts.stub +13 -13
  144. package/lib/migrations/util/fs.js +86 -86
  145. package/lib/migrations/util/import-file.js +12 -12
  146. package/lib/migrations/util/is-module-type.js +9 -9
  147. package/lib/migrations/util/template.js +52 -52
  148. package/lib/migrations/util/timestamp.js +14 -14
  149. package/lib/query/analytic.js +52 -52
  150. package/lib/query/constants.js +15 -15
  151. package/lib/query/joinclause.js +270 -270
  152. package/lib/query/method-constants.js +136 -136
  153. package/lib/query/querybuilder.js +1793 -1793
  154. package/lib/query/querycompiler.js +1634 -1634
  155. package/lib/raw.js +139 -139
  156. package/lib/ref.js +39 -39
  157. package/lib/schema/builder.js +115 -115
  158. package/lib/schema/columnbuilder.js +146 -146
  159. package/lib/schema/columncompiler.js +307 -307
  160. package/lib/schema/compiler.js +187 -187
  161. package/lib/schema/internal/helpers.js +55 -55
  162. package/lib/schema/tablebuilder.js +379 -379
  163. package/lib/schema/tablecompiler.js +450 -450
  164. package/lib/schema/viewbuilder.js +92 -92
  165. package/lib/schema/viewcompiler.js +138 -138
  166. package/lib/util/finally-mixin.js +13 -13
  167. package/lib/util/helpers.js +95 -95
  168. package/lib/util/is.js +32 -32
  169. package/lib/util/nanoid.js +40 -40
  170. package/lib/util/noop.js +1 -1
  171. package/lib/util/save-async-stack.js +14 -14
  172. package/lib/util/security.js +32 -32
  173. package/lib/util/string.js +190 -190
  174. package/lib/util/timeout.js +29 -29
  175. package/package.json +294 -296
  176. package/scripts/act-testing/act.sh +19 -19
  177. package/scripts/act-testing/merged-no-label.json +11 -11
  178. package/scripts/act-testing/merged-patch-labeled.json +12 -12
  179. package/scripts/act-testing/merged-skip-labeled.json +12 -12
  180. package/scripts/act-testing/not-merged-patch-labeled.json +12 -12
  181. package/scripts/build-for-release.sh +121 -121
  182. package/scripts/build.js +125 -125
  183. package/scripts/clean.js +31 -31
  184. package/scripts/docker-compose.yml +150 -150
  185. package/scripts/format-changelog.js +55 -55
  186. package/scripts/next-release-howto.md +24 -24
  187. package/scripts/oracledb-install-driver-libs.sh +82 -82
  188. package/scripts/release.sh +36 -36
  189. package/scripts/runkit-example.js +35 -35
  190. package/scripts/stress-test/README.txt +18 -18
  191. package/scripts/stress-test/docker-compose.yml +55 -55
  192. package/scripts/stress-test/knex-stress-test.js +212 -212
  193. package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +149 -149
  194. package/scripts/stress-test/mysql2-sudden-exit-without-error.js +101 -101
  195. package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +188 -188
  196. package/types/index.d.mts +11 -0
  197. package/types/index.d.ts +3321 -3321
  198. package/types/result.d.ts +27 -27
  199. package/types/tables.d.ts +4 -4
@@ -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;