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
package/lib/client.js CHANGED
@@ -1,475 +1,495 @@
1
- const { Pool, TimeoutError } = require('tarn');
2
- const { EventEmitter } = require('events');
3
- const { promisify } = require('util');
4
- const { makeEscape } = require('./util/string');
5
- const cloneDeep = require('lodash/cloneDeep');
6
- const defaults = require('lodash/defaults');
7
- const uniqueId = require('lodash/uniqueId');
8
-
9
- const Runner = require('./execution/runner');
10
- const Transaction = require('./execution/transaction');
11
- const {
12
- executeQuery,
13
- enrichQueryObject,
14
- } = require('./execution/internal/query-executioner');
15
- const QueryBuilder = require('./query/querybuilder');
16
- const QueryCompiler = require('./query/querycompiler');
17
- const SchemaBuilder = require('./schema/builder');
18
- const SchemaCompiler = require('./schema/compiler');
19
- const TableBuilder = require('./schema/tablebuilder');
20
- const TableCompiler = require('./schema/tablecompiler');
21
- const ColumnBuilder = require('./schema/columnbuilder');
22
- const ColumnCompiler = require('./schema/columncompiler');
23
- const { KnexTimeoutError } = require('./util/timeout');
24
- const { outputQuery, unwrapRaw } = require('./formatter/wrappingFormatter');
25
- const { compileCallback } = require('./formatter/formatterUtils');
26
- const Raw = require('./raw');
27
- const Ref = require('./ref');
28
- const Formatter = require('./formatter');
29
- const Logger = require('./logger');
30
- const { POOL_CONFIG_OPTIONS } = require('./constants');
31
- const ViewBuilder = require('./schema/viewbuilder.js');
32
- const ViewCompiler = require('./schema/viewcompiler.js');
33
- const isPlainObject = require('lodash/isPlainObject');
34
-
35
- const debug = require('debug')('knex:client');
36
-
37
- // The base client provides the general structure
38
- // for a dialect specific client object.
39
-
40
- class Client extends EventEmitter {
41
- constructor(config = {}) {
42
- super();
43
- this.config = config;
44
- this.logger = new Logger(config);
45
-
46
- //Client is a required field, so throw error if it's not supplied.
47
- //If 'this.dialect' is set, then this is a 'super()' call, in which case
48
- //'client' does not have to be set as it's already assigned on the client prototype.
49
-
50
- if (this.dialect && !this.config.client) {
51
- this.logger.warn(
52
- `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.`
53
- );
54
- }
55
-
56
- const dbClient = this.config.client || this.dialect;
57
- if (!dbClient) {
58
- throw new Error(
59
- `knex: Required configuration option 'client' is missing.`
60
- );
61
- }
62
-
63
- if (config.version) {
64
- this.version = config.version;
65
- }
66
-
67
- if (config.connection && config.connection instanceof Function) {
68
- this.connectionConfigProvider = config.connection;
69
- this.connectionConfigExpirationChecker = () => true; // causes the provider to be called on first use
70
- } else {
71
- this.connectionSettings = cloneDeep(config.connection || {});
72
- this.connectionConfigExpirationChecker = null;
73
- }
74
- if (this.driverName && config.connection) {
75
- this.initializeDriver();
76
- if (!config.pool || (config.pool && config.pool.max !== 0)) {
77
- this.initializePool(config);
78
- }
79
- }
80
- this.valueForUndefined = this.raw('DEFAULT');
81
- if (config.useNullAsDefault) {
82
- this.valueForUndefined = null;
83
- }
84
- }
85
- formatter(builder) {
86
- return new Formatter(this, builder);
87
- }
88
-
89
- queryBuilder() {
90
- return new QueryBuilder(this);
91
- }
92
-
93
- queryCompiler(builder, formatter) {
94
- return new QueryCompiler(this, builder, formatter);
95
- }
96
-
97
- schemaBuilder() {
98
- return new SchemaBuilder(this);
99
- }
100
-
101
- schemaCompiler(builder) {
102
- return new SchemaCompiler(this, builder);
103
- }
104
-
105
- tableBuilder(type, tableName, tableNameLike, fn) {
106
- return new TableBuilder(this, type, tableName, tableNameLike, fn);
107
- }
108
-
109
- viewBuilder(type, viewBuilder, fn) {
110
- return new ViewBuilder(this, type, viewBuilder, fn);
111
- }
112
-
113
- tableCompiler(tableBuilder) {
114
- return new TableCompiler(this, tableBuilder);
115
- }
116
-
117
- viewCompiler(viewCompiler) {
118
- return new ViewCompiler(this, viewCompiler);
119
- }
120
-
121
- columnBuilder(tableBuilder, type, args) {
122
- return new ColumnBuilder(this, tableBuilder, type, args);
123
- }
124
-
125
- columnCompiler(tableBuilder, columnBuilder) {
126
- return new ColumnCompiler(this, tableBuilder, columnBuilder);
127
- }
128
-
129
- runner(builder) {
130
- return new Runner(this, builder);
131
- }
132
-
133
- transaction(container, config, outerTx) {
134
- return new Transaction(this, container, config, outerTx);
135
- }
136
-
137
- raw() {
138
- return new Raw(this).set(...arguments);
139
- }
140
-
141
- ref() {
142
- return new Ref(this, ...arguments);
143
- }
144
- query(connection, queryParam) {
145
- const queryObject = enrichQueryObject(connection, queryParam, this);
146
- return executeQuery(connection, queryObject, this);
147
- }
148
-
149
- stream(connection, queryParam, stream, options) {
150
- const queryObject = enrichQueryObject(connection, queryParam, this);
151
- return this._stream(connection, queryObject, stream, options);
152
- }
153
-
154
- prepBindings(bindings) {
155
- return bindings;
156
- }
157
-
158
- positionBindings(sql) {
159
- return sql;
160
- }
161
-
162
- postProcessResponse(resp, queryContext) {
163
- if (this.config.postProcessResponse) {
164
- return this.config.postProcessResponse(resp, queryContext);
165
- }
166
- return resp;
167
- }
168
-
169
- wrapIdentifier(value, queryContext) {
170
- return this.customWrapIdentifier(
171
- value,
172
- this.wrapIdentifierImpl,
173
- queryContext
174
- );
175
- }
176
-
177
- customWrapIdentifier(value, origImpl, queryContext) {
178
- if (this.config.wrapIdentifier) {
179
- return this.config.wrapIdentifier(value, origImpl, queryContext);
180
- }
181
- return origImpl(value);
182
- }
183
-
184
- wrapIdentifierImpl(value) {
185
- return value !== '*' ? `"${value.replace(/"/g, '""')}"` : '*';
186
- }
187
-
188
- initializeDriver() {
189
- try {
190
- this.driver = this._driver();
191
- } catch (e) {
192
- const message = `Knex: run\n$ npm install ${this.driverName} --save`;
193
- this.logger.error(`${message}\n${e.message}\n${e.stack}`);
194
- throw new Error(`${message}\n${e.message}`);
195
- }
196
- }
197
-
198
- poolDefaults() {
199
- return { min: 2, max: 10, propagateCreateError: true };
200
- }
201
-
202
- getPoolSettings(poolConfig) {
203
- poolConfig = defaults({}, poolConfig, this.poolDefaults());
204
-
205
- POOL_CONFIG_OPTIONS.forEach((option) => {
206
- if (option in poolConfig) {
207
- this.logger.warn(
208
- [
209
- `Pool config option "${option}" is no longer supported.`,
210
- `See https://github.com/Vincit/tarn.js for possible pool config options.`,
211
- ].join(' ')
212
- );
213
- }
214
- });
215
-
216
- const DEFAULT_ACQUIRE_TIMEOUT = 60000;
217
- const timeouts = [
218
- this.config.acquireConnectionTimeout,
219
- poolConfig.acquireTimeoutMillis,
220
- ].filter((timeout) => timeout !== undefined);
221
-
222
- if (!timeouts.length) {
223
- timeouts.push(DEFAULT_ACQUIRE_TIMEOUT);
224
- }
225
-
226
- // acquire connection timeout can be set on config or config.pool
227
- // choose the smallest, positive timeout setting and set on poolConfig
228
- poolConfig.acquireTimeoutMillis = Math.min(...timeouts);
229
-
230
- const updatePoolConnectionSettingsFromProvider = async () => {
231
- if (!this.connectionConfigProvider) {
232
- return; // static configuration, nothing to update
233
- }
234
- if (
235
- !this.connectionConfigExpirationChecker ||
236
- !this.connectionConfigExpirationChecker()
237
- ) {
238
- return; // not expired, reuse existing connection
239
- }
240
- const providerResult = await this.connectionConfigProvider();
241
- if (providerResult.expirationChecker) {
242
- this.connectionConfigExpirationChecker =
243
- providerResult.expirationChecker;
244
- delete providerResult.expirationChecker; // MySQL2 driver warns on receiving extra properties
245
- } else {
246
- this.connectionConfigExpirationChecker = null;
247
- }
248
- this.connectionSettings = providerResult;
249
- };
250
-
251
- return Object.assign(poolConfig, {
252
- create: async () => {
253
- await updatePoolConnectionSettingsFromProvider();
254
- const connection = await this.acquireRawConnection();
255
- connection.__knexUid = uniqueId('__knexUid');
256
- if (poolConfig.afterCreate) {
257
- await promisify(poolConfig.afterCreate)(connection);
258
- }
259
- return connection;
260
- },
261
-
262
- destroy: (connection) => {
263
- if (connection !== void 0) {
264
- return this.destroyRawConnection(connection);
265
- }
266
- },
267
-
268
- validate: (connection) => {
269
- if (connection.__knex__disposed) {
270
- this.logger.warn(`Connection Error: ${connection.__knex__disposed}`);
271
- return false;
272
- }
273
-
274
- return this.validateConnection(connection);
275
- },
276
- });
277
- }
278
-
279
- initializePool(config = this.config) {
280
- if (this.pool) {
281
- this.logger.warn('The pool has already been initialized');
282
- return;
283
- }
284
-
285
- const tarnPoolConfig = {
286
- ...this.getPoolSettings(config.pool),
287
- };
288
- // afterCreate is an internal knex param, tarn.js does not support it
289
- if (tarnPoolConfig.afterCreate) {
290
- delete tarnPoolConfig.afterCreate;
291
- }
292
-
293
- this.pool = new Pool(tarnPoolConfig);
294
- }
295
-
296
- validateConnection(connection) {
297
- return true;
298
- }
299
-
300
- // Acquire a connection from the pool.
301
- async acquireConnection() {
302
- if (!this.pool) {
303
- throw new Error('Unable to acquire a connection');
304
- }
305
- try {
306
- const connection = await this.pool.acquire().promise;
307
- debug('acquired connection from pool: %s', connection.__knexUid);
308
- return connection;
309
- } catch (error) {
310
- let convertedError = error;
311
- if (error instanceof TimeoutError) {
312
- convertedError = new KnexTimeoutError(
313
- 'Knex: Timeout acquiring a connection. The pool is probably full. ' +
314
- 'Are you missing a .transacting(trx) call?'
315
- );
316
- }
317
- throw convertedError;
318
- }
319
- }
320
-
321
- // Releases a connection back to the connection pool,
322
- // returning a promise resolved when the connection is released.
323
- releaseConnection(connection) {
324
- debug('releasing connection to pool: %s', connection.__knexUid);
325
- const didRelease = this.pool.release(connection);
326
-
327
- if (!didRelease) {
328
- debug('pool refused connection: %s', connection.__knexUid);
329
- }
330
-
331
- return Promise.resolve();
332
- }
333
-
334
- // Destroy the current connection pool for the client.
335
- async destroy(callback) {
336
- try {
337
- if (this.pool && this.pool.destroy) {
338
- await this.pool.destroy();
339
- }
340
- this.pool = undefined;
341
-
342
- if (typeof callback === 'function') {
343
- callback();
344
- }
345
- } catch (err) {
346
- if (typeof callback === 'function') {
347
- return callback(err);
348
- }
349
- throw err;
350
- }
351
- }
352
-
353
- // Return the database being used by this client.
354
- database() {
355
- return this.connectionSettings.database;
356
- }
357
-
358
- toString() {
359
- return '[object KnexClient]';
360
- }
361
-
362
- assertCanCancelQuery() {
363
- if (!this.canCancelQuery) {
364
- throw new Error('Query cancelling not supported for this dialect');
365
- }
366
- }
367
-
368
- cancelQuery() {
369
- throw new Error('Query cancelling not supported for this dialect');
370
- }
371
-
372
- // Formatter part
373
-
374
- alias(first, second) {
375
- return first + ' as ' + second;
376
- }
377
-
378
- // Checks whether a value is a function... if it is, we compile it
379
- // otherwise we check whether it's a raw
380
- parameter(value, builder, bindingsHolder) {
381
- if (typeof value === 'function') {
382
- return outputQuery(
383
- compileCallback(value, undefined, this, bindingsHolder),
384
- true,
385
- builder,
386
- this
387
- );
388
- }
389
- return unwrapRaw(value, true, builder, this, bindingsHolder) || '?';
390
- }
391
-
392
- // Turns a list of values into a list of ?'s, joining them with commas unless
393
- // a "joining" value is specified (e.g. ' and ')
394
- parameterize(values, notSetValue, builder, bindingsHolder) {
395
- if (typeof values === 'function')
396
- return this.parameter(values, builder, bindingsHolder);
397
- values = Array.isArray(values) ? values : [values];
398
- let str = '',
399
- i = -1;
400
- while (++i < values.length) {
401
- if (i > 0) str += ', ';
402
- let value = values[i];
403
- // json columns can have object in values.
404
- if (isPlainObject(value)) {
405
- value = JSON.stringify(value);
406
- }
407
- str += this.parameter(
408
- value === undefined ? notSetValue : value,
409
- builder,
410
- bindingsHolder
411
- );
412
- }
413
- return str;
414
- }
415
-
416
- // Formats `values` into a parenthesized list of parameters for a `VALUES`
417
- // clause.
418
- //
419
- // [1, 2] -> '(?, ?)'
420
- // [[1, 2], [3, 4]] -> '((?, ?), (?, ?))'
421
- // knex('table') -> '(select * from "table")'
422
- // knex.raw('select ?', 1) -> '(select ?)'
423
- //
424
- values(values, builder, bindingsHolder) {
425
- if (Array.isArray(values)) {
426
- if (Array.isArray(values[0])) {
427
- return `(${values
428
- .map(
429
- (value) =>
430
- `(${this.parameterize(
431
- value,
432
- undefined,
433
- builder,
434
- bindingsHolder
435
- )})`
436
- )
437
- .join(', ')})`;
438
- }
439
- return `(${this.parameterize(
440
- values,
441
- undefined,
442
- builder,
443
- bindingsHolder
444
- )})`;
445
- }
446
-
447
- if (values && values.isRawInstance) {
448
- return `(${this.parameter(values, builder, bindingsHolder)})`;
449
- }
450
-
451
- return this.parameter(values, builder, bindingsHolder);
452
- }
453
-
454
- processPassedConnection(connection) {
455
- // Default implementation is noop
456
- }
457
-
458
- toPathForJson(jsonPath) {
459
- // By default, we want a json path, so if this function is not overriden,
460
- // we return the path.
461
- return jsonPath;
462
- }
463
- }
464
-
465
- Object.assign(Client.prototype, {
466
- _escapeBinding: makeEscape({
467
- escapeString(str) {
468
- return `'${str.replace(/'/g, "''")}'`;
469
- },
470
- }),
471
-
472
- canCancelQuery: false,
473
- });
474
-
475
- module.exports = Client;
1
+ const { Pool, TimeoutError } = require('tarn');
2
+ const { EventEmitter } = require('events');
3
+ const { promisify } = require('util');
4
+ const { makeEscape } = require('./util/string');
5
+ const cloneDeep = require('lodash/cloneDeep');
6
+ const defaults = require('lodash/defaults');
7
+ const uniqueId = require('lodash/uniqueId');
8
+
9
+ const Runner = require('./execution/runner');
10
+ const Transaction = require('./execution/transaction');
11
+ const {
12
+ executeQuery,
13
+ enrichQueryObject,
14
+ } = require('./execution/internal/query-executioner');
15
+ const QueryBuilder = require('./query/querybuilder');
16
+ const QueryCompiler = require('./query/querycompiler');
17
+ const SchemaBuilder = require('./schema/builder');
18
+ const SchemaCompiler = require('./schema/compiler');
19
+ const TableBuilder = require('./schema/tablebuilder');
20
+ const TableCompiler = require('./schema/tablecompiler');
21
+ const ColumnBuilder = require('./schema/columnbuilder');
22
+ const ColumnCompiler = require('./schema/columncompiler');
23
+ const { KnexTimeoutError } = require('./util/timeout');
24
+ const { outputQuery, unwrapRaw } = require('./formatter/wrappingFormatter');
25
+ const { compileCallback } = require('./formatter/formatterUtils');
26
+ const Raw = require('./raw');
27
+ const Ref = require('./ref');
28
+ const Formatter = require('./formatter');
29
+ const Logger = require('./logger');
30
+ const { POOL_CONFIG_OPTIONS } = require('./constants');
31
+ const ViewBuilder = require('./schema/viewbuilder.js');
32
+ const ViewCompiler = require('./schema/viewcompiler.js');
33
+ const isPlainObject = require('lodash/isPlainObject');
34
+ const { setHiddenProperty } = require('./util/security.js');
35
+
36
+ const debug = require('debug')('knex:client');
37
+
38
+ // The base client provides the general structure
39
+ // for a dialect specific client object.
40
+
41
+ class Client extends EventEmitter {
42
+ constructor(config = {}) {
43
+ super();
44
+ this.config = config;
45
+ this.logger = new Logger(config);
46
+
47
+ if (this.config.connection && this.config.connection.password) {
48
+ setHiddenProperty(this.config.connection);
49
+ }
50
+
51
+ //Client is a required field, so throw error if it's not supplied.
52
+ //If 'this.dialect' is set, then this is a 'super()' call, in which case
53
+ //'client' does not have to be set as it's already assigned on the client prototype.
54
+
55
+ if (this.dialect && !this.config.client) {
56
+ this.logger.warn(
57
+ `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.`
58
+ );
59
+ }
60
+
61
+ const dbClient = this.config.client || this.dialect;
62
+ if (!dbClient) {
63
+ throw new Error(
64
+ `knex: Required configuration option 'client' is missing.`
65
+ );
66
+ }
67
+
68
+ if (config.version) {
69
+ this.version = config.version;
70
+ }
71
+
72
+ if (config.connection && config.connection instanceof Function) {
73
+ this.connectionConfigProvider = config.connection;
74
+ this.connectionConfigExpirationChecker = () => true; // causes the provider to be called on first use
75
+ } else {
76
+ this.connectionSettings = cloneDeep(config.connection || {});
77
+ if (config.connection && config.connection.password) {
78
+ setHiddenProperty(this.connectionSettings, config.connection);
79
+ }
80
+ this.connectionConfigExpirationChecker = null;
81
+ }
82
+ if (this.driverName && config.connection) {
83
+ this.initializeDriver();
84
+ if (!config.pool || (config.pool && config.pool.max !== 0)) {
85
+ this.initializePool(config);
86
+ }
87
+ }
88
+ this.valueForUndefined = this.raw('DEFAULT');
89
+ if (config.useNullAsDefault) {
90
+ this.valueForUndefined = null;
91
+ }
92
+ }
93
+ formatter(builder) {
94
+ return new Formatter(this, builder);
95
+ }
96
+
97
+ queryBuilder() {
98
+ return new QueryBuilder(this);
99
+ }
100
+
101
+ queryCompiler(builder, formatter) {
102
+ return new QueryCompiler(this, builder, formatter);
103
+ }
104
+
105
+ schemaBuilder() {
106
+ return new SchemaBuilder(this);
107
+ }
108
+
109
+ schemaCompiler(builder) {
110
+ return new SchemaCompiler(this, builder);
111
+ }
112
+
113
+ tableBuilder(type, tableName, tableNameLike, fn) {
114
+ return new TableBuilder(this, type, tableName, tableNameLike, fn);
115
+ }
116
+
117
+ viewBuilder(type, viewBuilder, fn) {
118
+ return new ViewBuilder(this, type, viewBuilder, fn);
119
+ }
120
+
121
+ tableCompiler(tableBuilder) {
122
+ return new TableCompiler(this, tableBuilder);
123
+ }
124
+
125
+ viewCompiler(viewCompiler) {
126
+ return new ViewCompiler(this, viewCompiler);
127
+ }
128
+
129
+ columnBuilder(tableBuilder, type, args) {
130
+ return new ColumnBuilder(this, tableBuilder, type, args);
131
+ }
132
+
133
+ columnCompiler(tableBuilder, columnBuilder) {
134
+ return new ColumnCompiler(this, tableBuilder, columnBuilder);
135
+ }
136
+
137
+ runner(builder) {
138
+ return new Runner(this, builder);
139
+ }
140
+
141
+ transaction(container, config, outerTx) {
142
+ return new Transaction(this, container, config, outerTx);
143
+ }
144
+
145
+ raw() {
146
+ return new Raw(this).set(...arguments);
147
+ }
148
+
149
+ ref() {
150
+ return new Ref(this, ...arguments);
151
+ }
152
+ query(connection, queryParam) {
153
+ const queryObject = enrichQueryObject(connection, queryParam, this);
154
+ return executeQuery(connection, queryObject, this);
155
+ }
156
+
157
+ stream(connection, queryParam, stream, options) {
158
+ const queryObject = enrichQueryObject(connection, queryParam, this);
159
+ return this._stream(connection, queryObject, stream, options);
160
+ }
161
+
162
+ prepBindings(bindings) {
163
+ return bindings;
164
+ }
165
+
166
+ positionBindings(sql) {
167
+ return sql;
168
+ }
169
+
170
+ postProcessResponse(resp, queryContext) {
171
+ if (this.config.postProcessResponse) {
172
+ return this.config.postProcessResponse(resp, queryContext);
173
+ }
174
+ return resp;
175
+ }
176
+
177
+ wrapIdentifier(value, queryContext) {
178
+ return this.customWrapIdentifier(
179
+ value,
180
+ this.wrapIdentifierImpl,
181
+ queryContext
182
+ );
183
+ }
184
+
185
+ customWrapIdentifier(value, origImpl, queryContext) {
186
+ if (this.config.wrapIdentifier) {
187
+ return this.config.wrapIdentifier(value, origImpl, queryContext);
188
+ }
189
+ return origImpl(value);
190
+ }
191
+
192
+ wrapIdentifierImpl(value) {
193
+ return value !== '*' ? `"${value.replace(/"/g, '""')}"` : '*';
194
+ }
195
+
196
+ initializeDriver() {
197
+ try {
198
+ this.driver = this._driver();
199
+ } catch (e) {
200
+ const message = `Knex: run\n$ npm install ${this.driverName} --save`;
201
+ this.logger.error(`${message}\n${e.message}\n${e.stack}`);
202
+ throw new Error(`${message}\n${e.message}`);
203
+ }
204
+ }
205
+
206
+ poolDefaults() {
207
+ return { min: 2, max: 10, propagateCreateError: true };
208
+ }
209
+
210
+ getPoolSettings(poolConfig) {
211
+ poolConfig = defaults({}, poolConfig, this.poolDefaults());
212
+
213
+ POOL_CONFIG_OPTIONS.forEach((option) => {
214
+ if (option in poolConfig) {
215
+ this.logger.warn(
216
+ [
217
+ `Pool config option "${option}" is no longer supported.`,
218
+ `See https://github.com/Vincit/tarn.js for possible pool config options.`,
219
+ ].join(' ')
220
+ );
221
+ }
222
+ });
223
+
224
+ const DEFAULT_ACQUIRE_TIMEOUT = 60000;
225
+ const timeouts = [
226
+ this.config.acquireConnectionTimeout,
227
+ poolConfig.acquireTimeoutMillis,
228
+ ].filter((timeout) => timeout !== undefined);
229
+
230
+ if (!timeouts.length) {
231
+ timeouts.push(DEFAULT_ACQUIRE_TIMEOUT);
232
+ }
233
+
234
+ // acquire connection timeout can be set on config or config.pool
235
+ // choose the smallest, positive timeout setting and set on poolConfig
236
+ poolConfig.acquireTimeoutMillis = Math.min(...timeouts);
237
+
238
+ const updatePoolConnectionSettingsFromProvider = async () => {
239
+ if (!this.connectionConfigProvider) {
240
+ return; // static configuration, nothing to update
241
+ }
242
+ if (
243
+ !this.connectionConfigExpirationChecker ||
244
+ !this.connectionConfigExpirationChecker()
245
+ ) {
246
+ return; // not expired, reuse existing connection
247
+ }
248
+ const providerResult = await this.connectionConfigProvider();
249
+ if (providerResult.expirationChecker) {
250
+ this.connectionConfigExpirationChecker =
251
+ providerResult.expirationChecker;
252
+ delete providerResult.expirationChecker; // MySQL2 driver warns on receiving extra properties
253
+ } else {
254
+ this.connectionConfigExpirationChecker = null;
255
+ }
256
+ this.connectionSettings = providerResult;
257
+ };
258
+
259
+ return Object.assign(poolConfig, {
260
+ create: async () => {
261
+ await updatePoolConnectionSettingsFromProvider();
262
+ const connection = await this.acquireRawConnection();
263
+ connection.__knexUid = uniqueId('__knexUid');
264
+ if (poolConfig.afterCreate) {
265
+ await promisify(poolConfig.afterCreate)(connection);
266
+ }
267
+ return connection;
268
+ },
269
+
270
+ destroy: (connection) => {
271
+ if (connection !== void 0) {
272
+ return this.destroyRawConnection(connection);
273
+ }
274
+ },
275
+
276
+ validate: (connection) => {
277
+ if (connection.__knex__disposed) {
278
+ this.logger.warn(`Connection Error: ${connection.__knex__disposed}`);
279
+ return false;
280
+ }
281
+
282
+ return this.validateConnection(connection);
283
+ },
284
+ });
285
+ }
286
+
287
+ initializePool(config = this.config) {
288
+ if (this.pool) {
289
+ this.logger.warn('The pool has already been initialized');
290
+ return;
291
+ }
292
+
293
+ const tarnPoolConfig = {
294
+ ...this.getPoolSettings(config.pool),
295
+ };
296
+ // afterCreate is an internal knex param, tarn.js does not support it
297
+ if (tarnPoolConfig.afterCreate) {
298
+ delete tarnPoolConfig.afterCreate;
299
+ }
300
+
301
+ this.pool = new Pool(tarnPoolConfig);
302
+ }
303
+
304
+ validateConnection(connection) {
305
+ return true;
306
+ }
307
+
308
+ // Acquire a connection from the pool.
309
+ async acquireConnection() {
310
+ if (!this.pool) {
311
+ throw new Error('Unable to acquire a connection');
312
+ }
313
+ try {
314
+ const connection = await this.pool.acquire().promise;
315
+ debug('acquired connection from pool: %s', connection.__knexUid);
316
+ if (connection.config) {
317
+ if (connection.config.password) {
318
+ setHiddenProperty(connection.config);
319
+ }
320
+ if (
321
+ connection.config.authentication &&
322
+ connection.config.authentication.options &&
323
+ connection.config.authentication.options.password
324
+ ) {
325
+ setHiddenProperty(connection.config.authentication.options);
326
+ }
327
+ }
328
+ return connection;
329
+ } catch (error) {
330
+ let convertedError = error;
331
+ if (error instanceof TimeoutError) {
332
+ convertedError = new KnexTimeoutError(
333
+ 'Knex: Timeout acquiring a connection. The pool is probably full. ' +
334
+ 'Are you missing a .transacting(trx) call?'
335
+ );
336
+ }
337
+ throw convertedError;
338
+ }
339
+ }
340
+
341
+ // Releases a connection back to the connection pool,
342
+ // returning a promise resolved when the connection is released.
343
+ releaseConnection(connection) {
344
+ debug('releasing connection to pool: %s', connection.__knexUid);
345
+ const didRelease = this.pool.release(connection);
346
+
347
+ if (!didRelease) {
348
+ debug('pool refused connection: %s', connection.__knexUid);
349
+ }
350
+
351
+ return Promise.resolve();
352
+ }
353
+
354
+ // Destroy the current connection pool for the client.
355
+ async destroy(callback) {
356
+ try {
357
+ if (this.pool && this.pool.destroy) {
358
+ await this.pool.destroy();
359
+ }
360
+ this.pool = undefined;
361
+
362
+ if (typeof callback === 'function') {
363
+ callback();
364
+ }
365
+ } catch (err) {
366
+ if (typeof callback === 'function') {
367
+ return callback(err);
368
+ }
369
+ throw err;
370
+ }
371
+ }
372
+
373
+ // Return the database being used by this client.
374
+ database() {
375
+ return this.connectionSettings.database;
376
+ }
377
+
378
+ toString() {
379
+ return '[object KnexClient]';
380
+ }
381
+
382
+ assertCanCancelQuery() {
383
+ if (!this.canCancelQuery) {
384
+ throw new Error('Query cancelling not supported for this dialect');
385
+ }
386
+ }
387
+
388
+ cancelQuery() {
389
+ throw new Error('Query cancelling not supported for this dialect');
390
+ }
391
+
392
+ // Formatter part
393
+
394
+ alias(first, second) {
395
+ return first + ' as ' + second;
396
+ }
397
+
398
+ // Checks whether a value is a function... if it is, we compile it
399
+ // otherwise we check whether it's a raw
400
+ parameter(value, builder, bindingsHolder) {
401
+ if (typeof value === 'function') {
402
+ return outputQuery(
403
+ compileCallback(value, undefined, this, bindingsHolder),
404
+ true,
405
+ builder,
406
+ this
407
+ );
408
+ }
409
+ return unwrapRaw(value, true, builder, this, bindingsHolder) || '?';
410
+ }
411
+
412
+ // Turns a list of values into a list of ?'s, joining them with commas unless
413
+ // a "joining" value is specified (e.g. ' and ')
414
+ parameterize(values, notSetValue, builder, bindingsHolder) {
415
+ if (typeof values === 'function')
416
+ return this.parameter(values, builder, bindingsHolder);
417
+ values = Array.isArray(values) ? values : [values];
418
+ let str = '',
419
+ i = -1;
420
+ while (++i < values.length) {
421
+ if (i > 0) str += ', ';
422
+ let value = values[i];
423
+ // json columns can have object in values.
424
+ if (isPlainObject(value)) {
425
+ value = JSON.stringify(value);
426
+ }
427
+ str += this.parameter(
428
+ value === undefined ? notSetValue : value,
429
+ builder,
430
+ bindingsHolder
431
+ );
432
+ }
433
+ return str;
434
+ }
435
+
436
+ // Formats `values` into a parenthesized list of parameters for a `VALUES`
437
+ // clause.
438
+ //
439
+ // [1, 2] -> '(?, ?)'
440
+ // [[1, 2], [3, 4]] -> '((?, ?), (?, ?))'
441
+ // knex('table') -> '(select * from "table")'
442
+ // knex.raw('select ?', 1) -> '(select ?)'
443
+ //
444
+ values(values, builder, bindingsHolder) {
445
+ if (Array.isArray(values)) {
446
+ if (Array.isArray(values[0])) {
447
+ return `(${values
448
+ .map(
449
+ (value) =>
450
+ `(${this.parameterize(
451
+ value,
452
+ undefined,
453
+ builder,
454
+ bindingsHolder
455
+ )})`
456
+ )
457
+ .join(', ')})`;
458
+ }
459
+ return `(${this.parameterize(
460
+ values,
461
+ undefined,
462
+ builder,
463
+ bindingsHolder
464
+ )})`;
465
+ }
466
+
467
+ if (values && values.isRawInstance) {
468
+ return `(${this.parameter(values, builder, bindingsHolder)})`;
469
+ }
470
+
471
+ return this.parameter(values, builder, bindingsHolder);
472
+ }
473
+
474
+ processPassedConnection(connection) {
475
+ // Default implementation is noop
476
+ }
477
+
478
+ toPathForJson(jsonPath) {
479
+ // By default, we want a json path, so if this function is not overriden,
480
+ // we return the path.
481
+ return jsonPath;
482
+ }
483
+ }
484
+
485
+ Object.assign(Client.prototype, {
486
+ _escapeBinding: makeEscape({
487
+ escapeString(str) {
488
+ return `'${str.replace(/'/g, "''")}'`;
489
+ },
490
+ }),
491
+
492
+ canCancelQuery: false,
493
+ });
494
+
495
+ module.exports = Client;