@pgpmjs/core 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -0
- package/README.md +99 -0
- package/core/boilerplate-scanner.d.ts +41 -0
- package/core/boilerplate-scanner.js +106 -0
- package/core/boilerplate-types.d.ts +52 -0
- package/core/boilerplate-types.js +6 -0
- package/core/class/pgpm.d.ts +150 -0
- package/core/class/pgpm.js +1470 -0
- package/core/template-scaffold.d.ts +29 -0
- package/core/template-scaffold.js +168 -0
- package/esm/core/boilerplate-scanner.js +96 -0
- package/esm/core/boilerplate-types.js +5 -0
- package/esm/core/class/pgpm.js +1430 -0
- package/esm/core/template-scaffold.js +161 -0
- package/esm/export/export-meta.js +240 -0
- package/esm/export/export-migrations.js +180 -0
- package/esm/extensions/extensions.js +31 -0
- package/esm/files/extension/index.js +3 -0
- package/esm/files/extension/reader.js +79 -0
- package/esm/files/extension/writer.js +63 -0
- package/esm/files/index.js +6 -0
- package/esm/files/plan/generator.js +49 -0
- package/esm/files/plan/index.js +5 -0
- package/esm/files/plan/parser.js +296 -0
- package/esm/files/plan/validators.js +181 -0
- package/esm/files/plan/writer.js +114 -0
- package/esm/files/sql/index.js +1 -0
- package/esm/files/sql/writer.js +107 -0
- package/esm/files/sql-scripts/index.js +2 -0
- package/esm/files/sql-scripts/reader.js +19 -0
- package/esm/files/types/index.js +1 -0
- package/esm/files/types/package.js +1 -0
- package/esm/index.js +21 -0
- package/esm/init/client.js +144 -0
- package/esm/init/sql/bootstrap-roles.sql +55 -0
- package/esm/init/sql/bootstrap-test-roles.sql +72 -0
- package/esm/migrate/clean.js +23 -0
- package/esm/migrate/client.js +551 -0
- package/esm/migrate/index.js +5 -0
- package/esm/migrate/sql/procedures.sql +258 -0
- package/esm/migrate/sql/schema.sql +37 -0
- package/esm/migrate/types.js +1 -0
- package/esm/migrate/utils/event-logger.js +28 -0
- package/esm/migrate/utils/hash.js +27 -0
- package/esm/migrate/utils/transaction.js +125 -0
- package/esm/modules/modules.js +49 -0
- package/esm/packaging/package.js +96 -0
- package/esm/packaging/transform.js +70 -0
- package/esm/projects/deploy.js +123 -0
- package/esm/projects/revert.js +75 -0
- package/esm/projects/verify.js +61 -0
- package/esm/resolution/deps.js +526 -0
- package/esm/resolution/resolve.js +101 -0
- package/esm/utils/debug.js +147 -0
- package/esm/utils/target-utils.js +37 -0
- package/esm/workspace/paths.js +43 -0
- package/esm/workspace/utils.js +31 -0
- package/export/export-meta.d.ts +8 -0
- package/export/export-meta.js +244 -0
- package/export/export-migrations.d.ts +17 -0
- package/export/export-migrations.js +187 -0
- package/extensions/extensions.d.ts +5 -0
- package/extensions/extensions.js +35 -0
- package/files/extension/index.d.ts +2 -0
- package/files/extension/index.js +19 -0
- package/files/extension/reader.d.ts +24 -0
- package/files/extension/reader.js +86 -0
- package/files/extension/writer.d.ts +39 -0
- package/files/extension/writer.js +70 -0
- package/files/index.d.ts +5 -0
- package/files/index.js +22 -0
- package/files/plan/generator.d.ts +22 -0
- package/files/plan/generator.js +57 -0
- package/files/plan/index.d.ts +4 -0
- package/files/plan/index.js +21 -0
- package/files/plan/parser.d.ts +27 -0
- package/files/plan/parser.js +303 -0
- package/files/plan/validators.d.ts +52 -0
- package/files/plan/validators.js +187 -0
- package/files/plan/writer.d.ts +27 -0
- package/files/plan/writer.js +124 -0
- package/files/sql/index.d.ts +1 -0
- package/files/sql/index.js +17 -0
- package/files/sql/writer.d.ts +12 -0
- package/files/sql/writer.js +114 -0
- package/files/sql-scripts/index.d.ts +1 -0
- package/files/sql-scripts/index.js +18 -0
- package/files/sql-scripts/reader.d.ts +8 -0
- package/files/sql-scripts/reader.js +23 -0
- package/files/types/index.d.ts +46 -0
- package/files/types/index.js +17 -0
- package/files/types/package.d.ts +20 -0
- package/files/types/package.js +2 -0
- package/index.d.ts +21 -0
- package/index.js +45 -0
- package/init/client.d.ts +26 -0
- package/init/client.js +148 -0
- package/init/sql/bootstrap-roles.sql +55 -0
- package/init/sql/bootstrap-test-roles.sql +72 -0
- package/migrate/clean.d.ts +1 -0
- package/migrate/clean.js +27 -0
- package/migrate/client.d.ts +80 -0
- package/migrate/client.js +555 -0
- package/migrate/index.d.ts +5 -0
- package/migrate/index.js +21 -0
- package/migrate/sql/procedures.sql +258 -0
- package/migrate/sql/schema.sql +37 -0
- package/migrate/types.d.ts +67 -0
- package/migrate/types.js +2 -0
- package/migrate/utils/event-logger.d.ts +13 -0
- package/migrate/utils/event-logger.js +32 -0
- package/migrate/utils/hash.d.ts +12 -0
- package/migrate/utils/hash.js +32 -0
- package/migrate/utils/transaction.d.ts +27 -0
- package/migrate/utils/transaction.js +129 -0
- package/modules/modules.d.ts +31 -0
- package/modules/modules.js +56 -0
- package/package.json +70 -0
- package/packaging/package.d.ts +19 -0
- package/packaging/package.js +102 -0
- package/packaging/transform.d.ts +22 -0
- package/packaging/transform.js +75 -0
- package/projects/deploy.d.ts +8 -0
- package/projects/deploy.js +160 -0
- package/projects/revert.d.ts +15 -0
- package/projects/revert.js +112 -0
- package/projects/verify.d.ts +8 -0
- package/projects/verify.js +98 -0
- package/resolution/deps.d.ts +57 -0
- package/resolution/deps.js +531 -0
- package/resolution/resolve.d.ts +37 -0
- package/resolution/resolve.js +107 -0
- package/utils/debug.d.ts +21 -0
- package/utils/debug.js +153 -0
- package/utils/target-utils.d.ts +5 -0
- package/utils/target-utils.js +40 -0
- package/workspace/paths.d.ts +14 -0
- package/workspace/paths.js +50 -0
- package/workspace/utils.d.ts +8 -0
- package/workspace/utils.js +36 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getExtensionsAndModulesChanges = exports.getExtensionsAndModules = exports.latestChangeAndVersion = exports.latestChange = void 0;
|
|
4
|
+
const files_1 = require("../files");
|
|
5
|
+
const types_1 = require("@pgpmjs/types");
|
|
6
|
+
/**
|
|
7
|
+
* Get the latest change from the pgpm.plan file for a specific module.
|
|
8
|
+
*/
|
|
9
|
+
const latestChange = (sqlmodule, modules, basePath) => {
|
|
10
|
+
const module = modules[sqlmodule];
|
|
11
|
+
if (!module) {
|
|
12
|
+
throw types_1.errors.MODULE_NOT_FOUND({ name: sqlmodule });
|
|
13
|
+
}
|
|
14
|
+
const planPath = `${basePath}/${module.path}/pgpm.plan`;
|
|
15
|
+
return (0, files_1.getLatestChange)(planPath);
|
|
16
|
+
};
|
|
17
|
+
exports.latestChange = latestChange;
|
|
18
|
+
/**
|
|
19
|
+
* Get the latest change and version for a specific module.
|
|
20
|
+
*/
|
|
21
|
+
const latestChangeAndVersion = (sqlmodule, modules, basePath) => {
|
|
22
|
+
const module = modules[sqlmodule];
|
|
23
|
+
if (!module) {
|
|
24
|
+
throw types_1.errors.MODULE_NOT_FOUND({ name: sqlmodule });
|
|
25
|
+
}
|
|
26
|
+
const planPath = `${basePath}/${module.path}/pgpm.plan`;
|
|
27
|
+
const change = (0, files_1.getLatestChange)(planPath);
|
|
28
|
+
const pkg = require(`${basePath}/${module.path}/package.json`);
|
|
29
|
+
return { change, version: pkg.version };
|
|
30
|
+
};
|
|
31
|
+
exports.latestChangeAndVersion = latestChangeAndVersion;
|
|
32
|
+
/**
|
|
33
|
+
* Get extensions and modules required by a specific module.
|
|
34
|
+
*/
|
|
35
|
+
const getExtensionsAndModules = (sqlmodule, modules) => {
|
|
36
|
+
const module = modules[sqlmodule];
|
|
37
|
+
if (!module) {
|
|
38
|
+
throw types_1.errors.MODULE_NOT_FOUND({ name: sqlmodule });
|
|
39
|
+
}
|
|
40
|
+
const native = module.requires.filter((req) => !Object.keys(modules).includes(req));
|
|
41
|
+
const sqitch = module.requires.filter((req) => Object.keys(modules).includes(req));
|
|
42
|
+
return { native, sqitch };
|
|
43
|
+
};
|
|
44
|
+
exports.getExtensionsAndModules = getExtensionsAndModules;
|
|
45
|
+
/**
|
|
46
|
+
* Get extensions and modules with their latest changes and versions.
|
|
47
|
+
*/
|
|
48
|
+
const getExtensionsAndModulesChanges = (sqlmodule, modules, basePath) => {
|
|
49
|
+
const { native, sqitch } = (0, exports.getExtensionsAndModules)(sqlmodule, modules);
|
|
50
|
+
const sqitchWithDetails = sqitch.map((mod) => {
|
|
51
|
+
const { change, version } = (0, exports.latestChangeAndVersion)(mod, modules, basePath);
|
|
52
|
+
return { name: mod, latest: change, version };
|
|
53
|
+
});
|
|
54
|
+
return { native, sqitch: sqitchWithDetails };
|
|
55
|
+
};
|
|
56
|
+
exports.getExtensionsAndModulesChanges = getExtensionsAndModulesChanges;
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pgpmjs/core",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"author": "Constructive <developers@constructive.io>",
|
|
5
|
+
"description": "PGPM Package and Migration Tools",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"module": "esm/index.js",
|
|
8
|
+
"types": "index.d.ts",
|
|
9
|
+
"homepage": "https://github.com/constructive-io/constructive",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public",
|
|
13
|
+
"directory": "dist"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/constructive-io/constructive"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/constructive-io/constructive/issues"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"copy": "npm run copy:pkg; npm run copy:sql",
|
|
24
|
+
"copy:pkg": "makage assets",
|
|
25
|
+
"copy:sql": "copyfiles -f src/migrate/sql/* dist/migrate/sql && copyfiles -f src/migrate/sql/* dist/esm/migrate/sql && copyfiles -f src/init/sql/* dist/init/sql && copyfiles -f src/init/sql/* dist/esm/init/sql",
|
|
26
|
+
"clean": "makage clean",
|
|
27
|
+
"prepack": "npm run build",
|
|
28
|
+
"build": "makage build && npm run copy",
|
|
29
|
+
"build:dev": "makage build --dev",
|
|
30
|
+
"lint": "eslint . --fix",
|
|
31
|
+
"test": "jest",
|
|
32
|
+
"test:watch": "jest --watch"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"database",
|
|
36
|
+
"migration",
|
|
37
|
+
"postgresql",
|
|
38
|
+
"pgpm",
|
|
39
|
+
"pgpmjs",
|
|
40
|
+
"schema",
|
|
41
|
+
"sqitch"
|
|
42
|
+
],
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/pg": "^8.16.0",
|
|
45
|
+
"copyfiles": "^2.4.1",
|
|
46
|
+
"makage": "^0.1.8"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@pgpmjs/env": "^2.7.0",
|
|
50
|
+
"@pgpmjs/logger": "^1.3.0",
|
|
51
|
+
"@pgpmjs/server-utils": "^2.8.0",
|
|
52
|
+
"@pgpmjs/types": "^2.11.0",
|
|
53
|
+
"@pgsql/types": "^17.6.2",
|
|
54
|
+
"create-gen-app": "^0.3.3",
|
|
55
|
+
"csv-to-pg": "^2.0.10",
|
|
56
|
+
"glob": "^13.0.0",
|
|
57
|
+
"komoji": "^0.7.8",
|
|
58
|
+
"parse-package-name": "^1.0.0",
|
|
59
|
+
"pg": "^8.16.3",
|
|
60
|
+
"pg-cache": "^1.6.0",
|
|
61
|
+
"pg-env": "^1.2.1",
|
|
62
|
+
"pgsql-deparser": "^17.12.2",
|
|
63
|
+
"pgsql-parser": "^17.9.2",
|
|
64
|
+
"yanse": "^0.1.5"
|
|
65
|
+
},
|
|
66
|
+
"peerDependencies": {
|
|
67
|
+
"@pgsql/types": "^17.6.1"
|
|
68
|
+
},
|
|
69
|
+
"gitHead": "e4d5396a5d9154f4886176bb00c2b460b0f320e5"
|
|
70
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const cleanTree: (tree: any) => any;
|
|
2
|
+
interface PackageModuleOptions {
|
|
3
|
+
usePlan?: boolean;
|
|
4
|
+
extension?: boolean;
|
|
5
|
+
pretty?: boolean;
|
|
6
|
+
functionDelimiter?: string;
|
|
7
|
+
}
|
|
8
|
+
interface WritePackageOptions extends PackageModuleOptions {
|
|
9
|
+
version: string;
|
|
10
|
+
packageDir: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const packageModule: (packageDir: string, { usePlan, extension, pretty, functionDelimiter }?: PackageModuleOptions) => Promise<{
|
|
13
|
+
sql: string;
|
|
14
|
+
diff?: boolean;
|
|
15
|
+
tree1?: string;
|
|
16
|
+
tree2?: string;
|
|
17
|
+
}>;
|
|
18
|
+
export declare const writePackage: ({ version, extension, usePlan, packageDir, }: WritePackageOptions) => Promise<void>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writePackage = exports.packageModule = exports.cleanTree = void 0;
|
|
4
|
+
const logger_1 = require("@pgpmjs/logger");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const pgsql_deparser_1 = require("pgsql-deparser");
|
|
8
|
+
const pgsql_parser_1 = require("pgsql-parser");
|
|
9
|
+
const files_1 = require("../files");
|
|
10
|
+
const resolve_1 = require("../resolution/resolve");
|
|
11
|
+
const transform_1 = require("./transform");
|
|
12
|
+
const log = new logger_1.Logger('package');
|
|
13
|
+
const noop = () => undefined;
|
|
14
|
+
const cleanTree = (tree) => {
|
|
15
|
+
return (0, transform_1.transformProps)(tree, {
|
|
16
|
+
stmt_len: noop,
|
|
17
|
+
stmt_location: noop,
|
|
18
|
+
location: noop,
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
exports.cleanTree = cleanTree;
|
|
22
|
+
const filterStatements = (stmts, extension) => {
|
|
23
|
+
if (!extension)
|
|
24
|
+
return stmts;
|
|
25
|
+
return stmts.filter(node => {
|
|
26
|
+
const stmt = node.stmt;
|
|
27
|
+
return !stmt.hasOwnProperty('TransactionStmt') &&
|
|
28
|
+
!stmt.hasOwnProperty('CreateExtensionStmt');
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
const packageModule = async (packageDir, { usePlan = true, extension = true, pretty = true, functionDelimiter = '$EOFCODE$' } = {}) => {
|
|
32
|
+
const resolveFn = usePlan ? resolve_1.resolveWithPlan : resolve_1.resolve;
|
|
33
|
+
const sql = resolveFn(packageDir);
|
|
34
|
+
if (!sql?.trim()) {
|
|
35
|
+
log.warn(`โ ๏ธ No SQL generated for module at ${packageDir}. Skipping.`);
|
|
36
|
+
return { sql: '' };
|
|
37
|
+
}
|
|
38
|
+
const extname = (0, files_1.getExtensionName)(packageDir);
|
|
39
|
+
try {
|
|
40
|
+
const parsed = await (0, pgsql_parser_1.parse)(sql);
|
|
41
|
+
parsed.stmts = filterStatements(parsed.stmts, extension);
|
|
42
|
+
const topLine = extension
|
|
43
|
+
? `\\echo Use "CREATE EXTENSION ${extname}" to load this file. \\quit\n`
|
|
44
|
+
: '';
|
|
45
|
+
const finalSql = await (0, pgsql_deparser_1.deparse)(parsed, {
|
|
46
|
+
pretty,
|
|
47
|
+
functionDelimiter
|
|
48
|
+
});
|
|
49
|
+
const tree1 = parsed.stmts;
|
|
50
|
+
const tree2 = await (0, pgsql_parser_1.parse)(finalSql);
|
|
51
|
+
const results = {
|
|
52
|
+
sql: `${topLine}${finalSql}`,
|
|
53
|
+
};
|
|
54
|
+
const diff = JSON.stringify((0, exports.cleanTree)(tree1)) !== JSON.stringify((0, exports.cleanTree)(tree2));
|
|
55
|
+
if (diff) {
|
|
56
|
+
results.diff = true;
|
|
57
|
+
results.tree1 = JSON.stringify((0, exports.cleanTree)(tree1), null, 2);
|
|
58
|
+
results.tree2 = JSON.stringify((0, exports.cleanTree)(tree2), null, 2);
|
|
59
|
+
}
|
|
60
|
+
return results;
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
log.error(`โ Failed to parse SQL for ${packageDir}`);
|
|
64
|
+
console.error(e);
|
|
65
|
+
throw e;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
exports.packageModule = packageModule;
|
|
69
|
+
const writePackage = async ({ version, extension = true, usePlan = true, packageDir, }) => {
|
|
70
|
+
const pkgPath = `${packageDir}/package.json`;
|
|
71
|
+
const pkg = require(pkgPath);
|
|
72
|
+
const extname = await (0, files_1.getExtensionName)(packageDir);
|
|
73
|
+
const makePath = `${packageDir}/Makefile`;
|
|
74
|
+
const controlPath = `${packageDir}/${extname}.control`;
|
|
75
|
+
const sqlFileName = `${extname}--${version}.sql`;
|
|
76
|
+
const Makefile = (0, fs_1.readFileSync)(makePath, 'utf-8');
|
|
77
|
+
const control = (0, fs_1.readFileSync)(controlPath, 'utf-8');
|
|
78
|
+
const { sql, diff, tree1, tree2 } = await (0, exports.packageModule)(packageDir, {
|
|
79
|
+
extension,
|
|
80
|
+
usePlan,
|
|
81
|
+
});
|
|
82
|
+
const outPath = extension ? `${packageDir}/sql` : `${packageDir}/out`;
|
|
83
|
+
(0, fs_1.rmSync)(outPath, { recursive: true, force: true });
|
|
84
|
+
(0, fs_1.mkdirSync)(outPath, { recursive: true });
|
|
85
|
+
if (extension) {
|
|
86
|
+
(0, fs_1.writeFileSync)(controlPath, control.replace(/default_version = '[0-9\.]+'/, `default_version = '${version}'`));
|
|
87
|
+
pkg.version = version;
|
|
88
|
+
(0, fs_1.writeFileSync)(pkgPath, JSON.stringify(pkg, null, 2));
|
|
89
|
+
const regex = new RegExp(`${extname}--[0-9.]+.sql`);
|
|
90
|
+
(0, fs_1.writeFileSync)(makePath, Makefile.replace(regex, sqlFileName));
|
|
91
|
+
}
|
|
92
|
+
if (diff) {
|
|
93
|
+
log.warn(`โ ๏ธ SQL diff exists! Review the ${(0, path_1.relative)(packageDir, outPath)}/ folder.`);
|
|
94
|
+
// Uncomment if needed:
|
|
95
|
+
// writeFileSync(`${outPath}/orig.${sqlFileName}.tree.json`, tree1);
|
|
96
|
+
// writeFileSync(`${outPath}/parsed.${sqlFileName}.tree.json`, tree2);
|
|
97
|
+
}
|
|
98
|
+
const writePath = `${outPath}/${sqlFileName}`;
|
|
99
|
+
(0, fs_1.writeFileSync)(writePath, sql);
|
|
100
|
+
log.success(`${(0, path_1.relative)(packageDir, writePath)} written`);
|
|
101
|
+
};
|
|
102
|
+
exports.writePackage = writePackage;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type TransformProps = {
|
|
2
|
+
[key: string]: ((value: any) => any) | {
|
|
3
|
+
[key: string]: any;
|
|
4
|
+
};
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Recursively transforms the properties of an object based on a transformation map.
|
|
8
|
+
*
|
|
9
|
+
* @param obj - The object to transform.
|
|
10
|
+
* @param props - A map of properties and their transformation rules.
|
|
11
|
+
* @returns A new object with transformed properties.
|
|
12
|
+
*/
|
|
13
|
+
export declare const transformProps: (obj: any, props: TransformProps) => any;
|
|
14
|
+
/**
|
|
15
|
+
* Parses a SQL statement, transforms its properties, and regenerates the SQL.
|
|
16
|
+
*
|
|
17
|
+
* @param statement - The SQL statement to transform.
|
|
18
|
+
* @param props - A map of properties and their transformation rules.
|
|
19
|
+
* @returns The transformed SQL statement.
|
|
20
|
+
*/
|
|
21
|
+
export declare const transform: (statement: string, props: TransformProps) => Promise<string>;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.transform = exports.transformProps = void 0;
|
|
4
|
+
const pgsql_deparser_1 = require("pgsql-deparser");
|
|
5
|
+
const pgsql_parser_1 = require("pgsql-parser");
|
|
6
|
+
/**
|
|
7
|
+
* Recursively transforms the properties of an object based on a transformation map.
|
|
8
|
+
*
|
|
9
|
+
* @param obj - The object to transform.
|
|
10
|
+
* @param props - A map of properties and their transformation rules.
|
|
11
|
+
* @returns A new object with transformed properties.
|
|
12
|
+
*/
|
|
13
|
+
const transformProps = (obj, props) => {
|
|
14
|
+
let copy;
|
|
15
|
+
// Handle primitive types, null, or undefined
|
|
16
|
+
if (obj === null || typeof obj !== 'object')
|
|
17
|
+
return obj;
|
|
18
|
+
// Handle Date
|
|
19
|
+
if (obj instanceof Date) {
|
|
20
|
+
copy = new Date();
|
|
21
|
+
copy.setTime(obj.getTime());
|
|
22
|
+
return copy;
|
|
23
|
+
}
|
|
24
|
+
// Handle Array
|
|
25
|
+
if (Array.isArray(obj)) {
|
|
26
|
+
copy = [];
|
|
27
|
+
for (let i = 0, len = obj.length; i < len; i++) {
|
|
28
|
+
copy[i] = (0, exports.transformProps)(obj[i], props);
|
|
29
|
+
}
|
|
30
|
+
return copy;
|
|
31
|
+
}
|
|
32
|
+
// Handle Object
|
|
33
|
+
if (obj instanceof Object || typeof obj === 'object') {
|
|
34
|
+
copy = {};
|
|
35
|
+
for (const attr in obj) {
|
|
36
|
+
if (Object.prototype.hasOwnProperty.call(obj, attr)) {
|
|
37
|
+
if (props.hasOwnProperty(attr)) {
|
|
38
|
+
const propRule = props[attr];
|
|
39
|
+
if (typeof propRule === 'function') {
|
|
40
|
+
// Apply function transformation
|
|
41
|
+
copy[attr] = propRule(obj[attr]);
|
|
42
|
+
}
|
|
43
|
+
else if (typeof propRule === 'object' && propRule !== null) {
|
|
44
|
+
// Apply value-based transformation
|
|
45
|
+
if (propRule.hasOwnProperty(obj[attr])) {
|
|
46
|
+
copy[attr] = propRule[obj[attr]];
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
copy[attr] = (0, exports.transformProps)(obj[attr], props);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
copy[attr] = (0, exports.transformProps)(obj[attr], props);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return copy;
|
|
59
|
+
}
|
|
60
|
+
throw new Error("Unable to copy obj! Its type isn't supported.");
|
|
61
|
+
};
|
|
62
|
+
exports.transformProps = transformProps;
|
|
63
|
+
/**
|
|
64
|
+
* Parses a SQL statement, transforms its properties, and regenerates the SQL.
|
|
65
|
+
*
|
|
66
|
+
* @param statement - The SQL statement to transform.
|
|
67
|
+
* @param props - A map of properties and their transformation rules.
|
|
68
|
+
* @returns The transformed SQL statement.
|
|
69
|
+
*/
|
|
70
|
+
const transform = async (statement, props) => {
|
|
71
|
+
let tree = await (0, pgsql_parser_1.parse)(statement);
|
|
72
|
+
tree = (0, exports.transformProps)(tree, props);
|
|
73
|
+
return await (0, pgsql_deparser_1.deparse)(tree);
|
|
74
|
+
};
|
|
75
|
+
exports.transform = transform;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PgpmOptions } from '@pgpmjs/types';
|
|
2
|
+
import { PgpmPackage } from '../core/class/pgpm';
|
|
3
|
+
interface Extensions {
|
|
4
|
+
resolved: string[];
|
|
5
|
+
external: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare const deployProject: (opts: PgpmOptions, name: string, database: string, pkg: PgpmPackage, toChange?: string) => Promise<Extensions>;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.deployProject = void 0;
|
|
37
|
+
const env_1 = require("@pgpmjs/env");
|
|
38
|
+
const logger_1 = require("@pgpmjs/logger");
|
|
39
|
+
const types_1 = require("@pgpmjs/types");
|
|
40
|
+
const path_1 = require("path");
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const pg_cache_1 = require("pg-cache");
|
|
43
|
+
const pgpm_1 = require("../core/class/pgpm");
|
|
44
|
+
const client_1 = require("../migrate/client");
|
|
45
|
+
const package_1 = require("../packaging/package");
|
|
46
|
+
// Cache for fast deployment
|
|
47
|
+
const deployFastCache = {};
|
|
48
|
+
const getCacheKey = (pg, name, database) => {
|
|
49
|
+
const { host, port, user } = pg ?? {};
|
|
50
|
+
return `${host}:${port}:${user}:${database}:${name}`;
|
|
51
|
+
};
|
|
52
|
+
const log = new logger_1.Logger('deploy');
|
|
53
|
+
const deployProject = async (opts, name, database, pkg, toChange) => {
|
|
54
|
+
const mergedOpts = (0, env_1.getEnvOptions)(opts);
|
|
55
|
+
log.info(`๐ Gathering modules from ${pkg.workspacePath}...`);
|
|
56
|
+
const modules = pkg.getModuleMap();
|
|
57
|
+
if (!modules[name]) {
|
|
58
|
+
log.error(`โ Module "${name}" not found in modules list.`);
|
|
59
|
+
throw types_1.errors.MODULE_NOT_FOUND({ name });
|
|
60
|
+
}
|
|
61
|
+
const modulePath = path.resolve(pkg.workspacePath, modules[name].path);
|
|
62
|
+
const moduleProject = new pgpm_1.PgpmPackage(modulePath);
|
|
63
|
+
log.info(`๐ฆ Resolving dependencies for ${name}...`);
|
|
64
|
+
const extensions = moduleProject.getModuleExtensions();
|
|
65
|
+
const pgPool = (0, pg_cache_1.getPgPool)({ ...opts.pg, database });
|
|
66
|
+
log.success(`๐ Starting deployment to database ${database}...`);
|
|
67
|
+
for (const extension of extensions.resolved) {
|
|
68
|
+
try {
|
|
69
|
+
if (extensions.external.includes(extension)) {
|
|
70
|
+
const msg = `CREATE EXTENSION IF NOT EXISTS "${extension}" CASCADE;`;
|
|
71
|
+
log.info(`๐ฅ Installing external extension: ${extension}`);
|
|
72
|
+
log.debug(`> ${msg}`);
|
|
73
|
+
await pgPool.query(msg);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
const modulePath = (0, path_1.resolve)(pkg.workspacePath, modules[extension].path);
|
|
77
|
+
log.info(`๐ Deploying local module: ${extension}`);
|
|
78
|
+
log.debug(`โ Path: ${modulePath}`);
|
|
79
|
+
if (mergedOpts.deployment.fast) {
|
|
80
|
+
// Use fast deployment strategy
|
|
81
|
+
const localProject = new pgpm_1.PgpmPackage(modulePath);
|
|
82
|
+
const cacheKey = getCacheKey(mergedOpts.pg, extension, database);
|
|
83
|
+
if (mergedOpts.deployment.cache && deployFastCache[cacheKey]) {
|
|
84
|
+
log.warn(`โก Using cached package for ${extension}.`);
|
|
85
|
+
await pgPool.query(deployFastCache[cacheKey].sql);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
let modulePackage;
|
|
89
|
+
try {
|
|
90
|
+
modulePackage = await (0, package_1.packageModule)(localProject.modulePath, {
|
|
91
|
+
usePlan: mergedOpts.deployment.usePlan,
|
|
92
|
+
extension: false
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
// Build comprehensive error message
|
|
97
|
+
const errorLines = [];
|
|
98
|
+
errorLines.push(`โ Failed to package module "${extension}" at path: ${modulePath}`);
|
|
99
|
+
errorLines.push(` Module Path: ${modulePath}`);
|
|
100
|
+
errorLines.push(` Workspace Path: ${pkg.workspacePath}`);
|
|
101
|
+
errorLines.push(` Error Code: ${err.code || 'N/A'}`);
|
|
102
|
+
errorLines.push(` Error Message: ${err.message || 'Unknown error'}`);
|
|
103
|
+
// Provide debugging hints
|
|
104
|
+
if (err.code === 'ENOENT') {
|
|
105
|
+
errorLines.push('๐ก Hint: File or directory not found. Check if the module path is correct.');
|
|
106
|
+
}
|
|
107
|
+
else if (err.code === 'EACCES') {
|
|
108
|
+
errorLines.push('๐ก Hint: Permission denied. Check file permissions.');
|
|
109
|
+
}
|
|
110
|
+
else if (err.message && err.message.includes('pgpm.plan')) {
|
|
111
|
+
errorLines.push('๐ก Hint: pgpm.plan file issue. Check if the plan file exists and is valid.');
|
|
112
|
+
}
|
|
113
|
+
// Log the consolidated error message
|
|
114
|
+
log.error(errorLines.join('\n'));
|
|
115
|
+
console.error(err); // Preserve full stack trace
|
|
116
|
+
throw types_1.errors.DEPLOYMENT_FAILED({
|
|
117
|
+
type: 'Deployment',
|
|
118
|
+
module: extension
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
log.debug(`โ Command: sqitch deploy db:pg:${database}`);
|
|
122
|
+
log.debug(`> ${modulePackage.sql}`);
|
|
123
|
+
await pgPool.query(modulePackage.sql);
|
|
124
|
+
if (mergedOpts.deployment.cache) {
|
|
125
|
+
deployFastCache[cacheKey] = modulePackage;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
// Use new migration system
|
|
130
|
+
log.debug(`โ Command: launchql migrate deploy db:pg:${database}`);
|
|
131
|
+
try {
|
|
132
|
+
const client = new client_1.PgpmMigrate(mergedOpts.pg);
|
|
133
|
+
const result = await client.deploy({
|
|
134
|
+
modulePath,
|
|
135
|
+
toChange,
|
|
136
|
+
useTransaction: mergedOpts.deployment.useTx,
|
|
137
|
+
logOnly: mergedOpts.deployment.logOnly
|
|
138
|
+
});
|
|
139
|
+
if (result.failed) {
|
|
140
|
+
throw types_1.errors.OPERATION_FAILED({ operation: 'Deployment', target: result.failed });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (deployError) {
|
|
144
|
+
log.error(`โ Deployment failed for module ${extension}`);
|
|
145
|
+
console.error(deployError);
|
|
146
|
+
throw types_1.errors.DEPLOYMENT_FAILED({ type: 'Deployment', module: extension });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
log.error(`๐ Error during deployment: ${err instanceof Error ? err.message : err}`);
|
|
153
|
+
console.error(err); // Keep raw error output for stack traces
|
|
154
|
+
throw types_1.errors.DEPLOYMENT_FAILED({ type: 'Deployment', module: extension });
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
log.success(`โ
Deployment complete for ${name}.`);
|
|
158
|
+
return extensions;
|
|
159
|
+
};
|
|
160
|
+
exports.deployProject = deployProject;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { PgpmOptions } from '@pgpmjs/types';
|
|
2
|
+
import { PgpmPackage } from '../core/class/pgpm';
|
|
3
|
+
interface Extensions {
|
|
4
|
+
resolved: string[];
|
|
5
|
+
external: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare const revertProject: (opts: PgpmOptions, name: string, database: string, pkg: PgpmPackage, options?: {
|
|
8
|
+
useTransaction?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Revert to a specific change (exclusive - this change will NOT be reverted)
|
|
11
|
+
* Can be a change name or a tag reference (e.g., '@v1.0.0')
|
|
12
|
+
*/
|
|
13
|
+
toChange?: string;
|
|
14
|
+
}) => Promise<Extensions>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.revertProject = void 0;
|
|
37
|
+
const logger_1 = require("@pgpmjs/logger");
|
|
38
|
+
const types_1 = require("@pgpmjs/types");
|
|
39
|
+
const path_1 = require("path");
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const pg_cache_1 = require("pg-cache");
|
|
42
|
+
const pgpm_1 = require("../core/class/pgpm");
|
|
43
|
+
const client_1 = require("../migrate/client");
|
|
44
|
+
const log = new logger_1.Logger('revert');
|
|
45
|
+
const revertProject = async (opts, name, database, pkg, options) => {
|
|
46
|
+
log.info(`๐ Gathering modules from ${pkg.workspacePath}...`);
|
|
47
|
+
const modules = pkg.getModuleMap();
|
|
48
|
+
if (!modules[name]) {
|
|
49
|
+
log.error(`โ Module "${name}" not found in modules list.`);
|
|
50
|
+
throw types_1.errors.MODULE_NOT_FOUND({ name });
|
|
51
|
+
}
|
|
52
|
+
const modulePath = path.resolve(pkg.workspacePath, modules[name].path);
|
|
53
|
+
const moduleProject = new pgpm_1.PgpmPackage(modulePath);
|
|
54
|
+
log.info(`๐ฆ Resolving dependencies for ${name}...`);
|
|
55
|
+
const extensions = moduleProject.getModuleExtensions();
|
|
56
|
+
const pgPool = (0, pg_cache_1.getPgPool)({
|
|
57
|
+
...opts.pg,
|
|
58
|
+
database
|
|
59
|
+
});
|
|
60
|
+
log.success(`๐งน Starting revert process on database ${database}...`);
|
|
61
|
+
const reversedExtensions = [...extensions.resolved].reverse();
|
|
62
|
+
for (const extension of reversedExtensions) {
|
|
63
|
+
try {
|
|
64
|
+
if (extensions.external.includes(extension)) {
|
|
65
|
+
const msg = `DROP EXTENSION IF EXISTS "${extension}" RESTRICT;`;
|
|
66
|
+
log.warn(`โ ๏ธ Dropping external extension: ${extension}`);
|
|
67
|
+
log.debug(`> ${msg}`);
|
|
68
|
+
try {
|
|
69
|
+
await pgPool.query(msg);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
if (err.code === '2BP01') { // dependent_objects_still_exist
|
|
73
|
+
log.warn(`โ ๏ธ Cannot drop extension ${extension} due to dependencies, skipping`);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
throw err;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const modulePath = (0, path_1.resolve)(pkg.workspacePath, modules[extension].path);
|
|
82
|
+
log.info(`๐ Reverting local module: ${extension}`);
|
|
83
|
+
log.debug(`โ Path: ${modulePath}`);
|
|
84
|
+
// Use new migration system
|
|
85
|
+
log.debug(`โ Command: launchql migrate revert db:pg:${database}`);
|
|
86
|
+
try {
|
|
87
|
+
const client = new client_1.PgpmMigrate(opts.pg);
|
|
88
|
+
const result = await client.revert({
|
|
89
|
+
modulePath,
|
|
90
|
+
toChange: options?.toChange,
|
|
91
|
+
useTransaction: options?.useTransaction
|
|
92
|
+
});
|
|
93
|
+
if (result.failed) {
|
|
94
|
+
throw types_1.errors.OPERATION_FAILED({ operation: 'Revert', target: result.failed });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch (revertError) {
|
|
98
|
+
log.error(`โ Revert failed for module ${extension}`);
|
|
99
|
+
throw types_1.errors.DEPLOYMENT_FAILED({ type: 'Revert', module: extension });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
log.error(`๐ Error during revert: ${e instanceof Error ? e.message : e}`);
|
|
105
|
+
console.error(e); // optional raw stack trace
|
|
106
|
+
throw types_1.errors.DEPLOYMENT_FAILED({ type: 'Revert', module: extension });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
log.success(`โ
Revert complete for ${name}.`);
|
|
110
|
+
return extensions;
|
|
111
|
+
};
|
|
112
|
+
exports.revertProject = revertProject;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PgpmOptions } from '@pgpmjs/types';
|
|
2
|
+
import { PgpmPackage } from '../core/class/pgpm';
|
|
3
|
+
interface Extensions {
|
|
4
|
+
resolved: string[];
|
|
5
|
+
external: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare const verifyProject: (opts: PgpmOptions, name: string, database: string, pkg: PgpmPackage, options?: {}) => Promise<Extensions>;
|
|
8
|
+
export {};
|