@intentius/sql-yodeler 0.2.0 → 0.3.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/README.md +3 -3
- package/dist/chant/build.js +7 -0
- package/dist/chant/build.js.map +1 -1
- package/dist/ci/render.d.ts +289 -0
- package/dist/ci/render.js +688 -0
- package/dist/ci/render.js.map +1 -0
- package/dist/ci/replay.d.ts +17 -0
- package/dist/ci/replay.js +69 -0
- package/dist/ci/replay.js.map +1 -0
- package/dist/commands/apply.d.ts +113 -0
- package/dist/commands/apply.js +228 -21
- package/dist/commands/apply.js.map +1 -1
- package/dist/commands/approve.js +44 -0
- package/dist/commands/approve.js.map +1 -1
- package/dist/commands/checkpoint.d.ts +3 -0
- package/dist/commands/checkpoint.js +78 -0
- package/dist/commands/checkpoint.js.map +1 -0
- package/dist/commands/ci.d.ts +3 -0
- package/dist/commands/ci.js +118 -0
- package/dist/commands/ci.js.map +1 -0
- package/dist/commands/docs.d.ts +11 -0
- package/dist/commands/docs.js +108 -0
- package/dist/commands/docs.js.map +1 -0
- package/dist/commands/drift.d.ts +13 -1
- package/dist/commands/drift.js +18 -2
- package/dist/commands/drift.js.map +1 -1
- package/dist/commands/index.js +10 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/lint.js +11 -3
- package/dist/commands/lint.js.map +1 -1
- package/dist/commands/override.js +48 -16
- package/dist/commands/override.js.map +1 -1
- package/dist/commands/plan.js +5 -1
- package/dist/commands/plan.js.map +1 -1
- package/dist/commands/report.d.ts +13 -0
- package/dist/commands/report.js +121 -0
- package/dist/commands/report.js.map +1 -0
- package/dist/commands/revert.d.ts +20 -0
- package/dist/commands/revert.js +246 -0
- package/dist/commands/revert.js.map +1 -0
- package/dist/commands/status.js +32 -5
- package/dist/commands/status.js.map +1 -1
- package/dist/config/base.d.ts +69 -0
- package/dist/config/base.js +121 -0
- package/dist/config/base.js.map +1 -0
- package/dist/config/define.d.ts +123 -1
- package/dist/config/define.js +2 -0
- package/dist/config/define.js.map +1 -1
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/load.d.ts +1 -1
- package/dist/config/load.js +90 -5
- package/dist/config/load.js.map +1 -1
- package/dist/config/settings.d.ts +4 -1
- package/dist/config/settings.js +8 -2
- package/dist/config/settings.js.map +1 -1
- package/dist/exit.js +1 -1
- package/dist/exit.js.map +1 -1
- package/dist/history/postgres/ddl.d.ts +18 -0
- package/dist/history/postgres/ddl.js +27 -2
- package/dist/history/postgres/ddl.js.map +1 -1
- package/dist/history/postgres/store.d.ts +2 -0
- package/dist/history/postgres/store.js +7 -1
- package/dist/history/postgres/store.js.map +1 -1
- package/dist/history/rows.d.ts +16 -3
- package/dist/history/rows.js +30 -1
- package/dist/history/rows.js.map +1 -1
- package/dist/history/store.d.ts +2 -0
- package/dist/history/store.js +2 -2
- package/dist/history/store.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lint/check.js +17 -2
- package/dist/lint/check.js.map +1 -1
- package/dist/lint/report.js +1 -1
- package/dist/lint/report.js.map +1 -1
- package/dist/lint/routines.d.ts +26 -0
- package/dist/lint/routines.js +65 -0
- package/dist/lint/routines.js.map +1 -0
- package/dist/lint/rules.d.ts +16 -4
- package/dist/lint/rules.js +9 -4
- package/dist/lint/rules.js.map +1 -1
- package/dist/mcp/tools.d.ts +1 -1
- package/dist/mcp/tools.js +1 -1
- package/dist/mcp/tools.js.map +1 -1
- package/dist/migrations/checkpoint.d.ts +45 -0
- package/dist/migrations/checkpoint.js +110 -0
- package/dist/migrations/checkpoint.js.map +1 -0
- package/dist/migrations/create.js +2 -0
- package/dist/migrations/create.js.map +1 -1
- package/dist/migrations/document.d.ts +10 -0
- package/dist/migrations/document.js +1 -0
- package/dist/migrations/document.js.map +1 -1
- package/dist/migrations/index.d.ts +2 -0
- package/dist/migrations/index.js +2 -0
- package/dist/migrations/index.js.map +1 -1
- package/dist/migrations/routines.d.ts +31 -0
- package/dist/migrations/routines.js +55 -0
- package/dist/migrations/routines.js.map +1 -0
- package/dist/notify/index.d.ts +124 -0
- package/dist/notify/index.js +210 -0
- package/dist/notify/index.js.map +1 -0
- package/dist/notify/verify.d.ts +53 -0
- package/dist/notify/verify.js +71 -0
- package/dist/notify/verify.js.map +1 -0
- package/dist/pr/model.d.ts +3 -0
- package/dist/pr/model.js +16 -2
- package/dist/pr/model.js.map +1 -1
- package/dist/pr/render.js +27 -1
- package/dist/pr/render.js.map +1 -1
- package/dist/project.d.ts +19 -2
- package/dist/project.js +33 -1
- package/dist/project.js.map +1 -1
- package/dist/replay/replay.d.ts +9 -1
- package/dist/replay/replay.js +62 -31
- package/dist/replay/replay.js.map +1 -1
- package/dist/replay/report.js +1 -1
- package/dist/replay/report.js.map +1 -1
- package/dist/report/audit.d.ts +138 -0
- package/dist/report/audit.js +202 -0
- package/dist/report/audit.js.map +1 -0
- package/dist/report/jsonl.d.ts +21 -0
- package/dist/report/jsonl.js +52 -0
- package/dist/report/jsonl.js.map +1 -0
- package/dist/report/model.d.ts +68 -0
- package/dist/report/model.js +127 -0
- package/dist/report/model.js.map +1 -0
- package/dist/report/render.d.ts +18 -0
- package/dist/report/render.js +127 -0
- package/dist/report/render.js.map +1 -0
- package/dist/schema-docs/render.d.ts +49 -0
- package/dist/schema-docs/render.js +359 -0
- package/dist/schema-docs/render.js.map +1 -0
- package/dist/schemas.d.ts +5 -2
- package/dist/schemas.js +5 -2
- package/dist/schemas.js.map +1 -1
- package/dist/sources/ddl.d.ts +53 -0
- package/dist/sources/ddl.js +347 -0
- package/dist/sources/ddl.js.map +1 -0
- package/dist/sources/index.d.ts +69 -0
- package/dist/sources/index.js +170 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/steps/postgres-migration.d.ts +35 -25
- package/dist/steps/postgres-migration.js +42 -29
- package/dist/steps/postgres-migration.js.map +1 -1
- package/dist/tenants/index.d.ts +40 -0
- package/dist/tenants/index.js +122 -0
- package/dist/tenants/index.js.map +1 -0
- package/dist/tenants/target.d.ts +23 -0
- package/dist/tenants/target.js +29 -0
- package/dist/tenants/target.js.map +1 -0
- package/dist/versioned/engine.d.ts +6 -0
- package/dist/versioned/engine.js +12 -2
- package/dist/versioned/engine.js.map +1 -1
- package/dist/versioned/index.d.ts +1 -0
- package/dist/versioned/index.js +1 -0
- package/dist/versioned/index.js.map +1 -1
- package/dist/versioned/op.d.ts +6 -1
- package/dist/versioned/op.js +7 -2
- package/dist/versioned/op.js.map +1 -1
- package/dist/versioned/policy.d.ts +33 -2
- package/dist/versioned/policy.js +59 -8
- package/dist/versioned/policy.js.map +1 -1
- package/dist/versioned/report.js +9 -0
- package/dist/versioned/report.js.map +1 -1
- package/dist/versioned/revert.d.ts +128 -0
- package/dist/versioned/revert.js +251 -0
- package/dist/versioned/revert.js.map +1 -0
- package/dist/versioned/state.d.ts +25 -0
- package/dist/versioned/state.js +36 -3
- package/dist/versioned/state.js.map +1 -1
- package/dist/waves/index.d.ts +179 -0
- package/dist/waves/index.js +268 -0
- package/dist/waves/index.js.map +1 -0
- package/dist/waves/promotion.d.ts +56 -0
- package/dist/waves/promotion.js +108 -0
- package/dist/waves/promotion.js.map +1 -0
- package/dist/waves/record.d.ts +24 -0
- package/dist/waves/record.js +20 -0
- package/dist/waves/record.js.map +1 -0
- package/package.json +11 -7
- package/schemas/apply.schema.json +162 -3
- package/schemas/checkpoint.schema.json +19 -0
- package/schemas/drift.schema.json +26 -1
- package/schemas/event.schema.json +36 -0
- package/schemas/lint.schema.json +4 -0
- package/schemas/plan.schema.json +118 -0
- package/schemas/report.schema.json +114 -0
- package/schemas/revert.schema.json +69 -0
- package/schemas/status.schema.json +64 -3
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DDL sources (#67): schema that an ORM defines, read from the DDL it
|
|
3
|
+
* prints, beside the declarations in `src/`.
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* // yodel.config.ts
|
|
7
|
+
* export default defineConfig({
|
|
8
|
+
* sources: {
|
|
9
|
+
* prisma: { command: "npx prisma migrate diff --from-empty --to-schema-datamodel prisma/schema.prisma --script", schema: "app" },
|
|
10
|
+
* legacy: { file: "db/legacy.sql" },
|
|
11
|
+
* },
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* Before each build, yodel runs each source's command (or reads its file)
|
|
16
|
+
* in the project directory and writes the DDL out as declarations in
|
|
17
|
+
* `<sourceDir>/<name>.generated.ts`, the file `chant import` would write.
|
|
18
|
+
* The build, and so plan, new, apply and drift, read it like any other
|
|
19
|
+
* declaration; the ApplyOp's own build finds it there too. Commit it: a
|
|
20
|
+
* build that does not run yodel (chant build, an Op run elsewhere) reads
|
|
21
|
+
* the committed file.
|
|
22
|
+
*
|
|
23
|
+
* Each object has one owner: an object a source creates that `src/` (or
|
|
24
|
+
* another source) also declares is an error, naming both.
|
|
25
|
+
*/
|
|
26
|
+
import { exec } from "node:child_process";
|
|
27
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
28
|
+
import { isAbsolute, join, relative } from "node:path";
|
|
29
|
+
import { YodelError } from "../project.js";
|
|
30
|
+
import { ddlToDeclarations } from "./ddl.js";
|
|
31
|
+
const SOURCE_NAME = /^[a-z][a-z0-9-]*$/;
|
|
32
|
+
/** The generated file a source writes, relative to the project directory. */
|
|
33
|
+
export const generatedPath = (project, name) => join(project.sourceDir, `${name}.generated.ts`);
|
|
34
|
+
/** Checks `sources` in yodel.config.ts. */
|
|
35
|
+
export function checkSources(value, where) {
|
|
36
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
37
|
+
throw new YodelError(`${where}: expected an object keyed by source name`);
|
|
38
|
+
for (const [name, source] of Object.entries(value)) {
|
|
39
|
+
const at = `${where}.${name}`;
|
|
40
|
+
if (!SOURCE_NAME.test(name))
|
|
41
|
+
throw new YodelError(`${at}: a source's name is lowercase letters, digits and -, starting with a letter`);
|
|
42
|
+
if (typeof source !== "object" || source === null || Array.isArray(source))
|
|
43
|
+
throw new YodelError(`${at}: expected { command } or { file }`);
|
|
44
|
+
for (const k of Object.keys(source))
|
|
45
|
+
if (!["command", "file", "schema"].includes(k))
|
|
46
|
+
throw new YodelError(`${at}.${k}: unknown setting (expected command, file, schema)`);
|
|
47
|
+
const s = source;
|
|
48
|
+
if ((s.command === undefined) === (s.file === undefined))
|
|
49
|
+
throw new YodelError(`${at}: give one of command and file`);
|
|
50
|
+
for (const k of ["command", "file", "schema"]) {
|
|
51
|
+
if (s[k] !== undefined && (typeof s[k] !== "string" || s[k] === ""))
|
|
52
|
+
throw new YodelError(`${at}.${k}: expected a non-empty string`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
function runCommand(command, cwd, env) {
|
|
58
|
+
return new Promise((resolve, reject) => {
|
|
59
|
+
exec(command, { cwd, env: env ?? process.env, maxBuffer: 64 * 1024 * 1024 }, (error, stdout, stderr) => {
|
|
60
|
+
if (error)
|
|
61
|
+
reject(new YodelError(`${command} failed (exit ${String(error.code ?? "?")})${stderr.trim() ? `:\n${stderr.trim()}` : ""}`));
|
|
62
|
+
else
|
|
63
|
+
resolve(stdout);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/** Reads one source's DDL. */
|
|
68
|
+
async function readDdl(project, name, source, env) {
|
|
69
|
+
if (source.command !== undefined) {
|
|
70
|
+
const origin = `sources.${name} (${source.command})`;
|
|
71
|
+
try {
|
|
72
|
+
return { ddl: await runCommand(source.command, project.dir, env), origin };
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
throw new YodelError(`yodel.config.ts sources.${name}: ${e instanceof Error ? e.message : String(e)}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const given = source.file ?? "";
|
|
79
|
+
const file = isAbsolute(given) ? given : join(project.dir, given);
|
|
80
|
+
if (!existsSync(file))
|
|
81
|
+
throw new YodelError(`yodel.config.ts sources.${name}: no file ${relative(project.dir, file)}`);
|
|
82
|
+
return { ddl: readFileSync(file, "utf8"), origin: `sources.${name} (${relative(project.dir, file)})` };
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Writes each source's declarations to its generated file, and returns what
|
|
86
|
+
* each declared. A file whose content is unchanged is not rewritten.
|
|
87
|
+
*/
|
|
88
|
+
export async function syncSources(project, options = {}) {
|
|
89
|
+
const sources = project.yodel?.config.sources ?? {};
|
|
90
|
+
const synced = [];
|
|
91
|
+
for (const [name, source] of Object.entries(sources)) {
|
|
92
|
+
const { ddl, origin } = await readDdl(project, name, source, options.env);
|
|
93
|
+
const how = source.command !== undefined ? `the output of: ${source.command}` : `the DDL in ${source.file ?? ""}`;
|
|
94
|
+
const declarations = await ddlToDeclarations(project.dialect, ddl, {
|
|
95
|
+
origin: `yodel.config.ts ${origin}`,
|
|
96
|
+
schema: source.schema,
|
|
97
|
+
header: `Generated by yodel from the DDL source "${name}" in yodel.config.ts,\n${how}\nDo not edit: yodel writes it again before each build.`,
|
|
98
|
+
});
|
|
99
|
+
const path = generatedPath(project, name);
|
|
100
|
+
const full = join(project.dir, path);
|
|
101
|
+
const before = existsSync(full) ? readFileSync(full, "utf8") : undefined;
|
|
102
|
+
if (before !== declarations.content)
|
|
103
|
+
writeFileSync(full, declarations.content);
|
|
104
|
+
synced.push({ name, path, objects: declarations.objects });
|
|
105
|
+
}
|
|
106
|
+
return synced;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* chant's build refuses two declarations exported under one name. When one
|
|
110
|
+
* of them is a source's, that is an object declared twice: say so, naming
|
|
111
|
+
* the source.
|
|
112
|
+
*/
|
|
113
|
+
export function duplicateExport(buildOutput, synced) {
|
|
114
|
+
const name = /Duplicate export name "([^"]+)"/.exec(buildOutput)?.[1];
|
|
115
|
+
if (!name)
|
|
116
|
+
return undefined;
|
|
117
|
+
const owners = synced.flatMap((s) => s.objects.filter((o) => o.export === name).map((o) => ({ source: s, object: o })));
|
|
118
|
+
const [first] = owners;
|
|
119
|
+
if (!first)
|
|
120
|
+
return undefined;
|
|
121
|
+
const elsewhere = owners.length > 1 ? `the source "${owners[1]?.source.name ?? ""}"` : "src/";
|
|
122
|
+
return new YodelError(`each object has one owner, and ${first.object.name} is declared twice: by ${elsewhere} (export ${name}) and by the source "${first.source.name}" (${first.source.path}). Leave it to one of them.`);
|
|
123
|
+
}
|
|
124
|
+
/** `schema.name` of a built object, read from its CREATE, or undefined when it cannot be read. */
|
|
125
|
+
async function builtName(dialect, type, ddl) {
|
|
126
|
+
try {
|
|
127
|
+
const first = ddl.split(/;\s*\n\s*COMMENT ON\b/i)[0] ?? ddl;
|
|
128
|
+
const [object] = (await ddlToDeclarations(dialect, first, { origin: "build" })).objects;
|
|
129
|
+
return object && (type === undefined || object.type === type) ? object.name : undefined;
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Each object declared once: an object a source creates that another export
|
|
137
|
+
* in the build (in `src/`, or another source) also creates is an error.
|
|
138
|
+
*/
|
|
139
|
+
export async function checkOwnership(output, synced) {
|
|
140
|
+
if (synced.length === 0)
|
|
141
|
+
return;
|
|
142
|
+
const owner = new Map();
|
|
143
|
+
for (const source of synced)
|
|
144
|
+
for (const object of source.objects)
|
|
145
|
+
owner.set(`${object.type} ${object.name}`, { source, object });
|
|
146
|
+
const problems = [];
|
|
147
|
+
for (const built of output.objects) {
|
|
148
|
+
if (synced.some((s) => s.objects.some((o) => o.export === built.export)))
|
|
149
|
+
continue;
|
|
150
|
+
const name = await builtName(output.dialect, built.type, built.ddl);
|
|
151
|
+
if (!name)
|
|
152
|
+
continue;
|
|
153
|
+
const hit = owner.get(`${built.type ?? ""} ${name}`);
|
|
154
|
+
if (hit)
|
|
155
|
+
problems.push(`${name} is declared by ${built.export} and by the source "${hit.source.name}" (${hit.object.export} in ${hit.source.path})`);
|
|
156
|
+
}
|
|
157
|
+
const seen = new Map();
|
|
158
|
+
for (const source of synced) {
|
|
159
|
+
for (const object of source.objects) {
|
|
160
|
+
const key = `${object.type} ${object.name}`;
|
|
161
|
+
const other = seen.get(key);
|
|
162
|
+
if (other && other !== source.name)
|
|
163
|
+
problems.push(`${object.name} is declared by the sources "${other}" and "${source.name}"`);
|
|
164
|
+
seen.set(key, source.name);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (problems.length > 0)
|
|
168
|
+
throw new YodelError(`each object has one owner, and ${problems.length === 1 ? "one is declared twice" : `${String(problems.length)} are declared twice`}:\n${problems.map((p) => ` - ${p}`).join("\n")}`);
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sources/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,40 +15,50 @@
|
|
|
15
15
|
*
|
|
16
16
|
* - The declaration is the migration's recorded schema (`migration.json`'s
|
|
17
17
|
* `schema`), written to a temporary build file, not a fresh `chant build`.
|
|
18
|
-
* -
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* - It is built with `gates: "outer"`: the approval is the migration's (the
|
|
19
|
+
* step and its options are in the migration's checksum, so in the plan
|
|
20
|
+
* digest the migrations Op's gate approved), so the Op has neither of its
|
|
21
|
+
* gates (before the switch, before the contract) and no Contract phase of
|
|
22
|
+
* its own. The verification still runs before the switch, and a
|
|
22
23
|
* difference (a row whose new column is not the expression over the old,
|
|
23
24
|
* a NULL where NOT NULL is declared) fails the step with nothing switched.
|
|
24
|
-
* -
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
25
|
+
* - After the Retain phase the step runs the lexicon's contract activity
|
|
26
|
+
* (`postgresMigrationContract`, the Op's own Contract step, with the same
|
|
27
|
+
* arguments), under the same approval. It drops the old column (and a
|
|
28
|
+
* rename's trigger) only once its retention date has passed. The
|
|
29
|
+
* retention is the step's `options.retain` when it sets one, else none
|
|
30
|
+
* (`0s`): the contract drops the old column in the same run, right after
|
|
31
|
+
* the switch, as the migration's recorded schema says it is gone. A step
|
|
32
|
+
* that sets `retain` keeps the old column that long; the step succeeds
|
|
33
|
+
* with it kept, its note says until when, and dropping it after the date
|
|
34
|
+
* is `chant run` of the Op's declaration (in `migration.json`), whose
|
|
35
|
+
* contract is convergent.
|
|
36
|
+
* - It is built with `onFailure: "keep"`, so a step that failed or was
|
|
37
|
+
* stopped keeps what the expand added and resumes on the next `yodel
|
|
38
|
+
* apply`. Every phase of the Op re-reads the server and does what is left
|
|
39
|
+
* of it: the expand finds the new column there and adds nothing, the dual
|
|
40
|
+
* write finds its trigger, the backfill skips every batch whose receipt
|
|
41
|
+
* is in `<schema>.__chant_receipts` (each receipt commits with its batch,
|
|
42
|
+
* so a batch is never filled twice), the carry over builds only the
|
|
43
|
+
* indexes and constraints not yet built (an INVALID one it left is built
|
|
44
|
+
* again), the verification runs again over every row, and a switch that
|
|
45
|
+
* already ran is not run again. To start over instead, drop the new
|
|
46
|
+
* column, its trigger and function (chant's working objects, named in
|
|
47
|
+
* their comments; a refusal says so).
|
|
42
48
|
*/
|
|
43
|
-
import type { OpConfig
|
|
49
|
+
import type { OpConfig } from "@intentius/chant/op/types";
|
|
44
50
|
import type { ActivityFn } from "@intentius/chant/op/activity-registry";
|
|
45
51
|
import type { StepRecord } from "@intentius/chant/op/local-executor";
|
|
46
52
|
import type { PgMigrationOptions } from "./kinds.js";
|
|
47
53
|
import { type RunOpOptions } from "./run.js";
|
|
48
54
|
/** The retention a step runs with when its options set none: the contract runs in the same apply. */
|
|
49
55
|
export declare const STEP_RETAIN = "0s";
|
|
50
|
-
/**
|
|
51
|
-
|
|
56
|
+
/**
|
|
57
|
+
* The Op's Contract step for a config built with `gates: "outer"`: the
|
|
58
|
+
* lexicon's contract activity with the Retain step's arguments. It drops the
|
|
59
|
+
* old column only once its retention date has passed.
|
|
60
|
+
*/
|
|
61
|
+
export declare function contractPhase(config: OpConfig): OpConfig["phases"][number];
|
|
52
62
|
/** The Op a step runs. `buildPath` is the recorded schema's file; `projectDir` holds chant.config.ts. */
|
|
53
63
|
export declare function pgMigrationOpConfig(options: PgMigrationOptions, ctx: {
|
|
54
64
|
environment: string;
|
|
@@ -15,30 +15,36 @@
|
|
|
15
15
|
*
|
|
16
16
|
* - The declaration is the migration's recorded schema (`migration.json`'s
|
|
17
17
|
* `schema`), written to a temporary build file, not a fresh `chant build`.
|
|
18
|
-
* -
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* - It is built with `gates: "outer"`: the approval is the migration's (the
|
|
19
|
+
* step and its options are in the migration's checksum, so in the plan
|
|
20
|
+
* digest the migrations Op's gate approved), so the Op has neither of its
|
|
21
|
+
* gates (before the switch, before the contract) and no Contract phase of
|
|
22
|
+
* its own. The verification still runs before the switch, and a
|
|
22
23
|
* difference (a row whose new column is not the expression over the old,
|
|
23
24
|
* a NULL where NOT NULL is declared) fails the step with nothing switched.
|
|
24
|
-
* -
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
25
|
+
* - After the Retain phase the step runs the lexicon's contract activity
|
|
26
|
+
* (`postgresMigrationContract`, the Op's own Contract step, with the same
|
|
27
|
+
* arguments), under the same approval. It drops the old column (and a
|
|
28
|
+
* rename's trigger) only once its retention date has passed. The
|
|
29
|
+
* retention is the step's `options.retain` when it sets one, else none
|
|
30
|
+
* (`0s`): the contract drops the old column in the same run, right after
|
|
31
|
+
* the switch, as the migration's recorded schema says it is gone. A step
|
|
32
|
+
* that sets `retain` keeps the old column that long; the step succeeds
|
|
33
|
+
* with it kept, its note says until when, and dropping it after the date
|
|
34
|
+
* is `chant run` of the Op's declaration (in `migration.json`), whose
|
|
35
|
+
* contract is convergent.
|
|
36
|
+
* - It is built with `onFailure: "keep"`, so a step that failed or was
|
|
37
|
+
* stopped keeps what the expand added and resumes on the next `yodel
|
|
38
|
+
* apply`. Every phase of the Op re-reads the server and does what is left
|
|
39
|
+
* of it: the expand finds the new column there and adds nothing, the dual
|
|
40
|
+
* write finds its trigger, the backfill skips every batch whose receipt
|
|
41
|
+
* is in `<schema>.__chant_receipts` (each receipt commits with its batch,
|
|
42
|
+
* so a batch is never filled twice), the carry over builds only the
|
|
43
|
+
* indexes and constraints not yet built (an INVALID one it left is built
|
|
44
|
+
* again), the verification runs again over every row, and a switch that
|
|
45
|
+
* already ran is not run again. To start over instead, drop the new
|
|
46
|
+
* column, its trigger and function (chant's working objects, named in
|
|
47
|
+
* their comments; a refusal says so).
|
|
42
48
|
*/
|
|
43
49
|
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
44
50
|
import { tmpdir } from "node:os";
|
|
@@ -46,9 +52,16 @@ import { join } from "node:path";
|
|
|
46
52
|
import { runOp, StepOpFailed } from "./run.js";
|
|
47
53
|
/** The retention a step runs with when its options set none: the contract runs in the same apply. */
|
|
48
54
|
export const STEP_RETAIN = "0s";
|
|
49
|
-
/**
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
/**
|
|
56
|
+
* The Op's Contract step for a config built with `gates: "outer"`: the
|
|
57
|
+
* lexicon's contract activity with the Retain step's arguments. It drops the
|
|
58
|
+
* old column only once its retention date has passed.
|
|
59
|
+
*/
|
|
60
|
+
export function contractPhase(config) {
|
|
61
|
+
const retain = config.phases.flatMap((p) => p.steps).find((s) => s.kind === "activity" && s.fn === "postgresMigrationRetain");
|
|
62
|
+
if (!retain)
|
|
63
|
+
throw new Error(`PostgresMigrationOp "${config.name}" has no Retain step`);
|
|
64
|
+
return { name: "Contract", steps: [{ kind: "activity", fn: "postgresMigrationContract", ...(retain.args ? { args: retain.args } : {}) }] };
|
|
52
65
|
}
|
|
53
66
|
/** The Op a step runs. `buildPath` is the recorded schema's file; `projectDir` holds chant.config.ts. */
|
|
54
67
|
export async function pgMigrationOpConfig(options, ctx) {
|
|
@@ -68,11 +81,11 @@ export async function pgMigrationOpConfig(options, ctx) {
|
|
|
68
81
|
build: false,
|
|
69
82
|
output: ctx.buildPath,
|
|
70
83
|
path: ctx.projectDir,
|
|
84
|
+
gates: "outer",
|
|
85
|
+
onFailure: "keep",
|
|
71
86
|
});
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
delete rest.onFailure;
|
|
75
|
-
return rest;
|
|
87
|
+
const config = op.props;
|
|
88
|
+
return { ...config, phases: [...config.phases, contractPhase(config)] };
|
|
76
89
|
}
|
|
77
90
|
/** The migration activities whose results the history's summary keeps. */
|
|
78
91
|
const SUMMARIZED = ["postgresMigrationPlan", "postgresMigrationBackfill", "postgresMigrationCarry", "postgresMigrationVerify", "postgresMigrationSwitch", "postgresMigrationContract"];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-migration.js","sourceRoot":"","sources":["../../src/steps/postgres-migration.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"postgres-migration.js","sourceRoot":"","sources":["../../src/steps/postgres-migration.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tenant sets (#56): one environment over many databases (ClickHouse) or
|
|
3
|
+
* schemas (Postgres) with the same migrations.
|
|
4
|
+
*
|
|
5
|
+
* `yodel.config.ts` `environments.<env>.tenants` lists them (names, a file,
|
|
6
|
+
* or a read-only query on the environment's server). Each tenant is a
|
|
7
|
+
* target of its own, `<env>/<tenant>`: its profile is the environment's on
|
|
8
|
+
* the tenant's database or schema (`resolveEnvironment`), its history is
|
|
9
|
+
* `<history database>_<tenant>` (`environmentSettings`), and every
|
|
10
|
+
* statement and check is sent with the template's name replaced by the
|
|
11
|
+
* tenant's ({@link tenantDriver}). The apply pipeline renders the
|
|
12
|
+
* environment's wave with a run per tenant, one gate over all of them.
|
|
13
|
+
*/
|
|
14
|
+
import type { TenantSet } from "../config/define.js";
|
|
15
|
+
import { type Environment, type Project, type TenantOf } from "../project.js";
|
|
16
|
+
import type { VersionedDriver } from "../versioned/driver.js";
|
|
17
|
+
export * from "./target.js";
|
|
18
|
+
/** `env`'s tenant set in yodel.config.ts, if it has one. */
|
|
19
|
+
export declare const tenantSetOf: (project: Pick<Project, "yodel">, env: string) => TenantSet | undefined;
|
|
20
|
+
/** Reads a tenant file: a JSON array of names, or one name per line (`#` starts a comment). */
|
|
21
|
+
export declare function readTenantFile(path: string): string[];
|
|
22
|
+
/**
|
|
23
|
+
* The tenants of `env`, in the order the set gives them; undefined when it
|
|
24
|
+
* has no set. A query runs read-only on the environment's server, with its
|
|
25
|
+
* profile, and its rows' first column are the names.
|
|
26
|
+
*/
|
|
27
|
+
export declare function listTenants(project: Project, env: string): Promise<string[] | undefined>;
|
|
28
|
+
/** Throws unless `env`'s tenant set names the tenant `env` is. */
|
|
29
|
+
export declare function checkTenant(project: Project, env: Environment): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* The targets `names` stand for: an environment with a tenant set is each
|
|
32
|
+
* of its tenants, `<env>/<tenant>`; any other name is itself.
|
|
33
|
+
*/
|
|
34
|
+
export declare function expandTargets(project: Project, names: readonly string[]): Promise<string[]>;
|
|
35
|
+
/**
|
|
36
|
+
* A tenant's driver: the environment's, with the template's name replaced
|
|
37
|
+
* by the tenant's in every statement and check it sends. An Op step (a
|
|
38
|
+
* rebuild, a backfill) names its tables itself and does not run on a tenant.
|
|
39
|
+
*/
|
|
40
|
+
export declare function tenantDriver(driver: VersionedDriver, tenant: TenantOf): VersionedDriver;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tenant sets (#56): one environment over many databases (ClickHouse) or
|
|
3
|
+
* schemas (Postgres) with the same migrations.
|
|
4
|
+
*
|
|
5
|
+
* `yodel.config.ts` `environments.<env>.tenants` lists them (names, a file,
|
|
6
|
+
* or a read-only query on the environment's server). Each tenant is a
|
|
7
|
+
* target of its own, `<env>/<tenant>`: its profile is the environment's on
|
|
8
|
+
* the tenant's database or schema (`resolveEnvironment`), its history is
|
|
9
|
+
* `<history database>_<tenant>` (`environmentSettings`), and every
|
|
10
|
+
* statement and check is sent with the template's name replaced by the
|
|
11
|
+
* tenant's ({@link tenantDriver}). The apply pipeline renders the
|
|
12
|
+
* environment's wave with a run per tenant, one gate over all of them.
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
15
|
+
import { resolve } from "node:path";
|
|
16
|
+
import { resolveEnvironment, YodelError } from "../project.js";
|
|
17
|
+
import { renameIdentifier, splitTarget, TENANT_NAME, tenantTarget } from "./target.js";
|
|
18
|
+
export * from "./target.js";
|
|
19
|
+
/** `env`'s tenant set in yodel.config.ts, if it has one. */
|
|
20
|
+
export const tenantSetOf = (project, env) => project.yodel?.config.environments?.[env]?.tenants;
|
|
21
|
+
function checked(names, where) {
|
|
22
|
+
const bad = names.filter((n) => !TENANT_NAME.test(n));
|
|
23
|
+
if (bad.length > 0)
|
|
24
|
+
throw new YodelError(`${where} lists ${bad.map((b) => JSON.stringify(b)).join(", ")}, which ${bad.length === 1 ? "is not a tenant name" : "are not tenant names"} (letters, digits and _, not starting with a digit)`);
|
|
25
|
+
return [...new Set(names)];
|
|
26
|
+
}
|
|
27
|
+
/** Reads a tenant file: a JSON array of names, or one name per line (`#` starts a comment). */
|
|
28
|
+
export function readTenantFile(path) {
|
|
29
|
+
if (!existsSync(path))
|
|
30
|
+
throw new YodelError(`the tenant file ${path} does not exist`);
|
|
31
|
+
const text = readFileSync(path, "utf8");
|
|
32
|
+
if (text.trimStart().startsWith("[")) {
|
|
33
|
+
let parsed;
|
|
34
|
+
try {
|
|
35
|
+
parsed = JSON.parse(text);
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
throw new YodelError(`${path}: ${e instanceof Error ? e.message : String(e)}`);
|
|
39
|
+
}
|
|
40
|
+
if (!Array.isArray(parsed) || !parsed.every((t) => typeof t === "string"))
|
|
41
|
+
throw new YodelError(`${path}: expected a JSON array of tenant names`);
|
|
42
|
+
return checked(parsed, path);
|
|
43
|
+
}
|
|
44
|
+
return checked(text.split("\n").map((l) => l.replace(/#.*/, "").trim()).filter(Boolean), path);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The tenants of `env`, in the order the set gives them; undefined when it
|
|
48
|
+
* has no set. A query runs read-only on the environment's server, with its
|
|
49
|
+
* profile, and its rows' first column are the names.
|
|
50
|
+
*/
|
|
51
|
+
export async function listTenants(project, env) {
|
|
52
|
+
const set = tenantSetOf(project, env);
|
|
53
|
+
if (set === undefined)
|
|
54
|
+
return undefined;
|
|
55
|
+
if (Array.isArray(set))
|
|
56
|
+
return [...set];
|
|
57
|
+
if ("file" in set)
|
|
58
|
+
return readTenantFile(resolve(project.dir, set.file));
|
|
59
|
+
const { openVersioned, closeVersioned } = await import("../versioned/engine.js");
|
|
60
|
+
const venv = await openVersioned(project, resolveEnvironment(project, env));
|
|
61
|
+
try {
|
|
62
|
+
let rows;
|
|
63
|
+
try {
|
|
64
|
+
rows = await venv.driver.readCheck(set.query, {});
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
throw new YodelError(`${env}'s tenant query failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
68
|
+
}
|
|
69
|
+
return checked(rows.map((r) => { const v = Object.values(r)[0]; return typeof v === "string" ? v : JSON.stringify(v ?? ""); }), `${env}'s tenant query`);
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
await closeVersioned(venv);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** Throws unless `env`'s tenant set names the tenant `env` is. */
|
|
76
|
+
export async function checkTenant(project, env) {
|
|
77
|
+
if (!env.tenant)
|
|
78
|
+
return;
|
|
79
|
+
const set = tenantSetOf(project, env.tenant.env);
|
|
80
|
+
if (Array.isArray(set))
|
|
81
|
+
return; // resolveEnvironment checked it.
|
|
82
|
+
const names = (await listTenants(project, env.tenant.env)) ?? [];
|
|
83
|
+
if (!names.includes(env.tenant.name)) {
|
|
84
|
+
throw new YodelError(`no tenant "${env.tenant.name}" in ${env.tenant.env}'s tenant set (${set && "file" in set ? set.file : "its query"} lists ${names.length > 0 ? names.join(", ") : "none"})`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The targets `names` stand for: an environment with a tenant set is each
|
|
89
|
+
* of its tenants, `<env>/<tenant>`; any other name is itself.
|
|
90
|
+
*/
|
|
91
|
+
export async function expandTargets(project, names) {
|
|
92
|
+
const out = [];
|
|
93
|
+
for (const name of names) {
|
|
94
|
+
const tenants = splitTarget(name).tenant === undefined ? await listTenants(project, name) : undefined;
|
|
95
|
+
if (tenants)
|
|
96
|
+
out.push(...tenants.map((t) => tenantTarget(name, t)));
|
|
97
|
+
else
|
|
98
|
+
out.push(name);
|
|
99
|
+
}
|
|
100
|
+
return out;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A tenant's driver: the environment's, with the template's name replaced
|
|
104
|
+
* by the tenant's in every statement and check it sends. An Op step (a
|
|
105
|
+
* rebuild, a backfill) names its tables itself and does not run on a tenant.
|
|
106
|
+
*/
|
|
107
|
+
export function tenantDriver(driver, tenant) {
|
|
108
|
+
const rename = (sql) => renameIdentifier(sql, tenant.template, tenant.name);
|
|
109
|
+
const where = (w) => ({
|
|
110
|
+
...(w.defaultDatabase !== undefined ? { defaultDatabase: rename(w.defaultDatabase) } : {}),
|
|
111
|
+
...(w.defaultSchema !== undefined ? { defaultSchema: rename(w.defaultSchema) } : {}),
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
...driver,
|
|
115
|
+
readCheck: (sql, w) => driver.readCheck(rename(sql), where(w)),
|
|
116
|
+
runStatement: (step, run) => driver.runStatement({ ...step, sql: rename(step.sql) }, run),
|
|
117
|
+
stepContext: () => {
|
|
118
|
+
throw new YodelError(`an Op step does not run on a tenant (${tenantTarget(tenant.env, tenant.name)}): only statements are renamed from ${tenant.template} to ${tenant.name}`);
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tenants/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tenant targets (#56), the parts every module can import: a tenant of
|
|
3
|
+
* environment `prod` is the target `prod/<tenant>`, and its migrations are
|
|
4
|
+
* the environment's with the template database or schema renamed.
|
|
5
|
+
*/
|
|
6
|
+
/** Between an environment and a tenant in a target's name. */
|
|
7
|
+
export declare const TENANT_SEPARATOR = "/";
|
|
8
|
+
/** A tenant's name: a database or schema name, and part of a target's name and of a file's. */
|
|
9
|
+
export declare const TENANT_NAME: RegExp;
|
|
10
|
+
/** `prod/acme` is environment `prod`, tenant `acme`; `prod` is `prod` alone. */
|
|
11
|
+
export declare function splitTarget(name: string): {
|
|
12
|
+
env: string;
|
|
13
|
+
tenant?: string;
|
|
14
|
+
};
|
|
15
|
+
/** The environment a target belongs to: `prod` for `prod/acme` and for `prod`. */
|
|
16
|
+
export declare const baseEnvironment: (name: string) => string;
|
|
17
|
+
export declare const tenantTarget: (env: string, tenant: string) => string;
|
|
18
|
+
/**
|
|
19
|
+
* `sql` with every identifier `from` replaced by `to`: the name standing
|
|
20
|
+
* alone, bare or quoted (`from.orders`, `"from"`, `` `from` ``), never a
|
|
21
|
+
* longer name that contains it (`from_archive`).
|
|
22
|
+
*/
|
|
23
|
+
export declare function renameIdentifier(sql: string, from: string, to: string): string;
|