knex 2.5.0 → 3.0.0

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 (190) hide show
  1. package/CHANGELOG.md +78 -59
  2. package/CONTRIBUTING.md +194 -194
  3. package/LICENSE +22 -22
  4. package/README.md +149 -147
  5. package/UPGRADING.md +245 -233
  6. package/bin/cli.js +475 -473
  7. package/bin/utils/cli-config-utils.js +212 -210
  8. package/bin/utils/constants.js +7 -7
  9. package/bin/utils/migrationsLister.js +37 -37
  10. package/knex.js +23 -23
  11. package/knex.mjs +11 -11
  12. package/lib/builder-interface-augmenter.js +120 -120
  13. package/lib/client.js +495 -495
  14. package/lib/constants.js +61 -61
  15. package/lib/dialects/better-sqlite3/index.js +77 -77
  16. package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -14
  17. package/lib/dialects/cockroachdb/crdb-querybuilder.js +11 -11
  18. package/lib/dialects/cockroachdb/crdb-querycompiler.js +122 -122
  19. package/lib/dialects/cockroachdb/crdb-tablecompiler.js +37 -37
  20. package/lib/dialects/cockroachdb/crdb-viewcompiler.js +15 -15
  21. package/lib/dialects/cockroachdb/index.js +86 -86
  22. package/lib/dialects/mssql/index.js +500 -500
  23. package/lib/dialects/mssql/mssql-formatter.js +34 -34
  24. package/lib/dialects/mssql/query/mssql-querycompiler.js +601 -601
  25. package/lib/dialects/mssql/schema/mssql-columncompiler.js +185 -185
  26. package/lib/dialects/mssql/schema/mssql-compiler.js +91 -91
  27. package/lib/dialects/mssql/schema/mssql-tablecompiler.js +378 -378
  28. package/lib/dialects/mssql/schema/mssql-viewcompiler.js +55 -55
  29. package/lib/dialects/mssql/transaction.js +176 -176
  30. package/lib/dialects/mysql/index.js +201 -201
  31. package/lib/dialects/mysql/query/mysql-querycompiler.js +274 -274
  32. package/lib/dialects/mysql/schema/mysql-columncompiler.js +193 -193
  33. package/lib/dialects/mysql/schema/mysql-compiler.js +60 -60
  34. package/lib/dialects/mysql/schema/mysql-tablecompiler.js +381 -381
  35. package/lib/dialects/mysql/schema/mysql-viewbuilder.js +21 -21
  36. package/lib/dialects/mysql/schema/mysql-viewcompiler.js +15 -15
  37. package/lib/dialects/mysql/transaction.js +46 -46
  38. package/lib/dialects/mysql2/index.js +53 -53
  39. package/lib/dialects/mysql2/transaction.js +44 -44
  40. package/lib/dialects/oracle/DEAD_CODE.md +5 -5
  41. package/lib/dialects/oracle/index.js +92 -92
  42. package/lib/dialects/oracle/query/oracle-querycompiler.js +343 -343
  43. package/lib/dialects/oracle/schema/internal/incrementUtils.js +20 -20
  44. package/lib/dialects/oracle/schema/internal/trigger.js +135 -135
  45. package/lib/dialects/oracle/schema/oracle-columnbuilder.js +17 -17
  46. package/lib/dialects/oracle/schema/oracle-columncompiler.js +126 -126
  47. package/lib/dialects/oracle/schema/oracle-compiler.js +122 -122
  48. package/lib/dialects/oracle/schema/oracle-tablecompiler.js +190 -190
  49. package/lib/dialects/oracle/utils.js +87 -87
  50. package/lib/dialects/oracledb/index.js +327 -327
  51. package/lib/dialects/oracledb/query/oracledb-querycompiler.js +481 -481
  52. package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +61 -61
  53. package/lib/dialects/oracledb/schema/oracledb-tablecompiler.js +19 -19
  54. package/lib/dialects/oracledb/schema/oracledb-viewbuilder.js +13 -13
  55. package/lib/dialects/oracledb/schema/oracledb-viewcompiler.js +19 -19
  56. package/lib/dialects/oracledb/transaction.js +98 -98
  57. package/lib/dialects/oracledb/utils.js +208 -208
  58. package/lib/dialects/pgnative/index.js +60 -60
  59. package/lib/dialects/postgres/execution/pg-transaction.js +19 -19
  60. package/lib/dialects/postgres/index.js +358 -358
  61. package/lib/dialects/postgres/query/pg-querybuilder.js +43 -43
  62. package/lib/dialects/postgres/query/pg-querycompiler.js +400 -400
  63. package/lib/dialects/postgres/schema/pg-columncompiler.js +156 -156
  64. package/lib/dialects/postgres/schema/pg-compiler.js +138 -138
  65. package/lib/dialects/postgres/schema/pg-tablecompiler.js +304 -304
  66. package/lib/dialects/postgres/schema/pg-viewbuilder.js +21 -21
  67. package/lib/dialects/postgres/schema/pg-viewcompiler.js +35 -35
  68. package/lib/dialects/redshift/index.js +86 -86
  69. package/lib/dialects/redshift/query/redshift-querycompiler.js +163 -163
  70. package/lib/dialects/redshift/schema/redshift-columnbuilder.js +22 -22
  71. package/lib/dialects/redshift/schema/redshift-columncompiler.js +67 -67
  72. package/lib/dialects/redshift/schema/redshift-compiler.js +14 -14
  73. package/lib/dialects/redshift/schema/redshift-tablecompiler.js +122 -122
  74. package/lib/dialects/redshift/schema/redshift-viewcompiler.js +11 -11
  75. package/lib/dialects/redshift/transaction.js +32 -32
  76. package/lib/dialects/sqlite3/execution/sqlite-transaction.js +25 -25
  77. package/lib/dialects/sqlite3/index.js +250 -250
  78. package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -33
  79. package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +334 -334
  80. package/lib/dialects/sqlite3/schema/ddl.js +400 -400
  81. package/lib/dialects/sqlite3/schema/internal/compiler.js +327 -327
  82. package/lib/dialects/sqlite3/schema/internal/parser-combinator.js +161 -161
  83. package/lib/dialects/sqlite3/schema/internal/parser.js +638 -638
  84. package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +41 -41
  85. package/lib/dialects/sqlite3/schema/internal/tokenizer.js +38 -38
  86. package/lib/dialects/sqlite3/schema/internal/utils.js +12 -12
  87. package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +50 -50
  88. package/lib/dialects/sqlite3/schema/sqlite-compiler.js +80 -80
  89. package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +347 -347
  90. package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +40 -40
  91. package/lib/execution/batch-insert.js +51 -51
  92. package/lib/execution/internal/delay.js +6 -6
  93. package/lib/execution/internal/ensure-connection-callback.js +41 -41
  94. package/lib/execution/internal/query-executioner.js +62 -62
  95. package/lib/execution/runner.js +325 -325
  96. package/lib/execution/transaction.js +409 -409
  97. package/lib/formatter/formatterUtils.js +42 -42
  98. package/lib/formatter/rawFormatter.js +84 -84
  99. package/lib/formatter/wrappingFormatter.js +250 -250
  100. package/lib/formatter.js +25 -25
  101. package/lib/index.js +3 -3
  102. package/lib/knex-builder/FunctionHelper.js +80 -80
  103. package/lib/knex-builder/Knex.js +59 -59
  104. package/lib/knex-builder/internal/config-resolver.js +57 -57
  105. package/lib/knex-builder/internal/parse-connection.js +87 -87
  106. package/lib/knex-builder/make-knex.js +345 -345
  107. package/lib/logger.js +76 -76
  108. package/lib/migrations/common/MigrationsLoader.js +36 -36
  109. package/lib/migrations/migrate/MigrationGenerator.js +84 -84
  110. package/lib/migrations/migrate/Migrator.js +599 -598
  111. package/lib/migrations/migrate/migrate-stub.js +17 -17
  112. package/lib/migrations/migrate/migration-list-resolver.js +33 -33
  113. package/lib/migrations/migrate/migrator-configuration-merger.js +58 -58
  114. package/lib/migrations/migrate/sources/fs-migrations.js +74 -74
  115. package/lib/migrations/migrate/stub/cjs.stub +15 -15
  116. package/lib/migrations/migrate/stub/coffee.stub +13 -13
  117. package/lib/migrations/migrate/stub/eg.stub +14 -14
  118. package/lib/migrations/migrate/stub/js-schema.stub +22 -22
  119. package/lib/migrations/migrate/stub/js.stub +22 -22
  120. package/lib/migrations/migrate/stub/knexfile-coffee.stub +34 -34
  121. package/lib/migrations/migrate/stub/knexfile-eg.stub +43 -43
  122. package/lib/migrations/migrate/stub/knexfile-js.stub +47 -47
  123. package/lib/migrations/migrate/stub/knexfile-ls.stub +35 -35
  124. package/lib/migrations/migrate/stub/knexfile-ts.stub +47 -47
  125. package/lib/migrations/migrate/stub/ls.stub +14 -14
  126. package/lib/migrations/migrate/stub/mjs.stub +23 -23
  127. package/lib/migrations/migrate/stub/ts-schema.stub +21 -21
  128. package/lib/migrations/migrate/stub/ts.stub +21 -21
  129. package/lib/migrations/migrate/table-creator.js +77 -77
  130. package/lib/migrations/migrate/table-resolver.js +27 -27
  131. package/lib/migrations/seed/Seeder.js +137 -137
  132. package/lib/migrations/seed/seed-stub.js +13 -13
  133. package/lib/migrations/seed/seeder-configuration-merger.js +60 -60
  134. package/lib/migrations/seed/sources/fs-seeds.js +65 -65
  135. package/lib/migrations/seed/stub/coffee.stub +9 -9
  136. package/lib/migrations/seed/stub/eg.stub +11 -11
  137. package/lib/migrations/seed/stub/js.stub +13 -13
  138. package/lib/migrations/seed/stub/ls.stub +11 -11
  139. package/lib/migrations/seed/stub/mjs.stub +12 -12
  140. package/lib/migrations/seed/stub/ts.stub +13 -13
  141. package/lib/migrations/util/fs.js +86 -86
  142. package/lib/migrations/util/import-file.js +12 -12
  143. package/lib/migrations/util/is-module-type.js +9 -9
  144. package/lib/migrations/util/template.js +52 -52
  145. package/lib/migrations/util/timestamp.js +14 -14
  146. package/lib/query/analytic.js +52 -52
  147. package/lib/query/constants.js +15 -15
  148. package/lib/query/joinclause.js +270 -270
  149. package/lib/query/method-constants.js +136 -136
  150. package/lib/query/querybuilder.js +1793 -1793
  151. package/lib/query/querycompiler.js +1591 -1591
  152. package/lib/raw.js +139 -139
  153. package/lib/ref.js +39 -39
  154. package/lib/schema/builder.js +115 -115
  155. package/lib/schema/columnbuilder.js +146 -146
  156. package/lib/schema/columncompiler.js +307 -307
  157. package/lib/schema/compiler.js +187 -187
  158. package/lib/schema/internal/helpers.js +55 -55
  159. package/lib/schema/tablebuilder.js +376 -376
  160. package/lib/schema/tablecompiler.js +433 -433
  161. package/lib/schema/viewbuilder.js +92 -92
  162. package/lib/schema/viewcompiler.js +138 -138
  163. package/lib/util/finally-mixin.js +13 -13
  164. package/lib/util/helpers.js +95 -95
  165. package/lib/util/is.js +32 -32
  166. package/lib/util/nanoid.js +40 -40
  167. package/lib/util/noop.js +1 -1
  168. package/lib/util/save-async-stack.js +14 -14
  169. package/lib/util/security.js +26 -26
  170. package/lib/util/string.js +190 -190
  171. package/lib/util/timeout.js +29 -29
  172. package/package.json +13 -12
  173. package/scripts/build.js +125 -125
  174. package/scripts/clean.js +31 -31
  175. package/scripts/docker-compose.yml +152 -152
  176. package/scripts/next-release-howto.md +24 -24
  177. package/scripts/oracledb-install-driver-libs.sh +82 -82
  178. package/scripts/release.sh +36 -34
  179. package/scripts/runkit-example.js +35 -34
  180. package/scripts/stress-test/README.txt +18 -18
  181. package/scripts/stress-test/docker-compose.yml +57 -57
  182. package/scripts/stress-test/knex-stress-test.js +212 -208
  183. package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +149 -145
  184. package/scripts/stress-test/mysql2-sudden-exit-without-error.js +101 -100
  185. package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +188 -184
  186. package/scripts/update_gitignore_for_tsc_output.js +90 -90
  187. package/types/index.d.ts +3272 -3273
  188. package/types/result.d.ts +27 -27
  189. package/types/tables.d.ts +4 -4
  190. package/lib/dialects/index.js +0 -34
