knex 0.95.13 → 1.0.1

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 +74 -3
  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 +87 -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-tablecompiler.js +24 -9
  14. package/lib/dialects/mssql/schema/mssql-viewcompiler.js +15 -1
  15. package/lib/dialects/mysql/index.js +3 -7
  16. package/lib/dialects/mysql/query/mysql-querycompiler.js +91 -5
  17. package/lib/dialects/mysql/schema/mysql-columncompiler.js +32 -5
  18. package/lib/dialects/mysql/schema/mysql-tablecompiler.js +28 -4
  19. package/lib/dialects/mysql2/index.js +7 -4
  20. package/lib/dialects/oracle/query/oracle-querycompiler.js +7 -6
  21. package/lib/dialects/oracle/schema/internal/trigger.js +1 -1
  22. package/lib/dialects/oracle/schema/oracle-columncompiler.js +10 -4
  23. package/lib/dialects/oracle/schema/oracle-tablecompiler.js +17 -6
  24. package/lib/dialects/oracledb/index.js +0 -4
  25. package/lib/dialects/oracledb/query/oracledb-querycompiler.js +104 -0
  26. package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +23 -0
  27. package/lib/dialects/postgres/index.js +21 -6
  28. package/lib/dialects/postgres/query/pg-querybuilder.js +8 -0
  29. package/lib/dialects/postgres/query/pg-querycompiler.js +166 -5
  30. package/lib/dialects/postgres/schema/pg-columncompiler.js +24 -4
  31. package/lib/dialects/postgres/schema/pg-tablecompiler.js +55 -47
  32. package/lib/dialects/redshift/index.js +12 -0
  33. package/lib/dialects/redshift/query/redshift-querycompiler.js +62 -26
  34. package/lib/dialects/redshift/schema/redshift-columncompiler.js +2 -1
  35. package/lib/dialects/redshift/schema/redshift-tablecompiler.js +4 -1
  36. package/lib/dialects/sqlite3/index.js +18 -4
  37. package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +85 -18
  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 +21 -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 +20 -23
  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 +230 -5
  64. package/lib/query/querycompiler.js +269 -84
  65. package/lib/schema/columnbuilder.js +8 -0
  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 +57 -0
  70. package/lib/schema/viewcompiler.js +13 -10
  71. package/package.json +35 -22
  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 +124 -20
@@ -2,17 +2,10 @@
2
2
  // -------
3
3
 
4
4
  const path = require('path');
5
- const flatten = require('lodash/flatten');
6
- const extend = require('lodash/extend');
7
- const includes = require('lodash/includes');
8
- const { ensureDirectoryExists, getFilepathsInFolder } = require('../util/fs');
5
+ const { ensureDirectoryExists } = require('../util/fs');
9
6
  const { writeJsFileUsingTemplate } = require('../util/template');
10
7
  const { yyyymmddhhmmss } = require('../util/timestamp');
11
-
12
- const filterByLoadExtensions = (extensions) => (value) => {
13
- const extension = path.extname(value);
14
- return includes(extensions, extension);
15
- };
8
+ const { getMergedConfig } = require('./seeder-configuration-merger');
16
9
 
17
10
  // The new seeds we're performing, typically called from the `knex.seed`
18
11
  // interface on the main `knex` object. Passes the `knex` instance performing
