knex 0.21.20 → 0.21.21

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 (141) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/CONTRIBUTING.md +184 -184
  3. package/LICENSE +22 -22
  4. package/README.md +95 -95
  5. package/bin/cli.js +414 -414
  6. package/bin/utils/cli-config-utils.js +151 -151
  7. package/bin/utils/constants.js +7 -7
  8. package/bin/utils/migrationsLister.js +37 -37
  9. package/knex.js +8 -8
  10. package/lib/client.js +413 -413
  11. package/lib/config-resolver.js +61 -61
  12. package/lib/constants.js +44 -44
  13. package/lib/dialects/mssql/index.js +390 -390
  14. package/lib/dialects/mssql/query/compiler.js +444 -444
  15. package/lib/dialects/mssql/schema/columncompiler.js +103 -103
  16. package/lib/dialects/mssql/schema/compiler.js +59 -59
  17. package/lib/dialects/mssql/schema/tablecompiler.js +245 -245
  18. package/lib/dialects/mssql/transaction.js +97 -97
  19. package/lib/dialects/mysql/index.js +191 -191
  20. package/lib/dialects/mysql/query/compiler.js +142 -142
  21. package/lib/dialects/mysql/schema/columncompiler.js +171 -171
  22. package/lib/dialects/mysql/schema/compiler.js +60 -60
  23. package/lib/dialects/mysql/schema/tablecompiler.js +262 -262
  24. package/lib/dialects/mysql/transaction.js +48 -48
  25. package/lib/dialects/mysql2/index.js +35 -35
  26. package/lib/dialects/mysql2/transaction.js +46 -46
  27. package/lib/dialects/oracle/DEAD_CODE.md +5 -5
  28. package/lib/dialects/oracle/formatter.js +20 -20
  29. package/lib/dialects/oracle/index.js +79 -79
  30. package/lib/dialects/oracle/query/compiler.js +327 -327
  31. package/lib/dialects/oracle/schema/columnbuilder.js +18 -18
  32. package/lib/dialects/oracle/schema/columncompiler.js +139 -139
  33. package/lib/dialects/oracle/schema/compiler.js +81 -81
  34. package/lib/dialects/oracle/schema/tablecompiler.js +165 -165
  35. package/lib/dialects/oracle/schema/trigger.js +126 -126
  36. package/lib/dialects/oracle/utils.js +86 -86
  37. package/lib/dialects/oracledb/index.js +489 -489
  38. package/lib/dialects/oracledb/query/compiler.js +363 -363
  39. package/lib/dialects/oracledb/schema/columncompiler.js +35 -35
  40. package/lib/dialects/oracledb/transaction.js +76 -76
  41. package/lib/dialects/oracledb/utils.js +14 -14
  42. package/lib/dialects/postgres/index.js +319 -319
  43. package/lib/dialects/postgres/query/compiler.js +206 -206
  44. package/lib/dialects/postgres/schema/columncompiler.js +125 -125
  45. package/lib/dialects/postgres/schema/compiler.js +109 -109
  46. package/lib/dialects/postgres/schema/tablecompiler.js +183 -183
  47. package/lib/dialects/redshift/index.js +73 -73
  48. package/lib/dialects/redshift/query/compiler.js +119 -119
  49. package/lib/dialects/redshift/schema/columnbuilder.js +20 -20
  50. package/lib/dialects/redshift/schema/columncompiler.js +60 -60
  51. package/lib/dialects/redshift/schema/compiler.js +14 -14
  52. package/lib/dialects/redshift/schema/tablecompiler.js +123 -123
  53. package/lib/dialects/redshift/transaction.js +18 -18
  54. package/lib/dialects/sqlite3/formatter.js +21 -21
  55. package/lib/dialects/sqlite3/index.js +169 -169
  56. package/lib/dialects/sqlite3/query/compiler.js +222 -222
  57. package/lib/dialects/sqlite3/schema/columncompiler.js +27 -27
  58. package/lib/dialects/sqlite3/schema/compiler.js +49 -49
  59. package/lib/dialects/sqlite3/schema/ddl.js +525 -525
  60. package/lib/dialects/sqlite3/schema/tablecompiler.js +238 -238
  61. package/lib/formatter.js +295 -295
  62. package/lib/functionhelper.js +14 -14
  63. package/lib/helpers.js +92 -92
  64. package/lib/index.js +3 -3
  65. package/lib/interface.js +115 -115
  66. package/lib/knex.js +42 -42
  67. package/lib/logger.js +76 -76
  68. package/lib/migrate/MigrationGenerator.js +82 -82
  69. package/lib/migrate/Migrator.js +611 -611
  70. package/lib/migrate/configuration-merger.js +60 -60
  71. package/lib/migrate/migrate-stub.js +17 -17
  72. package/lib/migrate/migration-list-resolver.js +36 -36
  73. package/lib/migrate/sources/fs-migrations.js +99 -99
  74. package/lib/migrate/stub/cjs.stub +15 -15
  75. package/lib/migrate/stub/coffee.stub +13 -13
  76. package/lib/migrate/stub/eg.stub +14 -14
  77. package/lib/migrate/stub/js.stub +15 -15
  78. package/lib/migrate/stub/knexfile-coffee.stub +34 -34
  79. package/lib/migrate/stub/knexfile-eg.stub +43 -43
  80. package/lib/migrate/stub/knexfile-js.stub +44 -44
  81. package/lib/migrate/stub/knexfile-ls.stub +35 -35
  82. package/lib/migrate/stub/knexfile-ts.stub +44 -44
  83. package/lib/migrate/stub/ls.stub +14 -14
  84. package/lib/migrate/stub/ts.stub +21 -21
  85. package/lib/migrate/table-creator.js +67 -67
  86. package/lib/migrate/table-resolver.js +27 -27
  87. package/lib/query/builder.js +1372 -1372
  88. package/lib/query/compiler.js +889 -889
  89. package/lib/query/constants.js +13 -13
  90. package/lib/query/joinclause.js +263 -263
  91. package/lib/query/methods.js +92 -92
  92. package/lib/query/string.js +190 -190
  93. package/lib/raw.js +188 -188
  94. package/lib/ref.js +39 -39
  95. package/lib/runner.js +285 -285
  96. package/lib/schema/builder.js +82 -82
  97. package/lib/schema/columnbuilder.js +117 -117
  98. package/lib/schema/columncompiler.js +177 -177
  99. package/lib/schema/compiler.js +101 -101
  100. package/lib/schema/helpers.js +51 -51
  101. package/lib/schema/tablebuilder.js +288 -288
  102. package/lib/schema/tablecompiler.js +296 -296
  103. package/lib/seed/Seeder.js +203 -203
  104. package/lib/seed/seed-stub.js +13 -13
  105. package/lib/seed/stub/coffee.stub +9 -9
  106. package/lib/seed/stub/eg.stub +11 -11
  107. package/lib/seed/stub/js.stub +13 -13
  108. package/lib/seed/stub/ls.stub +11 -11
  109. package/lib/seed/stub/ts.stub +13 -13
  110. package/lib/transaction.js +363 -363
  111. package/lib/util/batchInsert.js +59 -59
  112. package/lib/util/delay.js +6 -6
  113. package/lib/util/fake-client.js +9 -9
  114. package/lib/util/finally-mixin.js +13 -13
  115. package/lib/util/fs.js +76 -76
  116. package/lib/util/import-file.js +13 -13
  117. package/lib/util/is-module-type.js +14 -14
  118. package/lib/util/is.js +32 -32
  119. package/lib/util/make-knex.js +338 -338
  120. package/lib/util/nanoid.js +29 -29
  121. package/lib/util/noop.js +1 -1
  122. package/lib/util/parse-connection.js +66 -66
  123. package/lib/util/save-async-stack.js +14 -14
  124. package/lib/util/template.js +52 -52
  125. package/lib/util/timeout.js +29 -29
  126. package/lib/util/timestamp.js +16 -16
  127. package/package.json +1 -1
  128. package/scripts/build.js +125 -125
  129. package/scripts/docker-compose.yml +111 -111
  130. package/scripts/next-release-howto.md +24 -24
  131. package/scripts/release.sh +34 -34
  132. package/scripts/runkit-example.js +34 -34
  133. package/scripts/stress-test/README.txt +18 -18
  134. package/scripts/stress-test/docker-compose.yml +47 -47
  135. package/scripts/stress-test/knex-stress-test.js +196 -196
  136. package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +145 -145
  137. package/scripts/stress-test/mysql2-sudden-exit-without-error.js +100 -100
  138. package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +184 -184
  139. package/types/index.d.ts +2249 -2249
  140. package/types/result.d.ts +27 -27
  141. package/types/tables.d.ts +4 -4