package/bin/cli.js CHANGED
@@ -1,473 +1,475 @@
1
- #!/usr/bin/env node
2
- const rechoir = require('rechoir');
3
- const merge = require('lodash/merge');
4
- const interpret = require('interpret');
5
- const resolveFrom = require('resolve-from');
6
- const path = require('path');
7
- const tildify = require('tildify');
8
- const commander = require('commander');
9
- const color = require('colorette');
10
- const argv = require('getopts')(process.argv.slice(2));
11
- const cliPkg = require('../package');
12
- const {
13
- parseConfigObj,
14
- mkConfigObj,
15
- resolveEnvironmentConfig,
16
- exit,
17
- success,
18
- checkLocalModule,
19
- checkConfigurationOptions,
20
- getMigrationExtension,
21
- getSeedExtension,
22
- getStubPath,
23
- findUpModulePath,
24
- findUpConfig,
25
- } = require('./utils/cli-config-utils');
26
- const {
27
- existsSync,
28
- readFile,
29
- writeFile,
30
- } = require('../lib/migrations/util/fs');
31
-
32
- const { listMigrations } = require('./utils/migrationsLister');
33
-
34
- async function openKnexfile(configPath) {
35
- const importFile = require('../lib/migrations/util/import-file'); // require me late!
36
- let config = await importFile(configPath);
37
- if (config && config.default) {
38
- config = config.default;
39
- }
40
- if (typeof config === 'function') {
41
- config = await config();
42
- }
43
- return config;
44
- }
45
-
46
- async function initKnex(env, opts, useDefaultClientIfNotSpecified) {
47
- checkLocalModule(env);
48
- if (process.cwd() !== env.cwd) {
49
- process.chdir(env.cwd);
50
- console.log(
51
- 'Working directory changed to',
52
- color.magenta(tildify(env.cwd))
53
- );
54
- }
55
-
56
- if (!useDefaultClientIfNotSpecified) {
57
- checkConfigurationOptions(env, opts);
58
- }
59
-
60
- env.configuration = env.configPath
61
- ? await openKnexfile(env.configPath)
62
- : mkConfigObj(opts);
63
-
64
- const resolvedConfig = resolveEnvironmentConfig(
65
- opts,
66
- env.configuration,
67
- env.configPath
68
- );
69
-
70
- const optionsConfig = parseConfigObj(opts);
71
- const config = merge(resolvedConfig, optionsConfig);
72
-
73
- // Migrations directory gets defaulted if it is undefined.
74
- if (!env.configPath && !config.migrations.directory) {
75
- config.migrations.directory = null;
76
- }
77
-
78
- // Client gets defaulted if undefined and it's allowed
79
- if (useDefaultClientIfNotSpecified && config.client === undefined) {
80
- config.client = 'sqlite3';
81
- }
82
-
83
- const knex = require(env.modulePath);
84
- return knex(config);
85
- }
86
-
87
- function invoke() {
88
- const filetypes = ['js', 'mjs', 'coffee', 'ts', 'eg', 'ls'];
89
-
90
- const cwd = argv.knexfile
91
- ? path.dirname(path.resolve(argv.knexfile))
92
- : process.cwd();
93
-
94
- // TODO add knexpath here eventually
95
- const modulePath =
96
- resolveFrom.silent(cwd, 'knex') ||
97
- findUpModulePath(cwd, 'knex') ||
98
- process.env.KNEX_PATH;
99
-
100
- const configPath =
101
- argv.knexfile && existsSync(argv.knexfile)
102
- ? path.resolve(argv.knexfile)
103
- : findUpConfig(cwd, 'knexfile', filetypes);
104
-
105
- if (configPath) {
106
- const autoloads = rechoir.prepare(
107
- interpret.jsVariants,
108
- configPath,
109
- cwd,
110
- true
111
- );
112
- if (autoloads instanceof Error) {
113
- // Only errors
114
- autoloads.failures.forEach(function (failed) {
115
- console.log(
116
- color.red('Failed to load external module'),
117
- color.magenta(failed.moduleName)
118
- );
119
- });
120
- } else if (Array.isArray(autoloads)) {
121
- const succeeded = autoloads[autoloads.length - 1];
122
- console.log(
123
- 'Requiring external module',
124
- color.magenta(succeeded.moduleName)
125
- );
126
- }
127
- }
128
-
129
- const env = {
130
- cwd,
131
- modulePath,
132
- configPath,
133
- configuration: null,
134
- };
135
-
136
- let modulePackage = {};
137
- try {
138
- modulePackage = require(path.join(
139
- path.dirname(env.modulePath),
140
- 'package.json'
141
- ));
142
- } catch (e) {}
143
-
144
- const cliVersion = [
145
- color.blue('Knex CLI version:'),
146
- color.green(cliPkg.version),
147
- ].join(' ');
148
-
149
- const localVersion = [
150
- color.blue('Knex Local version:'),
151
- color.green(modulePackage.version || 'None'),
152
- ].join(' ');
153
-
154
- commander
155
- .version(`${cliVersion}\n${localVersion}`)
156
- .option('--debug', 'Run with debugging.')
157
- .option('--knexfile [path]', 'Specify the knexfile path.')
158
- .option('--knexpath [path]', 'Specify the path to knex instance.')
159
- .option('--cwd [path]', 'Specify the working directory.')
160
- .option('--client [name]', 'Set DB client.')
161
- .option('--connection [address]', 'Set DB connection.')
162
- .option('--migrations-directory [path]', 'Set migrations directory.')
163
- .option('--migrations-table-name [path]', 'Set migrations table name.')
164
- .option(
165
- '--env [name]',
166
- 'environment, default: process.env.NODE_ENV || development'
167
- )
168
- .option('--esm', 'Enable ESM interop.')
169
- .option('--specific [path]', 'Specify one seed file to execute.')
170
- .option(
171
- '--timestamp-filename-prefix',
172
- 'Enable a timestamp prefix on name of generated seed files.'
173
- );
174
-
175
- commander
176
- .command('init')
177
- .description(' Create a fresh knexfile.')
178
- .option(
179
- `-x [${filetypes.join('|')}]`,
180
- 'Specify the knexfile extension (default js)'
181
- )
182
- .action(() => {
183
- const type = (argv.x || 'js').toLowerCase();
184
- if (filetypes.indexOf(type) === -1) {
185
- exit(`Invalid filetype specified: ${type}`);
186
- }
187
- if (env.configuration) {
188
- exit(`Error: ${env.knexfile} already exists`);
189
- }
190
- checkLocalModule(env);
191
- const stubPath = `./knexfile.${type}`;
192
- readFile(
193
- path.dirname(env.modulePath) +
194
- '/lib/migrations/migrate/stub/knexfile-' +
195
- type +
196
- '.stub'
197
- )
198
- .then((code) => {
199
- return writeFile(stubPath, code);
200
- })
201
- .then(() => {
202
- success(color.green(`Created ${stubPath}`));
203
- })
204
- .catch(exit);
205
- });
206
-
207
- commander
208
- .command('migrate:make <name>')
209
- .description(' Create a named migration file.')
210
- .option(
211
- `-x [${filetypes.join('|')}]`,
212
- 'Specify the stub extension (default js)'
213
- )
214
- .option(
215
- `--stub [<relative/path/from/knexfile>|<name>]`,
216
- 'Specify the migration stub to use. If using <name> the file must be located in config.migrations.directory'
217
- )
218
- .action(async (name) => {
219
- try {
220
- const opts = commander.opts();
221
- const instance = await initKnex(env, opts, true); // Skip config check, we don't really care about client when creating migrations
222
- const ext = getMigrationExtension(env, opts);
223
- const configOverrides = { extension: ext };
224
-
225
- const stub = getStubPath('migrations', env, opts);
226
- if (stub) {
227
- configOverrides.stub = stub;
228
- }
229
-
230
- instance.migrate
231
- .make(name, configOverrides)
232
- .then((name) => {
233
- success(color.green(`Created Migration: ${name}`));
234
- })
235
- .catch(exit);
236
- } catch (err) {
237
- exit(err);
238
- }
239
- });
240
-
241
- commander
242
- .command('migrate:latest')
243
- .description(' Run all migrations that have not yet been run.')
244
- .option('--verbose', 'verbose')
245
- .action(async () => {
246
- try {
247
- const instance = await initKnex(env, commander.opts());
248
- const [batchNo, log] = await instance.migrate.latest();
249
- if (log.length === 0) {
250
- success(color.cyan('Already up to date'));
251
- }
252
- success(
253
- color.green(`Batch ${batchNo} run: ${log.length} migrations`) +
254
- (argv.verbose ? `\n${color.cyan(log.join('\n'))}` : '')
255
- );
256
- } catch (err) {
257
- exit(err);
258
- }
259
- });
260
-
261
- commander
262
- .command('migrate:up [<name>]')
263
- .description(
264
- ' Run the next or the specified migration that has not yet been run.'
265
- )
266
- .action((name) => {
267
- initKnex(env, commander.opts())
268
- .then((instance) => instance.migrate.up({ name }))
269
- .then(([batchNo, log]) => {
270
- if (log.length === 0) {
271
- success(color.cyan('Already up to date'));
272
- }
273
-
274
- success(
275
- color.green(
276
- `Batch ${batchNo} ran the following migrations:\n${log.join(
277
- '\n'
278
- )}`
279
- )
280
- );
281
- })
282
- .catch(exit);
283
- });
284
-
285
- commander
286
- .command('migrate:rollback')
287
- .description(' Rollback the last batch of migrations performed.')
288
- .option('--all', 'rollback all completed migrations')
289
- .option('--verbose', 'verbose')
290
- .action((cmd) => {
291
- const { all } = cmd;
292
-
293
- initKnex(env, commander.opts())
294
- .then((instance) => instance.migrate.rollback(null, all))
295
- .then(([batchNo, log]) => {
296
- if (log.length === 0) {
297
- success(color.cyan('Already at the base migration'));
298
- }
299
- success(
300
- color.green(
301
- `Batch ${batchNo} rolled back: ${log.length} migrations`
302
- ) + (argv.verbose ? `\n${color.cyan(log.join('\n'))}` : '')
303
- );
304
- })
305
- .catch(exit);
306
- });
307
-
308
- commander
309
- .command('migrate:down [<name>]')
310
- .description(
311
- ' Undo the last or the specified migration that was already run.'
312
- )
313
- .action((name) => {
314
- initKnex(env, commander.opts())
315
- .then((instance) => instance.migrate.down({ name }))
316
- .then(([batchNo, log]) => {
317
- if (log.length === 0) {
318
- success(color.cyan('Already at the base migration'));
319
- }
320
- success(
321
- color.green(
322
- `Batch ${batchNo} rolled back the following migrations:\n${log.join(
323
- '\n'
324
- )}`
325
- )
326
- );
327
- })
328
- .catch(exit);
329
- });
330
-
331
- commander
332
- .command('migrate:currentVersion')
333
- .description(' View the current version for the migration.')
334
- .action(() => {
335
- initKnex(env, commander.opts())
336
- .then((instance) => instance.migrate.currentVersion())
337
- .then((version) => {
338
- success(color.green('Current Version: ') + color.blue(version));
339
- })
340
- .catch(exit);
341
- });
342
-
343
- commander
344
- .command('migrate:list')
345
- .alias('migrate:status')
346
- .description(' List all migrations files with status.')
347
- .action(() => {
348
- initKnex(env, commander.opts())
349
- .then((instance) => {
350
- return instance.migrate.list();
351
- })
352
- .then(([completed, newMigrations]) => {
353
- listMigrations(completed, newMigrations);
354
- })
355
- .catch(exit);
356
- });
357
-
358
- commander
359
- .command('migrate:unlock')
360
- .description(' Forcibly unlocks the migrations lock table.')
361
- .action(() => {
362
- initKnex(env, commander.opts())
363
- .then((instance) => instance.migrate.forceFreeMigrationsLock())
364
- .then(() => {
365
- success(
366
- color.green(`Succesfully unlocked the migrations lock table`)
367
- );
368
- })
369
- .catch(exit);
370
- });
371
-
372
- commander
373
- .command('seed:make <name>')
374
- .description(' Create a named seed file.')
375
- .option(
376
- `-x [${filetypes.join('|')}]`,
377
- 'Specify the stub extension (default js)'
378
- )
379
- .option(
380
- `--stub [<relative/path/from/knexfile>|<name>]`,
381
- 'Specify the seed stub to use. If using <name> the file must be located in config.seeds.directory'
382
- )
383
- .option(
384
- '--timestamp-filename-prefix',
385
- 'Enable a timestamp prefix on name of generated seed files.',
386
- false
387
- )
388
- .action(async (name) => {
389
- try {
390
- const opts = commander.opts();
391
- const instance = await initKnex(env, opts, true); // Skip config check, we don't really care about client when creating seeds
392
- const ext = getSeedExtension(env, opts);
393
- const configOverrides = { extension: ext };
394
- const stub = getStubPath('seeds', env, opts);
395
- if (stub) {
396
- configOverrides.stub = stub;
397
- }
398
-
399
- if (opts.timestampFilenamePrefix) {
400
- configOverrides.timestampFilenamePrefix =
401
- opts.timestampFilenamePrefix;
402
- }
403
-
404
- instance.seed
405
- .make(name, configOverrides)
406
- .then((name) => {
407
- success(color.green(`Created seed file: ${name}`));
408
- })
409
- .catch(exit);
410
- } catch (err) {
411
- exit(err);
412
- }
413
- });
414
-
415
- commander
416
- .command('seed:run')
417
- .description(' Run seed files.')
418
- .option('--verbose', 'verbose')
419
- .option('--specific', 'run specific seed file')
420
- .action(() => {
421
- initKnex(env, commander.opts())
422
- .then((instance) => instance.seed.run({ specific: argv.specific }))
423
- .then(([log]) => {
424
- if (log.length === 0) {
425
- success(color.cyan('No seed files exist'));
426
- }
427
- success(
428
- color.green(`Ran ${log.length} seed files`) +
429
- (argv.verbose ? `\n${color.cyan(log.join('\n'))}` : '')
430
- );
431
- })
432
- .catch(exit);
433
- });
434
-
435
- commander.parse(process.argv);
436
- }
437
-
438
- // FYI: The handling for the `--cwd` and `--knexfile` arguments is a bit strange,
439
- // but we decided to retain the behavior for backwards-compatibility. In
440
- // particular: if `--knexfile` is a relative path, then it will be resolved
441
- // relative to `--cwd` instead of the shell's CWD.
442
- //
443
- // So, the easiest way to replicate this behavior is to have the CLI change
444
- // its CWD to `--cwd` immediately before initializing everything else. This
445
- // ensures that path.resolve will then resolve the path to `--knexfile` correctly.
446
- if (argv.cwd) {
447
- process.chdir(argv.cwd);
448
- }
449
- // Initialize 'esm' before cli.launch
450
- if (argv.esm) {
451
- // enable esm interop via 'esm' module
452
- // eslint-disable-next-line no-global-assign
453
- require = require('esm')(module);
454
- // https://github.com/standard-things/esm/issues/868
455
- const ext = require.extensions['.js'];
456
- require.extensions['.js'] = (m, fileName) => {
457
- try {
458
- // default to the original extension
459
- // this fails if target file parent is of type='module'
460
- return ext(m, fileName);
461
- } catch (err) {
462
- if (err && err.code === 'ERR_REQUIRE_ESM') {
463
- return m._compile(
464
- require('fs').readFileSync(fileName, 'utf8'),
465
- fileName
466
- );
467
- }
468
- throw err;
469
- }
470
- };
471
- }
472
-
473
- invoke();
1
+ #!/usr/bin/env node
2
+ const rechoir = require('rechoir');
3
+ const merge = require('lodash/merge');
4
+ const interpret = require('interpret');
5
+ const resolveFrom = require('resolve-from');
6
+ const path = require('path');
7
+ const tildify = require('tildify');
8
+ const commander = require('commander');
9
+ const color = require('colorette');
10
+ const argv = require('getopts')(process.argv.slice(2));
11
+ const cliPkg = require('../package');
12
+ const {
13
+ parseConfigObj,
14
+ mkConfigObj,
15
+ resolveEnvironmentConfig,
16
+ exit,
17
+ success,
18
+ checkLocalModule,
19
+ checkConfigurationOptions,
20
+ getMigrationExtension,
21
+ getSeedExtension,
22
+ getStubPath,
23
+ findUpModulePath,
24
+ findUpConfig,
25
+ } = require('./utils/cli-config-utils');
26
+ const {
27
+ existsSync,
28
+ readFile,
29
+ writeFile,
30
+ } = require('../lib/migrations/util/fs');
31
+
32
+ const { listMigrations } = require('./utils/migrationsLister');
33
+
34
+ async function openKnexfile(configPath) {
35
+ const importFile = require('../lib/migrations/util/import-file'); // require me late!
36
+ let config = await importFile(configPath);
37
+ if (config && config.default) {
38
+ config = config.default;
39
+ }
40
+ if (typeof config === 'function') {
41
+ config = await config();
42
+ }
43
+ return config;
44
+ }
45
+
46
+ async function initKnex(env, opts, useDefaultClientIfNotSpecified) {
47
+ checkLocalModule(env);
48
+ if (process.cwd() !== env.cwd) {
49
+ process.chdir(env.cwd);
50
+ console.log(
51
+ 'Working directory changed to',
52
+ color.magenta(tildify(env.cwd))
53
+ );
54
+ }
55
+
56
+ if (!useDefaultClientIfNotSpecified) {
57
+ checkConfigurationOptions(env, opts);
58
+ }
59
+
60
+ env.configuration = env.configPath
61
+ ? await openKnexfile(env.configPath)
62
+ : mkConfigObj(opts);
63
+
64
+ const resolvedConfig = resolveEnvironmentConfig(
65
+ opts,
66
+ env.configuration,
67
+ env.configPath
68
+ );
69
+
70
+ const optionsConfig = parseConfigObj(opts);
71
+ const config = merge(resolvedConfig, optionsConfig);
72
+
73
+ // Migrations directory gets defaulted if it is undefined.
74
+ if (!env.configPath && !config.migrations.directory) {
75
+ config.migrations.directory = null;
76
+ }
77
+
78
+ // Client gets defaulted if undefined and it's allowed
79
+ if (useDefaultClientIfNotSpecified && config.client === undefined) {
80
+ config.client = 'sqlite3';
81
+ }
82
+
83
+ const knex = require(env.modulePath);
84
+ return knex(config);
85
+ }
86
+
87
+ function invoke() {
88
+ const filetypes = ['js', 'mjs', 'coffee', 'ts', 'eg', 'ls'];
89
+
90
+ const cwd = argv.knexfile
91
+ ? path.dirname(path.resolve(argv.knexfile))
92
+ : process.cwd();
93
+
94
+ // TODO add knexpath here eventually
95
+ const modulePath =
96
+ resolveFrom.silent(cwd, 'knex') ||
97
+ findUpModulePath(cwd, 'knex') ||
98
+ process.env.KNEX_PATH;
99
+
100
+ const configPath =
101
+ argv.knexfile && existsSync(argv.knexfile)
102
+ ? path.resolve(argv.knexfile)
103
+ : findUpConfig(cwd, 'knexfile', filetypes);
104
+
105
+ if (configPath) {
106
+ const autoloads = rechoir.prepare(
107
+ interpret.jsVariants,
108
+ configPath,
109
+ cwd,
110
+ true
111
+ );
112
+ if (autoloads instanceof Error) {
113
+ // Only errors
114
+ autoloads.failures.forEach(function (failed) {
115
+ console.log(
116
+ color.red('Failed to load external module'),
117
+ color.magenta(failed.moduleName)
118
+ );
119
+ });
120
+ } else if (Array.isArray(autoloads)) {
121
+ const succeeded = autoloads[autoloads.length - 1];
122
+ console.log(
123
+ 'Requiring external module',
124
+ color.magenta(succeeded.moduleName)
125
+ );
126
+ }
127
+ }
128
+
129
+ const env = {
130
+ cwd,
131
+ modulePath,
132
+ configPath,
133
+ configuration: null,
134
+ };
135
+
136
+ let modulePackage = {};
137
+ try {
138
+ modulePackage = require(path.join(
139
+ path.dirname(env.modulePath),
140
+ 'package.json'
141
+ ));
142
+ } catch (e) {
143
+ /* empty */
144
+ }
145
+
146
+ const cliVersion = [
147
+ color.blue('Knex CLI version:'),
148
+ color.green(cliPkg.version),
149
+ ].join(' ');
150
+
151
+ const localVersion = [
152
+ color.blue('Knex Local version:'),
153
+ color.green(modulePackage.version || 'None'),
154
+ ].join(' ');
155
+
156
+ commander
157
+ .version(`${cliVersion}\n${localVersion}`)
158
+ .option('--debug', 'Run with debugging.')
159
+ .option('--knexfile [path]', 'Specify the knexfile path.')
160
+ .option('--knexpath [path]', 'Specify the path to knex instance.')
161
+ .option('--cwd [path]', 'Specify the working directory.')
162
+ .option('--client [name]', 'Set DB client.')
163
+ .option('--connection [address]', 'Set DB connection.')
164
+ .option('--migrations-directory [path]', 'Set migrations directory.')
165
+ .option('--migrations-table-name [path]', 'Set migrations table name.')
166
+ .option(
167
+ '--env [name]',
168
+ 'environment, default: process.env.NODE_ENV || development'
169
+ )
170
+ .option('--esm', 'Enable ESM interop.')
171
+ .option('--specific [path]', 'Specify one seed file to execute.')
172
+ .option(
173
+ '--timestamp-filename-prefix',
174
+ 'Enable a timestamp prefix on name of generated seed files.'
175
+ );
176
+
177
+ commander
178
+ .command('init')
179
+ .description(' Create a fresh knexfile.')
180
+ .option(
181
+ `-x [${filetypes.join('|')}]`,
182
+ 'Specify the knexfile extension (default js)'
183
+ )
184
+ .action(() => {
185
+ const type = (argv.x || 'js').toLowerCase();
186
+ if (filetypes.indexOf(type) === -1) {
187
+ exit(`Invalid filetype specified: ${type}`);
188
+ }
189
+ if (env.configuration) {
190
+ exit(`Error: ${env.knexfile} already exists`);
191
+ }
192
+ checkLocalModule(env);
193
+ const stubPath = `./knexfile.${type}`;
194
+ readFile(
195
+ path.dirname(env.modulePath) +
196
+ '/lib/migrations/migrate/stub/knexfile-' +
197
+ type +
198
+ '.stub'
199
+ )
200
+ .then((code) => {
201
+ return writeFile(stubPath, code);
202
+ })
203
+ .then(() => {
204
+ success(color.green(`Created ${stubPath}`));
205
+ })
206
+ .catch(exit);
207
+ });
208
+
209
+ commander
210
+ .command('migrate:make <name>')
211
+ .description(' Create a named migration file.')
212
+ .option(
213
+ `-x [${filetypes.join('|')}]`,
214
+ 'Specify the stub extension (default js)'
215
+ )
216
+ .option(
217
+ `--stub [<relative/path/from/knexfile>|<name>]`,
218
+ 'Specify the migration stub to use. If using <name> the file must be located in config.migrations.directory'
219
+ )
220
+ .action(async (name) => {
221
+ try {
222
+ const opts = commander.opts();
223
+ const instance = await initKnex(env, opts, true); // Skip config check, we don't really care about client when creating migrations
224
+ const ext = getMigrationExtension(env, opts);
225
+ const configOverrides = { extension: ext };
226
+
227
+ const stub = getStubPath('migrations', env, opts);
228
+ if (stub) {
229
+ configOverrides.stub = stub;
230
+ }
231
+
232
+ instance.migrate
233
+ .make(name, configOverrides)
234
+ .then((name) => {
235
+ success(color.green(`Created Migration: ${name}`));
236
+ })
237
+ .catch(exit);
238
+ } catch (err) {
239
+ exit(err);
240
+ }
241
+ });
242
+
243
+ commander
244
+ .command('migrate:latest')
245
+ .description(' Run all migrations that have not yet been run.')
246
+ .option('--verbose', 'verbose')
247
+ .action(async () => {
248
+ try {
249
+ const instance = await initKnex(env, commander.opts());
250
+ const [batchNo, log] = await instance.migrate.latest();
251
+ if (log.length === 0) {
252
+ success(color.cyan('Already up to date'));
253
+ }
254
+ success(
255
+ color.green(`Batch ${batchNo} run: ${log.length} migrations`) +
256
+ (argv.verbose ? `\n${color.cyan(log.join('\n'))}` : '')
257
+ );
258
+ } catch (err) {
259
+ exit(err);
260
+ }
261
+ });
262
+
263
+ commander
264
+ .command('migrate:up [<name>]')
265
+ .description(
266
+ ' Run the next or the specified migration that has not yet been run.'
267
+ )
268
+ .action((name) => {
269
+ initKnex(env, commander.opts())
270
+ .then((instance) => instance.migrate.up({ name }))
271
+ .then(([batchNo, log]) => {
272
+ if (log.length === 0) {
273
+ success(color.cyan('Already up to date'));
274
+ }
275
+
276
+ success(
277
+ color.green(
278
+ `Batch ${batchNo} ran the following migrations:\n${log.join(
279
+ '\n'
280
+ )}`
281
+ )
282
+ );
283
+ })
284
+ .catch(exit);
285
+ });
286
+
287
+ commander
288
+ .command('migrate:rollback')
289
+ .description(' Rollback the last batch of migrations performed.')
290
+ .option('--all', 'rollback all completed migrations')
291
+ .option('--verbose', 'verbose')
292
+ .action((cmd) => {
293
+ const { all } = cmd;
294
+
295
+ initKnex(env, commander.opts())
296
+ .then((instance) => instance.migrate.rollback(null, all))
297
+ .then(([batchNo, log]) => {
298
+ if (log.length === 0) {
299
+ success(color.cyan('Already at the base migration'));
300
+ }
301
+ success(
302
+ color.green(
303
+ `Batch ${batchNo} rolled back: ${log.length} migrations`
304
+ ) + (argv.verbose ? `\n${color.cyan(log.join('\n'))}` : '')
305
+ );
306
+ })
307
+ .catch(exit);
308
+ });
309
+
310
+ commander
311
+ .command('migrate:down [<name>]')
312
+ .description(
313
+ ' Undo the last or the specified migration that was already run.'
314
+ )
315
+ .action((name) => {
316
+ initKnex(env, commander.opts())
317
+ .then((instance) => instance.migrate.down({ name }))
318
+ .then(([batchNo, log]) => {
319
+ if (log.length === 0) {
320
+ success(color.cyan('Already at the base migration'));
321
+ }
322
+ success(
323
+ color.green(
324
+ `Batch ${batchNo} rolled back the following migrations:\n${log.join(
325
+ '\n'
326
+ )}`
327
+ )
328
+ );
329
+ })
330
+ .catch(exit);
331
+ });
332
+
333
+ commander
334
+ .command('migrate:currentVersion')
335
+ .description(' View the current version for the migration.')
336
+ .action(() => {
337
+ initKnex(env, commander.opts())
338
+ .then((instance) => instance.migrate.currentVersion())
339
+ .then((version) => {
340
+ success(color.green('Current Version: ') + color.blue(version));
341
+ })
342
+ .catch(exit);
343
+ });
344
+
345
+ commander
346
+ .command('migrate:list')
347
+ .alias('migrate:status')
348
+ .description(' List all migrations files with status.')
349
+ .action(() => {
350
+ initKnex(env, commander.opts())
351
+ .then((instance) => {
352
+ return instance.migrate.list();
353
+ })
354
+ .then(([completed, newMigrations]) => {
355
+ listMigrations(completed, newMigrations);
356
+ })
357
+ .catch(exit);
358
+ });
359
+
360
+ commander
361
+ .command('migrate:unlock')
362
+ .description(' Forcibly unlocks the migrations lock table.')
363
+ .action(() => {
364
+ initKnex(env, commander.opts())
365
+ .then((instance) => instance.migrate.forceFreeMigrationsLock())
366
+ .then(() => {
367
+ success(
368
+ color.green(`Succesfully unlocked the migrations lock table`)
369
+ );
370
+ })
371
+ .catch(exit);
372
+ });
373
+
374
+ commander
375
+ .command('seed:make <name>')
376
+ .description(' Create a named seed file.')
377
+ .option(
378
+ `-x [${filetypes.join('|')}]`,
379
+ 'Specify the stub extension (default js)'
380
+ )
381
+ .option(
382
+ `--stub [<relative/path/from/knexfile>|<name>]`,
383
+ 'Specify the seed stub to use. If using <name> the file must be located in config.seeds.directory'
384
+ )
385
+ .option(
386
+ '--timestamp-filename-prefix',
387
+ 'Enable a timestamp prefix on name of generated seed files.',
388
+ false
389
+ )
390
+ .action(async (name) => {
391
+ try {
392
+ const opts = commander.opts();
393
+ const instance = await initKnex(env, opts, true); // Skip config check, we don't really care about client when creating seeds
394
+ const ext = getSeedExtension(env, opts);
395
+ const configOverrides = { extension: ext };
396
+ const stub = getStubPath('seeds', env, opts);
397
+ if (stub) {
398
+ configOverrides.stub = stub;
399
+ }
400
+
401
+ if (opts.timestampFilenamePrefix) {
402
+ configOverrides.timestampFilenamePrefix =
403
+ opts.timestampFilenamePrefix;
404
+ }
405
+
406
+ instance.seed
407
+ .make(name, configOverrides)
408
+ .then((name) => {
409
+ success(color.green(`Created seed file: ${name}`));
410
+ })
411
+ .catch(exit);
412
+ } catch (err) {
413
+ exit(err);
414
+ }
415
+ });
416
+
417
+ commander
418
+ .command('seed:run')
419
+ .description(' Run seed files.')
420
+ .option('--verbose', 'verbose')
421
+ .option('--specific', 'run specific seed file')
422
+ .action(() => {
423
+ initKnex(env, commander.opts())
424
+ .then((instance) => instance.seed.run({ specific: argv.specific }))
425
+ .then(([log]) => {
426
+ if (log.length === 0) {
427
+ success(color.cyan('No seed files exist'));
428
+ }
429
+ success(
430
+ color.green(`Ran ${log.length} seed files`) +
431
+ (argv.verbose ? `\n${color.cyan(log.join('\n'))}` : '')
432
+ );
433
+ })
434
+ .catch(exit);
435
+ });
436
+
437
+ commander.parse(process.argv);
438
+ }
439
+
440
+ // FYI: The handling for the `--cwd` and `--knexfile` arguments is a bit strange,
441
+ // but we decided to retain the behavior for backwards-compatibility. In
442
+ // particular: if `--knexfile` is a relative path, then it will be resolved
443
+ // relative to `--cwd` instead of the shell's CWD.
444
+ //
445
+ // So, the easiest way to replicate this behavior is to have the CLI change
446
+ // its CWD to `--cwd` immediately before initializing everything else. This
447
+ // ensures that path.resolve will then resolve the path to `--knexfile` correctly.
448
+ if (argv.cwd) {
449
+ process.chdir(argv.cwd);
450
+ }
451
+ // Initialize 'esm' before cli.launch
452
+ if (argv.esm) {
453
+ // enable esm interop via 'esm' module
454
+ // eslint-disable-next-line no-global-assign
455
+ require = require('esm')(module);
456
+ // https://github.com/standard-things/esm/issues/868
457
+ const ext = require.extensions['.js'];
458
+ require.extensions['.js'] = (m, fileName) => {
459
+ try {
460
+ // default to the original extension
461
+ // this fails if target file parent is of type='module'
462
+ return ext(m, fileName);
463
+ } catch (err) {
464
+ if (err && err.code === 'ERR_REQUIRE_ESM') {
465
+ return m._compile(
466
+ require('fs').readFileSync(fileName, 'utf8'),
467
+ fileName
468
+ );
469
+ }
470
+ throw err;
471
+ }
472
+ };
473
+ }
474
+
475
+ invoke();