knex 2.4.2 → 2.5.0

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 (190) hide show
  1. package/CHANGELOG.md +54 -18
  2. package/CONTRIBUTING.md +194 -194
  3. package/LICENSE +22 -22
  4. package/README.md +147 -148
  5. package/UPGRADING.md +233 -233
  6. package/bin/cli.js +473 -473
  7. package/bin/utils/cli-config-utils.js +210 -210
  8. package/bin/utils/constants.js +7 -7
  9. package/bin/utils/migrationsLister.js +37 -37
  10. package/knex.js +23 -23
  11. package/knex.mjs +11 -0
  12. package/lib/builder-interface-augmenter.js +120 -120
  13. package/lib/client.js +495 -475
  14. package/lib/constants.js +61 -61
  15. package/lib/dialects/better-sqlite3/index.js +77 -72
  16. package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -14
  17. package/lib/dialects/cockroachdb/crdb-querybuilder.js +11 -11
  18. package/lib/dialects/cockroachdb/crdb-querycompiler.js +122 -122
  19. package/lib/dialects/cockroachdb/crdb-tablecompiler.js +37 -37
  20. package/lib/dialects/cockroachdb/crdb-viewcompiler.js +15 -15
  21. package/lib/dialects/cockroachdb/index.js +86 -86
  22. package/lib/dialects/index.js +33 -33
  23. package/lib/dialects/mssql/index.js +500 -495
  24. package/lib/dialects/mssql/mssql-formatter.js +34 -34
  25. package/lib/dialects/mssql/query/mssql-querycompiler.js +601 -600
  26. package/lib/dialects/mssql/schema/mssql-columncompiler.js +185 -185
  27. package/lib/dialects/mssql/schema/mssql-compiler.js +91 -91
  28. package/lib/dialects/mssql/schema/mssql-tablecompiler.js +378 -378
  29. package/lib/dialects/mssql/schema/mssql-viewcompiler.js +55 -55
  30. package/lib/dialects/mssql/transaction.js +176 -176
  31. package/lib/dialects/mysql/index.js +201 -201
  32. package/lib/dialects/mysql/query/mysql-querycompiler.js +274 -274
  33. package/lib/dialects/mysql/schema/mysql-columncompiler.js +193 -193
  34. package/lib/dialects/mysql/schema/mysql-compiler.js +60 -60
  35. package/lib/dialects/mysql/schema/mysql-tablecompiler.js +381 -381
  36. package/lib/dialects/mysql/schema/mysql-viewbuilder.js +21 -21
  37. package/lib/dialects/mysql/schema/mysql-viewcompiler.js +15 -15
  38. package/lib/dialects/mysql/transaction.js +46 -46
  39. package/lib/dialects/mysql2/index.js +53 -33
  40. package/lib/dialects/mysql2/transaction.js +44 -44
  41. package/lib/dialects/oracle/DEAD_CODE.md +5 -5
  42. package/lib/dialects/oracle/index.js +92 -92
  43. package/lib/dialects/oracle/query/oracle-querycompiler.js +343 -342
  44. package/lib/dialects/oracle/schema/internal/incrementUtils.js +20 -20
  45. package/lib/dialects/oracle/schema/internal/trigger.js +135 -135
  46. package/lib/dialects/oracle/schema/oracle-columnbuilder.js +17 -17
  47. package/lib/dialects/oracle/schema/oracle-columncompiler.js +126 -126
  48. package/lib/dialects/oracle/schema/oracle-compiler.js +122 -122
  49. package/lib/dialects/oracle/schema/oracle-tablecompiler.js +190 -190
  50. package/lib/dialects/oracle/utils.js +87 -87
  51. package/lib/dialects/oracledb/index.js +327 -327
  52. package/lib/dialects/oracledb/query/oracledb-querycompiler.js +481 -481
  53. package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +61 -55
  54. package/lib/dialects/oracledb/schema/oracledb-tablecompiler.js +19 -19
  55. package/lib/dialects/oracledb/schema/oracledb-viewbuilder.js +13 -13
  56. package/lib/dialects/oracledb/schema/oracledb-viewcompiler.js +19 -19
  57. package/lib/dialects/oracledb/transaction.js +98 -98
  58. package/lib/dialects/oracledb/utils.js +208 -208
  59. package/lib/dialects/pgnative/index.js +60 -60
  60. package/lib/dialects/postgres/execution/pg-transaction.js +19 -12
  61. package/lib/dialects/postgres/index.js +358 -358
  62. package/lib/dialects/postgres/query/pg-querybuilder.js +43 -38
  63. package/lib/dialects/postgres/query/pg-querycompiler.js +400 -395
  64. package/lib/dialects/postgres/schema/pg-columncompiler.js +156 -156
  65. package/lib/dialects/postgres/schema/pg-compiler.js +138 -138
  66. package/lib/dialects/postgres/schema/pg-tablecompiler.js +304 -299
  67. package/lib/dialects/postgres/schema/pg-viewbuilder.js +21 -21
  68. package/lib/dialects/postgres/schema/pg-viewcompiler.js +35 -35
  69. package/lib/dialects/redshift/index.js +86 -86
  70. package/lib/dialects/redshift/query/redshift-querycompiler.js +163 -163
  71. package/lib/dialects/redshift/schema/redshift-columnbuilder.js +22 -22
  72. package/lib/dialects/redshift/schema/redshift-columncompiler.js +67 -67
  73. package/lib/dialects/redshift/schema/redshift-compiler.js +14 -14
  74. package/lib/dialects/redshift/schema/redshift-tablecompiler.js +122 -122
  75. package/lib/dialects/redshift/schema/redshift-viewcompiler.js +11 -11
  76. package/lib/dialects/redshift/transaction.js +32 -25
  77. package/lib/dialects/sqlite3/execution/sqlite-transaction.js +25 -18
  78. package/lib/dialects/sqlite3/index.js +250 -250
  79. package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -33
  80. package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +334 -334
  81. package/lib/dialects/sqlite3/schema/ddl.js +400 -400
  82. package/lib/dialects/sqlite3/schema/internal/compiler.js +327 -327
  83. package/lib/dialects/sqlite3/schema/internal/parser-combinator.js +161 -161
  84. package/lib/dialects/sqlite3/schema/internal/parser.js +638 -638
  85. package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +41 -41
  86. package/lib/dialects/sqlite3/schema/internal/tokenizer.js +38 -38
  87. package/lib/dialects/sqlite3/schema/internal/utils.js +12 -12
  88. package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +50 -50
  89. package/lib/dialects/sqlite3/schema/sqlite-compiler.js +80 -80
  90. package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +347 -347
  91. package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +40 -40
  92. package/lib/execution/batch-insert.js +51 -51
  93. package/lib/execution/internal/delay.js +6 -6
  94. package/lib/execution/internal/ensure-connection-callback.js +41 -41
  95. package/lib/execution/internal/query-executioner.js +62 -62
  96. package/lib/execution/runner.js +325 -307
  97. package/lib/execution/transaction.js +409 -401
  98. package/lib/formatter/formatterUtils.js +42 -42
  99. package/lib/formatter/rawFormatter.js +84 -84
  100. package/lib/formatter/wrappingFormatter.js +250 -250
  101. package/lib/formatter.js +25 -25
  102. package/lib/index.js +3 -3
  103. package/lib/knex-builder/FunctionHelper.js +80 -54
  104. package/lib/knex-builder/Knex.js +59 -59
  105. package/lib/knex-builder/internal/config-resolver.js +57 -57
  106. package/lib/knex-builder/internal/parse-connection.js +87 -87
  107. package/lib/knex-builder/make-knex.js +345 -340
  108. package/lib/logger.js +76 -76
  109. package/lib/migrations/common/MigrationsLoader.js +36 -36
  110. package/lib/migrations/migrate/MigrationGenerator.js +84 -84
  111. package/lib/migrations/migrate/Migrator.js +598 -598
  112. package/lib/migrations/migrate/migrate-stub.js +17 -17
  113. package/lib/migrations/migrate/migration-list-resolver.js +33 -33
  114. package/lib/migrations/migrate/migrator-configuration-merger.js +58 -58
  115. package/lib/migrations/migrate/sources/fs-migrations.js +74 -74
  116. package/lib/migrations/migrate/stub/cjs.stub +15 -15
  117. package/lib/migrations/migrate/stub/coffee.stub +13 -13
  118. package/lib/migrations/migrate/stub/eg.stub +14 -14
  119. package/lib/migrations/migrate/stub/js-schema.stub +22 -22
  120. package/lib/migrations/migrate/stub/js.stub +22 -22
  121. package/lib/migrations/migrate/stub/knexfile-coffee.stub +34 -34
  122. package/lib/migrations/migrate/stub/knexfile-eg.stub +43 -43
  123. package/lib/migrations/migrate/stub/knexfile-js.stub +47 -47
  124. package/lib/migrations/migrate/stub/knexfile-ls.stub +35 -35
  125. package/lib/migrations/migrate/stub/knexfile-ts.stub +47 -47
  126. package/lib/migrations/migrate/stub/ls.stub +14 -14
  127. package/lib/migrations/migrate/stub/mjs.stub +23 -23
  128. package/lib/migrations/migrate/stub/ts-schema.stub +21 -21
  129. package/lib/migrations/migrate/stub/ts.stub +21 -21
  130. package/lib/migrations/migrate/table-creator.js +77 -77
  131. package/lib/migrations/migrate/table-resolver.js +27 -27
  132. package/lib/migrations/seed/Seeder.js +137 -137
  133. package/lib/migrations/seed/seed-stub.js +13 -13
  134. package/lib/migrations/seed/seeder-configuration-merger.js +60 -60
  135. package/lib/migrations/seed/sources/fs-seeds.js +65 -65
  136. package/lib/migrations/seed/stub/coffee.stub +9 -9
  137. package/lib/migrations/seed/stub/eg.stub +11 -11
  138. package/lib/migrations/seed/stub/js.stub +13 -13
  139. package/lib/migrations/seed/stub/ls.stub +11 -11
  140. package/lib/migrations/seed/stub/mjs.stub +12 -12
  141. package/lib/migrations/seed/stub/ts.stub +13 -13
  142. package/lib/migrations/util/fs.js +86 -86
  143. package/lib/migrations/util/import-file.js +12 -12
  144. package/lib/migrations/util/is-module-type.js +9 -9
  145. package/lib/migrations/util/template.js +52 -52
  146. package/lib/migrations/util/timestamp.js +14 -14
  147. package/lib/query/analytic.js +52 -52
  148. package/lib/query/constants.js +15 -15
  149. package/lib/query/joinclause.js +270 -270
  150. package/lib/query/method-constants.js +136 -135
  151. package/lib/query/querybuilder.js +1793 -1794
  152. package/lib/query/querycompiler.js +1591 -1580
  153. package/lib/raw.js +139 -139
  154. package/lib/ref.js +39 -39
  155. package/lib/schema/builder.js +115 -115
  156. package/lib/schema/columnbuilder.js +146 -146
  157. package/lib/schema/columncompiler.js +307 -307
  158. package/lib/schema/compiler.js +187 -187
  159. package/lib/schema/internal/helpers.js +55 -55
  160. package/lib/schema/tablebuilder.js +376 -376
  161. package/lib/schema/tablecompiler.js +433 -433
  162. package/lib/schema/viewbuilder.js +92 -92
  163. package/lib/schema/viewcompiler.js +138 -138
  164. package/lib/util/finally-mixin.js +13 -13
  165. package/lib/util/helpers.js +95 -95
  166. package/lib/util/is.js +32 -32
  167. package/lib/util/nanoid.js +40 -40
  168. package/lib/util/noop.js +1 -1
  169. package/lib/util/save-async-stack.js +14 -14
  170. package/lib/util/security.js +26 -0
  171. package/lib/util/string.js +190 -190
  172. package/lib/util/timeout.js +29 -29
  173. package/package.json +12 -10
  174. package/scripts/build.js +125 -125
  175. package/scripts/clean.js +31 -31
  176. package/scripts/docker-compose.yml +152 -152
  177. package/scripts/next-release-howto.md +24 -24
  178. package/scripts/oracledb-install-driver-libs.sh +82 -82
  179. package/scripts/release.sh +34 -34
  180. package/scripts/runkit-example.js +34 -34
  181. package/scripts/stress-test/README.txt +18 -18
  182. package/scripts/stress-test/docker-compose.yml +57 -57
  183. package/scripts/stress-test/knex-stress-test.js +208 -208
  184. package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +145 -145
  185. package/scripts/stress-test/mysql2-sudden-exit-without-error.js +100 -100
  186. package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +184 -184
  187. package/scripts/update_gitignore_for_tsc_output.js +90 -90
  188. package/types/index.d.ts +3273 -3233
  189. package/types/result.d.ts +27 -27
  190. package/types/tables.d.ts +4 -4