@@ -20,27 +13,19 @@ const filterByLoadExtensions = (extensions) => (value) => {
20
13
  class Seeder {
21
14
  constructor(knex) {
22
15
  this.knex = knex;
23
- this.config = this.setConfig(knex.client.config.seeds);
16
+ this.config = this.resolveConfig(knex.client.config.seeds);
24
17
  }
25
18
 
26
19
  // Runs seed files for the given environment.
27
20
  async run(config) {
28
- this.config = this.setConfig(config);
29
- let files = await this._listAll();
30
- if (config && config.specific) {
31
- files = files.filter((file) => path.basename(file) === config.specific);
32
- if (files.length === 0) {
33
- throw new Error(
34
- `Invalid argument provided: the specific seed "${config.specific}" does not exist.`
35
- );
36
- }
37
- }
21
+ this.config = this.resolveConfig(config);
22
+ const files = await this.config.seedSource.getSeeds(this.config);
38
23
  return this._runSeeds(files);
39
24
  }
40
25
 
41
26
  // Creates a new seed file, with a given name.
42
27
  async make(name, config) {
43
- this.config = this.setConfig(config);
28
+ this.config = this.resolveConfig(config);
44
29
  if (!name)
45
30
  throw new Error('A name must be specified for the generated seed');
46
31
  await this._ensureFolder(config);
@@ -48,45 +33,26 @@ class Seeder {
48
33
  return seedPath;
49
34
  }
50
35
 
51
- // Lists all available seed files as a sorted array.
52
- async _listAll(config) {
53
- this.config = this.setConfig(config);
54
- const { loadExtensions, recursive } = this.config;
55
- const seeds = flatten(
56
- await Promise.all(
57
- this._absoluteConfigDirs().map((d) =>
58
- getFilepathsInFolder(d, recursive)
59
- )
60
- )
61
- );
62
- // if true, each dir are already sorted
63
- // (getFilepathsInFolderRecursively does this)
64
- // if false, we need to sort all the seeds
65
- if (this.config.sortDirsSeparately) {
66
- return seeds.filter(filterByLoadExtensions(loadExtensions));
67
- } else {
68
- return seeds.filter(filterByLoadExtensions(loadExtensions)).sort();
69
- }
70
- }
71
-
72
36
  // Ensures a folder for the seeds exist, dependent on the
73
37
  // seed config settings.
74
38
  _ensureFolder() {
75
- const dirs = this._absoluteConfigDirs();
39
+ const dirs = this.config.seedSource._getConfigDirectories(
40
+ this.config.logger
41
+ );
76
42
  const promises = dirs.map(ensureDirectoryExists);
77
43
  return Promise.all(promises);
78
44
  }
79
45
 
80
46
  // Run seed files, in sequence.
81
- _runSeeds(seeds) {
82
- seeds.forEach((seed) => this._validateSeedStructure(seed));
47
+ async _runSeeds(seeds) {
48
+ for (const seed of seeds) {
49
+ await this._validateSeedStructure(seed);
50
+ }
83
51
  return this._waterfallBatch(seeds);
84
52
  }
85
53
 
86
- // Validates seed files by requiring and checking for a `seed` function.
87
54
  async _validateSeedStructure(filepath) {
88
- const importFile = require('../util/import-file'); // late import
89
- const seed = await importFile(filepath);
55
+ const seed = await this.config.seedSource.getSeed(filepath);
90
56
  if (typeof seed.seed !== 'function') {
91
57
  throw new Error(
92
58
  `Invalid seed file: ${filepath} must have a seed function`
@@ -114,7 +80,9 @@ class Seeder {
114
80
 
115
81
  _getNewStubFilePath(name) {
116
82
  const fileName = this._getNewStubFileName(name);
117
- const dirs = this._absoluteConfigDirs();
83
+ const dirs = this.config.seedSource._getConfigDirectories(
84
+ this.config.logger
85
+ );
118
86
  const dir = dirs.slice(-1)[0]; // Get last specified directory
119
87
  return path.join(dir, fileName);
120
88
  }
@@ -132,13 +100,17 @@ class Seeder {
132
100
  return seedPath;
133
101
  }
134
102
 
103
+ async _listAll(config) {
104
+ this.config = this.resolveConfig(config);
105
+ return this.config.seedSource.getSeeds(this.config);
106
+ }
107
+
135
108
  // Runs a batch of seed files.
136
109
  async _waterfallBatch(seeds) {
137
110
  const { knex } = this;
138
111
  const log = [];
139
112
  for (const seedPath of seeds) {
140
- const importFile = require('../util/import-file'); // late import
141
- const seed = await importFile(seedPath);
113
+ const seed = await this.config.seedSource.getSeed(seedPath);
142
114
  try {
143
115
  await seed.seed(knex);
144
116
  log.push(seedPath);
@@ -157,47 +129,8 @@ class Seeder {
157
129
  return [log];
158
130
  }
159
131
 
160
- /**
161
- * Return all the config directories
162
- * @returns {string[]}
163
- */
164
- _absoluteConfigDirs() {
165
- const directories = Array.isArray(this.config.directory)
166
- ? this.config.directory
167
- : [this.config.directory];
168
- return directories.map((directory) => {
169
- if (!directory) {
170
- console.warn(
171
- 'Failed to resolve config file, knex cannot determine where to run or make seeds'
172
- );
173
- }
174
- return path.resolve(process.cwd(), directory);
175
- });
176
- }
177
-
178
- setConfig(config) {
179
- return extend(
180
- {
181
- extension: 'js',
182
- directory: './seeds',
183
- loadExtensions: [
184
- '.co',
185
- '.coffee',
186
- '.eg',
187
- '.iced',
188
- '.js',
189
- '.litcoffee',
190
- '.ls',
191
- '.ts',
192
- '.cjs',
193
- ],
194
- timestampFilenamePrefix: false,
195
- sortDirsSeparately: false,
196
- recursive: false,
197
- },
198
- this.config || {},
199
- config
200
- );
132
+ resolveConfig(config) {
133
+ return getMergedConfig(config, this.config, this.knex.client.logger);
201
134
  }
202
135
  }
203
136
 
@@ -0,0 +1,60 @@
1
+ const { FsSeeds } = require('./sources/fs-seeds');
2
+ const Logger = require('../../logger');
3
+ const { DEFAULT_LOAD_EXTENSIONS } = require('../common/MigrationsLoader');
4
+ const defaultLogger = new Logger();
5
+
6
+ const CONFIG_DEFAULT = Object.freeze({
7
+ extension: 'js',
8
+ directory: './seeds',
9
+ loadExtensions: DEFAULT_LOAD_EXTENSIONS,
10
+ specific: null,
11
+ timestampFilenamePrefix: false,
12
+ recursive: false,
13
+ sortDirsSeparately: false,
14
+ });
15
+
16
+ function getMergedConfig(config, currentConfig, logger = defaultLogger) {
17
+ // config is the user specified config, mergedConfig has defaults and current config
18
+ // applied to it.
19
+ const mergedConfig = Object.assign(
20
+ {},
21
+ CONFIG_DEFAULT,
22
+ currentConfig || {},
23
+ config,
24
+ {
25
+ logger,
26
+ }
27
+ );
28
+
29
+ if (
30
+ config &&
31
+ // If user specifies any FS related config,
32
+ // clear specified migrationSource to avoid ambiguity
33
+ (config.directory ||
34
+ config.sortDirsSeparately !== undefined ||
35
+ config.loadExtensions)
36
+ ) {
37
+ if (config.seedSource) {
38
+ logger.warn(
39
+ 'FS-related option specified for seed configuration. This resets seedSource to default FsMigrations'
40
+ );
41
+ }
42
+ mergedConfig.seedSource = null;
43
+ }
44
+
45
+ // If the user has not specified any configs, we need to
46
+ // default to fs migrations to maintain compatibility
47
+ if (!mergedConfig.seedSource) {
48
+ mergedConfig.seedSource = new FsSeeds(
49
+ mergedConfig.directory,
50
+ mergedConfig.sortDirsSeparately,
51
+ mergedConfig.loadExtensions
52
+ );
53
+ }
54
+
55
+ return mergedConfig;
56
+ }
57
+
58
+ module.exports = {
59
+ getMergedConfig,
60
+ };
@@ -0,0 +1,65 @@
1
+ const path = require('path');
2
+ const flatten = require('lodash/flatten');
3
+ const includes = require('lodash/includes');
4
+ const { AbstractMigrationsLoader } = require('../../common/MigrationsLoader');
5
+ const { getFilepathsInFolder } = require('../../util/fs');
6
+
7
+ const filterByLoadExtensions = (extensions) => (value) => {
8
+ const extension = path.extname(value);
9
+ return includes(extensions, extension);
10
+ };
11
+
12
+ class FsSeeds extends AbstractMigrationsLoader {
13
+ _getConfigDirectories(logger) {
14
+ const directories = this.migrationsPaths;
15
+ return directories.map((directory) => {
16
+ if (!directory) {
17
+ logger.warn(
18
+ 'Empty value passed as a directory for Seeder, this is not supported.'
19
+ );
20
+ }
21
+ return path.resolve(process.cwd(), directory);
22
+ });
23
+ }
24
+
25
+ async getSeeds(config) {
26
+ const { loadExtensions, recursive, specific } = config;
27
+
28
+ const seeds = flatten(
29
+ await Promise.all(
30
+ this._getConfigDirectories(config.logger).map((d) =>
31
+ getFilepathsInFolder(d, recursive)
32
+ )
33
+ )
34
+ );
35
+
36
+ // if true, each dir are already sorted
37
+ // (getFilepathsInFolderRecursively does this)
38
+ // if false, we need to sort all the seeds
39
+ let files = seeds.filter(filterByLoadExtensions(loadExtensions));
40
+ if (!this.sortDirsSeparately) {
41
+ files.sort();
42
+ }
43
+
44
+ if (specific) {
45
+ files = files.filter((file) => path.basename(file) === specific);
46
+ if (files.length === 0) {
47
+ throw new Error(
48
+ `Invalid argument provided: the specific seed "${specific}" does not exist.`
49
+ );
50
+ }
51
+ }
52
+
53
+ return files;
54
+ }
55
+
56
+ async getSeed(filepath) {
57
+ const importFile = require('../../util/import-file'); // late import
58
+ const seed = await importFile(filepath);
59
+ return seed;
60
+ }
61
+ }
62
+
63
+ module.exports = {
64
+ FsSeeds,
65
+ };
@@ -1,4 +1,7 @@
1
-
1
+ /**
2
+ * @param { import("knex").Knex } knex
3
+ * @returns { Promise<void> }
4
+ */
2
5
  exports.seed = function(knex) {
3
6
  // Deletes ALL existing entries
4
7
  return knex('table_name').del()
@@ -4,7 +4,6 @@ const isModuleType = require('./is-module-type');
4
4
  * imports 'mjs', else requires.
5
5
  * NOTE: require me late!
6
6
  * @param {string} filepath
7
- * @todo WARN on version 10 and '--experimental-modules' and '--esm'
8
7
  */
9
8
  module.exports = async function importFile(filepath) {
10
9
  return (await isModuleType(filepath))
@@ -70,16 +70,33 @@ class JoinClause {
70
70
  return this;
71
71
  }
72
72
 
73
- // Adds a "using" clause to the current join.
74
- using(column) {
75
- return this.clauses.push({ type: 'onUsing', column, bool: this._bool() });
76
- }
77
-
78
73
  // Adds an "or on" clause to the current join object.
79
74
  orOn(first, operator, second) {
80
75
  return this._bool('or').on.apply(this, arguments);
81
76
  }
82
77
 
78
+ onJsonPathEquals(columnFirst, jsonPathFirst, columnSecond, jsonPathSecond) {
79
+ this.clauses.push({
80
+ type: 'onJsonPathEquals',
81
+ columnFirst: columnFirst,
82
+ jsonPathFirst: jsonPathFirst,
83
+ columnSecond: columnSecond,
84
+ jsonPathSecond: jsonPathSecond,
85
+ bool: this._bool(),
86
+ not: this._not(),
87
+ });
88
+ return this;
89
+ }
90
+
91
+ orOnJsonPathEquals(columnFirst, jsonPathFirst, columnSecond, jsonPathSecond) {
92
+ return this._bool('or').onJsonPathEquals.apply(this, arguments);
93
+ }
94
+
95
+ // Adds a "using" clause to the current join.
96
+ using(column) {
97
+ return this.clauses.push({ type: 'onUsing', column, bool: this._bool() });
98
+ }
99
+
83
100
  onVal(first) {
84
101
  if (typeof first === 'object' && typeof first.toSQL !== 'function') {
85
102
  const keys = Object.keys(first);
@@ -247,5 +264,7 @@ JoinClause.prototype.andOnExists = JoinClause.prototype.onExists;
247
264
  JoinClause.prototype.andOnNotExists = JoinClause.prototype.onNotExists;
248
265
  JoinClause.prototype.andOnBetween = JoinClause.prototype.onBetween;
249
266
  JoinClause.prototype.andOnNotBetween = JoinClause.prototype.onNotBetween;
267
+ JoinClause.prototype.andOnJsonPathEquals =
268
+ JoinClause.prototype.onJsonPathEquals;
250
269
 
251
270
  module.exports = JoinClause;
@@ -9,6 +9,7 @@ module.exports = [
9
9
  'column',
10
10
  'from',
11
11
  'fromJS',
12
+ 'fromRaw',
12
13
  'into',
13
14
  'withSchema',
14
15
  'table',
@@ -24,6 +25,8 @@ module.exports = [
24
25
  'fullOuterJoin',
25
26
  'crossJoin',
26
27
  'where',
28
+ 'whereLike',
29
+ 'whereILike',
27
30
  'andWhere',
28
31
  'orWhere',
29
32
  'whereNot',
@@ -89,4 +92,38 @@ module.exports = [
89
92
  'truncate',
90
93
  'transacting',
91
94
  'connection',
95
+
96
+ // JSON methods
97
+
98
+ // Json manipulation functions
99
+ 'jsonExtract',
100
+ 'jsonSet',
101
+ 'jsonInsert',
102
+ 'jsonRemove',
103
+
104
+ // Wheres Json
105
+ 'whereJsonObject',
106
+ 'orWhereJsonObject',
107
+ 'andWhereJsonObject',
108
+ 'whereNotJsonObject',
109
+ 'orWhereNotJsonObject',
110
+ 'andWhereNotJsonObject',
111
+
112
+ 'whereJsonPath',
113
+ 'orWhereJsonPath',
114
+ 'andWhereJsonPath',
115
+
116
+ 'whereJsonSupersetOf',
117
+ 'orWhereJsonSupersetOf',
118
+ 'andWhereJsonSupersetOf',
119
+ 'whereJsonNotSupersetOf',
120
+ 'orWhereJsonNotSupersetOf',
121
+ 'andWhereJsonNotSupersetOf',
122
+
123
+ 'whereJsonSubsetOf',
124
+ 'orWhereJsonSubsetOf',
125
+ 'andWhereJsonSubsetOf',
126
+ 'whereJsonNotSubsetOf',
127
+ 'orWhereJsonNotSubsetOf',
128
+ 'andWhereJsonNotSubsetOf',
92
129
  ];