knex 0.20.9 → 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,22 @@
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
+
3
20
  # 0.20.9 - 08 February, 2020
4
21
 
5
22
  ### Bug fixes:
package/bin/cli.js CHANGED
@@ -28,26 +28,18 @@ const fsPromised = {
28
28
  writeFile: promisify(fs.writeFile),
29
29
  };
30
30
 
31
- function initKnex(env, opts) {
32
- if (opts.esm) {
33
- // enable esm interop via 'esm' module
34
- require = require('esm')(module);
35
- }
36
-
37
- env.configuration = env.configPath
38
- ? require(env.configPath)
39
- : mkConfigObj(opts);
31
+ function openKnexfile(configPath) {
32
+ const config = require(configPath);
40
33
 
41
34
  // FYI: By default, the extension for the migration files is inferred
42
35
  // from the knexfile's extension. So, the following lines are in
43
36
  // place for backwards compatibility purposes.
44
- if (!env.configuration.ext) {
45
- const p = env.configPath || opts.knexpath;
37
+ config.ext = config.ext || path.extname(configPath).replace('.', '');
46
38
 
47
- // TODO: Should this property be documented somewhere?
48
- env.configuration.ext = path.extname(p).replace('.', '');
49
- }
39
+ return config;
40
+ }
50
41
 
42
+ function initKnex(env, opts) {
51
43
  checkLocalModule(env);
52
44
  if (process.cwd() !== env.cwd) {
53
45
  process.chdir(env.cwd);
@@ -57,6 +49,15 @@ function initKnex(env, opts) {
57
49
  );
58
50
  }
59
51
 
52
+ if (opts.esm) {
53
+ // enable esm interop via 'esm' module
54
+ require = require('esm')(module);
55
+ }
56
+
57
+ env.configuration = env.configPath
58
+ ? openKnexfile(env.configPath)
59
+ : mkConfigObj(opts);
60
+
60
61
  const resolvedConfig = resolveEnvironmentConfig(opts, env.configuration);
61
62
  const knex = require(env.modulePath);
62
63
  return knex(resolvedConfig);
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);
@@ -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
 
@@ -108,9 +108,6 @@ Client_Oracledb.prototype.acquireRawConnection = function() {
108
108
  }
109
109
  connection.commitAsync = function() {
110
110
  return new Bluebird((commitResolve, commitReject) => {
111
- if (connection.isTransaction) {
112
- return commitResolve();
113
- }
114
111
  this.commit(function(err) {
115
112
  if (err) {
116
113
  return commitReject(err);
@@ -293,7 +290,9 @@ Client_Oracledb.prototype._query = function(connection, obj) {
293
290
  }
294
291
 
295
292
  if (!obj.returning && outBinds.length === 0) {
296
- await connection.commitAsync();
293
+ if (!connection.isTransaction) {
294
+ await connection.commitAsync();
295
+ }
297
296
  return obj;
298
297
  }
299
298
  const rowIds = [];
@@ -335,17 +334,15 @@ Client_Oracledb.prototype._query = function(connection, obj) {
335
334
  });
336
335
  }
337
336
  }
338
- return connection.commitAsync().then(function() {
339
- if (obj.returningSql) {
340
- return connection
341
- .executeAsync(obj.returningSql(), rowIds, { resultSet: true })
342
- .then(function(response) {
343
- obj.response = response.rows;
344
- return obj;
345
- });
346
- }
337
+ if (connection.isTransaction) {
347
338
  return obj;
348
- });
339
+ }
340
+ await connection.commitAsync();
341
+ if (obj.returningSql) {
342
+ const response = await connection.executeAsync(obj.returningSql(), rowIds, { resultSet: true })
343
+ obj.response = response.rows;
344
+ }
345
+ return obj;
349
346
  });
350
347
  };
351
348
 
@@ -2,6 +2,7 @@ const { isUndefined } = require('lodash');
2
2
 
3
3
  const Bluebird = require('bluebird');
4
4
  const Transaction = require('../../transaction');
5
+ const { timeout, KnexTimeoutError } = require('../../util/timeout');
5
6
  const debugTx = require('debug')('knex:tx');
6
7
 
7
8
  module.exports = class Oracle_Transaction extends Transaction {
@@ -10,12 +11,14 @@ module.exports = class Oracle_Transaction extends Transaction {
10
11
  return Bluebird.resolve();
11
12
  }
12
13
 
13
- commit(conn, value) {
14
+ async commit(conn, value) {
14
15
  this._completed = true;
15
- return conn
16
- .commitAsync()
17
- .then(() => value)
18
- .then(this._resolver, this._rejecter);
16
+ try {
17
+ await conn.commitAsync();
18
+ this._resolver(value);
19
+ } catch (err) {
20
+ this._rejecter(err);
21
+ }
19
22
  }
20
23
 
21
24
  release(conn, value) {
@@ -23,24 +26,24 @@ module.exports = class Oracle_Transaction extends Transaction {
23
26
  }
24
27
 
25
28
  rollback(conn, err) {
26
- const self = this;
27
29
  this._completed = true;
28
30
  debugTx('%s: rolling back', this.txid);
29
- return conn
30
- .rollbackAsync()
31
- .timeout(5000)
32
- .catch(Bluebird.TimeoutError, function(e) {
33
- self._rejecter(e);
31
+ return timeout(conn.rollbackAsync(), 5000)
32
+ .catch((e) => {
33
+ if (!(e instanceof KnexTimeoutError)) {
34
+ return Promise.reject(e);
35
+ }
36
+ this._rejecter(e);
34
37
  })
35
- .then(function() {
38
+ .then(() => {
36
39
  if (isUndefined(err)) {
37
- if (self.doNotRejectOnRollback) {
38
- self._resolver();
40
+ if (this.doNotRejectOnRollback) {
41
+ this._resolver();
39
42
  return;
40
43
  }
41
44
  err = new Error(`Transaction rejected with non-error: ${err}`);
42
45
  }
43
- self._rejecter(err);
46
+ this._rejecter(err);
44
47
  });
45
48
  }
46
49
 
package/lib/knex.js CHANGED
@@ -5,6 +5,7 @@ const QueryInterface = require('./query/methods');
5
5
 
6
6
  const makeKnex = require('./util/make-knex');
7
7
  const parseConnection = require('./util/parse-connection');
8
+ const { KnexTimeoutError } = require('./util/timeout');
8
9
  const fakeClient = require('./util/fake-client');
9
10
  const { SUPPORTED_CLIENTS } = require('./constants');
10
11
  const { resolveClientNameWithAliases } = require('./helpers');
@@ -58,6 +59,9 @@ function Knex(config) {
58
59
 
59
60
  // Expose Client on the main Knex namespace.
60
61
  Knex.Client = Client;
62
+
63
+ Knex.KnexTimeoutError = KnexTimeoutError;
64
+
61
65
  Knex.QueryBuilder = {
62
66
  extend: function(methodName, fn) {
63
67
  QueryBuilder.extend(methodName, fn);
package/lib/runner.js CHANGED
@@ -1,4 +1,6 @@
1
1
  const Bluebird = require('bluebird');
2
+ const { KnexTimeoutError } = require('./util/timeout');
3
+ const { timeout } = require('./util/timeout');
2
4
 
3
5
  let PassThrough;
4
6
 
@@ -133,7 +135,7 @@ Object.assign(Runner.prototype, {
133
135
  let queryPromise = this.client.query(this.connection, obj);
134
136
 
135
137
  if (obj.timeout) {
136
- queryPromise = queryPromise.timeout(obj.timeout);
138
+ queryPromise = timeout(queryPromise, obj.timeout);
137
139
  }
138
140
 
139
141
  // Await the return value of client.processResponse; in the case of sqlite3's
@@ -164,7 +166,10 @@ Object.assign(Runner.prototype, {
164
166
 
165
167
  return postProcessedResponse;
166
168
  })
167
- .catch(Bluebird.TimeoutError, (error) => {
169
+ .catch((error) => {
170
+ if (!(error instanceof KnexTimeoutError)) {
171
+ return Promise.reject(error);
172
+ }
168
173
  const { timeout, sql, bindings } = obj;
169
174
 
170
175
  let cancelQuery;
@@ -241,7 +246,10 @@ Object.assign(Runner.prototype, {
241
246
  }
242
247
  return this.client
243
248
  .acquireConnection()
244
- .catch(Bluebird.TimeoutError, (error) => {
249
+ .catch((error) => {
250
+ if (!(error instanceof KnexTimeoutError)) {
251
+ return Promise.reject(error);
252
+ }
245
253
  if (this.builder) {
246
254
  error.sql = this.builder.sql;
247
255
  error.bindings = this.builder.bindings;
@@ -5,6 +5,7 @@ const { EventEmitter } = require('events');
5
5
  const Debug = require('debug');
6
6
 
7
7
  const makeKnex = require('./util/make-knex');
8
+ const { timeout, KnexTimeoutError } = require('./util/timeout');
8
9
 
9
10
  const debug = Debug('knex:tx');
10
11
 
@@ -150,19 +151,26 @@ class Transaction extends EventEmitter {
150
151
  }
151
152
 
152
153
  rollback(conn, error) {
153
- return this.query(conn, 'ROLLBACK', 2, error)
154
- .timeout(5000)
155
- .catch(Bluebird.TimeoutError, () => {
154
+ return timeout(this.query(conn, 'ROLLBACK', 2, error), 5000).catch(
155
+ (err) => {
156
+ if (!(err instanceof KnexTimeoutError)) {
157
+ return Promise.reject(err);
158
+ }
156
159
  this._rejecter(error);
157
- });
160
+ }
161
+ );
158
162
  }
159
163
 
160
164
  rollbackTo(conn, error) {
161
- return this.query(conn, `ROLLBACK TO SAVEPOINT ${this.txid}`, 2, error)
162
- .timeout(5000)
163
- .catch(Bluebird.TimeoutError, () => {
164
- this._rejecter(error);
165
- });
165
+ return timeout(
166
+ this.query(conn, `ROLLBACK TO SAVEPOINT ${this.txid}`, 2, error),
167
+ 5000
168
+ ).catch((err) => {
169
+ if (!(err instanceof KnexTimeoutError)) {
170
+ return Promise.reject(err);
171
+ }
172
+ this._rejecter(error);
173
+ });
166
174
  }
167
175
 
168
176
  query(conn, sql, status, value) {
@@ -0,0 +1,20 @@
1
+ const Bluebird = require('bluebird');
2
+ const delay = require('./delay');
3
+
4
+ class KnexTimeoutError extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = 'KnexTimeoutError';
8
+ }
9
+ }
10
+
11
+ module.exports.KnexTimeoutError = KnexTimeoutError;
12
+ module.exports.timeout = (promise, ms) =>
13
+ Bluebird.resolve(
14
+ Promise.race([
15
+ promise,
16
+ delay(ms).then(() =>
17
+ Promise.reject(new KnexTimeoutError('operation timed out'))
18
+ ),
19
+ ])
20
+ );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knex",
3
- "version": "0.20.9",
3
+ "version": "0.20.10",
4
4
  "description": "A batteries-included SQL query & schema builder for Postgres, MySQL and SQLite3 and the Browser",
5
5
  "main": "knex.js",
6
6
  "types": "types/index.d.ts",
@@ -76,7 +76,7 @@
76
76
  ]
77
77
  },
78
78
  "devDependencies": {
79
- "@types/node": "^10.17.14",
79
+ "@types/node": "^10.17.15",
80
80
  "JSONStream": "^1.3.5",
81
81
  "chai": "^4.2.0",
82
82
  "chai-subset-in-order": "^2.1.3",
@@ -99,7 +99,7 @@
99
99
  "pg": "^7.18.1",
100
100
  "pg-query-stream": "^2.1.2",
101
101
  "prettier": "1.18.2",
102
- "rimraf": "^3.0.1",
102
+ "rimraf": "^3.0.2",
103
103
  "sinon": "^8.1.1",
104
104
  "sinon-chai": "^3.4.0",
105
105
  "source-map-support": "^0.5.16",
@@ -109,7 +109,7 @@
109
109
  "toxiproxy-node-client": "^2.0.6",
110
110
  "ts-node": "^8.6.2",
111
111
  "typescript": "3.7.4",
112
- "webpack-cli": "^3.3.10"
112
+ "webpack-cli": "^3.3.1"
113
113
  },
114
114
  "buildDependencies": [
115
115
  "rimraf"
package/types/index.d.ts CHANGED
@@ -13,6 +13,8 @@ import events = require('events');
13
13
  import stream = require('stream');
14
14
  import ResultTypes = require('./result');
15
15
 
16
+ import { ConnectionOptions } from "tls";
17
+
16
18
  // # Generic type-level utilities
17
19
 
18
20
  // If T is object then make it a partial otherwise fallback to any
@@ -1808,6 +1810,7 @@ declare namespace Knex {
1808
1810
  statement_timeout?: false | number;
1809
1811
  connectionTimeoutMillis?: number;
1810
1812
  keepAliveInitialDelayMillis?: number;
1813
+ ssl?: boolean | ConnectionOptions;
1811
1814
  }
1812
1815
 
1813
1816
  type RedshiftConnectionConfig = PgConnectionConfig;
@@ -1912,7 +1915,7 @@ declare namespace Knex {
1912
1915
  }
1913
1916
 
1914
1917
  interface FunctionHelper {
1915
- now(): Raw;
1918
+ now(precision?: number): Raw;
1916
1919
  }
1917
1920
 
1918
1921
  interface EnumOptions {
@@ -1990,6 +1993,8 @@ declare namespace Knex {
1990
1993
  ) => QueryBuilder<TRecord, TResult>
1991
1994
  ): void;
1992
1995
  }
1996
+
1997
+ export class KnexTimeoutError extends Error {}
1993
1998
  }
1994
1999
 
1995
2000
  export = Knex;