@prairielearn/postgres-tools 2.0.19 → 2.0.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 CHANGED
@@ -1,5 +1,22 @@
1
1
  # @prairielearn/postgres-tools
2
2
 
3
+ ## 2.0.21
4
+
5
+ ### Patch Changes
6
+
7
+ - 23adb05: Upgrade all JavaScript dependencies
8
+ - Updated dependencies [cd5ed49]
9
+ - Updated dependencies [2c19e43]
10
+ - Updated dependencies [23adb05]
11
+ - @prairielearn/postgres@4.0.0
12
+
13
+ ## 2.0.20
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies [b911b61]
18
+ - @prairielearn/postgres@3.0.0
19
+
3
20
  ## 2.0.19
4
21
 
5
22
  ### Patch Changes
@@ -2,65 +2,33 @@
2
2
  import path from 'path';
3
3
  import async from 'async';
4
4
  import chalk from 'chalk';
5
+ import { Command } from 'commander';
5
6
  import fs from 'fs-extra';
6
- import yargs from 'yargs';
7
7
  import { describeDatabase, formatDatabaseDescription, } from '../describe.js';
8
- const args = yargs(process.argv.slice(2))
9
- .usage('Usage: $0 <database name> [options]')
10
- .demandCommand(1)
11
- .option('output', {
12
- alias: 'o',
13
- nargs: 1,
14
- string: true,
15
- description: 'Specify a directory to output files to',
16
- })
17
- .option('ignore-tables', {
18
- array: true,
19
- description: 'a list of tables to ignore',
20
- })
21
- .option('ignore-enums', {
22
- array: true,
23
- description: 'a list of enums to ignore',
24
- })
25
- .option('ignore-columns', {
26
- array: true,
27
- description: 'a list of columns to ignore, formatted like [table].[column]',
28
- })
29
- .help('h')
30
- .alias('h', 'help')
31
- .example('$0 postgres', 'Describe the "postgres" database')
32
- .example('$0 userdb -o db_description --ignore-tables a b --ignore-columns a.col1 a.col2', 'Describe the "userdb" database; ignore specific tables and columns')
33
- .strict();
34
- const argv = args.parseSync();
35
- if (argv._.length !== 1) {
36
- args.showHelp();
37
- process.exit(1);
8
+ const program = new Command();
9
+ program
10
+ .name('pg-describe')
11
+ .usage('<database name> [options]')
12
+ .argument('<database>', 'Database name to describe')
13
+ .option('-o, --output <dir>', 'Specify a directory to output files to')
14
+ .option('--ignore-tables <tables...>', 'A list of tables to ignore')
15
+ .option('--ignore-enums <enums...>', 'A list of enums to ignore')
16
+ .option('--ignore-columns <columns...>', 'A list of columns to ignore, formatted like [table].[column]')
17
+ .showHelpAfterError();
18
+ program.parse(process.argv);
19
+ const opts = program.opts();
20
+ const dbName = program.args[0];
21
+ if (!dbName) {
22
+ program.help({ error: true });
38
23
  }
39
24
  // Disable color if we're not attached to a tty
40
- const coloredOutput = !argv.output && process.stdout.isTTY;
41
- const options = {
42
- ignoreTables: (argv['ignore-tables'] ?? []).map((table) => table.toString()),
43
- ignoreEnums: (argv['ignore-enums'] ?? []).map((enumName) => enumName.toString()),
44
- ignoreColumns: (argv['ignore-columns'] ?? []).map((column) => column.toString()),
45
- };
25
+ const coloredOutput = !opts.output && process.stdout.isTTY;
46
26
  function formatText(text, formatter) {
47
- if (!argv.output && coloredOutput) {
27
+ if (!opts.output && coloredOutput) {
48
28
  return formatter(text);
49
29
  }
50
30
  return text;
51
31
  }
52
- describeDatabase(argv._[0].toString(), options).then(async (description) => {
53
- if (argv.output) {
54
- await writeDescriptionToDisk(description, argv.output);
55
- }
56
- else {
57
- printDescription(description);
58
- }
59
- process.exit(0);
60
- }, (err) => {
61
- console.error(err);
62
- process.exit(1);
63
- });
64
32
  function printDescription(description) {
65
33
  const formattedDescription = formatDatabaseDescription(description, { coloredOutput });
66
34
  for (const tableName of Object.keys(formattedDescription.tables).sort()) {
@@ -87,4 +55,20 @@ async function writeDescriptionToDisk(description, dir) {
87
55
  await fs.writeFile(path.join(dir, 'enums', `${key}.pg`), value);
88
56
  });
89
57
  }
58
+ function parseListOption(option) {
59
+ return option.flatMap((item) => item.split(',').map((part) => part.trim()));
60
+ }
61
+ const options = {
62
+ ignoreTables: parseListOption(opts.ignoreTables ?? []),
63
+ ignoreEnums: parseListOption(opts.ignoreEnums ?? []),
64
+ ignoreColumns: parseListOption(opts.ignoreColumns ?? []),
65
+ };
66
+ const description = await describeDatabase(dbName, options);
67
+ if (opts.output) {
68
+ await writeDescriptionToDisk(description, opts.output);
69
+ }
70
+ else {
71
+ printDescription(description);
72
+ }
73
+ process.exit(0);
90
74
  //# sourceMappingURL=pg-describe.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pg-describe.js","sourceRoot":"","sources":["../../src/bin/pg-describe.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n\nimport path from 'path';\n\nimport async from 'async';\nimport chalk from 'chalk';\nimport fs from 'fs-extra';\nimport yargs from 'yargs';\n\nimport {\n type DatabaseDescription,\n describeDatabase,\n formatDatabaseDescription,\n} from '../describe.js';\n\nconst args = yargs(process.argv.slice(2))\n .usage('Usage: $0 <database name> [options]')\n .demandCommand(1)\n .option('output', {\n alias: 'o',\n nargs: 1,\n string: true,\n description: 'Specify a directory to output files to',\n })\n .option('ignore-tables', {\n array: true,\n description: 'a list of tables to ignore',\n })\n .option('ignore-enums', {\n array: true,\n description: 'a list of enums to ignore',\n })\n .option('ignore-columns', {\n array: true,\n description: 'a list of columns to ignore, formatted like [table].[column]',\n })\n .help('h')\n .alias('h', 'help')\n .example('$0 postgres', 'Describe the \"postgres\" database')\n .example(\n '$0 userdb -o db_description --ignore-tables a b --ignore-columns a.col1 a.col2',\n 'Describe the \"userdb\" database; ignore specific tables and columns',\n )\n .strict();\n\nconst argv = args.parseSync();\n\nif (argv._.length !== 1) {\n args.showHelp();\n process.exit(1);\n}\n\n// Disable color if we're not attached to a tty\nconst coloredOutput = !argv.output && process.stdout.isTTY;\n\nconst options = {\n ignoreTables: (argv['ignore-tables'] ?? []).map((table) => table.toString()),\n ignoreEnums: (argv['ignore-enums'] ?? []).map((enumName) => enumName.toString()),\n ignoreColumns: (argv['ignore-columns'] ?? []).map((column) => column.toString()),\n};\n\nfunction formatText(text: string, formatter: (text: string) => string) {\n if (!argv.output && coloredOutput) {\n return formatter(text);\n }\n return text;\n}\n\ndescribeDatabase(argv._[0].toString(), options).then(\n async (description) => {\n if (argv.output) {\n await writeDescriptionToDisk(description, argv.output);\n } else {\n printDescription(description);\n }\n process.exit(0);\n },\n (err) => {\n console.error(err);\n process.exit(1);\n },\n);\n\nfunction printDescription(description: DatabaseDescription) {\n const formattedDescription = formatDatabaseDescription(description, { coloredOutput });\n for (const tableName of Object.keys(formattedDescription.tables).sort()) {\n process.stdout.write(formatText(`[table] ${tableName}\\n`, chalk.bold));\n process.stdout.write(formattedDescription.tables[tableName]);\n process.stdout.write('\\n\\n');\n }\n\n for (const enumName of Object.keys(formattedDescription.enums).sort()) {\n process.stdout.write(formatText(`[enum] ${enumName}\\n`, chalk.bold));\n process.stdout.write(formattedDescription.enums[enumName]);\n process.stdout.write('\\n\\n');\n }\n}\n\nasync function writeDescriptionToDisk(description: DatabaseDescription, dir: string) {\n const formattedDescription = formatDatabaseDescription(description, { coloredOutput: false });\n await fs.ensureDir(path.join(dir, 'tables'));\n await fs.ensureDir(path.join(dir, 'enums'));\n await fs.emptyDir(path.join(dir, 'tables'));\n await fs.emptyDir(path.join(dir, 'enums'));\n await async.eachOf(formattedDescription.tables, async (value, key) => {\n await fs.writeFile(path.join(dir, 'tables', `${key}.pg`), value);\n });\n await async.eachOf(formattedDescription.enums, async (value, key) => {\n await fs.writeFile(path.join(dir, 'enums', `${key}.pg`), value);\n });\n}\n"]}
1
+ {"version":3,"file":"pg-describe.js","sourceRoot":"","sources":["../../src/bin/pg-describe.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n\nimport path from 'path';\n\nimport async from 'async';\nimport chalk from 'chalk';\nimport { Command } from 'commander';\nimport fs from 'fs-extra';\n\nimport {\n type DatabaseDescription,\n describeDatabase,\n formatDatabaseDescription,\n} from '../describe.js';\n\nconst program = new Command();\nprogram\n .name('pg-describe')\n .usage('<database name> [options]')\n .argument('<database>', 'Database name to describe')\n .option('-o, --output <dir>', 'Specify a directory to output files to')\n .option('--ignore-tables <tables...>', 'A list of tables to ignore')\n .option('--ignore-enums <enums...>', 'A list of enums to ignore')\n .option(\n '--ignore-columns <columns...>',\n 'A list of columns to ignore, formatted like [table].[column]',\n )\n .showHelpAfterError();\n\nprogram.parse(process.argv);\nconst opts = program.opts();\nconst dbName = program.args[0];\n\nif (!dbName) {\n program.help({ error: true });\n}\n\n// Disable color if we're not attached to a tty\nconst coloredOutput = !opts.output && process.stdout.isTTY;\n\nfunction formatText(text: string, formatter: (text: string) => string) {\n if (!opts.output && coloredOutput) {\n return formatter(text);\n }\n return text;\n}\n\nfunction printDescription(description: DatabaseDescription) {\n const formattedDescription = formatDatabaseDescription(description, { coloredOutput });\n for (const tableName of Object.keys(formattedDescription.tables).sort()) {\n process.stdout.write(formatText(`[table] ${tableName}\\n`, chalk.bold));\n process.stdout.write(formattedDescription.tables[tableName]);\n process.stdout.write('\\n\\n');\n }\n\n for (const enumName of Object.keys(formattedDescription.enums).sort()) {\n process.stdout.write(formatText(`[enum] ${enumName}\\n`, chalk.bold));\n process.stdout.write(formattedDescription.enums[enumName]);\n process.stdout.write('\\n\\n');\n }\n}\n\nasync function writeDescriptionToDisk(description: DatabaseDescription, dir: string) {\n const formattedDescription = formatDatabaseDescription(description, { coloredOutput: false });\n await fs.ensureDir(path.join(dir, 'tables'));\n await fs.ensureDir(path.join(dir, 'enums'));\n await fs.emptyDir(path.join(dir, 'tables'));\n await fs.emptyDir(path.join(dir, 'enums'));\n await async.eachOf(formattedDescription.tables, async (value, key) => {\n await fs.writeFile(path.join(dir, 'tables', `${key}.pg`), value);\n });\n await async.eachOf(formattedDescription.enums, async (value, key) => {\n await fs.writeFile(path.join(dir, 'enums', `${key}.pg`), value);\n });\n}\n\nfunction parseListOption(option: string[]): string[] {\n return option.flatMap((item: string) => item.split(',').map((part) => part.trim()));\n}\n\nconst options = {\n ignoreTables: parseListOption(opts.ignoreTables ?? []),\n ignoreEnums: parseListOption(opts.ignoreEnums ?? []),\n ignoreColumns: parseListOption(opts.ignoreColumns ?? []),\n};\n\nconst description = await describeDatabase(dbName, options);\nif (opts.output) {\n await writeDescriptionToDisk(description, opts.output);\n} else {\n printDescription(description);\n}\nprocess.exit(0);\n"]}
@@ -1,42 +1,36 @@
1
1
  #!/usr/bin/env node
2
- import yargs from 'yargs';
2
+ import { Command } from 'commander';
3
3
  import { diffDatabaseAndDirectory, diffDatabases, diffDirectories, diffDirectoryAndDatabase, } from '../diff.js';
4
- const args = yargs(process.argv.slice(2))
5
- .usage('Usage: $0 [options]')
6
- .option('db', {
7
- description: 'reads a description from the named database',
8
- })
9
- .option('dir', {
10
- description: "reads a description from a directory that's been generated by pg-describe",
11
- })
12
- .help('h')
13
- .alias('h', 'help')
14
- .example('$0 --db postgres --dir db_dump', 'Diffs the database "postgres" with the description in the directory "db_dump"')
15
- .example('$0 --db postgres --db old_restore', 'Diffs the database "postgres" with the database "old_restore"')
16
- .strict();
17
- const argv = args.parseSync();
4
+ const program = new Command();
5
+ program
6
+ .name('pg-diff')
7
+ .usage('[options]')
8
+ .option('--db <db...>', 'Reads a description from the named database (can be specified twice)')
9
+ .option('--dir <dir...>', "Reads a description from a directory that's been generated by pg-describe (can be specified twice)")
10
+ .showHelpAfterError();
11
+ program.parse(process.argv);
12
+ const opts = program.opts();
18
13
  const options = {
19
14
  outputFormat: 'string',
20
15
  coloredOutput: process.stdout.isTTY,
21
16
  };
22
- if (argv.db && typeof argv.db === 'string' && argv.dir && typeof argv.dir === 'string') {
23
- // Ensure correct ordering for the sake of diffs
24
- if (process.argv.indexOf('--db') < process.argv.indexOf('--dir')) {
25
- diffDatabaseAndDirectory(argv.db, argv.dir, options).then(handleResults, handleError);
17
+ if (opts.db.length === 2 && !opts.dir) {
18
+ diffDatabases(opts.db[0], opts.db[1], options).then(handleResults, handleError);
19
+ }
20
+ else if (opts.dir.length === 2 && !opts.db) {
21
+ diffDirectories(opts.dir[0], opts.dir[1], options).then(handleResults, handleError);
22
+ }
23
+ else if (opts.db.length === 1 && opts.dir.length === 1) {
24
+ const dbIsFirst = process.argv.lastIndexOf('--db') < process.argv.lastIndexOf('--dir');
25
+ if (dbIsFirst) {
26
+ diffDatabaseAndDirectory(opts.db[0], opts.dir[0], options).then(handleResults, handleError);
26
27
  }
27
28
  else {
28
- diffDirectoryAndDatabase(argv.dir, argv.db, options).then(handleResults, handleError);
29
+ diffDirectoryAndDatabase(opts.dir[0], opts.db[0], options).then(handleResults, handleError);
29
30
  }
30
31
  }
31
- else if (argv.db && Array.isArray(argv.db) && argv.db.length === 2 && !argv.dir) {
32
- diffDatabases(argv.db[0], argv.db[1], options).then(handleResults, handleError);
33
- }
34
- else if (argv.dir && Array.isArray(argv.dir) && argv.dir.length === 2 && !argv.db) {
35
- diffDirectories(argv.dir[0], argv.dir[1], options).then(handleResults, handleError);
36
- }
37
32
  else {
38
- args.showHelp();
39
- process.exit(1);
33
+ program.help({ error: true });
40
34
  }
41
35
  function handleResults(results) {
42
36
  process.stdout.write(results);
@@ -1 +1 @@
1
- {"version":3,"file":"pg-diff.js","sourceRoot":"","sources":["../../src/bin/pg-diff.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n\nimport yargs from 'yargs';\n\nimport {\n diffDatabaseAndDirectory,\n diffDatabases,\n diffDirectories,\n diffDirectoryAndDatabase,\n} from '../diff.js';\n\nconst args = yargs(process.argv.slice(2))\n .usage('Usage: $0 [options]')\n .option('db', {\n description: 'reads a description from the named database',\n })\n .option('dir', {\n description: \"reads a description from a directory that's been generated by pg-describe\",\n })\n .help('h')\n .alias('h', 'help')\n .example(\n '$0 --db postgres --dir db_dump',\n 'Diffs the database \"postgres\" with the description in the directory \"db_dump\"',\n )\n .example(\n '$0 --db postgres --db old_restore',\n 'Diffs the database \"postgres\" with the database \"old_restore\"',\n )\n .strict();\n\nconst argv = args.parseSync();\n\nconst options = {\n outputFormat: 'string',\n coloredOutput: process.stdout.isTTY,\n};\n\nif (argv.db && typeof argv.db === 'string' && argv.dir && typeof argv.dir === 'string') {\n // Ensure correct ordering for the sake of diffs\n if (process.argv.indexOf('--db') < process.argv.indexOf('--dir')) {\n diffDatabaseAndDirectory(argv.db, argv.dir, options).then(handleResults, handleError);\n } else {\n diffDirectoryAndDatabase(argv.dir, argv.db, options).then(handleResults, handleError);\n }\n} else if (argv.db && Array.isArray(argv.db) && argv.db.length === 2 && !argv.dir) {\n diffDatabases(argv.db[0], argv.db[1], options).then(handleResults, handleError);\n} else if (argv.dir && Array.isArray(argv.dir) && argv.dir.length === 2 && !argv.db) {\n diffDirectories(argv.dir[0], argv.dir[1], options).then(handleResults, handleError);\n} else {\n args.showHelp();\n process.exit(1);\n}\n\nfunction handleResults(results: string) {\n process.stdout.write(results);\n process.exit(0);\n}\n\nfunction handleError(err: any) {\n console.error(err);\n process.exit(1);\n}\n"]}
1
+ {"version":3,"file":"pg-diff.js","sourceRoot":"","sources":["../../src/bin/pg-diff.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EACL,wBAAwB,EACxB,aAAa,EACb,eAAe,EACf,wBAAwB,GACzB,MAAM,YAAY,CAAC;AAEpB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAC9B,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,KAAK,CAAC,WAAW,CAAC;KAClB,MAAM,CAAC,cAAc,EAAE,sEAAsE,CAAC;KAC9F,MAAM,CACL,gBAAgB,EAChB,oGAAoG,CACrG;KACA,kBAAkB,EAAE,CAAC;AAExB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;AAE5B,MAAM,OAAO,GAAG;IACd,YAAY,EAAE,QAAQ;IACtB,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK;CACpC,CAAC;AAEF,IAAI,IAAI,CAAC,EAAE,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;IACtC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;AAClF,CAAC;KAAM,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;IAC7C,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;AACtF,CAAC;KAAM,IAAI,IAAI,CAAC,EAAE,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;IACzD,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACvF,IAAI,SAAS,EAAE,CAAC;QACd,wBAAwB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IAC9F,CAAC;SAAM,CAAC;QACN,wBAAwB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IAC9F,CAAC;AACH,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,aAAa,CAAC,OAAe;IACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,WAAW,CAAC,GAAQ;IAC3B,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC","sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\n\nimport {\n diffDatabaseAndDirectory,\n diffDatabases,\n diffDirectories,\n diffDirectoryAndDatabase,\n} from '../diff.js';\n\nconst program = new Command();\nprogram\n .name('pg-diff')\n .usage('[options]')\n .option('--db <db...>', 'Reads a description from the named database (can be specified twice)')\n .option(\n '--dir <dir...>',\n \"Reads a description from a directory that's been generated by pg-describe (can be specified twice)\",\n )\n .showHelpAfterError();\n\nprogram.parse(process.argv);\nconst opts = program.opts();\n\nconst options = {\n outputFormat: 'string',\n coloredOutput: process.stdout.isTTY,\n};\n\nif (opts.db.length === 2 && !opts.dir) {\n diffDatabases(opts.db[0], opts.db[1], options).then(handleResults, handleError);\n} else if (opts.dir.length === 2 && !opts.db) {\n diffDirectories(opts.dir[0], opts.dir[1], options).then(handleResults, handleError);\n} else if (opts.db.length === 1 && opts.dir.length === 1) {\n const dbIsFirst = process.argv.lastIndexOf('--db') < process.argv.lastIndexOf('--dir');\n if (dbIsFirst) {\n diffDatabaseAndDirectory(opts.db[0], opts.dir[0], options).then(handleResults, handleError);\n } else {\n diffDirectoryAndDatabase(opts.dir[0], opts.db[0], options).then(handleResults, handleError);\n }\n} else {\n program.help({ error: true });\n}\n\nfunction handleResults(results: string) {\n process.stdout.write(results);\n process.exit(0);\n}\n\nfunction handleError(err: any) {\n console.error(err);\n process.exit(1);\n}\n"]}
package/dist/describe.js CHANGED
@@ -42,9 +42,7 @@ async function describeWithPool(pool, options) {
42
42
  const indexResults = await pool.queryAsync(sql.get_indexes_for_table, {
43
43
  oid: table.oid,
44
44
  });
45
- const foreignKeyConstraintResults = await pool.queryAsync(sql.get_foreign_key_constraints_for_table, {
46
- oid: table.oid,
47
- });
45
+ const foreignKeyConstraintResults = await pool.queryAsync(sql.get_foreign_key_constraints_for_table, { oid: table.oid });
48
46
  const referenceResults = await pool.queryAsync(sql.get_references_for_table, {
49
47
  oid: table.oid,
50
48
  });
@@ -1 +1 @@
1
- {"version":3,"file":"describe.js","sourceRoot":"","sources":["../src/describe.ts"],"names":[],"mappings":"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","sourcesContent":["import chalk from 'chalk';\nimport { parse as parsePostgresArray } from 'postgres-array';\n\nimport { PostgresPool, loadSqlEquiv } from '@prairielearn/postgres';\n\nconst sql = loadSqlEquiv(import.meta.url);\n\ninterface ColumnDescription {\n name: string;\n type: string;\n notnull: boolean;\n default: any;\n}\n\ninterface IndexDescription {\n name: string;\n isprimary: boolean;\n isunique: boolean;\n indexdef: string;\n constraintdef: string;\n contype: string;\n}\n\ninterface ForeignKeyConstraintDescription {\n name: string;\n def: string;\n}\n\ninterface ReferenceDescription {\n name: string;\n table: string;\n condef: string;\n}\n\ninterface CheckConstraintDescription {\n name: string;\n def: string;\n}\n\ninterface TableDescription {\n columns: ColumnDescription[];\n indexes: IndexDescription[];\n foreignKeyConstraints: ForeignKeyConstraintDescription[];\n references: ReferenceDescription[];\n checkConstraints: CheckConstraintDescription[];\n}\n\nexport interface DatabaseDescription {\n tables: Record<string, TableDescription>;\n enums: Record<string, string[]>;\n}\n\ninterface DescribeOptions {\n ignoreTables?: string[];\n ignoreColumns?: string[];\n ignoreEnums?: string[];\n}\n\nasync function describeWithPool(\n pool: PostgresPool,\n options: DescribeOptions,\n): Promise<DatabaseDescription> {\n const ignoreTables = options?.ignoreTables || [];\n const ignoreEnums = options?.ignoreEnums || [];\n let ignoreColumns: Record<string, string[]> = {};\n\n const output: DatabaseDescription = {\n tables: {},\n enums: {},\n };\n\n // Get the names of the tables and filter out any ignored tables\n const tablesRes = await pool.queryAsync(sql.get_tables, []);\n const tables = tablesRes.rows.filter((table) => ignoreTables.indexOf(table.name) === -1);\n\n // Transform ignored columns into a map from table names to arrays\n // of column names\n if (options.ignoreColumns && Array.isArray(options.ignoreColumns)) {\n ignoreColumns = options.ignoreColumns\n .filter((ignore) => {\n return /^[^\\s.]*\\.[^\\s.]*$/.test(ignore);\n })\n .reduce(\n (result, value) => {\n const res = /^(([^\\s.]*)\\.([^\\s.]*))$/.exec(value);\n if (!res) {\n throw new Error(`Invalid ignore column: ${value}`);\n }\n const table = res[2];\n const column = res[3];\n (result[table] || (result[table] = [])).push(column);\n return result;\n },\n {} as Record<string, string[]>,\n );\n }\n\n // Get column info for each table\n for (const table of tables) {\n const columnResults = await pool.queryAsync(sql.get_columns_for_table, {\n oid: table.oid,\n });\n\n const columns = columnResults.rows.filter((row) => {\n return (ignoreColumns[table.name] || []).indexOf(row.name) === -1;\n });\n\n const indexResults = await pool.queryAsync(sql.get_indexes_for_table, {\n oid: table.oid,\n });\n\n const foreignKeyConstraintResults = await pool.queryAsync(\n sql.get_foreign_key_constraints_for_table,\n {\n oid: table.oid,\n },\n );\n\n const referenceResults = await pool.queryAsync(sql.get_references_for_table, {\n oid: table.oid,\n });\n\n // Filter out references from ignored tables\n const references = referenceResults.rows.filter((row) => {\n return ignoreTables.indexOf(row.table) === -1;\n });\n\n const checkConstraintResults = await pool.queryAsync(sql.get_check_constraints_for_table, {\n oid: table.oid,\n });\n\n output.tables[table.name] = {\n columns,\n indexes: indexResults.rows,\n foreignKeyConstraints: foreignKeyConstraintResults.rows,\n references,\n checkConstraints: checkConstraintResults.rows,\n };\n }\n\n // Get all enums\n const enumsRes = await pool.queryAsync(sql.get_enums, []);\n\n // Filter ignored enums\n const rows = enumsRes.rows.filter((row) => {\n return ignoreEnums.indexOf(row.name) === -1;\n });\n\n rows.forEach((row) => {\n output.enums[row.name] = parsePostgresArray(row.values);\n });\n\n return output;\n}\n\n/**\n * Will produce a description of a given database's schema. This will include\n * information about tables, enums, constraints, indices, etc.\n */\nexport async function describeDatabase(\n databaseName: string,\n options: DescribeOptions = {},\n): Promise<DatabaseDescription> {\n // Connect to the database.\n const pool = new PostgresPool();\n const pgConfig = {\n user: 'postgres',\n database: databaseName,\n host: 'localhost',\n max: 10,\n idleTimeoutMillis: 30000,\n };\n function idleErrorHandler(err: Error) {\n throw err;\n }\n await pool.initAsync(pgConfig, idleErrorHandler);\n\n try {\n return await describeWithPool(pool, options);\n } finally {\n await pool.closeAsync();\n }\n}\n\nexport function formatDatabaseDescription(\n description: DatabaseDescription,\n options = { coloredOutput: true },\n): { tables: Record<string, string>; enums: Record<string, string> } {\n const output = {\n tables: {} as Record<string, string>,\n enums: {} as Record<string, string>,\n };\n\n Object.keys(description.tables).forEach((tableName) => (output.tables[tableName] = ''));\n\n /**\n * Optionally applies the given formatter to the text if colored output is\n * enabled.\n */\n function formatText(text: string, formatter: (s: string) => string): string {\n if (options.coloredOutput) {\n return formatter(text);\n }\n return text;\n }\n\n Object.entries(description.tables).forEach(([tableName, table]) => {\n if (table.columns.length > 0) {\n output.tables[tableName] += formatText('columns\\n', chalk.underline);\n output.tables[tableName] += table.columns\n .map((row) => {\n let rowText = formatText(` ${row.name}`, chalk.bold);\n rowText += ':' + formatText(` ${row.type}`, chalk.green);\n if (row.notnull) {\n rowText += formatText(' not null', chalk.gray);\n }\n if (row.default) {\n rowText += formatText(` default ${row.default}`, chalk.gray);\n }\n return rowText;\n })\n .join('\\n');\n }\n\n if (table.indexes.length > 0) {\n if (output.tables[tableName].length !== 0) {\n output.tables[tableName] += '\\n\\n';\n }\n output.tables[tableName] += formatText('indexes\\n', chalk.underline);\n output.tables[tableName] += table.indexes\n .map((row) => {\n const using = row.indexdef.substring(row.indexdef.indexOf('USING '));\n let rowText = formatText(` ${row.name}`, chalk.bold) + ':';\n // Primary indexes are implicitly unique, so we don't need to\n // capture that explicitly.\n if (row.isunique && !row.isprimary) {\n if (!row.constraintdef || row.constraintdef.indexOf('UNIQUE') === -1) {\n // Some unique indexes don't include the UNIQUE constraint\n // as part of the constraint definition, so we need to capture\n // that manually.\n rowText += formatText(' UNIQUE', chalk.green);\n }\n }\n rowText += row.constraintdef ? formatText(` ${row.constraintdef}`, chalk.green) : '';\n rowText += using ? formatText(` ${using}`, chalk.green) : '';\n return rowText;\n })\n .join('\\n');\n }\n\n if (table.checkConstraints.length > 0) {\n if (output.tables[tableName].length !== 0) {\n output.tables[tableName] += '\\n\\n';\n }\n output.tables[tableName] += formatText('check constraints\\n', chalk.underline);\n output.tables[tableName] += table.checkConstraints\n .map((row) => {\n // Particularly long constraints are formatted as multiple lines.\n // We'll collapse them into a single line for better appearance in\n // the resulting file.\n //\n // The first replace handles lines that end with a parenthesis: we\n // want to avoid spaces between the parenthesis and the next token.\n //\n // The second replace handles all other lines: we want to collapse\n // all leading whitespace into a single space.\n const def = row.def.replace(/\\(\\n/g, '(').replace(/\\n\\s*/g, ' ');\n\n let rowText = formatText(` ${row.name}:`, chalk.bold);\n rowText += formatText(` ${def}`, chalk.green);\n return rowText;\n })\n .join('\\n');\n }\n\n if (table.foreignKeyConstraints.length > 0) {\n if (output.tables[tableName].length !== 0) {\n output.tables[tableName] += '\\n\\n';\n }\n output.tables[tableName] += formatText('foreign-key constraints\\n', chalk.underline);\n output.tables[tableName] += table.foreignKeyConstraints\n .map((row) => {\n let rowText = formatText(` ${row.name}:`, chalk.bold);\n rowText += formatText(` ${row.def}`, chalk.green);\n return rowText;\n })\n .join('\\n');\n }\n\n if (table.references.length > 0) {\n if (output.tables[tableName].length !== 0) {\n output.tables[tableName] += '\\n\\n';\n }\n output.tables[tableName] += formatText('referenced by\\n', chalk.underline);\n output.tables[tableName] += table.references\n ?.map((row) => {\n let rowText = formatText(` ${row.table}:`, chalk.bold);\n rowText += formatText(` ${row.condef}`, chalk.green);\n return rowText;\n })\n .join('\\n');\n }\n });\n\n Object.entries(description.enums).forEach(([enumName, enumValues]) => {\n output.enums[enumName] = formatText(enumValues.join(', '), chalk.gray);\n });\n\n // We need to tack on a newline to everything.\n Object.entries(output.tables).forEach(([tableName, table]) => {\n output.tables[tableName] = table + '\\n';\n });\n Object.entries(output.enums).forEach(([enumName, enumValues]) => {\n output.enums[enumName] = enumValues + '\\n';\n });\n\n return output;\n}\n"]}
1
+ {"version":3,"file":"describe.js","sourceRoot":"","sources":["../src/describe.ts"],"names":[],"mappings":"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","sourcesContent":["import chalk from 'chalk';\nimport { parse as parsePostgresArray } from 'postgres-array';\n\nimport { PostgresPool, loadSqlEquiv } from '@prairielearn/postgres';\n\nconst sql = loadSqlEquiv(import.meta.url);\n\ninterface ColumnDescription {\n name: string;\n type: string;\n notnull: boolean;\n default: any;\n}\n\ninterface IndexDescription {\n name: string;\n isprimary: boolean;\n isunique: boolean;\n indexdef: string;\n constraintdef: string;\n contype: string;\n}\n\ninterface ForeignKeyConstraintDescription {\n name: string;\n def: string;\n}\n\ninterface ReferenceDescription {\n name: string;\n table: string;\n condef: string;\n}\n\ninterface CheckConstraintDescription {\n name: string;\n def: string;\n}\n\ninterface TableDescription {\n columns: ColumnDescription[];\n indexes: IndexDescription[];\n foreignKeyConstraints: ForeignKeyConstraintDescription[];\n references: ReferenceDescription[];\n checkConstraints: CheckConstraintDescription[];\n}\n\nexport interface DatabaseDescription {\n tables: Record<string, TableDescription>;\n enums: Record<string, string[]>;\n}\n\ninterface DescribeOptions {\n ignoreTables?: string[];\n ignoreColumns?: string[];\n ignoreEnums?: string[];\n}\n\nasync function describeWithPool(\n pool: PostgresPool,\n options: DescribeOptions,\n): Promise<DatabaseDescription> {\n const ignoreTables = options?.ignoreTables || [];\n const ignoreEnums = options?.ignoreEnums || [];\n let ignoreColumns: Record<string, string[]> = {};\n\n const output: DatabaseDescription = {\n tables: {},\n enums: {},\n };\n\n // Get the names of the tables and filter out any ignored tables\n const tablesRes = await pool.queryAsync(sql.get_tables, []);\n const tables = tablesRes.rows.filter((table) => ignoreTables.indexOf(table.name) === -1);\n\n // Transform ignored columns into a map from table names to arrays\n // of column names\n if (options.ignoreColumns && Array.isArray(options.ignoreColumns)) {\n ignoreColumns = options.ignoreColumns\n .filter((ignore) => {\n return /^[^\\s.]*\\.[^\\s.]*$/.test(ignore);\n })\n .reduce(\n (result, value) => {\n const res = /^(([^\\s.]*)\\.([^\\s.]*))$/.exec(value);\n if (!res) {\n throw new Error(`Invalid ignore column: ${value}`);\n }\n const table = res[2];\n const column = res[3];\n (result[table] || (result[table] = [])).push(column);\n return result;\n },\n {} as Record<string, string[]>,\n );\n }\n\n // Get column info for each table\n for (const table of tables) {\n const columnResults = await pool.queryAsync(sql.get_columns_for_table, {\n oid: table.oid,\n });\n\n const columns = columnResults.rows.filter((row) => {\n return (ignoreColumns[table.name] || []).indexOf(row.name) === -1;\n });\n\n const indexResults = await pool.queryAsync(sql.get_indexes_for_table, {\n oid: table.oid,\n });\n\n const foreignKeyConstraintResults = await pool.queryAsync(\n sql.get_foreign_key_constraints_for_table,\n { oid: table.oid },\n );\n\n const referenceResults = await pool.queryAsync(sql.get_references_for_table, {\n oid: table.oid,\n });\n\n // Filter out references from ignored tables\n const references = referenceResults.rows.filter((row) => {\n return ignoreTables.indexOf(row.table) === -1;\n });\n\n const checkConstraintResults = await pool.queryAsync(sql.get_check_constraints_for_table, {\n oid: table.oid,\n });\n\n output.tables[table.name] = {\n columns,\n indexes: indexResults.rows,\n foreignKeyConstraints: foreignKeyConstraintResults.rows,\n references,\n checkConstraints: checkConstraintResults.rows,\n };\n }\n\n // Get all enums\n const enumsRes = await pool.queryAsync(sql.get_enums, []);\n\n // Filter ignored enums\n const rows = enumsRes.rows.filter((row) => {\n return ignoreEnums.indexOf(row.name) === -1;\n });\n\n rows.forEach((row) => {\n output.enums[row.name] = parsePostgresArray(row.values);\n });\n\n return output;\n}\n\n/**\n * Will produce a description of a given database's schema. This will include\n * information about tables, enums, constraints, indices, etc.\n */\nexport async function describeDatabase(\n databaseName: string,\n options: DescribeOptions = {},\n): Promise<DatabaseDescription> {\n // Connect to the database.\n const pool = new PostgresPool();\n const pgConfig = {\n user: 'postgres',\n database: databaseName,\n host: 'localhost',\n max: 10,\n idleTimeoutMillis: 30000,\n };\n function idleErrorHandler(err: Error) {\n throw err;\n }\n await pool.initAsync(pgConfig, idleErrorHandler);\n\n try {\n return await describeWithPool(pool, options);\n } finally {\n await pool.closeAsync();\n }\n}\n\nexport function formatDatabaseDescription(\n description: DatabaseDescription,\n options = { coloredOutput: true },\n): { tables: Record<string, string>; enums: Record<string, string> } {\n const output = {\n tables: {} as Record<string, string>,\n enums: {} as Record<string, string>,\n };\n\n Object.keys(description.tables).forEach((tableName) => (output.tables[tableName] = ''));\n\n /**\n * Optionally applies the given formatter to the text if colored output is\n * enabled.\n */\n function formatText(text: string, formatter: (s: string) => string): string {\n if (options.coloredOutput) {\n return formatter(text);\n }\n return text;\n }\n\n Object.entries(description.tables).forEach(([tableName, table]) => {\n if (table.columns.length > 0) {\n output.tables[tableName] += formatText('columns\\n', chalk.underline);\n output.tables[tableName] += table.columns\n .map((row) => {\n let rowText = formatText(` ${row.name}`, chalk.bold);\n rowText += ':' + formatText(` ${row.type}`, chalk.green);\n if (row.notnull) {\n rowText += formatText(' not null', chalk.gray);\n }\n if (row.default) {\n rowText += formatText(` default ${row.default}`, chalk.gray);\n }\n return rowText;\n })\n .join('\\n');\n }\n\n if (table.indexes.length > 0) {\n if (output.tables[tableName].length !== 0) {\n output.tables[tableName] += '\\n\\n';\n }\n output.tables[tableName] += formatText('indexes\\n', chalk.underline);\n output.tables[tableName] += table.indexes\n .map((row) => {\n const using = row.indexdef.substring(row.indexdef.indexOf('USING '));\n let rowText = formatText(` ${row.name}`, chalk.bold) + ':';\n // Primary indexes are implicitly unique, so we don't need to\n // capture that explicitly.\n if (row.isunique && !row.isprimary) {\n if (!row.constraintdef || row.constraintdef.indexOf('UNIQUE') === -1) {\n // Some unique indexes don't include the UNIQUE constraint\n // as part of the constraint definition, so we need to capture\n // that manually.\n rowText += formatText(' UNIQUE', chalk.green);\n }\n }\n rowText += row.constraintdef ? formatText(` ${row.constraintdef}`, chalk.green) : '';\n rowText += using ? formatText(` ${using}`, chalk.green) : '';\n return rowText;\n })\n .join('\\n');\n }\n\n if (table.checkConstraints.length > 0) {\n if (output.tables[tableName].length !== 0) {\n output.tables[tableName] += '\\n\\n';\n }\n output.tables[tableName] += formatText('check constraints\\n', chalk.underline);\n output.tables[tableName] += table.checkConstraints\n .map((row) => {\n // Particularly long constraints are formatted as multiple lines.\n // We'll collapse them into a single line for better appearance in\n // the resulting file.\n //\n // The first replace handles lines that end with a parenthesis: we\n // want to avoid spaces between the parenthesis and the next token.\n //\n // The second replace handles all other lines: we want to collapse\n // all leading whitespace into a single space.\n const def = row.def.replace(/\\(\\n/g, '(').replace(/\\n\\s*/g, ' ');\n\n let rowText = formatText(` ${row.name}:`, chalk.bold);\n rowText += formatText(` ${def}`, chalk.green);\n return rowText;\n })\n .join('\\n');\n }\n\n if (table.foreignKeyConstraints.length > 0) {\n if (output.tables[tableName].length !== 0) {\n output.tables[tableName] += '\\n\\n';\n }\n output.tables[tableName] += formatText('foreign-key constraints\\n', chalk.underline);\n output.tables[tableName] += table.foreignKeyConstraints\n .map((row) => {\n let rowText = formatText(` ${row.name}:`, chalk.bold);\n rowText += formatText(` ${row.def}`, chalk.green);\n return rowText;\n })\n .join('\\n');\n }\n\n if (table.references.length > 0) {\n if (output.tables[tableName].length !== 0) {\n output.tables[tableName] += '\\n\\n';\n }\n output.tables[tableName] += formatText('referenced by\\n', chalk.underline);\n output.tables[tableName] += table.references\n ?.map((row) => {\n let rowText = formatText(` ${row.table}:`, chalk.bold);\n rowText += formatText(` ${row.condef}`, chalk.green);\n return rowText;\n })\n .join('\\n');\n }\n });\n\n Object.entries(description.enums).forEach(([enumName, enumValues]) => {\n output.enums[enumName] = formatText(enumValues.join(', '), chalk.gray);\n });\n\n // We need to tack on a newline to everything.\n Object.entries(output.tables).forEach(([tableName, table]) => {\n output.tables[tableName] = table + '\\n';\n });\n Object.entries(output.enums).forEach(([enumName, enumValues]) => {\n output.enums[enumName] = enumValues + '\\n';\n });\n\n return output;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prairielearn/postgres-tools",
3
- "version": "2.0.19",
3
+ "version": "2.0.21",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -17,21 +17,20 @@
17
17
  "dev": "tsc --watch --preserveWatchOutput & tscp --watch"
18
18
  },
19
19
  "dependencies": {
20
- "@prairielearn/postgres": "^2.1.15",
20
+ "@prairielearn/postgres": "^4.0.0",
21
21
  "async": "^3.2.6",
22
22
  "chalk": "^5.4.1",
23
+ "commander": "^14.0.0",
23
24
  "diff": "^8.0.2",
24
25
  "fs-extra": "^11.3.0",
25
26
  "lodash": "^4.17.21",
26
- "postgres-array": "^3.0.4",
27
- "yargs": "^18.0.0"
27
+ "postgres-array": "^3.0.4"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@prairielearn/tsconfig": "^0.0.0",
31
31
  "@types/fs-extra": "^11.0.4",
32
- "@types/lodash": "^4.17.19",
33
- "@types/node": "^22.15.34",
34
- "@types/yargs": "^17.0.33",
32
+ "@types/lodash": "^4.17.20",
33
+ "@types/node": "^22.17.0",
35
34
  "typescript": "^5.8.3",
36
35
  "typescript-cp": "^0.1.9"
37
36
  }
@@ -4,8 +4,8 @@ import path from 'path';
4
4
 
5
5
  import async from 'async';
6
6
  import chalk from 'chalk';
7
+ import { Command } from 'commander';
7
8
  import fs from 'fs-extra';
8
- import yargs from 'yargs';
9
9
 
10
10
  import {
11
11
  type DatabaseDescription,
@@ -13,74 +13,38 @@ import {
13
13
  formatDatabaseDescription,
14
14
  } from '../describe.js';
15
15
 
16
- const args = yargs(process.argv.slice(2))
17
- .usage('Usage: $0 <database name> [options]')
18
- .demandCommand(1)
19
- .option('output', {
20
- alias: 'o',
21
- nargs: 1,
22
- string: true,
23
- description: 'Specify a directory to output files to',
24
- })
25
- .option('ignore-tables', {
26
- array: true,
27
- description: 'a list of tables to ignore',
28
- })
29
- .option('ignore-enums', {
30
- array: true,
31
- description: 'a list of enums to ignore',
32
- })
33
- .option('ignore-columns', {
34
- array: true,
35
- description: 'a list of columns to ignore, formatted like [table].[column]',
36
- })
37
- .help('h')
38
- .alias('h', 'help')
39
- .example('$0 postgres', 'Describe the "postgres" database')
40
- .example(
41
- '$0 userdb -o db_description --ignore-tables a b --ignore-columns a.col1 a.col2',
42
- 'Describe the "userdb" database; ignore specific tables and columns',
16
+ const program = new Command();
17
+ program
18
+ .name('pg-describe')
19
+ .usage('<database name> [options]')
20
+ .argument('<database>', 'Database name to describe')
21
+ .option('-o, --output <dir>', 'Specify a directory to output files to')
22
+ .option('--ignore-tables <tables...>', 'A list of tables to ignore')
23
+ .option('--ignore-enums <enums...>', 'A list of enums to ignore')
24
+ .option(
25
+ '--ignore-columns <columns...>',
26
+ 'A list of columns to ignore, formatted like [table].[column]',
43
27
  )
44
- .strict();
28
+ .showHelpAfterError();
45
29
 
46
- const argv = args.parseSync();
30
+ program.parse(process.argv);
31
+ const opts = program.opts();
32
+ const dbName = program.args[0];
47
33
 
48
- if (argv._.length !== 1) {
49
- args.showHelp();
50
- process.exit(1);
34
+ if (!dbName) {
35
+ program.help({ error: true });
51
36
  }
52
37
 
53
38
  // Disable color if we're not attached to a tty
54
- const coloredOutput = !argv.output && process.stdout.isTTY;
55
-
56
- const options = {
57
- ignoreTables: (argv['ignore-tables'] ?? []).map((table) => table.toString()),
58
- ignoreEnums: (argv['ignore-enums'] ?? []).map((enumName) => enumName.toString()),
59
- ignoreColumns: (argv['ignore-columns'] ?? []).map((column) => column.toString()),
60
- };
39
+ const coloredOutput = !opts.output && process.stdout.isTTY;
61
40
 
62
41
  function formatText(text: string, formatter: (text: string) => string) {
63
- if (!argv.output && coloredOutput) {
42
+ if (!opts.output && coloredOutput) {
64
43
  return formatter(text);
65
44
  }
66
45
  return text;
67
46
  }
68
47
 
69
- describeDatabase(argv._[0].toString(), options).then(
70
- async (description) => {
71
- if (argv.output) {
72
- await writeDescriptionToDisk(description, argv.output);
73
- } else {
74
- printDescription(description);
75
- }
76
- process.exit(0);
77
- },
78
- (err) => {
79
- console.error(err);
80
- process.exit(1);
81
- },
82
- );
83
-
84
48
  function printDescription(description: DatabaseDescription) {
85
49
  const formattedDescription = formatDatabaseDescription(description, { coloredOutput });
86
50
  for (const tableName of Object.keys(formattedDescription.tables).sort()) {
@@ -109,3 +73,21 @@ async function writeDescriptionToDisk(description: DatabaseDescription, dir: str
109
73
  await fs.writeFile(path.join(dir, 'enums', `${key}.pg`), value);
110
74
  });
111
75
  }
76
+
77
+ function parseListOption(option: string[]): string[] {
78
+ return option.flatMap((item: string) => item.split(',').map((part) => part.trim()));
79
+ }
80
+
81
+ const options = {
82
+ ignoreTables: parseListOption(opts.ignoreTables ?? []),
83
+ ignoreEnums: parseListOption(opts.ignoreEnums ?? []),
84
+ ignoreColumns: parseListOption(opts.ignoreColumns ?? []),
85
+ };
86
+
87
+ const description = await describeDatabase(dbName, options);
88
+ if (opts.output) {
89
+ await writeDescriptionToDisk(description, opts.output);
90
+ } else {
91
+ printDescription(description);
92
+ }
93
+ process.exit(0);
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import yargs from 'yargs';
3
+ import { Command } from 'commander';
4
4
 
5
5
  import {
6
6
  diffDatabaseAndDirectory,
@@ -9,47 +9,38 @@ import {
9
9
  diffDirectoryAndDatabase,
10
10
  } from '../diff.js';
11
11
 
12
- const args = yargs(process.argv.slice(2))
13
- .usage('Usage: $0 [options]')
14
- .option('db', {
15
- description: 'reads a description from the named database',
16
- })
17
- .option('dir', {
18
- description: "reads a description from a directory that's been generated by pg-describe",
19
- })
20
- .help('h')
21
- .alias('h', 'help')
22
- .example(
23
- '$0 --db postgres --dir db_dump',
24
- 'Diffs the database "postgres" with the description in the directory "db_dump"',
12
+ const program = new Command();
13
+ program
14
+ .name('pg-diff')
15
+ .usage('[options]')
16
+ .option('--db <db...>', 'Reads a description from the named database (can be specified twice)')
17
+ .option(
18
+ '--dir <dir...>',
19
+ "Reads a description from a directory that's been generated by pg-describe (can be specified twice)",
25
20
  )
26
- .example(
27
- '$0 --db postgres --db old_restore',
28
- 'Diffs the database "postgres" with the database "old_restore"',
29
- )
30
- .strict();
21
+ .showHelpAfterError();
31
22
 
32
- const argv = args.parseSync();
23
+ program.parse(process.argv);
24
+ const opts = program.opts();
33
25
 
34
26
  const options = {
35
27
  outputFormat: 'string',
36
28
  coloredOutput: process.stdout.isTTY,
37
29
  };
38
30
 
39
- if (argv.db && typeof argv.db === 'string' && argv.dir && typeof argv.dir === 'string') {
40
- // Ensure correct ordering for the sake of diffs
41
- if (process.argv.indexOf('--db') < process.argv.indexOf('--dir')) {
42
- diffDatabaseAndDirectory(argv.db, argv.dir, options).then(handleResults, handleError);
31
+ if (opts.db.length === 2 && !opts.dir) {
32
+ diffDatabases(opts.db[0], opts.db[1], options).then(handleResults, handleError);
33
+ } else if (opts.dir.length === 2 && !opts.db) {
34
+ diffDirectories(opts.dir[0], opts.dir[1], options).then(handleResults, handleError);
35
+ } else if (opts.db.length === 1 && opts.dir.length === 1) {
36
+ const dbIsFirst = process.argv.lastIndexOf('--db') < process.argv.lastIndexOf('--dir');
37
+ if (dbIsFirst) {
38
+ diffDatabaseAndDirectory(opts.db[0], opts.dir[0], options).then(handleResults, handleError);
43
39
  } else {
44
- diffDirectoryAndDatabase(argv.dir, argv.db, options).then(handleResults, handleError);
40
+ diffDirectoryAndDatabase(opts.dir[0], opts.db[0], options).then(handleResults, handleError);
45
41
  }
46
- } else if (argv.db && Array.isArray(argv.db) && argv.db.length === 2 && !argv.dir) {
47
- diffDatabases(argv.db[0], argv.db[1], options).then(handleResults, handleError);
48
- } else if (argv.dir && Array.isArray(argv.dir) && argv.dir.length === 2 && !argv.db) {
49
- diffDirectories(argv.dir[0], argv.dir[1], options).then(handleResults, handleError);
50
42
  } else {
51
- args.showHelp();
52
- process.exit(1);
43
+ program.help({ error: true });
53
44
  }
54
45
 
55
46
  function handleResults(results: string) {
package/src/describe.ts CHANGED
@@ -111,9 +111,7 @@ async function describeWithPool(
111
111
 
112
112
  const foreignKeyConstraintResults = await pool.queryAsync(
113
113
  sql.get_foreign_key_constraints_for_table,
114
- {
115
- oid: table.oid,
116
- },
114
+ { oid: table.oid },
117
115
  );
118
116
 
119
117
  const referenceResults = await pool.queryAsync(sql.get_references_for_table, {