knex 0.19.4 → 0.19.5

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,28 @@
1
1
  # Master (Unreleased)
2
2
 
3
+ # 0.19.5 - 06 October, 2019
4
+
5
+ ### New features:
6
+
7
+ - CLI: Migrations up/down commands - filename parameter #3416
8
+ - Oracle: Support stored procedures #3449
9
+
10
+ ### Bug fixes:
11
+
12
+ - MSSQL: Escape column ids correctly in all cases (reported by Snyk Security Research Team) #3382
13
+ - SQLite: Fix handling of multiline SQL in SQLite3 schema #3411
14
+ - Fix concurrent child transactions failing #2213 #3440
15
+
16
+ ### Typings:
17
+
18
+ - Add missing Migrator.list typing #3460
19
+ - Fix Typescript type inference for to better support wildcard (*) calls #3444
20
+ - Make options argument optional in timeout #3442
21
+
22
+ ### Test / internal changes:
23
+
24
+ - Enable linting in CI #3450
25
+
3
26
  # 0.19.4 - 09 September, 2019
4
27
 
5
28
  ### New features:
package/bin/cli.js CHANGED
@@ -190,11 +190,13 @@ function invoke(env) {
190
190
  });
191
191
 
192
192
  commander
193
- .command('migrate:up')
194
- .description(' Run the next migration that has not yet been run.')
195
- .action(() => {
193
+ .command('migrate:up [<name>]')
194
+ .description(
195
+ ' Run the next or the specified migration that has not yet been run.'
196
+ )
197
+ .action((name) => {
196
198
  pending = initKnex(env, commander.opts())
197
- .migrate.up()
199
+ .migrate.up({ name })
198
200
  .then(([batchNo, log]) => {
199
201
  if (log.length === 0) {
200
202
  success(color.cyan('Already up to date'));
@@ -235,11 +237,13 @@ function invoke(env) {
235
237
  });
236
238
 
237
239
  commander
238
- .command('migrate:down')
239
- .description(' Undo the last migration performed.')
240
- .action(() => {
240
+ .command('migrate:down [<name>]')
241
+ .description(
242
+ ' Undo the last or the specified migration that was already run.'
243
+ )
244
+ .action((name) => {
241
245
  pending = initKnex(env, commander.opts())
242
- .migrate.down()
246
+ .migrate.down({ name })
243
247
  .then(([batchNo, log]) => {
244
248
  if (log.length === 0) {
245
249
  success(color.cyan('Already at the base migration'));
@@ -207,7 +207,11 @@ Object.assign(Client_MSSQL.prototype, {
207
207
  },
208
208
 
209
209
  wrapIdentifierImpl(value) {
210
- return value !== '*' ? `[${value.replace(/\[/g, '[')}]` : '*';
210
+ if (value === '*') {
211
+ return '*';
212
+ }
213
+
214
+ return `[${value.replace(/[[\]']+/g, '')}]`;
211
215
  },
212
216
 
213
217
  // Get a raw connection, called by the `pool` whenever a new
@@ -263,6 +263,13 @@ Client_Oracledb.prototype._query = function(connection, obj) {
263
263
  ? response.rows.rowsAffected
264
264
  : response.rowsAffected;
265
265
 
266
+ //added for outBind parameter
267
+ if (obj.method === 'raw' && outBinds.length > 0) {
268
+ return resolver({
269
+ response: outBinds,
270
+ });
271
+ }
272
+
266
273
  if (obj.method === 'update') {
267
274
  const modifiedRowsCount = obj.rowsAffected.length || obj.rowsAffected;
268
275
  const updatedObjOutBinding = [];
@@ -129,7 +129,8 @@ assign(SQLite3_DDL.prototype, {
129
129
  },
130
130
 
131
131
  _doReplace(sql, from, to) {
132
- const matched = sql.match(/^CREATE TABLE (\S+) \((.*)\)/);
132
+ const oneLineSql = sql.replace(/\s+/g, ' ');
133
+ const matched = oneLineSql.match(/^CREATE TABLE (\S+) \((.*)\)/);
133
134
 
134
135
  const tableName = matched[1];
135
136
  const defs = matched[2];
@@ -166,23 +167,27 @@ assign(SQLite3_DDL.prototype, {
166
167
  }
167
168
  args.push(defs.slice(ptr, i));
168
169
 
169
- // Backwards compatible for double quoted sqlite databases
170
- // Detect CREATE TABLE "accounts" ("id"...)
171
- // The "from" and "to" field use backsticks, because this is the default notation for
172
- // SQlite3 since Knex 0.14.
173
- // e.g. from: `about`
174
- //
175
- // We have to replace the from+to field with double slashes in case you created your SQlite3
176
- // database with Knex < 0.14.
177
- if (sql.match(/CREATE\sTABLE\s".*"\s\("/)) {
178
- from = from.replace(/[`]/g, '"');
179
- to = to.replace(/[`]/g, '"');
180
- }
170
+ const fromIdentifier = from.replace(/[`"]/g, '');
181
171
 
182
172
  args = args.map(function(item) {
183
- let split = item.split(' ');
173
+ let split = item.trim().split(' ');
174
+
175
+ let normalizedFrom = from;
184
176
 
185
- if (split[0] === from) {
177
+ // Backwards compatible for double quoted sqlite databases
178
+ // The "from" and "to" field use backsticks, because this is the default notation for
179
+ // SQlite3 since Knex 0.14.
180
+ // e.g. from: `about`
181
+ //
182
+ // We have to replace the from+to field with double slashes in case you created your SQlite3
183
+ // database with Knex < 0.14.
184
+ if (item.match(`"${fromIdentifier}"`)) {
185
+ normalizedFrom = `"${fromIdentifier}"`;
186
+ } else if (item.match(`\`${fromIdentifier}\``)) {
187
+ normalizedFrom = `\`${fromIdentifier}\``;
188
+ }
189
+
190
+ if (split[0] === normalizedFrom) {
186
191
  // column definition
187
192
  if (to) {
188
193
  split[0] = to;
@@ -198,7 +203,9 @@ assign(SQLite3_DDL.prototype, {
198
203
  // columns from this table listed between (); replace
199
204
  // one if it matches
200
205
  if (/primary|unique/i.test(split[idx])) {
201
- return item.replace(/\(.*\)/, (columns) => columns.replace(from, to));
206
+ return item.replace(/\(.*\)/, (columns) =>
207
+ columns.replace(normalizedFrom, to)
208
+ );
202
209
  }
203
210
 
204
211
  // foreign keys have one or more columns from this table
@@ -210,11 +217,11 @@ assign(SQLite3_DDL.prototype, {
210
217
  split = item.split(/ references /i);
211
218
  // the quoted column names save us from having to do anything
212
219
  // other than a straight replace here
213
- split[0] = split[0].replace(from, to);
220
+ split[0] = split[0].replace(normalizedFrom, to);
214
221
 
215
222
  if (split[1].slice(0, tableName.length) === tableName) {
216
223
  split[1] = split[1].replace(/\(.*\)/, (columns) =>
217
- columns.replace(from, to)
224
+ columns.replace(normalizedFrom, to)
218
225
  );
219
226
  }
220
227
  return split.join(' references ');
@@ -222,7 +229,7 @@ assign(SQLite3_DDL.prototype, {
222
229
 
223
230
  return item;
224
231
  });
225
- return sql
232
+ return oneLineSql
226
233
  .replace(/\(.*\)/, () => `(${args.join(', ')})`)
227
234
  .replace(/,\s*([,)])/, '$1');
228
235
  },
package/lib/helpers.js CHANGED
@@ -65,7 +65,7 @@ function getUndefinedIndices(mixed) {
65
65
  if (containsUndefined(mixed[key])) {
66
66
  indices.push(key);
67
67
  }
68
- })
68
+ });
69
69
  } else {
70
70
  indices.push(0);
71
71
  }
@@ -108,16 +108,38 @@ class Migrator {
108
108
  return value;
109
109
  })
110
110
  .then(([all, completed]) => {
111
- const migrationToRun = getNewMigrations(
111
+ const newMigrations = getNewMigrations(
112
112
  this.config.migrationSource,
113
113
  all,
114
114
  completed
115
- ).slice(0, 1);
115
+ );
116
+
117
+ let migrationToRun;
118
+ const name = this.config.name;
119
+ if (name) {
120
+ if (!completed.includes(name)) {
121
+ migrationToRun = newMigrations.find((migration) => {
122
+ return (
123
+ this.config.migrationSource.getMigrationName(migration) === name
124
+ );
125
+ });
126
+ if (!migrationToRun) {
127
+ throw new Error(`Migration "${name}" not found.`);
128
+ }
129
+ }
130
+ } else {
131
+ migrationToRun = newMigrations[0];
132
+ }
133
+
134
+ const migrationsToRun = [];
135
+ if (migrationToRun) {
136
+ migrationsToRun.push(migrationToRun);
137
+ }
116
138
 
117
139
  const transactionForAll =
118
140
  !this.config.disableTransactions &&
119
141
  isEmpty(
120
- filter(migrationToRun, (migration) => {
142
+ filter(migrationsToRun, (migration) => {
121
143
  const migrationContents = this.config.migrationSource.getMigration(
122
144
  migration
123
145
  );
@@ -128,10 +150,10 @@ class Migrator {
128
150
 
129
151
  if (transactionForAll) {
130
152
  return this.knex.transaction((trx) => {
131
- return this._runBatch(migrationToRun, 'up', trx);
153
+ return this._runBatch(migrationsToRun, 'up', trx);
132
154
  });
133
155
  } else {
134
- return this._runBatch(migrationToRun, 'up');
156
+ return this._runBatch(migrationsToRun, 'up');
135
157
  }
136
158
  });
137
159
  }
@@ -180,16 +202,33 @@ class Migrator {
180
202
  return value;
181
203
  })
182
204
  .then(([all, completed]) => {
183
- const migrationToRun = all
184
- .filter((migration) => {
185
- return completed.includes(
186
- this.config.migrationSource.getMigrationName(migration)
205
+ const completedMigrations = all.filter((migration) => {
206
+ return completed.includes(
207
+ this.config.migrationSource.getMigrationName(migration)
208
+ );
209
+ });
210
+
211
+ let migrationToRun;
212
+ const name = this.config.name;
213
+ if (name) {
214
+ migrationToRun = completedMigrations.find((migration) => {
215
+ return (
216
+ this.config.migrationSource.getMigrationName(migration) === name
187
217
  );
188
- })
189
- .reverse()
190
- .slice(0, 1);
218
+ });
219
+ if (!migrationToRun) {
220
+ throw new Error(`Migration "${name}" was not run.`);
221
+ }
222
+ } else {
223
+ migrationToRun = completedMigrations[completedMigrations.length - 1];
224
+ }
225
+
226
+ const migrationsToRun = [];
227
+ if (migrationToRun) {
228
+ migrationsToRun.push(migrationToRun);
229
+ }
191
230
 
192
- return this._runBatch(migrationToRun, 'down');
231
+ return this._runBatch(migrationsToRun, 'down');
193
232
  });
194
233
  }
195
234
 
@@ -1271,8 +1271,8 @@ Builder.prototype.del = Builder.prototype.delete;
1271
1271
  require('../interface')(Builder);
1272
1272
  helpers.addQueryContext(Builder);
1273
1273
 
1274
- Builder.extend = function(methodName, fn) {
1275
- if (Builder.prototype.hasOwnProperty(methodName)) {
1274
+ Builder.extend = (methodName, fn) => {
1275
+ if (Object.prototype.hasOwnProperty.call(Builder.prototype, methodName)) {
1276
1276
  throw new Error(
1277
1277
  `Can't extend QueryBuilder with existing method ('${methodName}').`
1278
1278
  );
@@ -100,7 +100,9 @@ assign(QueryCompiler.prototype, {
100
100
  debugBindings(query.bindings);
101
101
  throw new Error(
102
102
  `Undefined binding(s) detected when compiling ` +
103
- `${method.toUpperCase()}. Undefined column(s): [${this.undefinedBindingsInfo.join(', ')}] query: ${query.sql}`
103
+ `${method.toUpperCase()}. Undefined column(s): [${this.undefinedBindingsInfo.join(
104
+ ', '
105
+ )}] query: ${query.sql}`
104
106
  );
105
107
  }
106
108
 
@@ -373,7 +375,7 @@ assign(QueryCompiler.prototype, {
373
375
  Object.prototype.hasOwnProperty.call(stmt, 'value') &&
374
376
  helpers.containsUndefined(stmt.value)
375
377
  ) {
376
- this.undefinedBindingsInfo.push(stmt.column)
378
+ this.undefinedBindingsInfo.push(stmt.column);
377
379
  this._undefinedInWhereClause = true;
378
380
  }
379
381
  const val = this[stmt.type](stmt);
package/lib/raw.js CHANGED
@@ -104,7 +104,9 @@ assign(Raw.prototype, {
104
104
 
105
105
  obj.bindings = obj.bindings || [];
106
106
  if (helpers.containsUndefined(obj.bindings)) {
107
- const undefinedBindingIndices = helpers.getUndefinedIndices(this.bindings);
107
+ const undefinedBindingIndices = helpers.getUndefinedIndices(
108
+ this.bindings
109
+ );
108
110
  debugBindings(obj.bindings);
109
111
  throw new Error(
110
112
  `Undefined binding(s) detected for keys [${undefinedBindingIndices}] when compiling RAW query: ${obj.sql}`
@@ -210,6 +210,7 @@ class Transaction extends EventEmitter {
210
210
  // the original promise is marked completed.
211
211
  acquireConnection(client, config, txid) {
212
212
  const configConnection = config && config.connection;
213
+ const trx = this;
213
214
  return new Bluebird((resolve, reject) => {
214
215
  try {
215
216
  resolve(configConnection || client.acquireConnection());
@@ -220,7 +221,12 @@ class Transaction extends EventEmitter {
220
221
  .then(function(connection) {
221
222
  connection.__knexTxId = txid;
222
223
 
223
- return connection;
224
+ return (trx._previousSibling
225
+ ? trx._previousSibling.reflect()
226
+ : Promise.resolve()
227
+ ).then(function() {
228
+ return connection;
229
+ });
224
230
  })
225
231
  .disposer(function(connection) {
226
232
  if (!configConnection) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knex",
3
- "version": "0.19.4",
3
+ "version": "0.19.5",
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",
@@ -14,8 +14,10 @@
14
14
  "coveralls": "nyc report --reporter=text-lcov | coveralls",
15
15
  "lint": "eslint \"lib/**/*.js\" \"test/**/*.js\"",
16
16
  "lint:types": "dtslint types",
17
+ "lint:everything": "npm run lint:types && npm run lint",
17
18
  "test": "mocha --exit -t 10000 test/index.js && npm run test:tape && npm run test:cli",
18
- "test:nyc": "nyc mocha --exit --check-leaks --globals __core-js_shared__ -t 10000 test/index.js && npm run test:tape && npm run test:cli",
19
+ "test:coverage": "nyc mocha --exit --check-leaks --globals __core-js_shared__ -t 10000 test/index.js && npm run test:tape && npm run test:cli",
20
+ "test:everything": "npm run lint:everything && npm run test:coverage",
19
21
  "test:sqlite": "cross-env DB=sqlite3 npm test",
20
22
  "test:tape": "node test/tape/index.js | tap-spec",
21
23
  "test:cli": "cross-env KNEX_PATH=../knex.js KNEX=bin/cli.js jake -f test/jake/Jakefile",
@@ -26,9 +28,9 @@
26
28
  "stress:destroy": "docker-compose -f scripts/stress-test/docker-compose.yml stop"
27
29
  },
28
30
  "dependencies": {
29
- "bluebird": "^3.5.5",
31
+ "bluebird": "^3.7.0",
30
32
  "colorette": "1.1.0",
31
- "commander": "^3.0.1",
33
+ "commander": "^3.0.2",
32
34
  "debug": "4.1.1",
33
35
  "getopts": "2.2.5",
34
36
  "inherits": "~2.0.4",
@@ -49,21 +51,21 @@
49
51
  ]
50
52
  },
51
53
  "devDependencies": {
52
- "@types/node": "^10.14.17",
54
+ "@types/node": "^10.14.20",
53
55
  "JSONStream": "^1.3.5",
54
56
  "chai": "^4.2.0",
55
57
  "chai-subset-in-order": "^2.1.3",
56
- "cli-testlab": "^1.7.0",
58
+ "cli-testlab": "^1.8.0",
57
59
  "coveralls": "^3.0.6",
58
- "cross-env": "^5.2.1",
59
- "dtslint": "^0.9.6",
60
- "eslint": "^6.3.0",
61
- "eslint-config-prettier": "^6.2.0",
60
+ "cross-env": "^6.0.3",
61
+ "dtslint": "^0.9.8",
62
+ "eslint": "^6.5.1",
63
+ "eslint-config-prettier": "^6.4.0",
62
64
  "eslint-plugin-import": "^2.18.2",
63
- "husky": "^3.0.5",
65
+ "husky": "^3.0.8",
64
66
  "jake": "^8.1.1",
65
- "lint-staged": "^9.2.5",
66
- "mocha": "^6.2.0",
67
+ "lint-staged": "^9.4.1",
68
+ "mocha": "^6.2.1",
67
69
  "mock-fs": "^4.10.1",
68
70
  "mssql": "^5.1.0",
69
71
  "mysql": "^2.17.1",
@@ -73,15 +75,15 @@
73
75
  "pg-query-stream": "^2.0.0",
74
76
  "prettier": "^1.18.2",
75
77
  "rimraf": "^3.0.0",
76
- "sinon": "^7.4.2",
78
+ "sinon": "^7.5.0",
77
79
  "sinon-chai": "^3.3.0",
78
80
  "source-map-support": "^0.5.13",
79
81
  "sqlite3": "^4.1.0",
80
82
  "tap-spec": "^5.0.0",
81
83
  "tape": "^4.11.0",
82
84
  "toxiproxy-node-client": "^2.0.6",
83
- "typescript": "^3.6.2",
84
- "webpack-cli": "^3.3.8"
85
+ "typescript": "^3.6.3",
86
+ "webpack-cli": "^3.3.9"
85
87
  },
86
88
  "buildDependencies": [
87
89
  "rimraf"
package/types/index.d.ts CHANGED
@@ -548,6 +548,10 @@ declare namespace Knex {
548
548
  ): QueryBuilder<TRecord, TRecord[K][]>;
549
549
  pluck<TResult2 extends {}>(column: string): QueryBuilder<TRecord, TResult2>;
550
550
 
551
+ insert(
552
+ data: MaybeArray<SafePartial<TRecord>>,
553
+ returning: '*'
554
+ ): QueryBuilder<TRecord, DeferredKeySelection<TRecord, never>[]>;
551
555
  insert<
552
556
  TKey extends StrKey<TRecord>,
553
557
  TResult2 = DeferredIndex.Augment<
@@ -601,6 +605,10 @@ declare namespace Knex {
601
605
  ...args: any[]
602
606
  ): QueryBuilder<TRecord2, TResult2>;
603
607
 
608
+ update(
609
+ data: MaybeArray<SafePartial<TRecord>>,
610
+ returning: '*'
611
+ ): QueryBuilder<TRecord, DeferredKeySelection<TRecord, never>[]>;
604
612
  update<
605
613
  TKey extends StrKey<TRecord>,
606
614
  TResult2 = DeferredIndex.Augment<
@@ -685,6 +693,7 @@ declare namespace Knex {
685
693
  ): QueryBuilder<TRecord, TResult2>;
686
694
  update<TResult2 = number>(columnName: string, value: Value): QueryBuilder<TRecord, TResult2>;
687
695
 
696
+ returning(column: '*'): QueryBuilder<TRecord, DeferredKeySelection<TRecord, never>[]>;
688
697
  returning<
689
698
  TKey extends StrKey<TRecord>,
690
699
  TResult2 = DeferredIndex.Augment<
@@ -708,6 +717,9 @@ declare namespace Knex {
708
717
  column: string | string[]
709
718
  ): QueryBuilder<TRecord, TResult2>;
710
719
 
720
+ del(
721
+ returning: '*'
722
+ ): QueryBuilder<TRecord, DeferredKeySelection<TRecord, never>[]>;
711
723
  del<
712
724
  TKey extends StrKey<TRecord>,
713
725
  TResult2 = DeferredIndex.Augment<
@@ -733,6 +745,9 @@ declare namespace Knex {
733
745
  ): QueryBuilder<TRecord, TResult2>;
734
746
  del<TResult2 = number>(): QueryBuilder<TRecord, TResult2>;
735
747
 
748
+ delete(
749
+ returning: '*'
750
+ ): QueryBuilder<TRecord, DeferredKeySelection<TRecord, never>[]>;
736
751
  delete<
737
752
  TKey extends StrKey<TRecord>,
738
753
  TResult2 = DeferredIndex.Augment<
@@ -1340,7 +1355,6 @@ declare namespace Knex {
1340
1355
  >
1341
1356
  extends QueryInterface<TRecord, TResult>,
1342
1357
  ChainableInterface<ResolveResult<TResult>> {
1343
-
1344
1358
  or: QueryBuilder<TRecord, TResult>;
1345
1359
  not: QueryBuilder<TRecord, TResult>;
1346
1360
  and: QueryBuilder<TRecord, TResult>;
@@ -1364,7 +1378,7 @@ declare namespace Knex {
1364
1378
  queryContext(context: any): QueryBuilder<TRecord, TResult>;
1365
1379
 
1366
1380
  clone(): QueryBuilder<TRecord, TResult>;
1367
- timeout(ms: number, options: {cancel?: boolean}): QueryBuilder<TRecord, TResult>;
1381
+ timeout(ms: number, options?: {cancel?: boolean}): QueryBuilder<TRecord, TResult>;
1368
1382
  }
1369
1383
 
1370
1384
  interface Sql {
@@ -1812,6 +1826,7 @@ declare namespace Knex {
1812
1826
  rollback(config?: MigratorConfig, all?: boolean): Promise<any>;
1813
1827
  status(config?: MigratorConfig): Promise<number>;
1814
1828
  currentVersion(config?: MigratorConfig): Promise<string>;
1829
+ list(config?: MigratorConfig): Promise<any>;
1815
1830
  up(config?: MigratorConfig): Promise<any>;
1816
1831
  down(config?: MigratorConfig): Promise<any>;
1817
1832
  }
@@ -1858,7 +1873,7 @@ declare namespace Knex {
1858
1873
  }
1859
1874
 
1860
1875
  class QueryBuilder {
1861
- public static extend(
1876
+ static extend(
1862
1877
  methodName: string,
1863
1878
  fn: <TRecord extends {} = any, TResult = unknown[]>(
1864
1879
  this: Knex<TRecord, TResult>,