@@ -1,307 +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
- const connectionAcquirePromise = this.ensureConnection(
76
- ensureConnectionStreamCallback,
77
- {
78
- options,
79
- hasHandler,
80
- stream,
81
- }
82
- )
83
- // Emit errors on the stream if the error occurred before a connection
84
- // could be acquired.
85
- // If the connection was acquired, assume the error occurred in the client
86
- // code and has already been emitted on the stream. Don't emit it twice.
87
- .catch((err) => {
88
- if (!this.connection) {
89
- stream.emit('error', err);
90
- }
91
- });
92
-
93
- // If a function is passed to handle the stream, send the stream
94
- // there and return the promise, otherwise just return the stream
95
- // and the promise will take care of itself.
96
- if (hasHandler) {
97
- handler(stream);
98
- return connectionAcquirePromise;
99
- }
100
- return stream;
101
- }
102
-
103
- // Allow you to pipe the stream to a writable stream.
104
- pipe(writable, options) {
105
- return this.stream(options).pipe(writable);
106
- }
107
-
108
- // "Runs" a query, returning a promise. All queries specified by the builder are guaranteed
109
- // to run in sequence, and on the same connection, especially helpful when schema building
110
- // and dealing with foreign key constraints, etc.
111
- async query(obj) {
112
- const { __knexUid, __knexTxId } = this.connection;
113
-
114
- this.builder.emit('query', Object.assign({ __knexUid, __knexTxId }, obj));
115
-
116
- const runner = this;
117
- const queryContext = this.builder.queryContext();
118
- // query-error events are emitted before the queryPromise continuations.
119
- // pass queryContext into client.query so it can be raised properly.
120
- if (obj !== null && typeof obj === 'object') {
121
- obj.queryContext = queryContext;
122
- }
123
- let queryPromise = this.client.query(this.connection, obj);
124
-
125
- if (obj.timeout) {
126
- queryPromise = timeout(queryPromise, obj.timeout);
127
- }
128
-
129
- // Await the return value of client.processResponse; in the case of sqlite3's
130
- // dropColumn()/renameColumn(), it will be a Promise for the transaction
131
- // containing the complete rename procedure.
132
- return queryPromise
133
- .then((resp) => this.client.processResponse(resp, runner))
134
- .then((processedResponse) => {
135
- const postProcessedResponse = this.client.postProcessResponse(
136
- processedResponse,
137
- queryContext
138
- );
139
-
140
- this.builder.emit(
141
- 'query-response',
142
- postProcessedResponse,
143
- Object.assign({ __knexUid, __knexTxId }, obj),
144
- this.builder
145
- );
146
-
147
- this.client.emit(
148
- 'query-response',
149
- postProcessedResponse,
150
- Object.assign({ __knexUid, __knexTxId }, obj),
151
- this.builder
152
- );
153
-
154
- return postProcessedResponse;
155
- })
156
- .catch((error) => {
157
- if (!(error instanceof KnexTimeoutError)) {
158
- return Promise.reject(error);
159
- }
160
- const { timeout, sql, bindings } = obj;
161
-
162
- let cancelQuery;
163
- if (obj.cancelOnTimeout) {
164
- cancelQuery = this.client.cancelQuery(this.connection);
165
- } else {
166
- // If we don't cancel the query, we need to mark the connection as disposed so that
167
- // it gets destroyed by the pool and is never used again. If we don't do this and
168
- // return the connection to the pool, it will be useless until the current operation
169
- // that timed out, finally finishes.
170
- this.connection.__knex__disposed = error;
171
- cancelQuery = Promise.resolve();
172
- }
173
-
174
- return cancelQuery
175
- .catch((cancelError) => {
176
- // If the cancellation failed, we need to mark the connection as disposed so that
177
- // it gets destroyed by the pool and is never used again. If we don't do this and
178
- // return the connection to the pool, it will be useless until the current operation
179
- // that timed out, finally finishes.
180
- this.connection.__knex__disposed = error;
181
-
182
- // cancellation failed
183
- throw Object.assign(cancelError, {
184
- message: `After query timeout of ${timeout}ms exceeded, cancelling of query failed.`,
185
- sql,
186
- bindings,
187
- timeout,
188
- });
189
- })
190
- .then(() => {
191
- // cancellation succeeded, rethrow timeout error
192
- throw Object.assign(error, {
193
- message: `Defined query timeout of ${timeout}ms exceeded when running query.`,
194
- sql,
195
- bindings,
196
- timeout,
197
- });
198
- });
199
- })
200
- .catch((error) => {
201
- this.builder.emit(
202
- 'query-error',
203
- error,
204
- Object.assign({ __knexUid, __knexTxId, queryContext }, obj)
205
- );
206
- throw error;
207
- });
208
- }
209
-
210
- // In the case of the "schema builder" we call `queryArray`, which runs each
211
- // of the queries in sequence.
212
- async queryArray(queries) {
213
- if (queries.length === 1) {
214
- const query = queries[0];
215
-
216
- if (!query.statementsProducer) {
217
- return this.query(query);
218
- }
219
-
220
- const statements = await query.statementsProducer(
221
- undefined,
222
- this.connection
223
- );
224
-
225
- const sqlQueryObjects = statements.sql.map((statement) => ({
226
- sql: statement,
227
- bindings: query.bindings,
228
- }));
229
- const preQueryObjects = statements.pre.map((statement) => ({
230
- sql: statement,
231
- bindings: query.bindings,
232
- }));
233
- const postQueryObjects = statements.post.map((statement) => ({
234
- sql: statement,
235
- bindings: query.bindings,
236
- }));
237
-
238
- let results = [];
239
-
240
- await this.queryArray(preQueryObjects);
241
-
242
- try {
243
- await this.client.transaction(
244
- async (trx) => {
245
- const transactionRunner = new Runner(trx.client, this.builder);
246
- transactionRunner.connection = this.connection;
247
-
248
- results = await transactionRunner.queryArray(sqlQueryObjects);
249
-
250
- if (statements.check) {
251
- const foreignViolations = await trx.raw(statements.check);
252
-
253
- if (foreignViolations.length > 0) {
254
- throw new Error('FOREIGN KEY constraint failed');
255
- }
256
- }
257
- },
258
- { connection: this.connection }
259
- );
260
- } finally {
261
- await this.queryArray(postQueryObjects);
262
- }
263
-
264
- return results;
265
- }
266
-
267
- const results = [];
268
- for (const query of queries) {
269
- results.push(await this.queryArray([query]));
270
- }
271
- return results;
272
- }
273
-
274
- // Check whether there's a transaction flag, and that it has a connection.
275
- async ensureConnection(cb, cbParams) {
276
- // Use override from a builder if passed
277
- if (this.builder._connection) {
278
- this.connection = this.builder._connection;
279
- }
280
-
281
- if (this.connection) {
282
- return cb(this, cbParams);
283
- }
284
-
285
- let acquiredConnection;
286
- try {
287
- acquiredConnection = await this.client.acquireConnection();
288
- } catch (error) {
289
- if (!(error instanceof KnexTimeoutError)) {
290
- return Promise.reject(error);
291
- }
292
- if (this.builder) {
293
- error.sql = this.builder.sql;
294
- error.bindings = this.builder.bindings;
295
- }
296
- throw error;
297
- }
298
- try {
299
- this.connection = acquiredConnection;
300
- return await cb(this, cbParams);
301
- } finally {
302
- await this.client.releaseConnection(acquiredConnection);
303
- }
304
- }
305
- }
306
-
307
- 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;