knex 2.4.1 → 2.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/CONTRIBUTING.md +194 -194
  3. package/LICENSE +22 -22
  4. package/README.md +148 -148
  5. package/UPGRADING.md +233 -233
  6. package/bin/cli.js +473 -472
  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/lib/builder-interface-augmenter.js +120 -120
  12. package/lib/client.js +475 -475
  13. package/lib/constants.js +61 -61
  14. package/lib/dialects/better-sqlite3/index.js +72 -72
  15. package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -14
  16. package/lib/dialects/cockroachdb/crdb-querybuilder.js +11 -11
  17. package/lib/dialects/cockroachdb/crdb-querycompiler.js +122 -122
  18. package/lib/dialects/cockroachdb/crdb-tablecompiler.js +37 -37
  19. package/lib/dialects/cockroachdb/crdb-viewcompiler.js +15 -15
  20. package/lib/dialects/cockroachdb/index.js +86 -86
  21. package/lib/dialects/mssql/index.js +495 -495
  22. package/lib/dialects/mssql/mssql-formatter.js +34 -34
  23. package/lib/dialects/mssql/query/mssql-querycompiler.js +600 -600
  24. package/lib/dialects/mssql/schema/mssql-columncompiler.js +185 -185
  25. package/lib/dialects/mssql/schema/mssql-compiler.js +91 -91
  26. package/lib/dialects/mssql/schema/mssql-tablecompiler.js +378 -378
  27. package/lib/dialects/mssql/schema/mssql-viewcompiler.js +55 -55
  28. package/lib/dialects/mssql/transaction.js +176 -176
  29. package/lib/dialects/mysql/index.js +201 -201
  30. package/lib/dialects/mysql/query/mysql-querycompiler.js +274 -274
  31. package/lib/dialects/mysql/schema/mysql-columncompiler.js +193 -193
  32. package/lib/dialects/mysql/schema/mysql-compiler.js +60 -60
  33. package/lib/dialects/mysql/schema/mysql-tablecompiler.js +381 -381
  34. package/lib/dialects/mysql/schema/mysql-viewbuilder.js +21 -21
  35. package/lib/dialects/mysql/schema/mysql-viewcompiler.js +15 -15
  36. package/lib/dialects/mysql/transaction.js +46 -46
  37. package/lib/dialects/mysql2/index.js +33 -33
  38. package/lib/dialects/mysql2/transaction.js +44 -44
  39. package/lib/dialects/oracle/DEAD_CODE.md +5 -5
  40. package/lib/dialects/oracle/index.js +92 -92
  41. package/lib/dialects/oracle/query/oracle-querycompiler.js +342 -342
  42. package/lib/dialects/oracle/schema/internal/incrementUtils.js +20 -20
  43. package/lib/dialects/oracle/schema/internal/trigger.js +135 -135
  44. package/lib/dialects/oracle/schema/oracle-columnbuilder.js +17 -17
  45. package/lib/dialects/oracle/schema/oracle-columncompiler.js +126 -126
  46. package/lib/dialects/oracle/schema/oracle-compiler.js +122 -122
  47. package/lib/dialects/oracle/schema/oracle-tablecompiler.js +190 -190
  48. package/lib/dialects/oracle/utils.js +87 -87
  49. package/lib/dialects/oracledb/index.js +327 -327
  50. package/lib/dialects/oracledb/query/oracledb-querycompiler.js +481 -481
  51. package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +55 -55
  52. package/lib/dialects/oracledb/schema/oracledb-tablecompiler.js +19 -19
  53. package/lib/dialects/oracledb/schema/oracledb-viewbuilder.js +13 -13
  54. package/lib/dialects/oracledb/schema/oracledb-viewcompiler.js +19 -19
  55. package/lib/dialects/oracledb/transaction.js +98 -98
  56. package/lib/dialects/oracledb/utils.js +208 -208
  57. package/lib/dialects/pgnative/index.js +60 -60
  58. package/lib/dialects/postgres/execution/pg-transaction.js +12 -12
  59. package/lib/dialects/postgres/index.js +358 -358
  60. package/lib/dialects/postgres/query/pg-querybuilder.js +38 -38
  61. package/lib/dialects/postgres/query/pg-querycompiler.js +395 -395
  62. package/lib/dialects/postgres/schema/pg-columncompiler.js +156 -156
  63. package/lib/dialects/postgres/schema/pg-compiler.js +138 -136
  64. package/lib/dialects/postgres/schema/pg-tablecompiler.js +299 -299
  65. package/lib/dialects/postgres/schema/pg-viewbuilder.js +21 -21
  66. package/lib/dialects/postgres/schema/pg-viewcompiler.js +35 -35
  67. package/lib/dialects/redshift/index.js +86 -86
  68. package/lib/dialects/redshift/query/redshift-querycompiler.js +163 -163
  69. package/lib/dialects/redshift/schema/redshift-columnbuilder.js +22 -22
  70. package/lib/dialects/redshift/schema/redshift-columncompiler.js +67 -67
  71. package/lib/dialects/redshift/schema/redshift-compiler.js +14 -14
  72. package/lib/dialects/redshift/schema/redshift-tablecompiler.js +122 -122
  73. package/lib/dialects/redshift/schema/redshift-viewcompiler.js +11 -11
  74. package/lib/dialects/redshift/transaction.js +25 -25
  75. package/lib/dialects/sqlite3/execution/sqlite-transaction.js +18 -18
  76. package/lib/dialects/sqlite3/index.js +250 -250
  77. package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -33
  78. package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +334 -334
  79. package/lib/dialects/sqlite3/schema/ddl.js +400 -400
  80. package/lib/dialects/sqlite3/schema/internal/compiler.js +327 -327
  81. package/lib/dialects/sqlite3/schema/internal/parser-combinator.js +161 -161
  82. package/lib/dialects/sqlite3/schema/internal/parser.js +638 -638
  83. package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +41 -41
  84. package/lib/dialects/sqlite3/schema/internal/tokenizer.js +38 -38
  85. package/lib/dialects/sqlite3/schema/internal/utils.js +12 -12
  86. package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +50 -50
  87. package/lib/dialects/sqlite3/schema/sqlite-compiler.js +80 -80
  88. package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +347 -347
  89. package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +40 -40
  90. package/lib/execution/batch-insert.js +51 -51
  91. package/lib/execution/internal/delay.js +6 -6
  92. package/lib/execution/internal/ensure-connection-callback.js +41 -41
  93. package/lib/execution/internal/query-executioner.js +62 -62
  94. package/lib/execution/runner.js +307 -307
  95. package/lib/execution/transaction.js +401 -401
  96. package/lib/formatter/formatterUtils.js +42 -42
  97. package/lib/formatter/rawFormatter.js +84 -84
  98. package/lib/formatter/wrappingFormatter.js +250 -250
  99. package/lib/formatter.js +25 -25
  100. package/lib/index.js +3 -3
  101. package/lib/knex-builder/FunctionHelper.js +54 -54
  102. package/lib/knex-builder/Knex.js +59 -59
  103. package/lib/knex-builder/internal/config-resolver.js +57 -57
  104. package/lib/knex-builder/internal/parse-connection.js +87 -87
  105. package/lib/knex-builder/make-knex.js +340 -340
  106. package/lib/logger.js +76 -76
  107. package/lib/migrations/common/MigrationsLoader.js +36 -36
  108. package/lib/migrations/migrate/MigrationGenerator.js +84 -82
  109. package/lib/migrations/migrate/Migrator.js +598 -598
  110. package/lib/migrations/migrate/migrate-stub.js +17 -17
  111. package/lib/migrations/migrate/migration-list-resolver.js +33 -33
  112. package/lib/migrations/migrate/migrator-configuration-merger.js +58 -58
  113. package/lib/migrations/migrate/sources/fs-migrations.js +74 -74
  114. package/lib/migrations/migrate/stub/cjs.stub +15 -15
  115. package/lib/migrations/migrate/stub/coffee.stub +13 -13
  116. package/lib/migrations/migrate/stub/eg.stub +14 -14
  117. package/lib/migrations/migrate/stub/js-schema.stub +22 -22
  118. package/lib/migrations/migrate/stub/js.stub +22 -22
  119. package/lib/migrations/migrate/stub/knexfile-coffee.stub +34 -34
  120. package/lib/migrations/migrate/stub/knexfile-eg.stub +43 -43
  121. package/lib/migrations/migrate/stub/knexfile-js.stub +47 -47
  122. package/lib/migrations/migrate/stub/knexfile-ls.stub +35 -35
  123. package/lib/migrations/migrate/stub/knexfile-ts.stub +47 -47
  124. package/lib/migrations/migrate/stub/ls.stub +14 -14
  125. package/lib/migrations/migrate/stub/mjs.stub +23 -23
  126. package/lib/migrations/migrate/stub/ts-schema.stub +21 -21
  127. package/lib/migrations/migrate/stub/ts.stub +21 -21
  128. package/lib/migrations/migrate/table-creator.js +77 -77
  129. package/lib/migrations/migrate/table-resolver.js +27 -27
  130. package/lib/migrations/seed/Seeder.js +137 -137
  131. package/lib/migrations/seed/seed-stub.js +13 -13
  132. package/lib/migrations/seed/seeder-configuration-merger.js +60 -60
  133. package/lib/migrations/seed/sources/fs-seeds.js +65 -65
  134. package/lib/migrations/seed/stub/coffee.stub +9 -9
  135. package/lib/migrations/seed/stub/eg.stub +11 -11
  136. package/lib/migrations/seed/stub/js.stub +13 -13
  137. package/lib/migrations/seed/stub/ls.stub +11 -11
  138. package/lib/migrations/seed/stub/mjs.stub +12 -12
  139. package/lib/migrations/seed/stub/ts.stub +13 -13
  140. package/lib/migrations/util/fs.js +86 -86
  141. package/lib/migrations/util/import-file.js +12 -12
  142. package/lib/migrations/util/is-module-type.js +9 -9
  143. package/lib/migrations/util/template.js +52 -52
  144. package/lib/migrations/util/timestamp.js +14 -14
  145. package/lib/query/analytic.js +52 -52
  146. package/lib/query/constants.js +15 -15
  147. package/lib/query/joinclause.js +270 -270
  148. package/lib/query/method-constants.js +135 -135
  149. package/lib/query/querybuilder.js +1794 -1794
  150. package/lib/query/querycompiler.js +1580 -1580
  151. package/lib/raw.js +139 -139
  152. package/lib/ref.js +39 -39
  153. package/lib/schema/builder.js +115 -114
  154. package/lib/schema/columnbuilder.js +146 -145
  155. package/lib/schema/columncompiler.js +307 -307
  156. package/lib/schema/compiler.js +187 -187
  157. package/lib/schema/internal/helpers.js +55 -55
  158. package/lib/schema/tablebuilder.js +376 -375
  159. package/lib/schema/tablecompiler.js +433 -433
  160. package/lib/schema/viewbuilder.js +92 -93
  161. package/lib/schema/viewcompiler.js +138 -138
  162. package/lib/util/finally-mixin.js +13 -13
  163. package/lib/util/helpers.js +95 -95
  164. package/lib/util/is.js +32 -32
  165. package/lib/util/nanoid.js +40 -40
  166. package/lib/util/noop.js +1 -1
  167. package/lib/util/save-async-stack.js +14 -14
  168. package/lib/util/string.js +190 -190
  169. package/lib/util/timeout.js +29 -29
  170. package/package.json +8 -6
  171. package/scripts/build.js +125 -125
  172. package/scripts/clean.js +31 -29
  173. package/scripts/docker-compose.yml +152 -152
  174. package/scripts/next-release-howto.md +24 -24
  175. package/scripts/oracledb-install-driver-libs.sh +82 -82
  176. package/scripts/release.sh +34 -34
  177. package/scripts/runkit-example.js +34 -34
  178. package/scripts/stress-test/README.txt +18 -18
  179. package/scripts/stress-test/docker-compose.yml +57 -57
  180. package/scripts/stress-test/knex-stress-test.js +208 -208
  181. package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +145 -145
  182. package/scripts/stress-test/mysql2-sudden-exit-without-error.js +100 -100
  183. package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +184 -184
  184. package/scripts/update_gitignore_for_tsc_output.js +90 -86
  185. package/types/index.d.ts +3233 -3233
  186. package/types/result.d.ts +27 -27
  187. package/types/tables.d.ts +4 -4
