knex 0.95.14 → 1.0.2

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 (78) hide show
  1. package/CHANGELOG.md +90 -1
  2. package/README.md +1 -1
  3. package/UPGRADING.md +7 -0
  4. package/lib/client.js +14 -1
  5. package/lib/constants.js +2 -0
  6. package/lib/dialects/better-sqlite3/index.js +72 -0
  7. package/lib/dialects/cockroachdb/crdb-querycompiler.js +92 -33
  8. package/lib/dialects/cockroachdb/crdb-tablecompiler.js +19 -0
  9. package/lib/dialects/cockroachdb/index.js +13 -0
  10. package/lib/dialects/mssql/index.js +0 -11
  11. package/lib/dialects/mssql/query/mssql-querycompiler.js +122 -64
  12. package/lib/dialects/mssql/schema/mssql-columncompiler.js +41 -6
  13. package/lib/dialects/mssql/schema/mssql-compiler.js +3 -4
  14. package/lib/dialects/mssql/schema/mssql-tablecompiler.js +24 -9
  15. package/lib/dialects/mssql/schema/mssql-viewcompiler.js +15 -1
  16. package/lib/dialects/mysql/query/mysql-querycompiler.js +93 -5
  17. package/lib/dialects/mysql/schema/mysql-columncompiler.js +32 -5
  18. package/lib/dialects/mysql/schema/mysql-tablecompiler.js +33 -6
  19. package/lib/dialects/oracle/query/oracle-querycompiler.js +7 -6
  20. package/lib/dialects/oracle/schema/internal/trigger.js +1 -1
  21. package/lib/dialects/oracle/schema/oracle-columncompiler.js +10 -4
  22. package/lib/dialects/oracle/schema/oracle-tablecompiler.js +17 -6
  23. package/lib/dialects/oracledb/index.js +0 -4
  24. package/lib/dialects/oracledb/query/oracledb-querycompiler.js +89 -0
  25. package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +23 -0
  26. package/lib/dialects/postgres/index.js +21 -6
  27. package/lib/dialects/postgres/query/pg-querybuilder.js +38 -0
  28. package/lib/dialects/postgres/query/pg-querycompiler.js +172 -9
  29. package/lib/dialects/postgres/schema/pg-columncompiler.js +24 -4
  30. package/lib/dialects/postgres/schema/pg-tablecompiler.js +63 -46
  31. package/lib/dialects/redshift/index.js +12 -0
  32. package/lib/dialects/redshift/query/redshift-querycompiler.js +62 -26
  33. package/lib/dialects/redshift/schema/redshift-columncompiler.js +2 -1
  34. package/lib/dialects/redshift/schema/redshift-tablecompiler.js +4 -1
  35. package/lib/dialects/sqlite3/index.js +23 -4
  36. package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -0
  37. package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +87 -22
  38. package/lib/dialects/sqlite3/schema/ddl.js +274 -282
  39. package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +18 -8
  40. package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +20 -0
  41. package/lib/dialects/sqlite3/schema/sqlite-compiler.js +16 -12
  42. package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +15 -5
  43. package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +31 -2
  44. package/lib/execution/runner.js +37 -2
  45. package/lib/knex-builder/FunctionHelper.js +36 -0
  46. package/lib/migrations/common/MigrationsLoader.js +36 -0
  47. package/lib/migrations/migrate/MigrationGenerator.js +1 -1
  48. package/lib/migrations/migrate/Migrator.js +22 -24
  49. package/lib/migrations/migrate/migration-list-resolver.js +2 -5
  50. package/lib/migrations/migrate/{configuration-merger.js → migrator-configuration-merger.js} +2 -4
  51. package/lib/migrations/migrate/sources/fs-migrations.js +4 -29
  52. package/lib/migrations/migrate/stub/js.stub +8 -1
  53. package/lib/migrations/migrate/stub/knexfile-js.stub +3 -0
  54. package/lib/migrations/migrate/stub/knexfile-ts.stub +5 -2
  55. package/lib/migrations/migrate/table-creator.js +6 -5
  56. package/lib/migrations/seed/Seeder.js +25 -92
  57. package/lib/migrations/seed/seeder-configuration-merger.js +60 -0
  58. package/lib/migrations/seed/sources/fs-seeds.js +65 -0
  59. package/lib/migrations/seed/stub/js.stub +4 -1
  60. package/lib/migrations/util/import-file.js +0 -1
  61. package/lib/query/joinclause.js +24 -5
  62. package/lib/query/method-constants.js +37 -0
  63. package/lib/query/querybuilder.js +292 -53
  64. package/lib/query/querycompiler.js +309 -85
  65. package/lib/schema/columnbuilder.js +14 -1
  66. package/lib/schema/columncompiler.js +132 -5
  67. package/lib/schema/compiler.js +1 -0
  68. package/lib/schema/tablebuilder.js +41 -8
  69. package/lib/schema/tablecompiler.js +61 -4
  70. package/lib/schema/viewcompiler.js +13 -10
  71. package/package.json +37 -27
  72. package/scripts/docker-compose.yml +7 -7
  73. package/scripts/oracledb-install-driver-libs.sh +82 -0
  74. package/scripts/runkit-example.js +1 -1
  75. package/scripts/stress-test/docker-compose.yml +3 -3
  76. package/scripts/stress-test/knex-stress-test.js +1 -1
  77. package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +1 -1
  78. package/types/index.d.ts +133 -21
