knex 0.20.6 → 0.20.10

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 CHANGED
@@ -1,5 +1,67 @@
1
1
  # Master (Unreleased)
2
2
 
3
+ # 0.20.10 - 13 February, 2020
4
+
5
+ ### Bug fixes:
6
+
7
+ - Oracle: commit was a no-op causing race conditions #3668
8
+ - CLI: Knex calls process.chdir() before opening Knexfile #3661
9
+ - Fixed unresolved promise in cancelQuery() #3666
10
+
11
+ ### Typings:
12
+
13
+ - `fn.now` takes optionally a precision argument. #3662
14
+ - PG: Include SSL in connection definition #3659
15
+
16
+ ### Test / internal changes:
17
+
18
+ - replace Bluebird.timeout #3634
19
+
20
+ # 0.20.9 - 08 February, 2020
21
+
22
+ ### Bug fixes:
23
+
24
+ - CLI: Improve Support for Liftoff's Preloaders - this should fix some cases like using TS for your migrations #3613
25
+
26
+ ### Typings:
27
+
28
+ - MSSQL: Add `enableArithAbort` to `MsSqlConnectionConfig`
29
+
30
+ ### Test / internal changes:
31
+
32
+ - Refactor more tests to use cli-testlab #3640
33
+ - Update QueryCompiler implementation to use classes #3647
34
+
35
+ # 0.20.8 - 14 January, 2020
36
+
37
+ ### New features:
38
+
39
+ - CLI: Support ES6 modules via flag --esm #3616
40
+
41
+ ### Bug fixes:
42
+
43
+ - CLI: Print help only when there are no arguments #3617
44
+
45
+ ### Typings:
46
+
47
+ - Fix incorrect type of QueryBuilder.first('*') result #3621
48
+
49
+ # 0.20.7 - 07 January, 2020
50
+
51
+ ### New features:
52
+
53
+ - Throw better error when trying to modify schema while using unsupported dialect #3609
54
+
55
+ ### Bug fixes:
56
+
57
+ - Oracle: dispose connection on connection error #3611
58
+ - Oracle: fix not releasing connection from pool on disconnect #3605
59
+ - CLI: prevent warning with root command #3604
60
+
61
+ ### Typings:
62
+
63
+ - Add create/drop schema methods to SchemaBuilder #3579
64
+
3
65
  # 0.20.6 - 29 December, 2019
4
66
 
5
67
  ### Bug fixes:
package/README.md CHANGED
@@ -41,7 +41,7 @@ We have several examples [on the website](http://knexjs.org). Here is the first
41
41
 
42
42
  ```js
43
43
  const knex = require('knex')({
44
- dialect: 'sqlite3',
44
+ client: 'sqlite3',
45
45
  connection: {
46
46
  filename: './data.db',
47
47
  },
package/bin/cli.js CHANGED
@@ -12,7 +12,6 @@ const { promisify } = require('util');
12
12
  const cliPkg = require('../package');
13
13
  const {
14
14
  mkConfigObj,
15
- resolveKnexFilePath,
16
15
  resolveEnvironmentConfig,
17
16
  exit,
18
17
  success,
@@ -29,6 +28,17 @@ const fsPromised = {
29
28
  writeFile: promisify(fs.writeFile),
30
29
  };
31
30
 
31
+ function openKnexfile(configPath) {
32
+ const config = require(configPath);
33
+
34
+ // FYI: By default, the extension for the migration files is inferred
35
+ // from the knexfile's extension. So, the following lines are in
36
+ // place for backwards compatibility purposes.
37
+ config.ext = config.ext || path.extname(configPath).replace('.', '');
38
+
39
+ return config;
40
+ }
41
+
32
42
  function initKnex(env, opts) {
33
43
  checkLocalModule(env);
34
44
  if (process.cwd() !== env.cwd) {
@@ -39,37 +49,15 @@ function initKnex(env, opts) {
39
49
  );
40
50
  }
41
51
 
42
- if (!opts.knexfile) {
43
- const configurationPath = resolveKnexFilePath();
44
- const configuration = configurationPath
45
- ? require(configurationPath.path)
46
- : undefined;
47
-
48
- env.configuration = configuration || mkConfigObj(opts);
49
- if (!env.configuration.ext && configurationPath) {
50
- env.configuration.ext = configurationPath.extension;
51
- }
52
- }
53
- // If knexfile is specified
54
- else {
55
- const resolvedKnexfilePath = path.resolve(opts.knexfile);
56
- const knexfileDir = path.dirname(resolvedKnexfilePath);
57
- process.chdir(knexfileDir);
58
- env.configuration = require(resolvedKnexfilePath);
59
-
60
- if (!env.configuration) {
61
- exit(
62
- 'Knexfile not found. Specify a path with --knexfile or pass --client and --connection params in commandline'
63
- );
64
- }
65
-
66
- if (!env.configuration.ext) {
67
- env.configuration.ext = path
68
- .extname(resolvedKnexfilePath)
69
- .replace('.', '');
70
- }
52
+ if (opts.esm) {
53
+ // enable esm interop via 'esm' module
54
+ require = require('esm')(module);
71
55
  }
72
56
 
57
+ env.configuration = env.configPath
58
+ ? openKnexfile(env.configPath)
59
+ : mkConfigObj(opts);
60
+
73
61
  const resolvedConfig = resolveEnvironmentConfig(opts, env.configuration);
74
62
  const knex = require(env.modulePath);
75
63
  return knex(resolvedConfig);
@@ -110,7 +98,8 @@ function invoke(env) {
110
98
  .option(
111
99
  '--env [name]',
112
100
  'environment, default: process.env.NODE_ENV || development'
113
- );
101
+ )
102
+ .option('--esm', 'Enable ESM interop.');
114
103
 
115
104
  commander
116
105
  .command('init')
@@ -341,12 +330,11 @@ function invoke(env) {
341
330
  .catch(exit);
342
331
  });
343
332
 
344
- commander.parse(process.argv);
345
-
346
- Promise.resolve(pending).then(() => {
333
+ if (!process.argv.slice(2).length) {
347
334
  commander.outputHelp();
348
- exit('Unknown command-line options, exiting');
349
- });
335
+ }
336
+
337
+ commander.parse(process.argv);
350
338
  }
351
339
 
352
340
  const cli = new Liftoff({
@@ -364,11 +352,21 @@ cli.on('requireFail', function(name) {
364
352
  console.log(color.red('Failed to load external module'), color.magenta(name));
365
353
  });
366
354
 
355
+ // FYI: The handling for the `--cwd` and `--knexfile` arguments is a bit strange,
356
+ // but we decided to retain the behavior for backwards-compatibility. In
357
+ // particular: if `--knexfile` is a relative path, then it will be resolved
358
+ // relative to `--cwd` instead of the shell's CWD.
359
+ //
360
+ // So, the easiest way to replicate this behavior is to have the CLI change
361
+ // its CWD to `--cwd` immediately before initializing everything else. This
362
+ // ensures that Liftoff will then resolve the path to `--knexfile` correctly.
363
+ if (argv.cwd) {
364
+ process.chdir(argv.cwd);
365
+ }
366
+
367
367
  cli.launch(
368
368
  {
369
- cwd: argv.cwd,
370
- knexfile: argv.knexfile,
371
- knexpath: argv.knexpath,
369
+ configPath: argv.knexfile,
372
370
  require: argv.require,
373
371
  completion: argv.completion,
374
372
  },
@@ -8,9 +8,8 @@ const argv = require('getopts')(process.argv.slice(2));
8
8
 
9
9
  function mkConfigObj(opts) {
10
10
  if (!opts.client) {
11
- const path = resolveDefaultKnexfilePath();
12
11
  throw new Error(
13
- `No default configuration file '${path}' found and no commandline connection parameters passed`
12
+ `No configuration file found and no commandline connection parameters passed`
14
13
  );
15
14
  }
16
15
 
@@ -31,34 +30,6 @@ function mkConfigObj(opts) {
31
30
  };
32
31
  }
33
32
 
34
- function resolveKnexFilePath() {
35
- const jsPath = resolveDefaultKnexfilePath('js');
36
- if (fs.existsSync(jsPath)) {
37
- return {
38
- path: jsPath,
39
- extension: 'js',
40
- };
41
- }
42
-
43
- const tsPath = resolveDefaultKnexfilePath('ts');
44
- if (fs.existsSync(tsPath)) {
45
- return {
46
- path: tsPath,
47
- extension: 'ts',
48
- };
49
- }
50
-
51
- console.warn(
52
- `Failed to find configuration at default location of ${resolveDefaultKnexfilePath(
53
- 'js'
54
- )}`
55
- );
56
- }
57
-
58
- function resolveDefaultKnexfilePath(extension) {
59
- return process.cwd() + `/knexfile.${extension}`;
60
- }
61
-
62
33
  function resolveEnvironmentConfig(opts, allConfigs) {
63
34
  const environment = opts.env || process.env.NODE_ENV || 'development';
64
35
  const result = allConfigs[environment] || allConfigs;
@@ -156,7 +127,6 @@ function getStubPath(configKey, env, opts) {
156
127
 
157
128
  module.exports = {
158
129
  mkConfigObj,
159
- resolveKnexFilePath,
160
130
  resolveEnvironmentConfig,
161
131
  exit,
162
132
  success,
package/lib/client.js CHANGED
@@ -25,6 +25,7 @@ const { makeEscape } = require('./query/string');
25
25
  const { uniqueId, cloneDeep, defaults } = require('lodash');
26
26
 
27
27
  const Logger = require('./logger');
28
+ const { KnexTimeoutError } = require('./util/timeout');
28
29
 
29
30
  const debug = require('debug')('knex:client');
30
31
  const _debugQuery = require('debug')('knex:query');
@@ -344,11 +345,15 @@ Object.assign(Client.prototype, {
344
345
  debug('acquired connection from pool: %s', connection.__knexUid);
345
346
  return connection;
346
347
  })
347
- .catch(TimeoutError, () => {
348
- throw new Bluebird.TimeoutError(
349
- 'Knex: Timeout acquiring a connection. The pool is probably full. ' +
350
- 'Are you missing a .transacting(trx) call?'
351
- );
348
+ .catch((error) => {
349
+ let convertedError = error;
350
+ if (error instanceof TimeoutError) {
351
+ convertedError = new KnexTimeoutError(
352
+ 'Knex: Timeout acquiring a connection. The pool is probably full. ' +
353
+ 'Are you missing a .transacting(trx) call?'
354
+ );
355
+ }
356
+ throw convertedError;
352
357
  });
353
358
  } catch (e) {
354
359
  return Bluebird.reject(e);
@@ -1,15 +1,9 @@
1
1
  // MSSQL Query Compiler
2
2
  // ------
3
- const inherits = require('inherits');
4
3
  const QueryCompiler = require('../../../query/compiler');
5
4
 
6
5
  const { isEmpty, compact, identity } = require('lodash');
7
6
 
8
- function QueryCompiler_MSSQL(client, builder) {
9
- QueryCompiler.call(this, client, builder);
10
- }
11
- inherits(QueryCompiler_MSSQL, QueryCompiler);
12
-
13
7
  const components = [
14
8
  'columns',
15
9
  'join',
@@ -23,14 +17,17 @@ const components = [
23
17
  'offset',
24
18
  ];
25
19
 
26
- Object.assign(QueryCompiler_MSSQL.prototype, {
27
- _emptyInsertValue: 'default values',
20
+ class QueryCompiler_MSSQL extends QueryCompiler {
21
+ constructor(client, builder) {
22
+ super(client, builder);
23
+ this._emptyInsertValue = 'default values';
24
+ }
28
25
 
29
26
  select() {
30
27
  const sql = this.with();
31
28
  const statements = components.map((component) => this[component](this));
32
29
  return sql + compact(statements).join(' ');
33
- },
30
+ }
34
31
 
35
32
  // Compiles an "insert" query, allowing for multiple
36
33
  // inserts using a single query statement.
@@ -79,7 +76,7 @@ Object.assign(QueryCompiler_MSSQL.prototype, {
79
76
  sql,
80
77
  returning,
81
78
  };
82
- },
79
+ }
83
80
 
84
81
  // Compiles an `update` query, allowing for a return value.
85
82
  update() {
@@ -103,7 +100,7 @@ Object.assign(QueryCompiler_MSSQL.prototype, {
103
100
  (!returning ? this._returning('rowcount', '@@rowcount') : ''),
104
101
  returning: returning || '@@rowcount',
105
102
  };
106
- },
103
+ }
107
104
 
108
105
  // Compiles a `delete` query.
109
106
  del() {
@@ -121,7 +118,7 @@ Object.assign(QueryCompiler_MSSQL.prototype, {
121
118
  (!returning ? this._returning('rowcount', '@@rowcount') : ''),
122
119
  returning: returning || '@@rowcount',
123
120
  };
124
- },
121
+ }
125
122
 
126
123
  // Compiles the columns in the query, specifying if an item was distinct.
127
124
  columns() {
@@ -156,7 +153,7 @@ Object.assign(QueryCompiler_MSSQL.prototype, {
156
153
  sql.join(', ') +
157
154
  (this.tableName ? ` from ${this.tableName}` : '')
158
155
  );
159
- },
156
+ }
160
157
 
161
158
  _returning(method, value) {
162
159
  switch (method) {
@@ -172,23 +169,23 @@ Object.assign(QueryCompiler_MSSQL.prototype, {
172
169
  case 'rowcount':
173
170
  return value ? ';select @@rowcount' : '';
174
171
  }
175
- },
172
+ }
176
173
 
177
174
  // Compiles a `truncate` query.
178
175
  truncate() {
179
176
  return `truncate table ${this.tableName}`;
180
- },
177
+ }
181
178
 
182
179
  forUpdate() {
183
180
  // this doesn't work exacltly as it should, one should also mention index while locking
184
181
  // https://stackoverflow.com/a/9818448/360060
185
182
  return 'with (UPDLOCK)';
186
- },
183
+ }
187
184
 
188
185
  forShare() {
189
186
  // http://www.sqlteam.com/article/introduction-to-locking-in-sql-server
190
187
  return 'with (HOLDLOCK)';
191
- },
188
+ }
192
189
 
193
190
  // Compiles a `columnInfo` query.
194
191
  columnInfo() {
@@ -230,18 +227,18 @@ Object.assign(QueryCompiler_MSSQL.prototype, {
230
227
  return (column && out[column]) || out;
231
228
  },
232
229
  };
233
- },
230
+ }
234
231
 
235
232
  top() {
236
233
  const noLimit = !this.single.limit && this.single.limit !== 0;
237
234
  const noOffset = !this.single.offset;
238
235
  if (noLimit || !noOffset) return '';
239
236
  return `top (${this.formatter.parameter(this.single.limit)})`;
240
- },
237
+ }
241
238
 
242
239
  limit() {
243
240
  return '';
244
- },
241
+ }
245
242
 
246
243
  offset() {
247
244
  const noLimit = !this.single.limit && this.single.limit !== 0;
@@ -256,8 +253,8 @@ Object.assign(QueryCompiler_MSSQL.prototype, {
256
253
  )} rows only`;
257
254
  }
