@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,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.exportMigrations = void 0;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const glob_1 = require("glob");
|
|
9
|
+
const komoji_1 = require("komoji");
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const pg_cache_1 = require("pg-cache");
|
|
12
|
+
const files_1 = require("../files");
|
|
13
|
+
const export_meta_1 = require("./export-meta");
|
|
14
|
+
const exportMigrationsToDisk = async ({ project, options, database, databaseId, author, outdir, schema_names, extensionName, metaExtensionName }) => {
|
|
15
|
+
outdir = outdir + '/';
|
|
16
|
+
const pgPool = (0, pg_cache_1.getPgPool)({
|
|
17
|
+
...options.pg,
|
|
18
|
+
database
|
|
19
|
+
});
|
|
20
|
+
const db = await pgPool.query(`select * from collections_public.database where id=$1`, [databaseId]);
|
|
21
|
+
const schemas = await pgPool.query(`select * from collections_public.schema where database_id=$1`, [databaseId]);
|
|
22
|
+
if (!db?.rows?.length) {
|
|
23
|
+
console.log('NO DATABASES.');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (!schemas?.rows?.length) {
|
|
27
|
+
console.log('NO SCHEMAS.');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const name = extensionName || db.rows[0].name;
|
|
31
|
+
const { replace, replacer } = makeReplacer({
|
|
32
|
+
schemas: schemas.rows.filter((schema) => schema_names.includes(schema.schema_name)),
|
|
33
|
+
name
|
|
34
|
+
});
|
|
35
|
+
const results = await pgPool.query(`select * from db_migrate.sql_actions order by id`);
|
|
36
|
+
const opts = {
|
|
37
|
+
name,
|
|
38
|
+
replacer,
|
|
39
|
+
outdir,
|
|
40
|
+
author
|
|
41
|
+
};
|
|
42
|
+
if (results?.rows?.length > 0) {
|
|
43
|
+
await preparePackage({
|
|
44
|
+
project,
|
|
45
|
+
author,
|
|
46
|
+
outdir,
|
|
47
|
+
name,
|
|
48
|
+
extensions: [
|
|
49
|
+
'plpgsql',
|
|
50
|
+
'uuid-ossp',
|
|
51
|
+
'citext',
|
|
52
|
+
'pgcrypto',
|
|
53
|
+
'btree_gist',
|
|
54
|
+
'postgis',
|
|
55
|
+
'hstore',
|
|
56
|
+
'db-meta-schema',
|
|
57
|
+
'launchql-inflection',
|
|
58
|
+
'launchql-uuid',
|
|
59
|
+
'launchql-utils',
|
|
60
|
+
'launchql-database-jobs',
|
|
61
|
+
'launchql-jwt-claims',
|
|
62
|
+
'launchql-stamps',
|
|
63
|
+
'launchql-base32',
|
|
64
|
+
'launchql-totp',
|
|
65
|
+
'launchql-types',
|
|
66
|
+
'launchql-default-roles'
|
|
67
|
+
]
|
|
68
|
+
});
|
|
69
|
+
(0, files_1.writeSqitchPlan)(results.rows, opts);
|
|
70
|
+
(0, files_1.writeSqitchFiles)(results.rows, opts);
|
|
71
|
+
let meta = await (0, export_meta_1.exportMeta)({
|
|
72
|
+
opts: options,
|
|
73
|
+
dbname: database,
|
|
74
|
+
database_id: databaseId
|
|
75
|
+
});
|
|
76
|
+
meta = replacer(meta);
|
|
77
|
+
await preparePackage({
|
|
78
|
+
project,
|
|
79
|
+
author,
|
|
80
|
+
outdir,
|
|
81
|
+
extensions: ['plpgsql', 'db-meta-schema', 'db-meta-modules'],
|
|
82
|
+
name: metaExtensionName
|
|
83
|
+
});
|
|
84
|
+
const metaReplacer = makeReplacer({
|
|
85
|
+
schemas: schemas.rows.filter((schema) => schema_names.includes(schema.schema_name)),
|
|
86
|
+
name: metaExtensionName
|
|
87
|
+
});
|
|
88
|
+
const metaPackage = [
|
|
89
|
+
{
|
|
90
|
+
deps: [],
|
|
91
|
+
deploy: 'migrate/meta',
|
|
92
|
+
content: `SET session_replication_role TO replica;
|
|
93
|
+
-- using replica in case we are deploying triggers to collections_public
|
|
94
|
+
|
|
95
|
+
-- unaccent, postgis affected and require grants
|
|
96
|
+
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public to public;
|
|
97
|
+
|
|
98
|
+
DO $LQLMIGRATION$
|
|
99
|
+
DECLARE
|
|
100
|
+
BEGIN
|
|
101
|
+
|
|
102
|
+
EXECUTE format('GRANT CONNECT ON DATABASE %I TO %I', current_database(), 'app_user');
|
|
103
|
+
EXECUTE format('GRANT CONNECT ON DATABASE %I TO %I', current_database(), 'app_admin');
|
|
104
|
+
|
|
105
|
+
END;
|
|
106
|
+
$LQLMIGRATION$;
|
|
107
|
+
|
|
108
|
+
${meta}
|
|
109
|
+
|
|
110
|
+
UPDATE meta_public.apis
|
|
111
|
+
SET dbname = current_database() WHERE TRUE;
|
|
112
|
+
|
|
113
|
+
UPDATE meta_public.sites
|
|
114
|
+
SET dbname = current_database() WHERE TRUE;
|
|
115
|
+
|
|
116
|
+
SET session_replication_role TO DEFAULT;
|
|
117
|
+
`
|
|
118
|
+
}
|
|
119
|
+
];
|
|
120
|
+
opts.replacer = metaReplacer.replacer;
|
|
121
|
+
opts.name = metaExtensionName;
|
|
122
|
+
(0, files_1.writeSqitchPlan)(metaPackage, opts);
|
|
123
|
+
(0, files_1.writeSqitchFiles)(metaPackage, opts);
|
|
124
|
+
}
|
|
125
|
+
pgPool.end();
|
|
126
|
+
};
|
|
127
|
+
const exportMigrations = async ({ project, options, dbInfo, author, outdir, schema_names, extensionName, metaExtensionName }) => {
|
|
128
|
+
for (let v = 0; v < dbInfo.database_ids.length; v++) {
|
|
129
|
+
const databaseId = dbInfo.database_ids[v];
|
|
130
|
+
await exportMigrationsToDisk({
|
|
131
|
+
project,
|
|
132
|
+
options,
|
|
133
|
+
extensionName,
|
|
134
|
+
metaExtensionName,
|
|
135
|
+
database: dbInfo.dbname,
|
|
136
|
+
databaseId,
|
|
137
|
+
schema_names,
|
|
138
|
+
author,
|
|
139
|
+
outdir
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
exports.exportMigrations = exportMigrations;
|
|
144
|
+
/**
|
|
145
|
+
* Creates a Sqitch package directory or resets the deploy/revert/verify directories if it exists.
|
|
146
|
+
*/
|
|
147
|
+
const preparePackage = async ({ project, author, outdir, name, extensions }) => {
|
|
148
|
+
const curDir = process.cwd();
|
|
149
|
+
const sqitchDir = path_1.default.resolve(path_1.default.join(outdir, name));
|
|
150
|
+
(0, fs_1.mkdirSync)(sqitchDir, { recursive: true });
|
|
151
|
+
process.chdir(sqitchDir);
|
|
152
|
+
const plan = (0, glob_1.sync)(path_1.default.join(sqitchDir, 'pgpm.plan'));
|
|
153
|
+
if (!plan.length) {
|
|
154
|
+
await project.initModule({
|
|
155
|
+
name,
|
|
156
|
+
description: name,
|
|
157
|
+
author,
|
|
158
|
+
extensions,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
(0, fs_1.rmSync)(path_1.default.resolve(sqitchDir, 'deploy'), { recursive: true, force: true });
|
|
163
|
+
(0, fs_1.rmSync)(path_1.default.resolve(sqitchDir, 'revert'), { recursive: true, force: true });
|
|
164
|
+
(0, fs_1.rmSync)(path_1.default.resolve(sqitchDir, 'verify'), { recursive: true, force: true });
|
|
165
|
+
}
|
|
166
|
+
process.chdir(curDir);
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Generates a function for replacing schema names and extension names in strings.
|
|
170
|
+
*/
|
|
171
|
+
const makeReplacer = ({ schemas, name }) => {
|
|
172
|
+
const replacements = ['launchql-extension-name', name];
|
|
173
|
+
const schemaReplacers = schemas.map((schema) => [
|
|
174
|
+
schema.schema_name,
|
|
175
|
+
(0, komoji_1.toSnakeCase)(`${name}_${schema.name}`)
|
|
176
|
+
]);
|
|
177
|
+
const replace = [...schemaReplacers, replacements].map(([from, to]) => [new RegExp(from, 'g'), to]);
|
|
178
|
+
const replacer = (str, n = 0) => {
|
|
179
|
+
if (!str)
|
|
180
|
+
return '';
|
|
181
|
+
if (replace[n] && replace[n].length === 2) {
|
|
182
|
+
return replacer(str.replace(replace[n][0], replace[n][1]), n + 1);
|
|
183
|
+
}
|
|
184
|
+
return str;
|
|
185
|
+
};
|
|
186
|
+
return { replacer, replace };
|
|
187
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAvailableExtensions = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Get the list of available extensions, including predefined core extensions.
|
|
6
|
+
*/
|
|
7
|
+
const getAvailableExtensions = (modules) => {
|
|
8
|
+
const coreExtensions = [
|
|
9
|
+
'address_standardizer',
|
|
10
|
+
'address_standardizer_data_us',
|
|
11
|
+
'bloom',
|
|
12
|
+
'btree_gin',
|
|
13
|
+
'btree_gist',
|
|
14
|
+
'citext',
|
|
15
|
+
'hstore',
|
|
16
|
+
'intarray',
|
|
17
|
+
'pg_trgm',
|
|
18
|
+
'pgcrypto',
|
|
19
|
+
'plpgsql',
|
|
20
|
+
'plperl',
|
|
21
|
+
'plv8',
|
|
22
|
+
'postgis_tiger_geocoder',
|
|
23
|
+
'postgis_topology',
|
|
24
|
+
'postgis',
|
|
25
|
+
'postgres_fdw',
|
|
26
|
+
'unaccent',
|
|
27
|
+
'uuid-ossp',
|
|
28
|
+
];
|
|
29
|
+
return Object.keys(modules).reduce((acc, module) => {
|
|
30
|
+
if (!acc.includes(module))
|
|
31
|
+
acc.push(module);
|
|
32
|
+
return acc;
|
|
33
|
+
}, [...coreExtensions]);
|
|
34
|
+
};
|
|
35
|
+
exports.getAvailableExtensions = getAvailableExtensions;
|
|
@@ -0,0 +1,19 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
// Re-export all extension functionality
|
|
18
|
+
__exportStar(require("./reader"), exports);
|
|
19
|
+
__exportStar(require("./writer"), exports);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ExtensionInfo } from './writer';
|
|
2
|
+
export interface Module {
|
|
3
|
+
path: string;
|
|
4
|
+
requires: string[];
|
|
5
|
+
version: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Parse a .control file and extract its metadata.
|
|
9
|
+
* https://www.postgresql.org/docs/current/extend-extensions.html
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseControlFile(filePath: string, basePath: string): Module;
|
|
12
|
+
/**
|
|
13
|
+
* Parse the pgpm.plan file to get the extension name.
|
|
14
|
+
*/
|
|
15
|
+
export declare const getExtensionName: (packageDir: string) => string;
|
|
16
|
+
/**
|
|
17
|
+
* Get detailed information about an extension in the specified directory.
|
|
18
|
+
*/
|
|
19
|
+
export declare const getExtensionInfo: (packageDir: string) => ExtensionInfo;
|
|
20
|
+
/**
|
|
21
|
+
* Get a list of extensions required by an extension from its control file.
|
|
22
|
+
* Returns an empty array if the file doesn't exist or has no requires line.
|
|
23
|
+
*/
|
|
24
|
+
export declare const getInstalledExtensions: (controlFilePath: string) => string[];
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getInstalledExtensions = exports.getExtensionInfo = exports.getExtensionName = void 0;
|
|
4
|
+
exports.parseControlFile = parseControlFile;
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const plan_1 = require("../plan");
|
|
8
|
+
/**
|
|
9
|
+
* Parse a .control file and extract its metadata.
|
|
10
|
+
* https://www.postgresql.org/docs/current/extend-extensions.html
|
|
11
|
+
*/
|
|
12
|
+
function parseControlFile(filePath, basePath) {
|
|
13
|
+
const contents = (0, fs_1.readFileSync)(filePath, 'utf-8');
|
|
14
|
+
const key = (0, path_1.basename)(filePath).split('.control')[0];
|
|
15
|
+
const requires = contents
|
|
16
|
+
.split('\n')
|
|
17
|
+
.find((line) => /^requires/.test(line))
|
|
18
|
+
?.split('=')[1]
|
|
19
|
+
.split(',')
|
|
20
|
+
.map((req) => req.replace(/[\'\s]*/g, '').trim()) || [];
|
|
21
|
+
const version = contents
|
|
22
|
+
.split('\n')
|
|
23
|
+
.find((line) => /^default_version/.test(line))
|
|
24
|
+
?.split('=')[1]
|
|
25
|
+
.replace(/[\']*/g, '')
|
|
26
|
+
.trim() || '';
|
|
27
|
+
return {
|
|
28
|
+
path: (0, path_1.dirname)((0, path_1.relative)(basePath, filePath)),
|
|
29
|
+
requires,
|
|
30
|
+
version,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Parse the pgpm.plan file to get the extension name.
|
|
35
|
+
*/
|
|
36
|
+
const getExtensionName = (packageDir) => {
|
|
37
|
+
const planPath = `${packageDir}/pgpm.plan`;
|
|
38
|
+
const plan = (0, plan_1.parsePlanFileSimple)(planPath);
|
|
39
|
+
if (!plan.package) {
|
|
40
|
+
throw new Error('No package name found in pgpm.plan!');
|
|
41
|
+
}
|
|
42
|
+
return plan.package;
|
|
43
|
+
};
|
|
44
|
+
exports.getExtensionName = getExtensionName;
|
|
45
|
+
/**
|
|
46
|
+
* Get detailed information about an extension in the specified directory.
|
|
47
|
+
*/
|
|
48
|
+
const getExtensionInfo = (packageDir) => {
|
|
49
|
+
const pkgPath = `${packageDir}/package.json`;
|
|
50
|
+
const pkg = require(pkgPath);
|
|
51
|
+
const extname = (0, exports.getExtensionName)(packageDir);
|
|
52
|
+
const version = pkg.version;
|
|
53
|
+
const Makefile = `${packageDir}/Makefile`;
|
|
54
|
+
const controlFile = `${packageDir}/${extname}.control`;
|
|
55
|
+
const sqlFile = `sql/${extname}--${version}.sql`;
|
|
56
|
+
return { extname, packageDir, version, Makefile, controlFile, sqlFile };
|
|
57
|
+
};
|
|
58
|
+
exports.getExtensionInfo = getExtensionInfo;
|
|
59
|
+
/**
|
|
60
|
+
* Get a list of extensions required by an extension from its control file.
|
|
61
|
+
* Returns an empty array if the file doesn't exist or has no requires line.
|
|
62
|
+
*/
|
|
63
|
+
const getInstalledExtensions = (controlFilePath) => {
|
|
64
|
+
try {
|
|
65
|
+
const contents = (0, fs_1.readFileSync)(controlFilePath, 'utf-8');
|
|
66
|
+
const match = contents.match(/^\s*requires\s*=\s*'([^']*)'/m);
|
|
67
|
+
if (!match) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const requiresValue = match[1];
|
|
71
|
+
if (!requiresValue || requiresValue.trim() === '') {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
return requiresValue
|
|
75
|
+
.split(',')
|
|
76
|
+
.map((ext) => ext.trim())
|
|
77
|
+
.filter((ext) => ext.length > 0);
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
if (e.code === 'ENOENT') {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
throw new Error(`Error reading control file at ${controlFilePath}: ${e.message}`);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
exports.getInstalledExtensions = getInstalledExtensions;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write the Makefile for the extension.
|
|
3
|
+
*/
|
|
4
|
+
export declare const writeExtensionMakefile: (outputPath: string, extname: string, version: string) => void;
|
|
5
|
+
/**
|
|
6
|
+
* Generate content for a .control file
|
|
7
|
+
* https://www.postgresql.org/docs/current/extend-extensions.html
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateControlFileContent(options: {
|
|
10
|
+
name: string;
|
|
11
|
+
version: string;
|
|
12
|
+
comment?: string;
|
|
13
|
+
requires?: string[];
|
|
14
|
+
default_version?: string;
|
|
15
|
+
relocatable?: boolean;
|
|
16
|
+
superuser?: boolean;
|
|
17
|
+
schema?: string;
|
|
18
|
+
module_pathname?: string;
|
|
19
|
+
}): string;
|
|
20
|
+
/**
|
|
21
|
+
* Write the control file for the extension.
|
|
22
|
+
*/
|
|
23
|
+
export declare const writeExtensionControlFile: (outputPath: string, extname: string, extensions: string[], version: string) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Interface for extension information
|
|
26
|
+
*/
|
|
27
|
+
export interface ExtensionInfo {
|
|
28
|
+
extname: string;
|
|
29
|
+
packageDir: string;
|
|
30
|
+
version: string;
|
|
31
|
+
Makefile: string;
|
|
32
|
+
controlFile: string;
|
|
33
|
+
sqlFile: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Write control and Makefile for the extension with given data.
|
|
37
|
+
* If extInfo is not provided, it will be generated from packageDir.
|
|
38
|
+
*/
|
|
39
|
+
export declare const writeExtensions: (packageDir: string, extensions: string[], extInfo?: ExtensionInfo) => void;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeExtensions = exports.writeExtensionControlFile = exports.writeExtensionMakefile = void 0;
|
|
4
|
+
exports.generateControlFileContent = generateControlFileContent;
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const reader_1 = require("./reader");
|
|
7
|
+
/**
|
|
8
|
+
* Write the Makefile for the extension.
|
|
9
|
+
*/
|
|
10
|
+
const writeExtensionMakefile = (outputPath, extname, version) => {
|
|
11
|
+
const content = `EXTENSION = ${extname}
|
|
12
|
+
DATA = sql/${extname}--${version}.sql
|
|
13
|
+
|
|
14
|
+
PG_CONFIG = pg_config
|
|
15
|
+
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
|
16
|
+
include $(PGXS)
|
|
17
|
+
`;
|
|
18
|
+
(0, fs_1.writeFileSync)(outputPath, content);
|
|
19
|
+
};
|
|
20
|
+
exports.writeExtensionMakefile = writeExtensionMakefile;
|
|
21
|
+
/**
|
|
22
|
+
* Generate content for a .control file
|
|
23
|
+
* https://www.postgresql.org/docs/current/extend-extensions.html
|
|
24
|
+
*/
|
|
25
|
+
function generateControlFileContent(options) {
|
|
26
|
+
const { name, version, comment = `${name} extension`, requires = [], default_version = version, relocatable = false, superuser = false, schema, module_pathname } = options;
|
|
27
|
+
let content = `# ${name} extension
|
|
28
|
+
comment = '${comment}'
|
|
29
|
+
default_version = '${default_version}'
|
|
30
|
+
`;
|
|
31
|
+
if (module_pathname) {
|
|
32
|
+
content += `module_pathname = '${module_pathname}'\n`;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
content += `module_pathname = '$libdir/${name}'\n`;
|
|
36
|
+
}
|
|
37
|
+
if (requires.length > 0) {
|
|
38
|
+
content += `requires = '${requires.join(',')}'\n`;
|
|
39
|
+
}
|
|
40
|
+
content += `relocatable = ${relocatable}
|
|
41
|
+
superuser = ${superuser}\n`;
|
|
42
|
+
if (schema) {
|
|
43
|
+
content += `schema = ${schema}\n`;
|
|
44
|
+
}
|
|
45
|
+
return content;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Write the control file for the extension.
|
|
49
|
+
*/
|
|
50
|
+
const writeExtensionControlFile = (outputPath, extname, extensions, version) => {
|
|
51
|
+
const content = generateControlFileContent({
|
|
52
|
+
name: extname,
|
|
53
|
+
version,
|
|
54
|
+
requires: extensions
|
|
55
|
+
});
|
|
56
|
+
(0, fs_1.writeFileSync)(outputPath, content);
|
|
57
|
+
};
|
|
58
|
+
exports.writeExtensionControlFile = writeExtensionControlFile;
|
|
59
|
+
/**
|
|
60
|
+
* Write control and Makefile for the extension with given data.
|
|
61
|
+
* If extInfo is not provided, it will be generated from packageDir.
|
|
62
|
+
*/
|
|
63
|
+
const writeExtensions = (packageDir, extensions, extInfo) => {
|
|
64
|
+
// If extInfo is not provided, get it from packageDir
|
|
65
|
+
const info = extInfo || (0, reader_1.getExtensionInfo)(packageDir);
|
|
66
|
+
const { controlFile, Makefile, extname, version } = info;
|
|
67
|
+
(0, exports.writeExtensionControlFile)(controlFile, extname, extensions, version);
|
|
68
|
+
(0, exports.writeExtensionMakefile)(Makefile, extname, version);
|
|
69
|
+
};
|
|
70
|
+
exports.writeExtensions = writeExtensions;
|
package/files/index.d.ts
ADDED
package/files/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
// Re-export all functionality from package-files
|
|
18
|
+
__exportStar(require("./extension"), exports);
|
|
19
|
+
__exportStar(require("./plan"), exports);
|
|
20
|
+
__exportStar(require("./sql"), exports);
|
|
21
|
+
__exportStar(require("./sql-scripts"), exports);
|
|
22
|
+
__exportStar(require("./types"), exports);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get a timestamp for the plan file
|
|
3
|
+
*/
|
|
4
|
+
export declare function getNow(): string;
|
|
5
|
+
export interface PlanEntry {
|
|
6
|
+
change: string;
|
|
7
|
+
dependencies: string[];
|
|
8
|
+
comment?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface GeneratePlanOptions {
|
|
11
|
+
moduleName: string;
|
|
12
|
+
uri?: string;
|
|
13
|
+
entries: PlanEntry[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Generate a plan file content from structured data
|
|
17
|
+
*/
|
|
18
|
+
export declare function generatePlan(options: GeneratePlanOptions): string;
|
|
19
|
+
/**
|
|
20
|
+
* Write a generated plan file to disk
|
|
21
|
+
*/
|
|
22
|
+
export declare function writePlan(planPath: string, plan: string): void;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getNow = getNow;
|
|
7
|
+
exports.generatePlan = generatePlan;
|
|
8
|
+
exports.writePlan = writePlan;
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
/**
|
|
11
|
+
* Get a UTC timestamp string
|
|
12
|
+
*/
|
|
13
|
+
function getUTCTimestamp(d = new Date()) {
|
|
14
|
+
return (d.getUTCFullYear() +
|
|
15
|
+
'-' + String(d.getUTCMonth() + 1).padStart(2, '0') +
|
|
16
|
+
'-' + String(d.getUTCDate()).padStart(2, '0') +
|
|
17
|
+
'T' + String(d.getUTCHours()).padStart(2, '0') +
|
|
18
|
+
':' + String(d.getUTCMinutes()).padStart(2, '0') +
|
|
19
|
+
':' + String(d.getUTCSeconds()).padStart(2, '0') +
|
|
20
|
+
'Z');
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get a timestamp for the plan file
|
|
24
|
+
*/
|
|
25
|
+
function getNow() {
|
|
26
|
+
return process.env.NODE_ENV === 'test'
|
|
27
|
+
? getUTCTimestamp(new Date('2017-08-11T08:11:51Z'))
|
|
28
|
+
: getUTCTimestamp(new Date());
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Generate a plan file content from structured data
|
|
32
|
+
*/
|
|
33
|
+
function generatePlan(options) {
|
|
34
|
+
const { moduleName, uri, entries } = options;
|
|
35
|
+
const now = getNow();
|
|
36
|
+
const planfile = [
|
|
37
|
+
`%syntax-version=1.0.0`,
|
|
38
|
+
`%project=${moduleName}`,
|
|
39
|
+
`%uri=${uri || moduleName}`
|
|
40
|
+
];
|
|
41
|
+
// Generate the plan entries
|
|
42
|
+
entries.forEach(entry => {
|
|
43
|
+
if (entry.dependencies && entry.dependencies.length > 0) {
|
|
44
|
+
planfile.push(`${entry.change} [${entry.dependencies.join(' ')}] ${now} launchql <launchql@5b0c196eeb62>${entry.comment ? ` # ${entry.comment}` : ''}`);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
planfile.push(`${entry.change} ${now} launchql <launchql@5b0c196eeb62>${entry.comment ? ` # ${entry.comment}` : ''}`);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return planfile.join('\n');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Write a generated plan file to disk
|
|
54
|
+
*/
|
|
55
|
+
function writePlan(planPath, plan) {
|
|
56
|
+
fs_1.default.writeFileSync(planPath, plan);
|
|
57
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
// Re-export all plan functionality
|
|
18
|
+
__exportStar(require("./generator"), exports);
|
|
19
|
+
__exportStar(require("./parser"), exports);
|
|
20
|
+
__exportStar(require("./validators"), exports);
|
|
21
|
+
__exportStar(require("./writer"), exports);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ExtendedPlanFile, ParseResult, PlanFile } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Parse a Sqitch plan file with full validation
|
|
4
|
+
* Supports both changes and tags
|
|
5
|
+
*/
|
|
6
|
+
export declare function parsePlanFile(planPath: string): ParseResult<ExtendedPlanFile>;
|
|
7
|
+
/**
|
|
8
|
+
* Resolve a reference within a plan file context
|
|
9
|
+
* Handles symbolic references (HEAD, ROOT) and relative references
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveReference(ref: string, plan: ExtendedPlanFile, currentPackage?: string): {
|
|
12
|
+
change?: string;
|
|
13
|
+
tag?: string;
|
|
14
|
+
error?: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Simple plan file parser without validation (for backwards compatibility)
|
|
18
|
+
*/
|
|
19
|
+
export declare function parsePlanFileSimple(planPath: string): PlanFile;
|
|
20
|
+
/**
|
|
21
|
+
* Get all change names from a plan file
|
|
22
|
+
*/
|
|
23
|
+
export declare function getChanges(planPath: string): string[];
|
|
24
|
+
/**
|
|
25
|
+
* Get the latest (last) change from a plan file
|
|
26
|
+
*/
|
|
27
|
+
export declare function getLatestChange(planPath: string): string;
|