@@ -118,25 +118,82 @@ class Builder extends EventEmitter {
118
118
 
119
119
  // With
120
120
  // ------
121
+ isValidStatementArg(statement) {
122
+ return (
123
+ typeof statement === 'function' ||
124
+ statement instanceof Builder ||
125
+ (statement && statement.isRawInstance)
126
+ );
127
+ }
128
+
129
+ _validateWithArgs(alias, statementOrColumnList, nothingOrStatement, method) {
130
+ const [query, columnList] =
131
+ typeof nothingOrStatement === 'undefined'
132
+ ? [statementOrColumnList, undefined]
133
+ : [nothingOrStatement, statementOrColumnList];
134
+ if (typeof alias !== 'string') {
135
+ throw new Error(`${method}() first argument must be a string`);
136
+ }
137
+
138
+ if (this.isValidStatementArg(query) && typeof columnList === 'undefined') {
139
+ // Validated as two-arg variant (alias, statement).
140
+ return;
141
+ }
142
+
143
+ // Attempt to interpret as three-arg variant (alias, columnList, statement).
144
+ const isNonEmptyNameList =
145
+ Array.isArray(columnList) &&
146
+ columnList.length > 0 &&
147
+ columnList.every((it) => typeof it === 'string');
148
+ if (!isNonEmptyNameList) {
149
+ throw new Error(
150
+ `${method}() second argument must be a statement or non-empty column name list.`
151
+ );
152
+ }
153
+
154
+ if (this.isValidStatementArg(query)) {
155
+ return;
156
+ }
157
+ throw new Error(
158
+ `${method}() third argument must be a function / QueryBuilder or a raw when its second argument is a column name list`
159
+ );
160
+ }
121
161
 
122
162
  with(alias, statementOrColumnList, nothingOrStatement) {
123
- validateWithArgs(alias, statementOrColumnList, nothingOrStatement, 'with');
163
+ this._validateWithArgs(
164
+ alias,
165
+ statementOrColumnList,
166
+ nothingOrStatement,
167
+ 'with'
168
+ );
124
169
  return this.withWrapped(alias, statementOrColumnList, nothingOrStatement);
125
170
  }
126
171
 
172
+ withMaterialized(alias, statementOrColumnList, nothingOrStatement) {
173
+ throw new Error('With materialized is not supported by this dialect');
174
+ }
175
+
176
+ withNotMaterialized(alias, statementOrColumnList, nothingOrStatement) {
177
+ throw new Error('With materialized is not supported by this dialect');
178
+ }
179
+
127
180
  // Helper for compiling any advanced `with` queries.
128
- withWrapped(alias, statementOrColumnList, nothingOrStatement) {
181
+ withWrapped(alias, statementOrColumnList, nothingOrStatement, materialized) {
129
182
  const [query, columnList] =
130
183
  typeof nothingOrStatement === 'undefined'
131
184
  ? [statementOrColumnList, undefined]
132
185
  : [nothingOrStatement, statementOrColumnList];
133
- this._statements.push({
186
+ const statement = {
134
187
  grouping: 'with',
135
188
  type: 'withWrapped',
136
189
  alias: alias,
137
190
  columnList,
138
191
  value: query,
139
- });
192
+ };
193
+ if (materialized !== undefined) {
194
+ statement.materialized = materialized;
195
+ }
196
+ this._statements.push(statement);
140
197
  return this;
141
198
  }
142
199
 
@@ -144,7 +201,7 @@ class Builder extends EventEmitter {
144
201
  // ------
145
202
 
146
203
  withRecursive(alias, statementOrColumnList, nothingOrStatement) {
147
- validateWithArgs(
204
+ this._validateWithArgs(
148
205
  alias,
149
206
  statementOrColumnList,
150
207
  nothingOrStatement,
@@ -246,7 +303,6 @@ class Builder extends EventEmitter {
246
303
 
247
304
  // Adds a join clause to the query, allowing for advanced joins
248
305
  // with an anonymous function as the second argument.
249
- // function(table, first, operator, second)
250
306
  join(table, first, ...args) {
251
307
  let join;
252
308
  const schema =
@@ -269,6 +325,12 @@ class Builder extends EventEmitter {
269
325
  return this;
270
326
  }
271
327
 
328
+ using(tables) {
329
+ throw new Error(
330
+ "'using' function is only available in PostgreSQL dialect with Delete statements."
331
+ );
332
+ }
333
+
272
334
  // JOIN blocks:
273
335
  innerJoin(...args) {
274
336
  return this._joinType('inner').join(...args);
@@ -429,7 +491,7 @@ class Builder extends EventEmitter {
429
491
 
430
492
  // Adds an `not where` clause to the query.
431
493
  whereNot(column, ...args) {
432
- if (args.length >= 1) {
494
+ if (args.length >= 2) {
433
495
  if (args[0] === 'in' || args[0] === 'between') {
434
496
  this.client.logger.warn(
435
497
  'whereNot is not suitable for "in" and "between" type subqueries. You should use "not in" and "not between" instead.'
@@ -611,6 +673,29 @@ class Builder extends EventEmitter {
611
673
  return this._bool('or').whereNotBetween(column, values);
612
674
  }
613
675
 
676
+ _whereLike(type, column, value) {
677
+ this._statements.push({
678
+ grouping: 'where',
679
+ type: type,
680
+ column,
681
+ value: value,
682
+ not: this._not(),
683
+ bool: this._bool(),
684
+ asColumn: this._asColumnFlag,
685
+ });
686
+ return this;
687
+ }
688
+
689
+ // Adds a `where like` clause to the query.
690
+ whereLike(column, value) {
691
+ return this._whereLike('whereLike', column, value);
692
+ }
693
+
694
+ // Adds a `where ilike` clause to the query.
695
+ whereILike(column, value) {
696
+ return this._whereLike('whereILike', column, value);
697
+ }
698
+
614
699
  // Adds a `group by` clause to the query.
615
700
  groupBy(item) {
616
701
  if (item && item.isRawInstance) {
@@ -920,8 +1005,18 @@ class Builder extends EventEmitter {
920
1005
  return this._bool('or').havingRaw(sql, bindings);
921
1006
  }
922
1007
 
1008
+ // set the skip binding parameter (= insert the raw value in the query) for an attribute.
1009
+ _setSkipBinding(attribute, options) {
1010
+ let skipBinding = options;
1011
+ if (isObject(options)) {
1012
+ skipBinding = options.skipBinding;
1013
+ }
1014
+ this._single.skipBinding = this._single.skipBinding || {};
1015
+ this._single.skipBinding[attribute] = skipBinding;
1016
+ }
1017
+
923
1018
  // Only allow a single "offset" to be set for the current query.
924
- offset(value) {
1019
+ offset(value, options) {
925
1020
  if (value == null || value.isRawInstance || value instanceof Builder) {
926
1021
  // Builder for backward compatibility
927
1022
  this._single.offset = value;
@@ -935,16 +1030,18 @@ class Builder extends EventEmitter {
935
1030
  this._single.offset = val;
936
1031
  }
937
1032
  }
1033
+ this._setSkipBinding('offset', options);
938
1034
  return this;
939
1035
  }
940
1036
 
941
1037
  // Only allow a single "limit" to be set for the current query.
942
- limit(value) {
1038
+ limit(value, options) {
943
1039
  const val = parseInt(value, 10);
944
1040
  if (isNaN(val)) {
945
1041
  this.client.logger.warn('A valid integer must be provided to limit');
946
1042
  } else {
947
1043
  this._single.limit = val;
1044
+ this._setSkipBinding('limit', options);
948
1045
  }
949
1046
  return this;
950
1047
  }
@@ -1192,7 +1289,11 @@ class Builder extends EventEmitter {
1192
1289
  // Set a lock for update constraint.
1193
1290
  forUpdate(...tables) {
1194
1291
  this._single.lock = lockMode.forUpdate;
1195
- this._single.lockTables = tables;
1292
+ if (tables.length === 1 && Array.isArray(tables[0])) {
1293
+ this._single.lockTables = tables[0];
1294
+ } else {
1295
+ this._single.lockTables = tables;
1296
+ }
1196
1297
  return this;
1197
1298
  }
1198
1299
 
@@ -1266,6 +1367,11 @@ class Builder extends EventEmitter {
1266
1367
  return this;
1267
1368
  }
1268
1369
 
1370
+ fromRaw(sql, bindings) {
1371
+ const raw = sql.isRawInstance ? sql : this.client.raw(sql, bindings);
1372
+ return this.from(raw);
1373
+ }
1374
+
1269
1375
  // Passes query to provided callback function, useful for e.g. composing
1270
1376
  // domain-specific helpers
1271
1377
  modify(callback) {
@@ -1279,6 +1385,179 @@ class Builder extends EventEmitter {
1279
1385
  );
1280
1386
  }
1281
1387
 
1388
+ // JSON support functions
1389
+ _json(nameFunction, params) {
1390
+ this._statements.push({
1391
+ grouping: 'columns',
1392
+ type: 'json',
1393
+ method: nameFunction,
1394
+ params: params,
1395
+ });
1396
+ return this;
1397
+ }
1398
+
1399
+ jsonExtract() {
1400
+ const column = arguments[0];
1401
+ let path;
1402
+ let alias;
1403
+ let singleValue = true;
1404
+
1405
+ // We use arguments to have the signatures :
1406
+ // - column (string or array)
1407
+ // - column + path
1408
+ // - column + path + alias
1409
+ // - column + path + alias + singleValue
1410
+ // - column array + singleValue
1411
+ if (arguments.length >= 2) {
1412
+ path = arguments[1];
1413
+ }
1414
+ if (arguments.length >= 3) {
1415
+ alias = arguments[2];
1416
+ }
1417
+ if (arguments.length === 4) {
1418
+ singleValue = arguments[3];
1419
+ }
1420
+ if (
1421
+ arguments.length === 2 &&
1422
+ Array.isArray(arguments[0]) &&
1423
+ isBoolean(arguments[1])
1424
+ ) {
1425
+ singleValue = arguments[1];
1426
+ }
1427
+ return this._json('jsonExtract', {
1428
+ column: column,
1429
+ path: path,
1430
+ alias: alias,
1431
+ singleValue, // boolean used only in MSSQL to use function for extract value instead of object/array.
1432
+ });
1433
+ }
1434
+
1435
+ jsonSet(column, path, value, alias) {
1436
+ return this._json('jsonSet', {
1437
+ column: column,
1438
+ path: path,
1439
+ value: value,
1440
+ alias: alias,
1441
+ });
1442
+ }
1443
+
1444
+ jsonInsert(column, path, value, alias) {
1445
+ return this._json('jsonInsert', {
1446
+ column: column,
1447
+ path: path,
1448
+ value: value,
1449
+ alias: alias,
1450
+ });
1451
+ }
1452
+
1453
+ jsonRemove(column, path, alias) {
1454
+ return this._json('jsonRemove', {
1455
+ column: column,
1456
+ path: path,
1457
+ alias: alias,
1458
+ });
1459
+ }
1460
+
1461
+ // Wheres for JSON
1462
+ _isJsonObject(jsonValue) {
1463
+ return isObject(jsonValue) && !(jsonValue instanceof Builder);
1464
+ }
1465
+
1466
+ _whereJsonWrappedValue(type, column, value) {
1467
+ const whereJsonClause = {
1468
+ grouping: 'where',
1469
+ type: type,
1470
+ column,
1471
+ value: value,
1472
+ not: this._not(),
1473
+ bool: this._bool(),
1474
+ asColumn: this._asColumnFlag,
1475
+ };
1476
+ if (arguments[3]) {
1477
+ whereJsonClause.operator = arguments[3];
1478
+ }
1479
+ if (arguments[4]) {
1480
+ whereJsonClause.jsonPath = arguments[4];
1481
+ }
1482
+ this._statements.push(whereJsonClause);
1483
+ }
1484
+
1485
+ whereJsonObject(column, value) {
1486
+ this._whereJsonWrappedValue('whereJsonObject', column, value);
1487
+ return this;
1488
+ }
1489
+
1490
+ orWhereJsonObject(column, operator, value) {
1491
+ return this._bool('or').whereJsonObject(column, operator, value);
1492
+ }
1493
+
1494
+ whereNotJsonObject(column, value) {
1495
+ this._not(true)._whereJsonWrappedValue('whereJsonObject', column, value);
1496
+ return this;
1497
+ }
1498
+
1499
+ orWhereNotJsonObject(column, operator, value) {
1500
+ return this._not(true)._bool('or').whereJsonObject(column, operator, value);
1501
+ }
1502
+
1503
+ whereJsonPath(column, path, operator, value) {
1504
+ this._whereJsonWrappedValue('whereJsonPath', column, value, operator, path);
1505
+ return this;
1506
+ }
1507
+
1508
+ orWhereJsonPath(column, operator, value) {
1509
+ return this._bool('or').whereJsonPath(column, operator, value);
1510
+ }
1511
+
1512
+ // Json superset wheres
1513
+ whereJsonSupersetOf(column, value) {
1514
+ this._whereJsonWrappedValue('whereJsonSupersetOf', column, value);
1515
+ return this;
1516
+ }
1517
+
1518
+ whereJsonNotSupersetOf(column, value) {
1519
+ this._not(true).whereJsonSupersetOf(column, value);
1520
+ return this;
1521
+ }
1522
+
1523
+ orWhereJsonSupersetOf(column, value) {
1524
+ this._whereJsonWrappedValue('whereJsonSupersetOf', column, value);
1525
+ return this;
1526
+ }
1527
+
1528
+ orWhereJsonNotSupersetOf(column, value) {
1529
+ this._not(true)._bool('or').whereJsonSupersetOf(column, value);
1530
+ return this;
1531
+ }
1532
+
1533
+ // Json subset wheres
1534
+ whereJsonSubsetOf(column, value) {
1535
+ this._whereJsonWrappedValue('whereJsonSubsetOf', column, value);
1536
+ return this;
1537
+ }
1538
+
1539
+ whereJsonNotSubsetOf(column, value) {
1540
+ this._not(true).whereJsonSubsetOf(column, value);
1541
+ return this;
1542
+ }
1543
+
1544
+ orWhereJsonSubsetOf(column, value) {
1545
+ this._whereJsonWrappedValue('whereJsonSubsetOf', column, value);
1546
+ return this;
1547
+ }
1548
+
1549
+ orWhereJsonNotSubsetOf(column, value) {
1550
+ this._not(true)._bool('or').whereJsonSubsetOf(column, value);
1551
+ return this;
1552
+ }
1553
+
1554
+ whereJsonHasNone(column, values) {
1555
+ this._not(true).whereJsonHasAll(column, values);
1556
+ return this;
1557
+ }
1558
+
1559
+ // end of wheres for JSON
1560
+
1282
1561
  _analytic(alias, second, third) {
1283
1562
  let analytic;
1284
1563
  const { schema } = this._single;
@@ -1434,49 +1713,6 @@ class Builder extends EventEmitter {
1434
1713
  }
1435
1714
  }
1436
1715
 
1437
- const isValidStatementArg = (statement) =>
1438
- typeof statement === 'function' ||
1439
- statement instanceof Builder ||
1440
- (statement && statement.isRawInstance);
1441
-
1442
- const validateWithArgs = function (
1443
- alias,
1444
- statementOrColumnList,
1445
- nothingOrStatement,
1446
- method
1447
- ) {
1448
- const [query, columnList] =
1449
- typeof nothingOrStatement === 'undefined'
1450
- ? [statementOrColumnList, undefined]
1451
- : [nothingOrStatement, statementOrColumnList];
1452
- if (typeof alias !== 'string') {
1453
- throw new Error(`${method}() first argument must be a string`);
1454
- }
1455
-
1456
- if (isValidStatementArg(query) && typeof columnList === 'undefined') {
1457
- // Validated as two-arg variant (alias, statement).
1458
- return;
1459
- }
1460
-
1461
- // Attempt to interpret as three-arg variant (alias, columnList, statement).
1462
- const isNonEmptyNameList =
1463
- Array.isArray(columnList) &&
1464
- columnList.length > 0 &&
1465
- columnList.every((it) => typeof it === 'string');
1466
- if (!isNonEmptyNameList) {
1467
- throw new Error(
1468
- `${method}() second argument must be a statement or non-empty column name list.`
1469
- );
1470
- }
1471
-
1472
- if (isValidStatementArg(query)) {
1473
- return;
1474
- }
1475
- throw new Error(
1476
- `${method}() third argument must be a function / QueryBuilder or a raw when its second argument is a column name list`
1477
- );
1478
- };
1479
-
1480
1716
  Builder.prototype.select = Builder.prototype.columns;
1481
1717
  Builder.prototype.column = Builder.prototype.columns;
1482
1718
  Builder.prototype.andWhereNot = Builder.prototype.whereNot;
@@ -1486,6 +1722,9 @@ Builder.prototype.andWhereColumn = Builder.prototype.whereColumn;
1486
1722
  Builder.prototype.andWhereRaw = Builder.prototype.whereRaw;
1487
1723
  Builder.prototype.andWhereBetween = Builder.prototype.whereBetween;
1488
1724
  Builder.prototype.andWhereNotBetween = Builder.prototype.whereNotBetween;
1725
+ Builder.prototype.andWhereJsonObject = Builder.prototype.whereJsonObject;
1726
+ Builder.prototype.andWhereNotJsonObject = Builder.prototype.whereJsonObject;
1727
+ Builder.prototype.andWhereJsonPath = Builder.prototype.whereJsonPath;
1489
1728
  Builder.prototype.andHaving = Builder.prototype.having;
1490
1729
  Builder.prototype.andHavingIn = Builder.prototype.havingIn;
1491
1730
  Builder.prototype.andHavingNotIn = Builder.prototype.havingNotIn;