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