knex 2.4.2 → 2.5.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 +54 -18
  2. package/CONTRIBUTING.md +194 -194
  3. package/LICENSE +22 -22
  4. package/README.md +147 -148
  5. package/UPGRADING.md +233 -233
  6. package/bin/cli.js +473 -473
  7. package/bin/utils/cli-config-utils.js +210 -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 -0
  12. package/lib/builder-interface-augmenter.js +120 -120
  13. package/lib/client.js +495 -475
  14. package/lib/constants.js +61 -61
  15. package/lib/dialects/better-sqlite3/index.js +77 -72
  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/index.js +33 -33
  23. package/lib/dialects/mssql/index.js +500 -495
  24. package/lib/dialects/mssql/mssql-formatter.js +34 -34
  25. package/lib/dialects/mssql/query/mssql-querycompiler.js +601 -600
  26. package/lib/dialects/mssql/schema/mssql-columncompiler.js +185 -185
  27. package/lib/dialects/mssql/schema/mssql-compiler.js +91 -91
  28. package/lib/dialects/mssql/schema/mssql-tablecompiler.js +378 -378
  29. package/lib/dialects/mssql/schema/mssql-viewcompiler.js +55 -55
  30. package/lib/dialects/mssql/transaction.js +176 -176
  31. package/lib/dialects/mysql/index.js +201 -201
  32. package/lib/dialects/mysql/query/mysql-querycompiler.js +274 -274
  33. package/lib/dialects/mysql/schema/mysql-columncompiler.js +193 -193
  34. package/lib/dialects/mysql/schema/mysql-compiler.js +60 -60
  35. package/lib/dialects/mysql/schema/mysql-tablecompiler.js +381 -381
  36. package/lib/dialects/mysql/schema/mysql-viewbuilder.js +21 -21
  37. package/lib/dialects/mysql/schema/mysql-viewcompiler.js +15 -15
  38. package/lib/dialects/mysql/transaction.js +46 -46
  39. package/lib/dialects/mysql2/index.js +53 -33
  40. package/lib/dialects/mysql2/transaction.js +44 -44
  41. package/lib/dialects/oracle/DEAD_CODE.md +5 -5
  42. package/lib/dialects/oracle/index.js +92 -92
  43. package/lib/dialects/oracle/query/oracle-querycompiler.js +343 -342
  44. package/lib/dialects/oracle/schema/internal/incrementUtils.js +20 -20
  45. package/lib/dialects/oracle/schema/internal/trigger.js +135 -135
  46. package/lib/dialects/oracle/schema/oracle-columnbuilder.js +17 -17
  47. package/lib/dialects/oracle/schema/oracle-columncompiler.js +126 -126
  48. package/lib/dialects/oracle/schema/oracle-compiler.js +122 -122
  49. package/lib/dialects/oracle/schema/oracle-tablecompiler.js +190 -190
  50. package/lib/dialects/oracle/utils.js +87 -87
  51. package/lib/dialects/oracledb/index.js +327 -327
  52. package/lib/dialects/oracledb/query/oracledb-querycompiler.js +481 -481
  53. package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +61 -55
  54. package/lib/dialects/oracledb/schema/oracledb-tablecompiler.js +19 -19
  55. package/lib/dialects/oracledb/schema/oracledb-viewbuilder.js +13 -13
  56. package/lib/dialects/oracledb/schema/oracledb-viewcompiler.js +19 -19
  57. package/lib/dialects/oracledb/transaction.js +98 -98
  58. package/lib/dialects/oracledb/utils.js +208 -208
  59. package/lib/dialects/pgnative/index.js +60 -60
  60. package/lib/dialects/postgres/execution/pg-transaction.js +19 -12
  61. package/lib/dialects/postgres/index.js +358 -358
  62. package/lib/dialects/postgres/query/pg-querybuilder.js +43 -38
  63. package/lib/dialects/postgres/query/pg-querycompiler.js +400 -395
  64. package/lib/dialects/postgres/schema/pg-columncompiler.js +156 -156
  65. package/lib/dialects/postgres/schema/pg-compiler.js +138 -138
  66. package/lib/dialects/postgres/schema/pg-tablecompiler.js +304 -299
  67. package/lib/dialects/postgres/schema/pg-viewbuilder.js +21 -21
  68. package/lib/dialects/postgres/schema/pg-viewcompiler.js +35 -35
  69. package/lib/dialects/redshift/index.js +86 -86
  70. package/lib/dialects/redshift/query/redshift-querycompiler.js +163 -163
  71. package/lib/dialects/redshift/schema/redshift-columnbuilder.js +22 -22
  72. package/lib/dialects/redshift/schema/redshift-columncompiler.js +67 -67
  73. package/lib/dialects/redshift/schema/redshift-compiler.js +14 -14
  74. package/lib/dialects/redshift/schema/redshift-tablecompiler.js +122 -122
  75. package/lib/dialects/redshift/schema/redshift-viewcompiler.js +11 -11
  76. package/lib/dialects/redshift/transaction.js +32 -25
  77. package/lib/dialects/sqlite3/execution/sqlite-transaction.js +25 -18
  78. package/lib/dialects/sqlite3/index.js +250 -250
  79. package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -33
  80. package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +334 -334
  81. package/lib/dialects/sqlite3/schema/ddl.js +400 -400
  82. package/lib/dialects/sqlite3/schema/internal/compiler.js +327 -327
  83. package/lib/dialects/sqlite3/schema/internal/parser-combinator.js +161 -161
  84. package/lib/dialects/sqlite3/schema/internal/parser.js +638 -638
  85. package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +41 -41
  86. package/lib/dialects/sqlite3/schema/internal/tokenizer.js +38 -38
  87. package/lib/dialects/sqlite3/schema/internal/utils.js +12 -12
  88. package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +50 -50
  89. package/lib/dialects/sqlite3/schema/sqlite-compiler.js +80 -80
  90. package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +347 -347
  91. package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +40 -40
  92. package/lib/execution/batch-insert.js +51 -51
  93. package/lib/execution/internal/delay.js +6 -6
  94. package/lib/execution/internal/ensure-connection-callback.js +41 -41
  95. package/lib/execution/internal/query-executioner.js +62 -62
  96. package/lib/execution/runner.js +325 -307
  97. package/lib/execution/transaction.js +409 -401
  98. package/lib/formatter/formatterUtils.js +42 -42
  99. package/lib/formatter/rawFormatter.js +84 -84
  100. package/lib/formatter/wrappingFormatter.js +250 -250
  101. package/lib/formatter.js +25 -25
  102. package/lib/index.js +3 -3
  103. package/lib/knex-builder/FunctionHelper.js +80 -54
  104. package/lib/knex-builder/Knex.js +59 -59
  105. package/lib/knex-builder/internal/config-resolver.js +57 -57
  106. package/lib/knex-builder/internal/parse-connection.js +87 -87
  107. package/lib/knex-builder/make-knex.js +345 -340
  108. package/lib/logger.js +76 -76
  109. package/lib/migrations/common/MigrationsLoader.js +36 -36
  110. package/lib/migrations/migrate/MigrationGenerator.js +84 -84
  111. package/lib/migrations/migrate/Migrator.js +598 -598
  112. package/lib/migrations/migrate/migrate-stub.js +17 -17
  113. package/lib/migrations/migrate/migration-list-resolver.js +33 -33
  114. package/lib/migrations/migrate/migrator-configuration-merger.js +58 -58
  115. package/lib/migrations/migrate/sources/fs-migrations.js +74 -74
  116. package/lib/migrations/migrate/stub/cjs.stub +15 -15
  117. package/lib/migrations/migrate/stub/coffee.stub +13 -13
  118. package/lib/migrations/migrate/stub/eg.stub +14 -14
  119. package/lib/migrations/migrate/stub/js-schema.stub +22 -22
  120. package/lib/migrations/migrate/stub/js.stub +22 -22
  121. package/lib/migrations/migrate/stub/knexfile-coffee.stub +34 -34
  122. package/lib/migrations/migrate/stub/knexfile-eg.stub +43 -43
  123. package/lib/migrations/migrate/stub/knexfile-js.stub +47 -47
  124. package/lib/migrations/migrate/stub/knexfile-ls.stub +35 -35
  125. package/lib/migrations/migrate/stub/knexfile-ts.stub +47 -47
  126. package/lib/migrations/migrate/stub/ls.stub +14 -14
  127. package/lib/migrations/migrate/stub/mjs.stub +23 -23
  128. package/lib/migrations/migrate/stub/ts-schema.stub +21 -21
  129. package/lib/migrations/migrate/stub/ts.stub +21 -21
  130. package/lib/migrations/migrate/table-creator.js +77 -77
  131. package/lib/migrations/migrate/table-resolver.js +27 -27
  132. package/lib/migrations/seed/Seeder.js +137 -137
  133. package/lib/migrations/seed/seed-stub.js +13 -13
  134. package/lib/migrations/seed/seeder-configuration-merger.js +60 -60
  135. package/lib/migrations/seed/sources/fs-seeds.js +65 -65
  136. package/lib/migrations/seed/stub/coffee.stub +9 -9
  137. package/lib/migrations/seed/stub/eg.stub +11 -11
  138. package/lib/migrations/seed/stub/js.stub +13 -13
  139. package/lib/migrations/seed/stub/ls.stub +11 -11
  140. package/lib/migrations/seed/stub/mjs.stub +12 -12
  141. package/lib/migrations/seed/stub/ts.stub +13 -13
  142. package/lib/migrations/util/fs.js +86 -86
  143. package/lib/migrations/util/import-file.js +12 -12
  144. package/lib/migrations/util/is-module-type.js +9 -9
  145. package/lib/migrations/util/template.js +52 -52
  146. package/lib/migrations/util/timestamp.js +14 -14
  147. package/lib/query/analytic.js +52 -52
  148. package/lib/query/constants.js +15 -15
  149. package/lib/query/joinclause.js +270 -270
  150. package/lib/query/method-constants.js +136 -135
  151. package/lib/query/querybuilder.js +1793 -1794
  152. package/lib/query/querycompiler.js +1591 -1580
  153. package/lib/raw.js +139 -139
  154. package/lib/ref.js +39 -39
  155. package/lib/schema/builder.js +115 -115
  156. package/lib/schema/columnbuilder.js +146 -146
  157. package/lib/schema/columncompiler.js +307 -307
  158. package/lib/schema/compiler.js +187 -187
  159. package/lib/schema/internal/helpers.js +55 -55
  160. package/lib/schema/tablebuilder.js +376 -376
  161. package/lib/schema/tablecompiler.js +433 -433
  162. package/lib/schema/viewbuilder.js +92 -92
  163. package/lib/schema/viewcompiler.js +138 -138
  164. package/lib/util/finally-mixin.js +13 -13
  165. package/lib/util/helpers.js +95 -95
  166. package/lib/util/is.js +32 -32
  167. package/lib/util/nanoid.js +40 -40
  168. package/lib/util/noop.js +1 -1
  169. package/lib/util/save-async-stack.js +14 -14
  170. package/lib/util/security.js +26 -0
  171. package/lib/util/string.js +190 -190
  172. package/lib/util/timeout.js +29 -29
  173. package/package.json +12 -10
  174. package/scripts/build.js +125 -125
  175. package/scripts/clean.js +31 -31
  176. package/scripts/docker-compose.yml +152 -152
  177. package/scripts/next-release-howto.md +24 -24
  178. package/scripts/oracledb-install-driver-libs.sh +82 -82
  179. package/scripts/release.sh +34 -34
  180. package/scripts/runkit-example.js +34 -34
  181. package/scripts/stress-test/README.txt +18 -18
  182. package/scripts/stress-test/docker-compose.yml +57 -57
  183. package/scripts/stress-test/knex-stress-test.js +208 -208
  184. package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +145 -145
  185. package/scripts/stress-test/mysql2-sudden-exit-without-error.js +100 -100
  186. package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +184 -184
  187. package/scripts/update_gitignore_for_tsc_output.js +90 -90
  188. package/types/index.d.ts +3273 -3233
  189. package/types/result.d.ts +27 -27
  190. package/types/tables.d.ts +4 -4
package/bin/cli.js CHANGED
@@ -1,473 +1,473 @@
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', '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
+
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();