|
| 1 | +#!/usr/bin/env node |
| 2 | + |
| 3 | +import { readFile, writeFile } from 'node:fs/promises' |
| 4 | +import yargs from 'yargs/yargs' |
| 5 | +import { hideBin } from 'yargs/helpers' |
| 6 | +import { cosmiconfig } from 'cosmiconfig' |
| 7 | +import Confirm from 'prompt-confirm' |
| 8 | +import sqldef from './index.js' |
| 9 | + |
| 10 | +// get a reasonable port |
| 11 | +const getPort = (args) => { |
| 12 | + if (args.port) { |
| 13 | + return args.port |
| 14 | + } |
| 15 | + switch (args.type) { |
| 16 | + case 'mysql': |
| 17 | + return 3306 |
| 18 | + case 'postgres': |
| 19 | + return 5432 |
| 20 | + case 'mssql': |
| 21 | + return 1433 |
| 22 | + } |
| 23 | +} |
| 24 | + |
| 25 | +// get the current structure of database, as text |
| 26 | +async function getStructure({ type, host, database, user, password, socket, port }) { |
| 27 | + console.log({ type, host, database, user, password, socket, port }) |
| 28 | +} |
| 29 | + |
| 30 | +// export the current database as a file |
| 31 | +async function handleExport({ file, type, host, database, user, password, socket, port }) { |
| 32 | + const current = await getStructure({ type, host, database, user, password, socket, port }) |
| 33 | + await writeFile(file, current) |
| 34 | +} |
| 35 | + |
| 36 | +// import database from file (using diff) |
| 37 | +async function handleImport({ newStruct, type, host, database, user, password, socket, port, dry = false }) { |
| 38 | + const current = await getStructure({ type, host, database, user, password, socket, port }) |
| 39 | + if (dry) { |
| 40 | + console.log('dry') |
| 41 | + } |
| 42 | +} |
| 43 | + |
| 44 | +const explorer = cosmiconfig('sqldef') |
| 45 | +const r = (await explorer.search()) || { config: {} } |
| 46 | +const { config = {} } = r |
| 47 | +yargs(hideBin(process.argv)) |
| 48 | + .demandCommand() |
| 49 | + .usage('Usage: $0 <command> [options]') |
| 50 | + .help('?') |
| 51 | + .alias('?', 'help') |
| 52 | + |
| 53 | + .alias('v', 'version') |
| 54 | + .example('$0 export --user=cool --password=mysecret --database=mydatabase', 'Save your current schema, from your mysql database, in schema.sql') |
| 55 | + .example('$0 import --user=cool --password=mysecret --database=mydatabase', 'Update your database to match schema.sql') |
| 56 | + |
| 57 | + .command( |
| 58 | + 'export', |
| 59 | + 'Export your database to a file', |
| 60 | + (a) => {}, |
| 61 | + async (args) => { |
| 62 | + args.port = args.port || getPort(args) |
| 63 | + |
| 64 | + const { file, type, host, database, user, password, socket, port = getPort(args) } = args |
| 65 | + await handleExport({ file, type, host, database, user, password, socket, port, ...config }) |
| 66 | + } |
| 67 | + ) |
| 68 | + |
| 69 | + .command( |
| 70 | + 'import', |
| 71 | + 'Import your database from a file', |
| 72 | + (a) => {}, |
| 73 | + async (args) => { |
| 74 | + const { file, type, host, database, user, password, socket, noConfirm, port = getPort(args) } = args |
| 75 | + const newStruct = await readFile(file) |
| 76 | + if (!noConfirm) { |
| 77 | + await handleImport({ file, type, host, database, user, password, socket, port, ...config, dry: true }) |
| 78 | + const prompt = new Confirm('Do you want to run this?') |
| 79 | + if (!(await prompt.run())) { |
| 80 | + console.error('Export canceled.') |
| 81 | + process.exit(1) |
| 82 | + } |
| 83 | + } |
| 84 | + await handleImport({ newStruct, type, host, database, user, password, socket, port, ...config, dry: false }) |
| 85 | + } |
| 86 | + ) |
| 87 | + |
| 88 | + .option('f', { |
| 89 | + alias: 'file', |
| 90 | + describe: 'The schema file to import/export', |
| 91 | + nargs: 1, |
| 92 | + default: config.file || 'schema.sql' |
| 93 | + }) |
| 94 | + |
| 95 | + .option('t', { |
| 96 | + alias: 'type', |
| 97 | + describe: 'The type of the database', |
| 98 | + nargs: 1, |
| 99 | + default: config.type || 'mysql' |
| 100 | + }) |
| 101 | + |
| 102 | + .option('h', { |
| 103 | + alias: 'host', |
| 104 | + describe: 'The host of the database', |
| 105 | + nargs: 1, |
| 106 | + default: config.host || 'localhost' |
| 107 | + }) |
| 108 | + |
| 109 | + .option('d', { |
| 110 | + alias: 'database', |
| 111 | + describe: 'The name of the database', |
| 112 | + nargs: 1, |
| 113 | + default: config.database || 'test' |
| 114 | + }) |
| 115 | + |
| 116 | + .option('u', { |
| 117 | + alias: 'user', |
| 118 | + describe: 'The user of the database', |
| 119 | + nargs: 1, |
| 120 | + default: config.user || 'root' |
| 121 | + }) |
| 122 | + |
| 123 | + .option('P', { |
| 124 | + alias: 'password', |
| 125 | + describe: 'The password for the database', |
| 126 | + nargs: 1, |
| 127 | + default: config.password || '' |
| 128 | + }) |
| 129 | + |
| 130 | + .option('p', { |
| 131 | + alias: 'port', |
| 132 | + describe: 'The port of the database', |
| 133 | + nargs: 1, |
| 134 | + default: config.port |
| 135 | + }) |
| 136 | + |
| 137 | + .option('s', { |
| 138 | + alias: 'socket', |
| 139 | + describe: 'The socket of the database (only for mysql)', |
| 140 | + nargs: 1, |
| 141 | + default: config.socket |
| 142 | + }) |
| 143 | + |
| 144 | + .option('x', { |
| 145 | + alias: 'no-confirm', |
| 146 | + describe: "Don't confirm before running the import/export", |
| 147 | + type: 'boolean', |
| 148 | + default: config['no-confirm'] |
| 149 | + }).argv |
0 commit comments