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.
- package/CHANGELOG.md +54 -18
- package/CONTRIBUTING.md +194 -194
- package/LICENSE +22 -22
- package/README.md +147 -148
- package/UPGRADING.md +233 -233
- package/bin/cli.js +473 -473
- package/bin/utils/cli-config-utils.js +210 -210
- package/bin/utils/constants.js +7 -7
- package/bin/utils/migrationsLister.js +37 -37
- package/knex.js +23 -23
- package/knex.mjs +11 -0
- package/lib/builder-interface-augmenter.js +120 -120
- package/lib/client.js +495 -475
- package/lib/constants.js +61 -61
- package/lib/dialects/better-sqlite3/index.js +77 -72
- package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -14
- package/lib/dialects/cockroachdb/crdb-querybuilder.js +11 -11
- package/lib/dialects/cockroachdb/crdb-querycompiler.js +122 -122
- package/lib/dialects/cockroachdb/crdb-tablecompiler.js +37 -37
- package/lib/dialects/cockroachdb/crdb-viewcompiler.js +15 -15
- package/lib/dialects/cockroachdb/index.js +86 -86
- package/lib/dialects/index.js +33 -33
- package/lib/dialects/mssql/index.js +500 -495
- package/lib/dialects/mssql/mssql-formatter.js +34 -34
- package/lib/dialects/mssql/query/mssql-querycompiler.js +601 -600
- package/lib/dialects/mssql/schema/mssql-columncompiler.js +185 -185
- package/lib/dialects/mssql/schema/mssql-compiler.js +91 -91
- package/lib/dialects/mssql/schema/mssql-tablecompiler.js +378 -378
- package/lib/dialects/mssql/schema/mssql-viewcompiler.js +55 -55
- package/lib/dialects/mssql/transaction.js +176 -176
- package/lib/dialects/mysql/index.js +201 -201
- package/lib/dialects/mysql/query/mysql-querycompiler.js +274 -274
- package/lib/dialects/mysql/schema/mysql-columncompiler.js +193 -193
- package/lib/dialects/mysql/schema/mysql-compiler.js +60 -60
- package/lib/dialects/mysql/schema/mysql-tablecompiler.js +381 -381
- package/lib/dialects/mysql/schema/mysql-viewbuilder.js +21 -21
- package/lib/dialects/mysql/schema/mysql-viewcompiler.js +15 -15
- package/lib/dialects/mysql/transaction.js +46 -46
- package/lib/dialects/mysql2/index.js +53 -33
- package/lib/dialects/mysql2/transaction.js +44 -44
- package/lib/dialects/oracle/DEAD_CODE.md +5 -5
- package/lib/dialects/oracle/index.js +92 -92
- package/lib/dialects/oracle/query/oracle-querycompiler.js +343 -342
- package/lib/dialects/oracle/schema/internal/incrementUtils.js +20 -20
- package/lib/dialects/oracle/schema/internal/trigger.js +135 -135
- package/lib/dialects/oracle/schema/oracle-columnbuilder.js +17 -17
- package/lib/dialects/oracle/schema/oracle-columncompiler.js +126 -126
- package/lib/dialects/oracle/schema/oracle-compiler.js +122 -122
- package/lib/dialects/oracle/schema/oracle-tablecompiler.js +190 -190
- package/lib/dialects/oracle/utils.js +87 -87
- package/lib/dialects/oracledb/index.js +327 -327
- package/lib/dialects/oracledb/query/oracledb-querycompiler.js +481 -481
- package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +61 -55
- package/lib/dialects/oracledb/schema/oracledb-tablecompiler.js +19 -19
- package/lib/dialects/oracledb/schema/oracledb-viewbuilder.js +13 -13
- package/lib/dialects/oracledb/schema/oracledb-viewcompiler.js +19 -19
- package/lib/dialects/oracledb/transaction.js +98 -98
- package/lib/dialects/oracledb/utils.js +208 -208
- package/lib/dialects/pgnative/index.js +60 -60
- package/lib/dialects/postgres/execution/pg-transaction.js +19 -12
- package/lib/dialects/postgres/index.js +358 -358
- package/lib/dialects/postgres/query/pg-querybuilder.js +43 -38
- package/lib/dialects/postgres/query/pg-querycompiler.js +400 -395
- package/lib/dialects/postgres/schema/pg-columncompiler.js +156 -156
- package/lib/dialects/postgres/schema/pg-compiler.js +138 -138
- package/lib/dialects/postgres/schema/pg-tablecompiler.js +304 -299
- package/lib/dialects/postgres/schema/pg-viewbuilder.js +21 -21
- package/lib/dialects/postgres/schema/pg-viewcompiler.js +35 -35
- package/lib/dialects/redshift/index.js +86 -86
- package/lib/dialects/redshift/query/redshift-querycompiler.js +163 -163
- package/lib/dialects/redshift/schema/redshift-columnbuilder.js +22 -22
- package/lib/dialects/redshift/schema/redshift-columncompiler.js +67 -67
- package/lib/dialects/redshift/schema/redshift-compiler.js +14 -14
- package/lib/dialects/redshift/schema/redshift-tablecompiler.js +122 -122
- package/lib/dialects/redshift/schema/redshift-viewcompiler.js +11 -11
- package/lib/dialects/redshift/transaction.js +32 -25
- package/lib/dialects/sqlite3/execution/sqlite-transaction.js +25 -18
- package/lib/dialects/sqlite3/index.js +250 -250
- package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -33
- package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +334 -334
- package/lib/dialects/sqlite3/schema/ddl.js +400 -400
- package/lib/dialects/sqlite3/schema/internal/compiler.js +327 -327
- package/lib/dialects/sqlite3/schema/internal/parser-combinator.js +161 -161
- package/lib/dialects/sqlite3/schema/internal/parser.js +638 -638
- package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +41 -41
- package/lib/dialects/sqlite3/schema/internal/tokenizer.js +38 -38
- package/lib/dialects/sqlite3/schema/internal/utils.js +12 -12
- package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +50 -50
- package/lib/dialects/sqlite3/schema/sqlite-compiler.js +80 -80
- package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +347 -347
- package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +40 -40
- package/lib/execution/batch-insert.js +51 -51
- package/lib/execution/internal/delay.js +6 -6
- package/lib/execution/internal/ensure-connection-callback.js +41 -41
- package/lib/execution/internal/query-executioner.js +62 -62
- package/lib/execution/runner.js +325 -307
- package/lib/execution/transaction.js +409 -401
- package/lib/formatter/formatterUtils.js +42 -42
- package/lib/formatter/rawFormatter.js +84 -84
- package/lib/formatter/wrappingFormatter.js +250 -250
- package/lib/formatter.js +25 -25
- package/lib/index.js +3 -3
- package/lib/knex-builder/FunctionHelper.js +80 -54
- package/lib/knex-builder/Knex.js +59 -59
- package/lib/knex-builder/internal/config-resolver.js +57 -57
- package/lib/knex-builder/internal/parse-connection.js +87 -87
- package/lib/knex-builder/make-knex.js +345 -340
- package/lib/logger.js +76 -76
- package/lib/migrations/common/MigrationsLoader.js +36 -36
- package/lib/migrations/migrate/MigrationGenerator.js +84 -84
- package/lib/migrations/migrate/Migrator.js +598 -598
- package/lib/migrations/migrate/migrate-stub.js +17 -17
- package/lib/migrations/migrate/migration-list-resolver.js +33 -33
- package/lib/migrations/migrate/migrator-configuration-merger.js +58 -58
- package/lib/migrations/migrate/sources/fs-migrations.js +74 -74
- package/lib/migrations/migrate/stub/cjs.stub +15 -15
- package/lib/migrations/migrate/stub/coffee.stub +13 -13
- package/lib/migrations/migrate/stub/eg.stub +14 -14
- package/lib/migrations/migrate/stub/js-schema.stub +22 -22
- package/lib/migrations/migrate/stub/js.stub +22 -22
- package/lib/migrations/migrate/stub/knexfile-coffee.stub +34 -34
- package/lib/migrations/migrate/stub/knexfile-eg.stub +43 -43
- package/lib/migrations/migrate/stub/knexfile-js.stub +47 -47
- package/lib/migrations/migrate/stub/knexfile-ls.stub +35 -35
- package/lib/migrations/migrate/stub/knexfile-ts.stub +47 -47
- package/lib/migrations/migrate/stub/ls.stub +14 -14
- package/lib/migrations/migrate/stub/mjs.stub +23 -23
- package/lib/migrations/migrate/stub/ts-schema.stub +21 -21
- package/lib/migrations/migrate/stub/ts.stub +21 -21
- package/lib/migrations/migrate/table-creator.js +77 -77
- package/lib/migrations/migrate/table-resolver.js +27 -27
- package/lib/migrations/seed/Seeder.js +137 -137
- package/lib/migrations/seed/seed-stub.js +13 -13
- package/lib/migrations/seed/seeder-configuration-merger.js +60 -60
- package/lib/migrations/seed/sources/fs-seeds.js +65 -65
- package/lib/migrations/seed/stub/coffee.stub +9 -9
- package/lib/migrations/seed/stub/eg.stub +11 -11
- package/lib/migrations/seed/stub/js.stub +13 -13
- package/lib/migrations/seed/stub/ls.stub +11 -11
- package/lib/migrations/seed/stub/mjs.stub +12 -12
- package/lib/migrations/seed/stub/ts.stub +13 -13
- package/lib/migrations/util/fs.js +86 -86
- package/lib/migrations/util/import-file.js +12 -12
- package/lib/migrations/util/is-module-type.js +9 -9
- package/lib/migrations/util/template.js +52 -52
- package/lib/migrations/util/timestamp.js +14 -14
- package/lib/query/analytic.js +52 -52
- package/lib/query/constants.js +15 -15
- package/lib/query/joinclause.js +270 -270
- package/lib/query/method-constants.js +136 -135
- package/lib/query/querybuilder.js +1793 -1794
- package/lib/query/querycompiler.js +1591 -1580
- package/lib/raw.js +139 -139
- package/lib/ref.js +39 -39
- package/lib/schema/builder.js +115 -115
- package/lib/schema/columnbuilder.js +146 -146
- package/lib/schema/columncompiler.js +307 -307
- package/lib/schema/compiler.js +187 -187
- package/lib/schema/internal/helpers.js +55 -55
- package/lib/schema/tablebuilder.js +376 -376
- package/lib/schema/tablecompiler.js +433 -433
- package/lib/schema/viewbuilder.js +92 -92
- package/lib/schema/viewcompiler.js +138 -138
- package/lib/util/finally-mixin.js +13 -13
- package/lib/util/helpers.js +95 -95
- package/lib/util/is.js +32 -32
- package/lib/util/nanoid.js +40 -40
- package/lib/util/noop.js +1 -1
- package/lib/util/save-async-stack.js +14 -14
- package/lib/util/security.js +26 -0
- package/lib/util/string.js +190 -190
- package/lib/util/timeout.js +29 -29
- package/package.json +12 -10
- package/scripts/build.js +125 -125
- package/scripts/clean.js +31 -31
- package/scripts/docker-compose.yml +152 -152
- package/scripts/next-release-howto.md +24 -24
- package/scripts/oracledb-install-driver-libs.sh +82 -82
- package/scripts/release.sh +34 -34
- package/scripts/runkit-example.js +34 -34
- package/scripts/stress-test/README.txt +18 -18
- package/scripts/stress-test/docker-compose.yml +57 -57
- package/scripts/stress-test/knex-stress-test.js +208 -208
- package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +145 -145
- package/scripts/stress-test/mysql2-sudden-exit-without-error.js +100 -100
- package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +184 -184
- package/scripts/update_gitignore_for_tsc_output.js +90 -90
- package/types/index.d.ts +3273 -3233
- package/types/result.d.ts +27 -27
- 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();
|