258
255
  return offset;
259
- },
260
- });
256
+ }
257
+ }
261
258
 
262
259
  // Set the QueryBuilder & QueryCompiler on the client object,
263
260
  // in case anyone wants to modify things to suit their own purposes.
@@ -170,28 +170,18 @@ Object.assign(Client_MySQL.prototype, {
170
170
 
171
171
  canCancelQuery: true,
172
172
 
173
- cancelQuery(connectionToKill) {
174
- const acquiringConn = this.acquireConnection();
175
-
176
- // Error out if we can't acquire connection in time.
177
- // Purposely not putting timeout on `KILL QUERY` execution because erroring
178
- // early there would release the `connectionToKill` back to the pool with
179
- // a `KILL QUERY` command yet to finish.
180
- return acquiringConn
181
- .timeout(100)
182
- .then((conn) =>
183
- this.query(conn, {
184
- method: 'raw',
185
- sql: 'KILL QUERY ?',
186
- bindings: [connectionToKill.threadId],
187
- options: {},
188
- })
189
- )
190
- .finally(() => {
191
- // NOT returning this promise because we want to release the connection
192
- // in a non-blocking fashion
193
- acquiringConn.then((conn) => this.releaseConnection(conn));
173
+ async cancelQuery(connectionToKill) {
174
+ const conn = await this.acquireConnection();
175
+ try {
176
+ return await this.query(conn, {
177
+ method: 'raw',
178
+ sql: 'KILL QUERY ?',
179
+ bindings: [connectionToKill.threadId],
180
+ options: {},
194
181
  });
182
+ } finally {
183
+ await this.releaseConnection(conn);
184
+ }
195
185
  },
196
186
  });
197
187
 
@@ -1,26 +1,22 @@
1
1
  // MySQL Query Compiler
2
2
  // ------
3
- const inherits = require('inherits');
4
3
  const QueryCompiler = require('../../../query/compiler');
5
4
 
6
5
  const { identity } = require('lodash');
7
6
 
8
- function QueryCompiler_MySQL(client, builder) {
9
- QueryCompiler.call(this, client, builder);
7
+ class QueryCompiler_MySQL extends QueryCompiler {
8
+ constructor(client, builder) {
9
+ super(client, builder);
10
10
 
11
- const { returning } = this.single;
11
+ const { returning } = this.single;
12
12
 
13
- if (returning) {
14
- this.client.logger.warn(
15
- '.returning() is not supported by mysql and will not have any effect.'
16
- );
13
+ if (returning) {
14
+ this.client.logger.warn(
15
+ '.returning() is not supported by mysql and will not have any effect.'
16
+ );
17
+ }
18
+ this._emptyInsertValue = '() values ()';
17
19
  }
18
- }
19
-
20
- inherits(QueryCompiler_MySQL, QueryCompiler);
21
-
22
- Object.assign(QueryCompiler_MySQL.prototype, {
23
- _emptyInsertValue: '() values ()',
24
20
 
25
21
  // Update method, including joins, wheres, order & limits.
26
22
  update() {
@@ -38,25 +34,25 @@ Object.assign(QueryCompiler_MySQL.prototype, {
38
34
  (order ? ` ${order}` : '') +
39
35
  (limit ? ` ${limit}` : '')
40
36
  );
41
- },
37
+ }
42
38
 
43
39
  forUpdate() {
44
40
  return 'for update';
45
- },
41
+ }
46
42
 
47
43
  forShare() {
48
44
  return 'lock in share mode';
49
- },
45
+ }
50
46
 
51
47
  // Only supported on MySQL 8.0+
52
48
  skipLocked() {
53
49
  return 'skip locked';
54
- },
50
+ }
55
51
 
56
52
  // Supported on MySQL 8.0+ and MariaDB 10.3.0+
57
53
  noWait() {
58
54
  return 'nowait';
59
- },
55
+ }
60
56
 
61
57
  // Compiles a `columnInfo` query.
62
58
  columnInfo() {
@@ -72,7 +68,7 @@ Object.assign(QueryCompiler_MySQL.prototype, {
72
68
  'select * from information_schema.columns where table_name = ? and table_schema = ?',
73
69
  bindings: [table, this.client.database()],
74
70
  output(resp) {
75
- const out = resp.reduce(function(columns, val) {
71
+ const out = resp.reduce(function (columns, val) {
76
72
  columns[val.COLUMN_NAME] = {
77
73
  defaultValue: val.COLUMN_DEFAULT,
78
74
  type: val.DATA_TYPE,
@@ -84,7 +80,7 @@ Object.assign(QueryCompiler_MySQL.prototype, {
84
80
  return (column && out[column]) || out;
85
81
  },
86
82
  };
87
- },
83
+ }
88
84
 
89
85
  limit() {
90
86
  const noLimit = !this.single.limit && this.single.limit !== 0;
@@ -97,8 +93,8 @@ Object.assign(QueryCompiler_MySQL.prototype, {
97
93
  ? '18446744073709551615'
98
94
  : this.formatter.parameter(this.single.limit);
99
95
  return `limit ${limit}`;
100
- },
101
- });
96
+ }
97
+ }
102
98
 
103
99
  // Set the QueryBuilder & QueryCompiler on the client object,
104
100
  // in case anyone wants to modify things to suit their own purposes.
@@ -3,7 +3,6 @@
3
3
  // Oracle Query Builder & Compiler
4
4
  // ------
5
5
  const {
6
- assign,
7
6
  isPlainObject,
8
7
  isEmpty,
9
8
  isString,
@@ -12,7 +11,6 @@ const {
12
11
  compact,
13
12
  identity,
14
13
  } = require('lodash');
15
- const inherits = require('inherits');
16
14
  const QueryCompiler = require('../../../query/compiler');
17
15
  const { ReturningHelper } = require('../utils');
18
16
 
@@ -33,13 +31,16 @@ const components = [
33
31
  // Set the "Formatter" to use for the queries,
34
32
  // ensuring that all parameterized values (even across sub-queries)
35
33
  // are properly built into the same query.
36
- function QueryCompiler_Oracle(client, builder) {
37
- QueryCompiler.call(this, client, builder);
38
- }
34
+ class QueryCompiler_Oracle extends QueryCompiler {
35
+ constructor(client, builder) {
36
+ super(client, builder);
39
37
 
40
- inherits(QueryCompiler_Oracle, QueryCompiler);
38
+ // Compiles the `select` statement, or nested sub-selects
39
+ // by calling each of the component compilers, trimming out
40
+ // the empties, and returning a generated query string.
41
+ this.first = this.select;
42
+ }
41
43
 
42
- assign(QueryCompiler_Oracle.prototype, {
43
44
  // Compiles an "insert" query, allowing for multiple
44
45
  // inserts using a single query statement.
45
46
  insert() {
@@ -167,7 +168,7 @@ assign(QueryCompiler_Oracle.prototype, {
167
168
  }
168
169
 
169
170
  return sql;
170
- },
171
+ }
171
172
 
172
173
  // Update method, including joins, wheres, order & limits.
173
174
  update() {
@@ -190,16 +191,16 @@ assign(QueryCompiler_Oracle.prototype, {
190
191
  }
191
192
 
192
193
  return this._addReturningToSqlAndConvert(sql, returning, this.tableName);
193
- },
194
+ }
194
195
 
195
196
  // Compiles a `truncate` query.
196
197
  truncate() {
197
198
  return `truncate table ${this.tableName}`;
198
- },
199
+ }
199
200
 
200
201
  forUpdate() {
201
202
  return 'for update';
202
- },
203
+ }
203
204
 
204
205
  forShare() {
205
206
  // lock for share is not directly supported by oracle
@@ -208,7 +209,7 @@ assign(QueryCompiler_Oracle.prototype, {
208
209
  'lock for share is not supported by oracle dialect'
209
210
  );
210
211
  return '';
211
- },
212
+ }
212
213
 
213
214
  // Compiles a `columnInfo` query.
214
215
  columnInfo() {
@@ -247,7 +248,7 @@ assign(QueryCompiler_Oracle.prototype, {
247
248
  return (column && out[column]) || out;
248
249
  },
249
250
  };
250
- },
251
+ }
251
252
 
252
253
  select() {
253
254
  let query = this.with();
@@ -256,11 +257,11 @@ assign(QueryCompiler_Oracle.prototype, {
256
257
  });
257
258
  query += compact(statements).join(' ');
258
259
  return this._surroundQueryWithLimitAndOffset(query);
259
- },
260
+ }
260
261
 
261
262
  aggregate(stmt) {
262
263
  return this._aggregate(stmt, { aliasSeparator: ' ' });
263
- },
264
+ }
264
265
 
265
266
  // for single commands only
266
267
  _addReturningToSqlAndConvert(sql, returning, tableName) {
@@ -284,7 +285,7 @@ assign(QueryCompiler_Oracle.prototype, {
284
285
  res.outParams = [returningHelper];
285
286
  res.returning = returning;
286
287
  return res;
287
- },
288
+ }
288
289
 
289
290
  _surroundQueryWithLimitAndOffset(query) {
290
291
  let { limit } = this.single;
@@ -314,12 +315,7 @@ assign(QueryCompiler_Oracle.prototype, {
314
315
  'where rownum_ > ' +
315
316
  this.formatter.parameter(offset)
316
317
  );
317
- },
318
- });
319
-
320
- // Compiles the `select` statement, or nested sub-selects
321
- // by calling each of the component compilers, trimming out
322
- // the empties, and returning a generated query string.
323
- QueryCompiler_Oracle.prototype.first = QueryCompiler_Oracle.prototype.select;
318
+ }
319
+ }
324
320
 
325
321
  module.exports = QueryCompiler_Oracle;