@prairielearn/postgres-tools 2.0.13 → 2.0.15
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 +18 -0
- package/dist/bin/pg-describe.js +4 -5
- package/dist/bin/pg-describe.js.map +1 -1
- package/dist/diff.js +11 -11
- package/dist/diff.js.map +1 -1
- package/package.json +4 -4
- package/src/bin/pg-describe.ts +4 -5
- package/src/diff.ts +29 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @prairielearn/postgres-tools
|
|
2
2
|
|
|
3
|
+
## 2.0.15
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 82f9c2f: Upgrade all JavaScript dependencies
|
|
8
|
+
- Updated dependencies [82f9c2f]
|
|
9
|
+
- @prairielearn/postgres@2.1.11
|
|
10
|
+
|
|
11
|
+
## 2.0.14
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- c24120e: Minor changes to reduce dependency on lodash
|
|
16
|
+
- 03f1008: Upgrade all JavaScript dependencies
|
|
17
|
+
- Updated dependencies [c24120e]
|
|
18
|
+
- Updated dependencies [03f1008]
|
|
19
|
+
- @prairielearn/postgres@2.1.10
|
|
20
|
+
|
|
3
21
|
## 2.0.13
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/dist/bin/pg-describe.js
CHANGED
|
@@ -3,7 +3,6 @@ import path from 'path';
|
|
|
3
3
|
import async from 'async';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import fs from 'fs-extra';
|
|
6
|
-
import _ from 'lodash';
|
|
7
6
|
import yargs from 'yargs';
|
|
8
7
|
import { describeDatabase, formatDatabaseDescription, } from '../describe.js';
|
|
9
8
|
const args = yargs(process.argv.slice(2))
|
|
@@ -64,16 +63,16 @@ describeDatabase(argv._[0].toString(), options).then(async (description) => {
|
|
|
64
63
|
});
|
|
65
64
|
function printDescription(description) {
|
|
66
65
|
const formattedDescription = formatDatabaseDescription(description, { coloredOutput });
|
|
67
|
-
|
|
66
|
+
for (const tableName of Object.keys(formattedDescription.tables).sort()) {
|
|
68
67
|
process.stdout.write(formatText(`[table] ${tableName}\n`, chalk.bold));
|
|
69
68
|
process.stdout.write(formattedDescription.tables[tableName]);
|
|
70
69
|
process.stdout.write('\n\n');
|
|
71
|
-
}
|
|
72
|
-
|
|
70
|
+
}
|
|
71
|
+
for (const enumName of Object.keys(formattedDescription.enums).sort()) {
|
|
73
72
|
process.stdout.write(formatText(`[enum] ${enumName}\n`, chalk.bold));
|
|
74
73
|
process.stdout.write(formattedDescription.enums[enumName]);
|
|
75
74
|
process.stdout.write('\n\n');
|
|
76
|
-
}
|
|
75
|
+
}
|
|
77
76
|
}
|
|
78
77
|
async function writeDescriptionToDisk(description, dir) {
|
|
79
78
|
const formattedDescription = formatDatabaseDescription(description, { coloredOutput: false });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pg-describe.js","sourceRoot":"","sources":["../../src/bin/pg-describe.ts"],"names":[],"mappings":";AAEA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,
|
|
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.emptyDir(dir);\n await fs.mkdir(path.join(dir, 'tables'));\n await fs.mkdir(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"]}
|
package/dist/diff.js
CHANGED
|
@@ -17,8 +17,8 @@ async function diff(db1, db2, options) {
|
|
|
17
17
|
const description1 = await loadDescription(db1);
|
|
18
18
|
const description2 = await loadDescription(db2);
|
|
19
19
|
// Determine if both databases have the same tables
|
|
20
|
-
const tablesMissingFrom1 = _.difference(
|
|
21
|
-
const tablesMissingFrom2 = _.difference(
|
|
20
|
+
const tablesMissingFrom1 = _.difference(Object.keys(description2.tables), Object.keys(description1.tables));
|
|
21
|
+
const tablesMissingFrom2 = _.difference(Object.keys(description1.tables), Object.keys(description2.tables));
|
|
22
22
|
if (tablesMissingFrom1.length > 0) {
|
|
23
23
|
result += formatText(`Tables added to ${db2NameBold} (${db2.type})\n`, chalk.underline);
|
|
24
24
|
result += formatText(tablesMissingFrom1.map((table) => `+ ${table}`).join('\n') + '\n\n', chalk.green);
|
|
@@ -28,8 +28,8 @@ async function diff(db1, db2, options) {
|
|
|
28
28
|
result += formatText(tablesMissingFrom2.map((table) => `- ${table}`).join('\n') + '\n\n', chalk.red);
|
|
29
29
|
}
|
|
30
30
|
// Determine if both databases have the same enums
|
|
31
|
-
const enumsMissingFrom1 = _.difference(
|
|
32
|
-
const enumsMissingFrom2 = _.difference(
|
|
31
|
+
const enumsMissingFrom1 = _.difference(Object.keys(description2.enums), Object.keys(description1.enums));
|
|
32
|
+
const enumsMissingFrom2 = _.difference(Object.keys(description1.enums), Object.keys(description2.enums));
|
|
33
33
|
if (enumsMissingFrom1.length > 0) {
|
|
34
34
|
result += formatText(`Enums added to ${db2NameBold} (${db1.type})\n`, chalk.underline);
|
|
35
35
|
result += formatText(enumsMissingFrom1.map((enumName) => `+ ${enumName}`).join('\n') + '\n\n', chalk.green);
|
|
@@ -39,11 +39,11 @@ async function diff(db1, db2, options) {
|
|
|
39
39
|
result += formatText(enumsMissingFrom2.map((enumName) => `- ${enumName}`).join('\n') + '\n\n', chalk.red);
|
|
40
40
|
}
|
|
41
41
|
// Determine if the columns of any table differ
|
|
42
|
-
const intersection = _.intersection(
|
|
43
|
-
|
|
42
|
+
const intersection = _.intersection(Object.keys(description1.tables), Object.keys(description2.tables));
|
|
43
|
+
for (const table of intersection) {
|
|
44
44
|
const patch = structuredPatch(`tables/${table}`, `tables/${table}`, description1.tables[table], description2.tables[table]);
|
|
45
45
|
if (patch.hunks.length === 0)
|
|
46
|
-
|
|
46
|
+
continue;
|
|
47
47
|
const boldTable = formatText(table, chalk.bold);
|
|
48
48
|
result += formatText(`Differences in ${boldTable} table\n`, chalk.underline);
|
|
49
49
|
patch.hunks.forEach((hunk, index) => {
|
|
@@ -57,10 +57,10 @@ async function diff(db1, db2, options) {
|
|
|
57
57
|
});
|
|
58
58
|
});
|
|
59
59
|
result += '\n\n';
|
|
60
|
-
}
|
|
60
|
+
}
|
|
61
61
|
// Determine if the values of any enums differ
|
|
62
|
-
const enumsIntersection = _.intersection(
|
|
63
|
-
|
|
62
|
+
const enumsIntersection = _.intersection(Object.keys(description1.enums), Object.keys(description2.enums));
|
|
63
|
+
for (const enumName of enumsIntersection) {
|
|
64
64
|
// We don't need to do a particularly fancy diff here, since
|
|
65
65
|
// enums are just represented here as strings
|
|
66
66
|
if (description1.enums[enumName].trim() !== description2.enums[enumName].trim()) {
|
|
@@ -70,7 +70,7 @@ async function diff(db1, db2, options) {
|
|
|
70
70
|
result += formatText(`+ ${description2.enums[enumName].trim()}\n`, chalk.green);
|
|
71
71
|
result += '\n\n';
|
|
72
72
|
}
|
|
73
|
-
}
|
|
73
|
+
}
|
|
74
74
|
return result;
|
|
75
75
|
}
|
|
76
76
|
async function loadDescriptionFromDisk(dirPath) {
|
package/dist/diff.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'node:path';\n\nimport chalk from 'chalk';\nimport { structuredPatch } from 'diff';\nimport fs from 'fs-extra';\nimport _ from 'lodash';\n\nimport { describeDatabase, formatDatabaseDescription } from './describe.js';\n\ninterface DatabaseInfo {\n type: 'database';\n name: string;\n}\n\ninterface DirectoryInfo {\n type: 'directory';\n path: string;\n}\n\ntype DiffTarget = DatabaseInfo | DirectoryInfo;\n\ninterface DiffOptions {\n coloredOutput?: boolean;\n}\n\ninterface Description {\n tables: Record<string, string>;\n enums: Record<string, string>;\n}\n\nasync function diff(db1: DiffTarget, db2: DiffTarget, options: DiffOptions): Promise<string> {\n function formatText(text: string, formatter?: ((s: string) => string) | null): string {\n if (options.coloredOutput && formatter) {\n return formatter(text);\n }\n return text;\n }\n\n const db2Name = db2.type === 'database' ? db2.name : db2.path;\n const db2NameBold = formatText(db2Name, chalk.bold);\n\n let result = '';\n\n const description1 = await loadDescription(db1);\n const description2 = await loadDescription(db2);\n\n // Determine if both databases have the same tables\n const tablesMissingFrom1 = _.difference(_.keys(description2.tables), _.keys(description1.tables));\n const tablesMissingFrom2 = _.difference(_.keys(description1.tables), _.keys(description2.tables));\n\n if (tablesMissingFrom1.length > 0) {\n result += formatText(`Tables added to ${db2NameBold} (${db2.type})\\n`, chalk.underline);\n result += formatText(\n tablesMissingFrom1.map((table) => `+ ${table}`).join('\\n') + '\\n\\n',\n chalk.green,\n );\n }\n\n if (tablesMissingFrom2.length > 0) {\n result += formatText(`Tables missing from ${db2NameBold} (${db2.type})\\n`, chalk.underline);\n result += formatText(\n tablesMissingFrom2.map((table) => `- ${table}`).join('\\n') + '\\n\\n',\n chalk.red,\n );\n }\n\n // Determine if both databases have the same enums\n const enumsMissingFrom1 = _.difference(_.keys(description2.enums), _.keys(description1.enums));\n const enumsMissingFrom2 = _.difference(_.keys(description1.enums), _.keys(description2.enums));\n\n if (enumsMissingFrom1.length > 0) {\n result += formatText(`Enums added to ${db2NameBold} (${db1.type})\\n`, chalk.underline);\n result += formatText(\n enumsMissingFrom1.map((enumName) => `+ ${enumName}`).join('\\n') + '\\n\\n',\n chalk.green,\n );\n }\n\n if (enumsMissingFrom2.length > 0) {\n result += formatText(`Enums missing from ${db2NameBold} (${db2.type})\\n`, chalk.underline);\n result += formatText(\n enumsMissingFrom2.map((enumName) => `- ${enumName}`).join('\\n') + '\\n\\n',\n chalk.red,\n );\n }\n\n // Determine if the columns of any table differ\n const intersection = _.intersection(_.keys(description1.tables), _.keys(description2.tables));\n _.forEach(intersection, (table) => {\n const patch = structuredPatch(\n `tables/${table}`,\n `tables/${table}`,\n description1.tables[table],\n description2.tables[table],\n );\n\n if (patch.hunks.length === 0) return;\n\n const boldTable = formatText(table, chalk.bold);\n result += formatText(`Differences in ${boldTable} table\\n`, chalk.underline);\n\n patch.hunks.forEach((hunk, index) => {\n if (index !== 0) {\n result += formatText('...\\n', chalk.gray);\n }\n hunk.lines.forEach((line) => {\n const color = line[0] === '+' ? chalk.green : line[0] === '-' ? chalk.red : null;\n result += formatText(line, color);\n result += '\\n';\n });\n });\n\n result += '\\n\\n';\n });\n\n // Determine if the values of any enums differ\n const enumsIntersection = _.intersection(_.keys(description1.enums), _.keys(description2.enums));\n _.forEach(enumsIntersection, (enumName) => {\n // We don't need to do a particularly fancy diff here, since\n // enums are just represented here as strings\n if (description1.enums[enumName].trim() !== description2.enums[enumName].trim()) {\n const boldEnum = formatText(enumName, chalk.bold);\n result += formatText(`Differences in ${boldEnum} enum\\n`);\n result += formatText(`- ${description1.enums[enumName].trim()}\\n`, chalk.red);\n result += formatText(`+ ${description2.enums[enumName].trim()}\\n`, chalk.green);\n result += '\\n\\n';\n }\n });\n\n return result;\n}\n\nasync function loadDescriptionFromDisk(dirPath: string): Promise<Description> {\n const description: Description = {\n tables: {},\n enums: {},\n };\n\n const tables = await fs.readdir(path.join(dirPath, 'tables'));\n for (const table of tables) {\n const data = await fs.readFile(path.join(dirPath, 'tables', table), 'utf8');\n description.tables[table.replace('.pg', '')] = data;\n }\n\n const enums = await fs.readdir(path.join(dirPath, 'enums'));\n for (const enumName of enums) {\n const data = await fs.readFile(path.join(dirPath, 'enums', enumName), 'utf8');\n description.enums[enumName.replace('.pg', '')] = data;\n }\n\n return description;\n}\n\nasync function loadDescriptionFromDatabase(name: string) {\n const description = await describeDatabase(name);\n return formatDatabaseDescription(description, { coloredOutput: false });\n}\n\nasync function loadDescription(db: DiffTarget): Promise<Description> {\n if (db.type === 'database') {\n return loadDescriptionFromDatabase(db.name);\n } else if (db.type === 'directory') {\n return loadDescriptionFromDisk(db.path);\n } else {\n throw new Error('Invalid database type');\n }\n}\n\nexport async function diffDatabases(database1: string, database2: string, options: DiffOptions) {\n return diff(\n {\n type: 'database',\n name: database1,\n },\n {\n type: 'database',\n name: database2,\n },\n options,\n );\n}\n\nexport async function diffDatabaseAndDirectory(\n database: string,\n directory: string,\n options: DiffOptions,\n) {\n return diff(\n {\n type: 'database',\n name: database,\n },\n {\n type: 'directory',\n path: directory,\n },\n options,\n );\n}\n\nexport async function diffDirectoryAndDatabase(\n directory: string,\n database: string,\n options: DiffOptions,\n) {\n return diff(\n {\n type: 'directory',\n path: directory,\n },\n {\n type: 'database',\n name: database,\n },\n options,\n );\n}\n\nexport async function diffDirectories(\n directory1: string,\n directory2: string,\n options: DiffOptions,\n) {\n return diff(\n {\n type: 'directory',\n path: directory1,\n },\n {\n type: 'directory',\n path: directory2,\n },\n options,\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'node:path';\n\nimport chalk from 'chalk';\nimport { structuredPatch } from 'diff';\nimport fs from 'fs-extra';\nimport _ from 'lodash';\n\nimport { describeDatabase, formatDatabaseDescription } from './describe.js';\n\ninterface DatabaseInfo {\n type: 'database';\n name: string;\n}\n\ninterface DirectoryInfo {\n type: 'directory';\n path: string;\n}\n\ntype DiffTarget = DatabaseInfo | DirectoryInfo;\n\ninterface DiffOptions {\n coloredOutput?: boolean;\n}\n\ninterface Description {\n tables: Record<string, string>;\n enums: Record<string, string>;\n}\n\nasync function diff(db1: DiffTarget, db2: DiffTarget, options: DiffOptions): Promise<string> {\n function formatText(text: string, formatter?: ((s: string) => string) | null): string {\n if (options.coloredOutput && formatter) {\n return formatter(text);\n }\n return text;\n }\n\n const db2Name = db2.type === 'database' ? db2.name : db2.path;\n const db2NameBold = formatText(db2Name, chalk.bold);\n\n let result = '';\n\n const description1 = await loadDescription(db1);\n const description2 = await loadDescription(db2);\n\n // Determine if both databases have the same tables\n const tablesMissingFrom1 = _.difference(\n Object.keys(description2.tables),\n Object.keys(description1.tables),\n );\n const tablesMissingFrom2 = _.difference(\n Object.keys(description1.tables),\n Object.keys(description2.tables),\n );\n\n if (tablesMissingFrom1.length > 0) {\n result += formatText(`Tables added to ${db2NameBold} (${db2.type})\\n`, chalk.underline);\n result += formatText(\n tablesMissingFrom1.map((table) => `+ ${table}`).join('\\n') + '\\n\\n',\n chalk.green,\n );\n }\n\n if (tablesMissingFrom2.length > 0) {\n result += formatText(`Tables missing from ${db2NameBold} (${db2.type})\\n`, chalk.underline);\n result += formatText(\n tablesMissingFrom2.map((table) => `- ${table}`).join('\\n') + '\\n\\n',\n chalk.red,\n );\n }\n\n // Determine if both databases have the same enums\n const enumsMissingFrom1 = _.difference(\n Object.keys(description2.enums),\n Object.keys(description1.enums),\n );\n const enumsMissingFrom2 = _.difference(\n Object.keys(description1.enums),\n Object.keys(description2.enums),\n );\n\n if (enumsMissingFrom1.length > 0) {\n result += formatText(`Enums added to ${db2NameBold} (${db1.type})\\n`, chalk.underline);\n result += formatText(\n enumsMissingFrom1.map((enumName) => `+ ${enumName}`).join('\\n') + '\\n\\n',\n chalk.green,\n );\n }\n\n if (enumsMissingFrom2.length > 0) {\n result += formatText(`Enums missing from ${db2NameBold} (${db2.type})\\n`, chalk.underline);\n result += formatText(\n enumsMissingFrom2.map((enumName) => `- ${enumName}`).join('\\n') + '\\n\\n',\n chalk.red,\n );\n }\n\n // Determine if the columns of any table differ\n const intersection = _.intersection(\n Object.keys(description1.tables),\n Object.keys(description2.tables),\n );\n for (const table of intersection) {\n const patch = structuredPatch(\n `tables/${table}`,\n `tables/${table}`,\n description1.tables[table],\n description2.tables[table],\n );\n\n if (patch.hunks.length === 0) continue;\n\n const boldTable = formatText(table, chalk.bold);\n result += formatText(`Differences in ${boldTable} table\\n`, chalk.underline);\n\n patch.hunks.forEach((hunk, index) => {\n if (index !== 0) {\n result += formatText('...\\n', chalk.gray);\n }\n hunk.lines.forEach((line) => {\n const color = line[0] === '+' ? chalk.green : line[0] === '-' ? chalk.red : null;\n result += formatText(line, color);\n result += '\\n';\n });\n });\n\n result += '\\n\\n';\n }\n\n // Determine if the values of any enums differ\n const enumsIntersection = _.intersection(\n Object.keys(description1.enums),\n Object.keys(description2.enums),\n );\n for (const enumName of enumsIntersection) {\n // We don't need to do a particularly fancy diff here, since\n // enums are just represented here as strings\n if (description1.enums[enumName].trim() !== description2.enums[enumName].trim()) {\n const boldEnum = formatText(enumName, chalk.bold);\n result += formatText(`Differences in ${boldEnum} enum\\n`);\n result += formatText(`- ${description1.enums[enumName].trim()}\\n`, chalk.red);\n result += formatText(`+ ${description2.enums[enumName].trim()}\\n`, chalk.green);\n result += '\\n\\n';\n }\n }\n\n return result;\n}\n\nasync function loadDescriptionFromDisk(dirPath: string): Promise<Description> {\n const description: Description = {\n tables: {},\n enums: {},\n };\n\n const tables = await fs.readdir(path.join(dirPath, 'tables'));\n for (const table of tables) {\n const data = await fs.readFile(path.join(dirPath, 'tables', table), 'utf8');\n description.tables[table.replace('.pg', '')] = data;\n }\n\n const enums = await fs.readdir(path.join(dirPath, 'enums'));\n for (const enumName of enums) {\n const data = await fs.readFile(path.join(dirPath, 'enums', enumName), 'utf8');\n description.enums[enumName.replace('.pg', '')] = data;\n }\n\n return description;\n}\n\nasync function loadDescriptionFromDatabase(name: string) {\n const description = await describeDatabase(name);\n return formatDatabaseDescription(description, { coloredOutput: false });\n}\n\nasync function loadDescription(db: DiffTarget): Promise<Description> {\n if (db.type === 'database') {\n return loadDescriptionFromDatabase(db.name);\n } else if (db.type === 'directory') {\n return loadDescriptionFromDisk(db.path);\n } else {\n throw new Error('Invalid database type');\n }\n}\n\nexport async function diffDatabases(database1: string, database2: string, options: DiffOptions) {\n return diff(\n {\n type: 'database',\n name: database1,\n },\n {\n type: 'database',\n name: database2,\n },\n options,\n );\n}\n\nexport async function diffDatabaseAndDirectory(\n database: string,\n directory: string,\n options: DiffOptions,\n) {\n return diff(\n {\n type: 'database',\n name: database,\n },\n {\n type: 'directory',\n path: directory,\n },\n options,\n );\n}\n\nexport async function diffDirectoryAndDatabase(\n directory: string,\n database: string,\n options: DiffOptions,\n) {\n return diff(\n {\n type: 'directory',\n path: directory,\n },\n {\n type: 'database',\n name: database,\n },\n options,\n );\n}\n\nexport async function diffDirectories(\n directory1: string,\n directory2: string,\n options: DiffOptions,\n) {\n return diff(\n {\n type: 'directory',\n path: directory1,\n },\n {\n type: 'directory',\n path: directory2,\n },\n options,\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prairielearn/postgres-tools",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"dev": "tsc --watch --preserveWatchOutput & tscp --watch"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@prairielearn/postgres": "^2.1.
|
|
20
|
+
"@prairielearn/postgres": "^2.1.11",
|
|
21
21
|
"async": "^3.2.6",
|
|
22
22
|
"chalk": "^5.4.1",
|
|
23
23
|
"diff": "^7.0.0",
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"@types/diff": "^7.0.2",
|
|
32
32
|
"@types/fs-extra": "^11.0.4",
|
|
33
33
|
"@types/lodash": "^4.17.16",
|
|
34
|
-
"@types/node": "^20.17.
|
|
34
|
+
"@types/node": "^20.17.30",
|
|
35
35
|
"@types/yargs": "^17.0.33",
|
|
36
|
-
"typescript": "^5.8.
|
|
36
|
+
"typescript": "^5.8.3",
|
|
37
37
|
"typescript-cp": "^0.1.9"
|
|
38
38
|
}
|
|
39
39
|
}
|
package/src/bin/pg-describe.ts
CHANGED
|
@@ -5,7 +5,6 @@ import path from 'path';
|
|
|
5
5
|
import async from 'async';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
7
|
import fs from 'fs-extra';
|
|
8
|
-
import _ from 'lodash';
|
|
9
8
|
import yargs from 'yargs';
|
|
10
9
|
|
|
11
10
|
import {
|
|
@@ -84,17 +83,17 @@ describeDatabase(argv._[0].toString(), options).then(
|
|
|
84
83
|
|
|
85
84
|
function printDescription(description: DatabaseDescription) {
|
|
86
85
|
const formattedDescription = formatDatabaseDescription(description, { coloredOutput });
|
|
87
|
-
|
|
86
|
+
for (const tableName of Object.keys(formattedDescription.tables).sort()) {
|
|
88
87
|
process.stdout.write(formatText(`[table] ${tableName}\n`, chalk.bold));
|
|
89
88
|
process.stdout.write(formattedDescription.tables[tableName]);
|
|
90
89
|
process.stdout.write('\n\n');
|
|
91
|
-
}
|
|
90
|
+
}
|
|
92
91
|
|
|
93
|
-
|
|
92
|
+
for (const enumName of Object.keys(formattedDescription.enums).sort()) {
|
|
94
93
|
process.stdout.write(formatText(`[enum] ${enumName}\n`, chalk.bold));
|
|
95
94
|
process.stdout.write(formattedDescription.enums[enumName]);
|
|
96
95
|
process.stdout.write('\n\n');
|
|
97
|
-
}
|
|
96
|
+
}
|
|
98
97
|
}
|
|
99
98
|
|
|
100
99
|
async function writeDescriptionToDisk(description: DatabaseDescription, dir: string) {
|
package/src/diff.ts
CHANGED
|
@@ -45,8 +45,14 @@ async function diff(db1: DiffTarget, db2: DiffTarget, options: DiffOptions): Pro
|
|
|
45
45
|
const description2 = await loadDescription(db2);
|
|
46
46
|
|
|
47
47
|
// Determine if both databases have the same tables
|
|
48
|
-
const tablesMissingFrom1 = _.difference(
|
|
49
|
-
|
|
48
|
+
const tablesMissingFrom1 = _.difference(
|
|
49
|
+
Object.keys(description2.tables),
|
|
50
|
+
Object.keys(description1.tables),
|
|
51
|
+
);
|
|
52
|
+
const tablesMissingFrom2 = _.difference(
|
|
53
|
+
Object.keys(description1.tables),
|
|
54
|
+
Object.keys(description2.tables),
|
|
55
|
+
);
|
|
50
56
|
|
|
51
57
|
if (tablesMissingFrom1.length > 0) {
|
|
52
58
|
result += formatText(`Tables added to ${db2NameBold} (${db2.type})\n`, chalk.underline);
|
|
@@ -65,8 +71,14 @@ async function diff(db1: DiffTarget, db2: DiffTarget, options: DiffOptions): Pro
|
|
|
65
71
|
}
|
|
66
72
|
|
|
67
73
|
// Determine if both databases have the same enums
|
|
68
|
-
const enumsMissingFrom1 = _.difference(
|
|
69
|
-
|
|
74
|
+
const enumsMissingFrom1 = _.difference(
|
|
75
|
+
Object.keys(description2.enums),
|
|
76
|
+
Object.keys(description1.enums),
|
|
77
|
+
);
|
|
78
|
+
const enumsMissingFrom2 = _.difference(
|
|
79
|
+
Object.keys(description1.enums),
|
|
80
|
+
Object.keys(description2.enums),
|
|
81
|
+
);
|
|
70
82
|
|
|
71
83
|
if (enumsMissingFrom1.length > 0) {
|
|
72
84
|
result += formatText(`Enums added to ${db2NameBold} (${db1.type})\n`, chalk.underline);
|
|
@@ -85,8 +97,11 @@ async function diff(db1: DiffTarget, db2: DiffTarget, options: DiffOptions): Pro
|
|
|
85
97
|
}
|
|
86
98
|
|
|
87
99
|
// Determine if the columns of any table differ
|
|
88
|
-
const intersection = _.intersection(
|
|
89
|
-
|
|
100
|
+
const intersection = _.intersection(
|
|
101
|
+
Object.keys(description1.tables),
|
|
102
|
+
Object.keys(description2.tables),
|
|
103
|
+
);
|
|
104
|
+
for (const table of intersection) {
|
|
90
105
|
const patch = structuredPatch(
|
|
91
106
|
`tables/${table}`,
|
|
92
107
|
`tables/${table}`,
|
|
@@ -94,7 +109,7 @@ async function diff(db1: DiffTarget, db2: DiffTarget, options: DiffOptions): Pro
|
|
|
94
109
|
description2.tables[table],
|
|
95
110
|
);
|
|
96
111
|
|
|
97
|
-
if (patch.hunks.length === 0)
|
|
112
|
+
if (patch.hunks.length === 0) continue;
|
|
98
113
|
|
|
99
114
|
const boldTable = formatText(table, chalk.bold);
|
|
100
115
|
result += formatText(`Differences in ${boldTable} table\n`, chalk.underline);
|
|
@@ -111,11 +126,14 @@ async function diff(db1: DiffTarget, db2: DiffTarget, options: DiffOptions): Pro
|
|
|
111
126
|
});
|
|
112
127
|
|
|
113
128
|
result += '\n\n';
|
|
114
|
-
}
|
|
129
|
+
}
|
|
115
130
|
|
|
116
131
|
// Determine if the values of any enums differ
|
|
117
|
-
const enumsIntersection = _.intersection(
|
|
118
|
-
|
|
132
|
+
const enumsIntersection = _.intersection(
|
|
133
|
+
Object.keys(description1.enums),
|
|
134
|
+
Object.keys(description2.enums),
|
|
135
|
+
);
|
|
136
|
+
for (const enumName of enumsIntersection) {
|
|
119
137
|
// We don't need to do a particularly fancy diff here, since
|
|
120
138
|
// enums are just represented here as strings
|
|
121
139
|
if (description1.enums[enumName].trim() !== description2.enums[enumName].trim()) {
|
|
@@ -125,7 +143,7 @@ async function diff(db1: DiffTarget, db2: DiffTarget, options: DiffOptions): Pro
|
|
|
125
143
|
result += formatText(`+ ${description2.enums[enumName].trim()}\n`, chalk.green);
|
|
126
144
|
result += '\n\n';
|
|
127
145
|
}
|
|
128
|
-
}
|
|
146
|
+
}
|
|
129
147
|
|
|
130
148
|
return result;
|
|
131
149
|
}
|