package/lib/client.js CHANGED
@@ -1,413 +1,413 @@
1
- const Raw = require('./raw');
2
- const Ref = require('./ref');
3
- const Runner = require('./runner');
4
- const Formatter = require('./formatter');
5
- const Transaction = require('./transaction');
6
-
7
- const QueryBuilder = require('./query/builder');
8
- const QueryCompiler = require('./query/compiler');
9
-
10
- const SchemaBuilder = require('./schema/builder');
11
- const SchemaCompiler = require('./schema/compiler');
12
- const TableBuilder = require('./schema/tablebuilder');
13
- const TableCompiler = require('./schema/tablecompiler');
14
- const ColumnBuilder = require('./schema/columnbuilder');
15
- const ColumnCompiler = require('./schema/columncompiler');
16
-
17
- const { Pool, TimeoutError } = require('tarn');
18
- const { EventEmitter } = require('events');
19
- const { promisify, inherits } = require('util');
20
-
21
- const { makeEscape } = require('./query/string');
22
- const cloneDeep = require('lodash/cloneDeep');
23
- const defaults = require('lodash/defaults');
24
- const uniqueId = require('lodash/uniqueId');
25
-
26
- const Logger = require('./logger');
27
- const { KnexTimeoutError } = require('./util/timeout');
28
-
29
- const debug = require('debug')('knex:client');
30
- const _debugQuery = require('debug')('knex:query');
31
- const debugBindings = require('debug')('knex:bindings');
32
-
33
- const debugQuery = (sql, txId) => _debugQuery(sql.replace(/%/g, '%%'), txId);
34
-
35
- const { POOL_CONFIG_OPTIONS } = require('./constants');
36
-
37
- // The base client provides the general structure
38
- // for a dialect specific client object.
39
- function Client(config = {}) {
40
- this.config = config;
41
- this.logger = new Logger(config);
42
-
43
- //Client is a required field, so throw error if it's not supplied.
44
- //If 'this.dialect' is set, then this is a 'super()' call, in which case
45
- //'client' does not have to be set as it's already assigned on the client prototype.
46
-
47
- if (this.dialect && !this.config.client) {
48
- this.logger.warn(
49
- `Using 'this.dialect' to identify the client is deprecated and support for it will be removed in the future. Please use configuration option 'client' instead.`
50
- );
51
- }
52
- const dbClient = this.config.client || this.dialect;
53
- if (!dbClient) {
54
- throw new Error(`knex: Required configuration option 'client' is missing.`);
55
- }
56
-
57
- if (config.version) {
58
- this.version = config.version;
59
- }
60
-
61
- if (config.connection && config.connection instanceof Function) {
62
- this.connectionConfigProvider = config.connection;
63
- this.connectionConfigExpirationChecker = () => true; // causes the provider to be called on first use
64
- } else {
65
- this.connectionSettings = cloneDeep(config.connection || {});
66
- this.connectionConfigExpirationChecker = null;
67
- }
68
- if (this.driverName && config.connection) {
69
- this.initializeDriver();
70
- if (!config.pool || (config.pool && config.pool.max !== 0)) {
71
- this.initializePool(config);
72
- }
73
- }
74
- this.valueForUndefined = this.raw('DEFAULT');
75
- if (config.useNullAsDefault) {
76
- this.valueForUndefined = null;
77
- }
78
- }
79
-
80
- inherits(Client, EventEmitter);
81
-
82
- Object.assign(Client.prototype, {
83
- formatter(builder) {
84
- return new Formatter(this, builder);
85
- },
86
-
87
- queryBuilder() {
88
- return new QueryBuilder(this);
89
- },
90
-
91
- queryCompiler(builder) {
92
- return new QueryCompiler(this, builder);
93
- },
94
-
95
- schemaBuilder() {
96
- return new SchemaBuilder(this);
97
- },
98
-
99
- schemaCompiler(builder) {
100
- return new SchemaCompiler(this, builder);
101
- },
102
-
103
- tableBuilder(type, tableName, fn) {
104
- return new TableBuilder(this, type, tableName, fn);
105
- },
106
-
107
- tableCompiler(tableBuilder) {
108
- return new TableCompiler(this, tableBuilder);
109
- },
110
-
111
- columnBuilder(tableBuilder, type, args) {
112
- return new ColumnBuilder(this, tableBuilder, type, args);
113
- },
114
-
115
- columnCompiler(tableBuilder, columnBuilder) {
116
- return new ColumnCompiler(this, tableBuilder, columnBuilder);
117
- },
118
-
119
- runner(builder) {
120
- return new Runner(this, builder);
121
- },
122
-
123
- transaction(container, config, outerTx) {
124
- return new Transaction(this, container, config, outerTx);
125
- },
126
-
127
- raw() {
128
- return new Raw(this).set(...arguments);
129
- },
130
-
131
- ref() {
132
- return new Ref(this, ...arguments);
133
- },
134
-
135
- _formatQuery(sql, bindings, timeZone) {
136
- bindings = bindings == null ? [] : [].concat(bindings);
137
- let index = 0;
138
- return sql.replace(/\\?\?/g, (match) => {
139
- if (match === '\\?') {
140
- return '?';
141
- }
142
- if (index === bindings.length) {
143
- return match;
144
- }
145
- const value = bindings[index++];
146
- return this._escapeBinding(value, { timeZone });
147
- });
148
- },
149
-
150
- _escapeBinding: makeEscape({
151
- escapeString(str) {
152
- return `'${str.replace(/'/g, "''")}'`;
153
- },
154
- }),
155
-
156
- query(connection, obj) {
157
- if (typeof obj === 'string') obj = { sql: obj };
158
- obj.bindings = this.prepBindings(obj.bindings);
159
-
160
- const { __knexUid, __knexTxId } = connection;
161
-
162
- this.emit('query', Object.assign({ __knexUid, __knexTxId }, obj));
163
- debugQuery(obj.sql, __knexTxId);
164
- debugBindings(obj.bindings, __knexTxId);
165
-
166
- obj.sql = this.positionBindings(obj.sql);
167
-
168
- return this._query(connection, obj).catch((err) => {
169
- err.message =
170
- this._formatQuery(obj.sql, obj.bindings) + ' - ' + err.message;
171
- this.emit(
172
- 'query-error',
173
- err,
174
- Object.assign({ __knexUid, __knexTxId }, obj)
175
- );
176
- throw err;
177
- });
178
- },
179
-
180
- stream(connection, obj, stream, options) {
181
- if (typeof obj === 'string') obj = { sql: obj };
182
- obj.bindings = this.prepBindings(obj.bindings);
183
-
184
- const { __knexUid, __knexTxId } = connection;
185
-
186
- this.emit('query', Object.assign({ __knexUid, __knexTxId }, obj));
187
- debugQuery(obj.sql, __knexTxId);
188
- debugBindings(obj.bindings, __knexTxId);
189
-
190
- obj.sql = this.positionBindings(obj.sql);
191
-
192
- return this._stream(connection, obj, stream, options);
193
- },
194
-
195
- prepBindings(bindings) {
196
- return bindings;
197
- },
198
-
199
- positionBindings(sql) {
200
- return sql;
201
- },
202
-
203
- postProcessResponse(resp, queryContext) {
204
- if (this.config.postProcessResponse) {
205
- return this.config.postProcessResponse(resp, queryContext);
206
- }
207
- return resp;
208
- },
209
-
210
- wrapIdentifier(value, queryContext) {
211
- return this.customWrapIdentifier(
212
- value,
213
- this.wrapIdentifierImpl,
214
- queryContext
215
- );
216
- },
217
-
218
- customWrapIdentifier(value, origImpl, queryContext) {
219
- if (this.config.wrapIdentifier) {
220
- return this.config.wrapIdentifier(value, origImpl, queryContext);
221
- }
222
- return origImpl(value);
223
- },
224
-
225
- wrapIdentifierImpl(value) {
226
- return value !== '*' ? `"${value.replace(/"/g, '""')}"` : '*';
227
- },
228
-
229
- initializeDriver() {
230
- try {
231
- this.driver = this._driver();
232
- } catch (e) {
233
- const message = `Knex: run\n$ npm install ${this.driverName} --save`;
234
- this.logger.error(`${message}\n${e.message}\n${e.stack}`);
235
- throw new Error(`${message}\n${e.message}`);
236
- }
237
- },
238
-
239
- poolDefaults() {
240
- return { min: 2, max: 10, propagateCreateError: true };
241
- },
242
-
243
- getPoolSettings(poolConfig) {
244
- poolConfig = defaults({}, poolConfig, this.poolDefaults());
245
-
246
- POOL_CONFIG_OPTIONS.forEach((option) => {
247
- if (option in poolConfig) {
248
- this.logger.warn(
249
- [
250
- `Pool config option "${option}" is no longer supported.`,
251
- `See https://github.com/Vincit/tarn.js for possible pool config options.`,
252
- ].join(' ')
253
- );
254
- }
255
- });
256
-
257
- const timeouts = [
258
- this.config.acquireConnectionTimeout || 60000,
259
- poolConfig.acquireTimeoutMillis,
260
- ].filter((timeout) => timeout !== undefined);
261
-
262
- // acquire connection timeout can be set on config or config.pool
263
- // choose the smallest, positive timeout setting and set on poolConfig
264
- poolConfig.acquireTimeoutMillis = Math.min(...timeouts);
265
-
266
- const updatePoolConnectionSettingsFromProvider = async () => {
267
- if (!this.connectionConfigProvider) {
268
- return; // static configuration, nothing to update
269
- }
270
- if (
271
- !this.connectionConfigExpirationChecker ||
272
- !this.connectionConfigExpirationChecker()
273
- ) {
274
- return; // not expired, reuse existing connection
275
- }
276
- const providerResult = await this.connectionConfigProvider();
277
- if (providerResult.expirationChecker) {
278
- this.connectionConfigExpirationChecker =
279
- providerResult.expirationChecker;
280
- delete providerResult.expirationChecker; // MySQL2 driver warns on receiving extra properties
281
- } else {
282
- this.connectionConfigExpirationChecker = null;
283
- }
284
- this.connectionSettings = providerResult;
285
- };
286
-
287
- return Object.assign(poolConfig, {
288
- create: async () => {
289
- await updatePoolConnectionSettingsFromProvider();
290
- const connection = await this.acquireRawConnection();
291
- connection.__knexUid = uniqueId('__knexUid');
292
- if (poolConfig.afterCreate) {
293
- await promisify(poolConfig.afterCreate)(connection);
294
- }
295
- return connection;
296
- },
297
-
298
- destroy: (connection) => {
299
- if (connection !== void 0) {
300
- return this.destroyRawConnection(connection);
301
- }
302
- },
303
-
304
- validate: (connection) => {
305
- if (connection.__knex__disposed) {
306
- this.logger.warn(`Connection Error: ${connection.__knex__disposed}`);
307
- return false;
308
- }
309
-
310
- return this.validateConnection(connection);
311
- },
312
- });
313
- },
314
-
315
- initializePool(config = this.config) {
316
- if (this.pool) {
317
- this.logger.warn('The pool has already been initialized');
318
- return;
319
- }
320
-
321
- const tarnPoolConfig = {
322
- ...this.getPoolSettings(config.pool),
323
- };
324
- // afterCreate is an internal knex param, tarn.js does not support it
325
- if (tarnPoolConfig.afterCreate) {
326
- delete tarnPoolConfig.afterCreate;
327
- }
328
-
329
- this.pool = new Pool(tarnPoolConfig);
330
- },
331
-
332
- validateConnection(connection) {
333
- return true;
334
- },
335
-
336
- // Acquire a connection from the pool.
337
- async acquireConnection() {
338
- if (!this.pool) {
339
- throw new Error('Unable to acquire a connection');
340
- }
341
- try {
342
- const connection = await this.pool.acquire().promise;
343
- debug('acquired connection from pool: %s', connection.__knexUid);
344
- return connection;
345
- } catch (error) {
346
- let convertedError = error;
347
- if (error instanceof TimeoutError) {
348
- convertedError = new KnexTimeoutError(
349
- 'Knex: Timeout acquiring a connection. The pool is probably full. ' +
350
- 'Are you missing a .transacting(trx) call?'
351
- );
352
- }
353
- throw convertedError;
354
- }
355
- },
356
-
357
- // Releases a connection back to the connection pool,
358
- // returning a promise resolved when the connection is released.
359
- releaseConnection(connection) {
360
- debug('releasing connection to pool: %s', connection.__knexUid);
361
- const didRelease = this.pool.release(connection);
362
-
363
- if (!didRelease) {
364
- debug('pool refused connection: %s', connection.__knexUid);
365
- }
366
-
367
- return Promise.resolve();
368
- },
369
-
370
- // Destroy the current connection pool for the client.
371
- destroy(callback) {
372
- const maybeDestroy = this.pool && this.pool.destroy();
373
-
374
- return Promise.resolve(maybeDestroy)
375
- .then(() => {
376
- this.pool = void 0;
377
-
378
- if (typeof callback === 'function') {
379
- callback();
380
- }
381
- })
382
- .catch((err) => {
383
- if (typeof callback === 'function') {
384
- callback(err);
385
- }
386
-
387
- return Promise.reject(err);
388
- });
389
- },
390
-
391
- // Return the database being used by this client.
392
- database() {
393
- return this.connectionSettings.database;
394
- },
395
-
396
- toString() {
397
- return '[object KnexClient]';
398
- },
399
-
400
- canCancelQuery: false,
401
-
402
- assertCanCancelQuery() {
403
- if (!this.canCancelQuery) {
404
- throw new Error('Query cancelling not supported for this dialect');
405
- }
406
- },
407
-
408
- cancelQuery() {
409
- throw new Error('Query cancelling not supported for this dialect');
410
- },
411
- });
412
-
413
- module.exports = Client;
1
+ const Raw = require('./raw');
2
+ const Ref = require('./ref');
3
+ const Runner = require('./runner');
4
+ const Formatter = require('./formatter');
5
+ const Transaction = require('./transaction');
6
+
7
+ const QueryBuilder = require('./query/builder');
8
+ const QueryCompiler = require('./query/compiler');
9
+
10
+ const SchemaBuilder = require('./schema/builder');
11
+ const SchemaCompiler = require('./schema/compiler');
12
+ const TableBuilder = require('./schema/tablebuilder');
13
+ const TableCompiler = require('./schema/tablecompiler');
14
+ const ColumnBuilder = require('./schema/columnbuilder');
15
+ const ColumnCompiler = require('./schema/columncompiler');
16
+
17
+ const { Pool, TimeoutError } = require('tarn');
18
+ const { EventEmitter } = require('events');
19
+ const { promisify, inherits } = require('util');
20
+
21
+ const { makeEscape } = require('./query/string');
22
+ const cloneDeep = require('lodash/cloneDeep');
23
+ const defaults = require('lodash/defaults');
24
+ const uniqueId = require('lodash/uniqueId');
25
+
26
+ const Logger = require('./logger');
27
+ const { KnexTimeoutError } = require('./util/timeout');
28
+
29
+ const debug = require('debug')('knex:client');
30
+ const _debugQuery = require('debug')('knex:query');
31
+ const debugBindings = require('debug')('knex:bindings');
32
+
33
+ const debugQuery = (sql, txId) => _debugQuery(sql.replace(/%/g, '%%'), txId);
34
+
35
+ const { POOL_CONFIG_OPTIONS } = require('./constants');
36
+
37
+ // The base client provides the general structure
38
+ // for a dialect specific client object.
39
+ function Client(config = {}) {
40
+ this.config = config;
41
+ this.logger = new Logger(config);
42
+
43
+ //Client is a required field, so throw error if it's not supplied.
44
+ //If 'this.dialect' is set, then this is a 'super()' call, in which case
45
+ //'client' does not have to be set as it's already assigned on the client prototype.
46
+
47
+ if (this.dialect && !this.config.client) {
48
+ this.logger.warn(
49
+ `Using 'this.dialect' to identify the client is deprecated and support for it will be removed in the future. Please use configuration option 'client' instead.`
50
+ );
51
+ }
52
+ const dbClient = this.config.client || this.dialect;
53
+ if (!dbClient) {
54
+ throw new Error(`knex: Required configuration option 'client' is missing.`);
55
+ }
56
+
57
+ if (config.version) {
58
+ this.version = config.version;
59
+ }
60
+
61
+ if (config.connection && config.connection instanceof Function) {
62
+ this.connectionConfigProvider = config.connection;
63
+ this.connectionConfigExpirationChecker = () => true; // causes the provider to be called on first use
64
+ } else {
65
+ this.connectionSettings = cloneDeep(config.connection || {});
66
+ this.connectionConfigExpirationChecker = null;
67
+ }
68
+ if (this.driverName && config.connection) {
69
+ this.initializeDriver();
70
+ if (!config.pool || (config.pool && config.pool.max !== 0)) {
71
+ this.initializePool(config);
72
+ }
73
+ }
74
+ this.valueForUndefined = this.raw('DEFAULT');
75
+ if (config.useNullAsDefault) {
76
+ this.valueForUndefined = null;
77
+ }
78
+ }
79
+
80
+ inherits(Client, EventEmitter);
81
+
82
+ Object.assign(Client.prototype, {
83
+ formatter(builder) {
84
+ return new Formatter(this, builder);
85
+ },
86
+
87
+ queryBuilder() {
88
+ return new QueryBuilder(this);
89
+ },
90
+
91
+ queryCompiler(builder) {
92
+ return new QueryCompiler(this, builder);
93
+ },
94
+
95
+ schemaBuilder() {
96
+ return new SchemaBuilder(this);
97
+ },
98
+
99
+ schemaCompiler(builder) {
100
+ return new SchemaCompiler(this, builder);
101
+ },
102
+
103
+ tableBuilder(type, tableName, fn) {
104
+ return new TableBuilder(this, type, tableName, fn);
105
+ },
106
+
107
+ tableCompiler(tableBuilder) {
108
+ return new TableCompiler(this, tableBuilder);
109
+ },
110
+
111
+ columnBuilder(tableBuilder, type, args) {
112
+ return new ColumnBuilder(this, tableBuilder, type, args);
113
+ },
114
+
115
+ columnCompiler(tableBuilder, columnBuilder) {
116
+ return new ColumnCompiler(this, tableBuilder, columnBuilder);
117
+ },
118
+
119
+ runner(builder) {
120
+ return new Runner(this, builder);
121
+ },
122
+
123
+ transaction(container, config, outerTx) {
124
+ return new Transaction(this, container, config, outerTx);
125
+ },
126
+
127
+ raw() {
128
+ return new Raw(this).set(...arguments);
129
+ },
130
+
131
+ ref() {
132
+ return new Ref(this, ...arguments);
133
+ },
134
+
135
+ _formatQuery(sql, bindings, timeZone) {
136
+ bindings = bindings == null ? [] : [].concat(bindings);
137
+ let index = 0;
138
+ return sql.replace(/\\?\?/g, (match) => {
139
+ if (match === '\\?') {
140
+ return '?';
141
+ }
142
+ if (index === bindings.length) {
143
+ return match;
144
+ }
145
+ const value = bindings[index++];
146
+ return this._escapeBinding(value, { timeZone });
147
+ });
148
+ },
149
+
150
+ _escapeBinding: makeEscape({
151
+ escapeString(str) {
152
+ return `'${str.replace(/'/g, "''")}'`;
153
+ },
154
+ }),
155
+
156
+ query(connection, obj) {
157
+ if (typeof obj === 'string') obj = { sql: obj };
158
+ obj.bindings = this.prepBindings(obj.bindings);
159
+
160
+ const { __knexUid, __knexTxId } = connection;
161
+
162
+ this.emit('query', Object.assign({ __knexUid, __knexTxId }, obj));
163
+ debugQuery(obj.sql, __knexTxId);
164
+ debugBindings(obj.bindings, __knexTxId);
165
+
166
+ obj.sql = this.positionBindings(obj.sql);
167
+
168
+ return this._query(connection, obj).catch((err) => {
169
+ err.message =
170
+ this._formatQuery(obj.sql, obj.bindings) + ' - ' + err.message;
171
+ this.emit(
172
+ 'query-error',
173
+ err,
174
+ Object.assign({ __knexUid, __knexTxId }, obj)
175
+ );
176
+ throw err;
177
+ });
178
+ },
179
+
180
+ stream(connection, obj, stream, options) {
181
+ if (typeof obj === 'string') obj = { sql: obj };
182
+ obj.bindings = this.prepBindings(obj.bindings);
183
+
184
+ const { __knexUid, __knexTxId } = connection;
185
+
186
+ this.emit('query', Object.assign({ __knexUid, __knexTxId }, obj));
187
+ debugQuery(obj.sql, __knexTxId);
188
+ debugBindings(obj.bindings, __knexTxId);
189
+
190
+ obj.sql = this.positionBindings(obj.sql);
191
+
192
+ return this._stream(connection, obj, stream, options);
193
+ },
194
+
195
+ prepBindings(bindings) {
196
+ return bindings;
197
+ },
198
+
199
+ positionBindings(sql) {
200
+ return sql;
201
+ },
202
+
203
+ postProcessResponse(resp, queryContext) {
204
+ if (this.config.postProcessResponse) {
205
+ return this.config.postProcessResponse(resp, queryContext);
206
+ }
207
+ return resp;
208
+ },
209
+
210
+ wrapIdentifier(value, queryContext) {
211
+ return this.customWrapIdentifier(
212
+ value,
213
+ this.wrapIdentifierImpl,
214
+ queryContext
215
+ );
216
+ },
217
+
218
+ customWrapIdentifier(value, origImpl, queryContext) {
219
+ if (this.config.wrapIdentifier) {
220
+ return this.config.wrapIdentifier(value, origImpl, queryContext);
221
+ }
222
+ return origImpl(value);
223
+ },
224
+
225
+ wrapIdentifierImpl(value) {
226
+ return value !== '*' ? `"${value.replace(/"/g, '""')}"` : '*';
227
+ },
228
+
229
+ initializeDriver() {
230
+ try {
231
+ this.driver = this._driver();
232
+ } catch (e) {
233
+ const message = `Knex: run\n$ npm install ${this.driverName} --save`;
234
+ this.logger.error(`${message}\n${e.message}\n${e.stack}`);
235
+ throw new Error(`${message}\n${e.message}`);
236
+ }
237
+ },
238
+
239
+ poolDefaults() {
240
+ return { min: 2, max: 10, propagateCreateError: true };
241
+ },
242
+
243
+ getPoolSettings(poolConfig) {
244
+ poolConfig = defaults({}, poolConfig, this.poolDefaults());
245
+
246
+ POOL_CONFIG_OPTIONS.forEach((option) => {
247
+ if (option in poolConfig) {
248
+ this.logger.warn(
249
+ [
250
+ `Pool config option "${option}" is no longer supported.`,
251
+ `See https://github.com/Vincit/tarn.js for possible pool config options.`,
252
+ ].join(' ')
253
+ );
254
+ }
255
+ });
256
+
257
+ const timeouts = [
258
+ this.config.acquireConnectionTimeout || 60000,
259
+ poolConfig.acquireTimeoutMillis,
260
+ ].filter((timeout) => timeout !== undefined);
261
+
262
+ // acquire connection timeout can be set on config or config.pool
263
+ // choose the smallest, positive timeout setting and set on poolConfig
264
+ poolConfig.acquireTimeoutMillis = Math.min(...timeouts);
265
+
266
+ const updatePoolConnectionSettingsFromProvider = async () => {
267
+ if (!this.connectionConfigProvider) {
268
+ return; // static configuration, nothing to update
269
+ }
270
+ if (
271
+ !this.connectionConfigExpirationChecker ||
272
+ !this.connectionConfigExpirationChecker()
273
+ ) {
274
+ return; // not expired, reuse existing connection
275
+ }
276
+ const providerResult = await this.connectionConfigProvider();
277
+ if (providerResult.expirationChecker) {
278
+ this.connectionConfigExpirationChecker =
279
+ providerResult.expirationChecker;
280
+ delete providerResult.expirationChecker; // MySQL2 driver warns on receiving extra properties
281
+ } else {
282
+ this.connectionConfigExpirationChecker = null;
283
+ }
284
+ this.connectionSettings = providerResult;
285
+ };
286
+
287
+ return Object.assign(poolConfig, {
288
+ create: async () => {
289
+ await updatePoolConnectionSettingsFromProvider();
290
+ const connection = await this.acquireRawConnection();
291
+ connection.__knexUid = uniqueId('__knexUid');
292
+ if (poolConfig.afterCreate) {
293
+ await promisify(poolConfig.afterCreate)(connection);
294
+ }
295
+ return connection;
296
+ },
297
+
298
+ destroy: (connection) => {
299
+ if (connection !== void 0) {
300
+ return this.destroyRawConnection(connection);
301
+ }
302
+ },
303
+
304
+ validate: (connection) => {
305
+ if (connection.__knex__disposed) {
306
+ this.logger.warn(`Connection Error: ${connection.__knex__disposed}`);
307
+ return false;
308
+ }
309
+
310
+ return this.validateConnection(connection);
311
+ },
312
+ });
313
+ },
314
+
315
+ initializePool(config = this.config) {
316
+ if (this.pool) {
317
+ this.logger.warn('The pool has already been initialized');
318
+ return;
319
+ }
320
+
321
+ const tarnPoolConfig = {
322
+ ...this.getPoolSettings(config.pool),
323
+ };
324
+ // afterCreate is an internal knex param, tarn.js does not support it
325
+ if (tarnPoolConfig.afterCreate) {
326
+ delete tarnPoolConfig.afterCreate;
327
+ }
328
+
329
+ this.pool = new Pool(tarnPoolConfig);
330
+ },
331
+
332
+ validateConnection(connection) {
333
+ return true;
334
+ },
335
+
336
+ // Acquire a connection from the pool.
337
+ async acquireConnection() {
338
+ if (!this.pool) {
339
+ throw new Error('Unable to acquire a connection');
340
+ }
341
+ try {
342
+ const connection = await this.pool.acquire().promise;
343
+ debug('acquired connection from pool: %s', connection.__knexUid);
344
+ return connection;
345
+ } catch (error) {
346
+ let convertedError = error;
347
+ if (error instanceof TimeoutError) {
348
+ convertedError = new KnexTimeoutError(
349
+ 'Knex: Timeout acquiring a connection. The pool is probably full. ' +
350
+ 'Are you missing a .transacting(trx) call?'
351
+ );
352
+ }
353
+ throw convertedError;
354
+ }
355
+ },
356
+
357
+ // Releases a connection back to the connection pool,
358
+ // returning a promise resolved when the connection is released.
359
+ releaseConnection(connection) {
360
+ debug('releasing connection to pool: %s', connection.__knexUid);
361
+ const didRelease = this.pool.release(connection);
362
+
363
+ if (!didRelease) {
364
+ debug('pool refused connection: %s', connection.__knexUid);
365
+ }
366
+
367
+ return Promise.resolve();
368
+ },
369
+
370
+ // Destroy the current connection pool for the client.
371
+ destroy(callback) {
372
+ const maybeDestroy = this.pool && this.pool.destroy();
373
+
374
+ return Promise.resolve(maybeDestroy)
375
+ .then(() => {
376
+ this.pool = void 0;
377
+
378
+ if (typeof callback === 'function') {
379
+ callback();
380
+ }
381
+ })
382
+ .catch((err) => {
383
+ if (typeof callback === 'function') {
384
+ callback(err);
385
+ }
386
+
387
+ return Promise.reject(err);
388
+ });
389
+ },
390
+
391
+ // Return the database being used by this client.
392
+ database() {
393
+ return this.connectionSettings.database;
394
+ },
395
+
396
+ toString() {
397
+ return '[object KnexClient]';
398
+ },
399
+
400
+ canCancelQuery: false,
401
+
402
+ assertCanCancelQuery() {
403
+ if (!this.canCancelQuery) {
404
+ throw new Error('Query cancelling not supported for this dialect');
405
+ }
406
+ },
407
+
408
+ cancelQuery() {
409
+ throw new Error('Query cancelling not supported for this dialect');
410
+ },
411
+ });
412
+
413
+ module.exports = Client;