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.
- package/CHANGELOG.md +6 -0
- package/CONTRIBUTING.md +184 -184
- package/LICENSE +22 -22
- package/README.md +95 -95
- package/bin/cli.js +414 -414
- package/bin/utils/cli-config-utils.js +151 -151
- package/bin/utils/constants.js +7 -7
- package/bin/utils/migrationsLister.js +37 -37
- package/knex.js +8 -8
- package/lib/client.js +413 -413
- package/lib/config-resolver.js +61 -61
- package/lib/constants.js +44 -44
- package/lib/dialects/mssql/index.js +390 -390
- package/lib/dialects/mssql/query/compiler.js +444 -444
- package/lib/dialects/mssql/schema/columncompiler.js +103 -103
- package/lib/dialects/mssql/schema/compiler.js +59 -59
- package/lib/dialects/mssql/schema/tablecompiler.js +245 -245
- package/lib/dialects/mssql/transaction.js +97 -97
- package/lib/dialects/mysql/index.js +191 -191
- package/lib/dialects/mysql/query/compiler.js +142 -142
- package/lib/dialects/mysql/schema/columncompiler.js +171 -171
- package/lib/dialects/mysql/schema/compiler.js +60 -60
- package/lib/dialects/mysql/schema/tablecompiler.js +262 -262
- package/lib/dialects/mysql/transaction.js +48 -48
- package/lib/dialects/mysql2/index.js +35 -35
- package/lib/dialects/mysql2/transaction.js +46 -46
- package/lib/dialects/oracle/DEAD_CODE.md +5 -5
- package/lib/dialects/oracle/formatter.js +20 -20
- package/lib/dialects/oracle/index.js +79 -79
- package/lib/dialects/oracle/query/compiler.js +327 -327
- package/lib/dialects/oracle/schema/columnbuilder.js +18 -18
- package/lib/dialects/oracle/schema/columncompiler.js +139 -139
- package/lib/dialects/oracle/schema/compiler.js +81 -81
- package/lib/dialects/oracle/schema/tablecompiler.js +165 -165
- package/lib/dialects/oracle/schema/trigger.js +126 -126
- package/lib/dialects/oracle/utils.js +86 -86
- package/lib/dialects/oracledb/index.js +489 -489
- package/lib/dialects/oracledb/query/compiler.js +363 -363
- package/lib/dialects/oracledb/schema/columncompiler.js +35 -35
- package/lib/dialects/oracledb/transaction.js +76 -76
- package/lib/dialects/oracledb/utils.js +14 -14
- package/lib/dialects/postgres/index.js +319 -319
- package/lib/dialects/postgres/query/compiler.js +206 -206
- package/lib/dialects/postgres/schema/columncompiler.js +125 -125
- package/lib/dialects/postgres/schema/compiler.js +109 -109
- package/lib/dialects/postgres/schema/tablecompiler.js +183 -183
- package/lib/dialects/redshift/index.js +73 -73
- package/lib/dialects/redshift/query/compiler.js +119 -119
- package/lib/dialects/redshift/schema/columnbuilder.js +20 -20
- package/lib/dialects/redshift/schema/columncompiler.js +60 -60
- package/lib/dialects/redshift/schema/compiler.js +14 -14
- package/lib/dialects/redshift/schema/tablecompiler.js +123 -123
- package/lib/dialects/redshift/transaction.js +18 -18
- package/lib/dialects/sqlite3/formatter.js +21 -21
- package/lib/dialects/sqlite3/index.js +169 -169
- package/lib/dialects/sqlite3/query/compiler.js +222 -222
- package/lib/dialects/sqlite3/schema/columncompiler.js +27 -27
- package/lib/dialects/sqlite3/schema/compiler.js +49 -49
- package/lib/dialects/sqlite3/schema/ddl.js +525 -525
- package/lib/dialects/sqlite3/schema/tablecompiler.js +238 -238
- package/lib/formatter.js +295 -295
- package/lib/functionhelper.js +14 -14
- package/lib/helpers.js +92 -92
- package/lib/index.js +3 -3
- package/lib/interface.js +115 -115
- package/lib/knex.js +42 -42
- package/lib/logger.js +76 -76
- package/lib/migrate/MigrationGenerator.js +82 -82
- package/lib/migrate/Migrator.js +611 -611
- package/lib/migrate/configuration-merger.js +60 -60
- package/lib/migrate/migrate-stub.js +17 -17
- package/lib/migrate/migration-list-resolver.js +36 -36
- package/lib/migrate/sources/fs-migrations.js +99 -99
- package/lib/migrate/stub/cjs.stub +15 -15
- package/lib/migrate/stub/coffee.stub +13 -13
- package/lib/migrate/stub/eg.stub +14 -14
- package/lib/migrate/stub/js.stub +15 -15
- package/lib/migrate/stub/knexfile-coffee.stub +34 -34
- package/lib/migrate/stub/knexfile-eg.stub +43 -43
- package/lib/migrate/stub/knexfile-js.stub +44 -44
- package/lib/migrate/stub/knexfile-ls.stub +35 -35
- package/lib/migrate/stub/knexfile-ts.stub +44 -44
- package/lib/migrate/stub/ls.stub +14 -14
- package/lib/migrate/stub/ts.stub +21 -21
- package/lib/migrate/table-creator.js +67 -67
- package/lib/migrate/table-resolver.js +27 -27
- package/lib/query/builder.js +1372 -1372
- package/lib/query/compiler.js +889 -889
- package/lib/query/constants.js +13 -13
- package/lib/query/joinclause.js +263 -263
- package/lib/query/methods.js +92 -92
- package/lib/query/string.js +190 -190
- package/lib/raw.js +188 -188
- package/lib/ref.js +39 -39
- package/lib/runner.js +285 -285
- package/lib/schema/builder.js +82 -82
- package/lib/schema/columnbuilder.js +117 -117
- package/lib/schema/columncompiler.js +177 -177
- package/lib/schema/compiler.js +101 -101
- package/lib/schema/helpers.js +51 -51
- package/lib/schema/tablebuilder.js +288 -288
- package/lib/schema/tablecompiler.js +296 -296
- package/lib/seed/Seeder.js +203 -203
- package/lib/seed/seed-stub.js +13 -13
- package/lib/seed/stub/coffee.stub +9 -9
- package/lib/seed/stub/eg.stub +11 -11
- package/lib/seed/stub/js.stub +13 -13
- package/lib/seed/stub/ls.stub +11 -11
- package/lib/seed/stub/ts.stub +13 -13
- package/lib/transaction.js +363 -363
- package/lib/util/batchInsert.js +59 -59
- package/lib/util/delay.js +6 -6
- package/lib/util/fake-client.js +9 -9
- package/lib/util/finally-mixin.js +13 -13
- package/lib/util/fs.js +76 -76
- package/lib/util/import-file.js +13 -13
- package/lib/util/is-module-type.js +14 -14
- package/lib/util/is.js +32 -32
- package/lib/util/make-knex.js +338 -338
- package/lib/util/nanoid.js +29 -29
- package/lib/util/noop.js +1 -1
- package/lib/util/parse-connection.js +66 -66
- package/lib/util/save-async-stack.js +14 -14
- package/lib/util/template.js +52 -52
- package/lib/util/timeout.js +29 -29
- package/lib/util/timestamp.js +16 -16
- package/package.json +1 -1
- package/scripts/build.js +125 -125
- package/scripts/docker-compose.yml +111 -111
- package/scripts/next-release-howto.md +24 -24
- package/scripts/release.sh +34 -34
- package/scripts/runkit-example.js +34 -34
- package/scripts/stress-test/README.txt +18 -18
- package/scripts/stress-test/docker-compose.yml +47 -47
- package/scripts/stress-test/knex-stress-test.js +196 -196
- package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +145 -145
- package/scripts/stress-test/mysql2-sudden-exit-without-error.js +100 -100
- package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +184 -184
- package/types/index.d.ts +2249 -2249
- package/types/result.d.ts +27 -27
- 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;
|