package/bin/cli.js CHANGED
@@ -1,472 +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 = opts.timestampFilenamePrefix;
401
- }
402
-
403
- instance.seed
404
- .make(name, configOverrides)
405
- .then((name) => {
406
- success(color.green(`Created seed file: ${name}`));
407
- })
408
- .catch(exit);
409
- } catch(err) {
410
- exit(err);
411
- }
412
- });
413
-
414
- commander
415
- .command('seed:run')
416
- .description(' Run seed files.')
417
- .option('--verbose', 'verbose')
418
- .option('--specific', 'run specific seed file')
419
- .action(() => {
420
- initKnex(env, commander.opts())
421
- .then((instance) => instance.seed.run({ specific: argv.specific }))
422
- .then(([log]) => {
423
- if (log.length === 0) {
424
- success(color.cyan('No seed files exist'));
425
- }
426
- success(
427
- color.green(`Ran ${log.length} seed files`) +
428
- (argv.verbose ? `\n${color.cyan(log.join('\n'))}` : '')
429
- );
430
- })
431
- .catch(exit);
432
- });
433
-
434
- commander.parse(process.argv);
435
- }
436
-
437
- // FYI: The handling for the `--cwd` and `--knexfile` arguments is a bit strange,
438
- // but we decided to retain the behavior for backwards-compatibility. In
439
- // particular: if `--knexfile` is a relative path, then it will be resolved
440
- // relative to `--cwd` instead of the shell's CWD.
441
- //
442
- // So, the easiest way to replicate this behavior is to have the CLI change
443
- // its CWD to `--cwd` immediately before initializing everything else. This
444
- // ensures that path.resolve will then resolve the path to `--knexfile` correctly.
445
- if (argv.cwd) {
446
- process.chdir(argv.cwd);
447
- }
448
- // Initialize 'esm' before cli.launch
449
- if (argv.esm) {
450
- // enable esm interop via 'esm' module
451
- // eslint-disable-next-line no-global-assign
452
- require = require('esm')(module);
453
- // https://github.com/standard-things/esm/issues/868
454
- const ext = require.extensions['.js'];
455
- require.extensions['.js'] = (m, fileName) => {
456
- try {
457
- // default to the original extension
458
- // this fails if target file parent is of type='module'
459
- return ext(m, fileName);
460
- } catch (err) {
461
- if (err && err.code === 'ERR_REQUIRE_ESM') {
462
- return m._compile(
463
- require('fs').readFileSync(fileName, 'utf8'),
464
- fileName
465
- );
466
- }
467
- throw err;
468
- }
469
- };
470
- }
471
-
472
- 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', '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();