@intentius/sql-yodeler 0.1.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 +28 -26
- package/dist/bin.js +15 -0
- package/dist/bin.js.map +1 -1
- package/dist/chant/apply.d.ts +9 -1
- package/dist/chant/apply.js +13 -1
- package/dist/chant/apply.js.map +1 -1
- package/dist/chant/build.js +7 -0
- package/dist/chant/build.js.map +1 -1
- package/dist/chant/drift.d.ts +69 -1
- package/dist/chant/drift.js +152 -5
- package/dist/chant/drift.js.map +1 -1
- package/dist/chant/runnable.d.ts +19 -0
- package/dist/chant/runnable.js +47 -0
- package/dist/chant/runnable.js.map +1 -0
- 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/cli.d.ts +4 -0
- package/dist/cli.js +40 -0
- package/dist/cli.js.map +1 -1
- package/dist/command.d.ts +6 -0
- package/dist/command.js.map +1 -1
- package/dist/commands/apply.d.ts +113 -0
- package/dist/commands/apply.js +376 -49
- package/dist/commands/apply.js.map +1 -1
- package/dist/commands/approve.d.ts +5 -0
- package/dist/commands/approve.js +155 -0
- package/dist/commands/approve.js.map +1 -0
- 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 +23 -0
- package/dist/commands/drift.js +263 -18
- package/dist/commands/drift.js.map +1 -1
- package/dist/commands/index.js +16 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.js +15 -11
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/lint.js +25 -8
- package/dist/commands/lint.js.map +1 -1
- package/dist/commands/mcp.d.ts +3 -0
- package/dist/commands/mcp.js +50 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/new.d.ts +2 -0
- package/dist/commands/new.js +134 -10
- package/dist/commands/new.js.map +1 -1
- package/dist/commands/override.d.ts +3 -0
- package/dist/commands/override.js +150 -0
- package/dist/commands/override.js.map +1 -0
- package/dist/commands/plan.js +43 -27
- package/dist/commands/plan.js.map +1 -1
- package/dist/commands/repair.d.ts +11 -0
- package/dist/commands/repair.js +15 -7
- package/dist/commands/repair.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 +44 -17
- 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 +223 -3
- package/dist/config/define.js +3 -1
- 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 +150 -5
- package/dist/config/load.js.map +1 -1
- package/dist/config/settings.d.ts +18 -2
- package/dist/config/settings.js +40 -6
- package/dist/config/settings.js.map +1 -1
- package/dist/env-args.d.ts +6 -0
- package/dist/env-args.js +31 -1
- package/dist/env-args.js.map +1 -1
- package/dist/exit.d.ts +20 -0
- package/dist/exit.js +28 -0
- package/dist/exit.js.map +1 -0
- package/dist/history/client.d.ts +8 -0
- package/dist/history/client.js +24 -1
- package/dist/history/client.js.map +1 -1
- package/dist/history/lock.d.ts +5 -1
- package/dist/history/lock.js +8 -2
- package/dist/history/lock.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/init/adopt.js +8 -3
- package/dist/init/adopt.js.map +1 -1
- package/dist/init/live.d.ts +11 -0
- package/dist/init/live.js +25 -2
- package/dist/init/live.js.map +1 -1
- package/dist/lint/check.d.ts +8 -1
- package/dist/lint/check.js +38 -4
- 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/server.d.ts +40 -0
- package/dist/mcp/server.js +106 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +72 -0
- package/dist/mcp/tools.js +178 -0
- package/dist/mcp/tools.js.map +1 -0
- 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/checks.d.ts +28 -0
- package/dist/migrations/checks.js +97 -0
- package/dist/migrations/checks.js.map +1 -0
- package/dist/migrations/create.d.ts +3 -1
- package/dist/migrations/create.js +3 -0
- package/dist/migrations/create.js.map +1 -1
- package/dist/migrations/directory.js +4 -0
- package/dist/migrations/directory.js.map +1 -1
- package/dist/migrations/document.d.ts +33 -0
- package/dist/migrations/document.js +2 -0
- package/dist/migrations/document.js.map +1 -1
- package/dist/migrations/index.d.ts +3 -0
- package/dist/migrations/index.js +3 -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/forge.d.ts +4 -0
- package/dist/pr/forge.js +21 -7
- package/dist/pr/forge.js.map +1 -1
- package/dist/pr/issue.d.ts +68 -0
- package/dist/pr/issue.js +107 -0
- package/dist/pr/issue.js.map +1 -0
- package/dist/pr/model.d.ts +12 -1
- package/dist/pr/model.js +44 -6
- package/dist/pr/model.js.map +1 -1
- package/dist/pr/render.d.ts +3 -1
- package/dist/pr/render.js +63 -4
- 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/index.d.ts +3 -0
- package/dist/replay/index.js +3 -0
- package/dist/replay/index.js.map +1 -1
- package/dist/replay/replay.d.ts +9 -1
- package/dist/replay/replay.js +63 -32
- 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/replay/shared.d.ts +28 -0
- package/dist/replay/shared.js +77 -0
- package/dist/replay/shared.js.map +1 -0
- 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 +37 -0
- package/dist/schemas.js +41 -0
- package/dist/schemas.js.map +1 -0
- package/dist/server.d.ts +40 -0
- package/dist/server.js +87 -0
- package/dist/server.js.map +1 -0
- 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/backfill.d.ts +21 -17
- package/dist/steps/backfill.js +20 -20
- package/dist/steps/backfill.js.map +1 -1
- package/dist/steps/index.d.ts +2 -2
- package/dist/steps/index.js +3 -3
- package/dist/steps/index.js.map +1 -1
- 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/steps/rebuild.d.ts +15 -15
- package/dist/steps/rebuild.js +17 -24
- package/dist/steps/rebuild.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/checks.d.ts +29 -0
- package/dist/versioned/checks.js +54 -0
- package/dist/versioned/checks.js.map +1 -0
- package/dist/versioned/clickhouse.js +8 -0
- package/dist/versioned/clickhouse.js.map +1 -1
- package/dist/versioned/driver.d.ts +10 -0
- package/dist/versioned/engine.d.ts +61 -1
- package/dist/versioned/engine.js +109 -6
- package/dist/versioned/engine.js.map +1 -1
- package/dist/versioned/explain.js +7 -2
- package/dist/versioned/explain.js.map +1 -1
- package/dist/versioned/index.d.ts +10 -0
- package/dist/versioned/index.js +25 -1
- package/dist/versioned/index.js.map +1 -1
- package/dist/versioned/op.d.ts +16 -1
- package/dist/versioned/op.js +43 -6
- package/dist/versioned/op.js.map +1 -1
- package/dist/versioned/policy.d.ts +98 -0
- package/dist/versioned/policy.js +212 -0
- package/dist/versioned/policy.js.map +1 -0
- package/dist/versioned/postgres/driver.d.ts +3 -1
- package/dist/versioned/postgres/driver.js +30 -3
- package/dist/versioned/postgres/driver.js.map +1 -1
- package/dist/versioned/postgres/waits.d.ts +46 -0
- package/dist/versioned/postgres/waits.js +78 -0
- package/dist/versioned/postgres/waits.js.map +1 -0
- package/dist/versioned/report.d.ts +3 -0
- package/dist/versioned/report.js +13 -1
- 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/stand-down.d.ts +30 -0
- package/dist/versioned/stand-down.js +56 -0
- package/dist/versioned/stand-down.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 +22 -8
- package/schemas/apply.schema.json +428 -0
- package/schemas/checkpoint.schema.json +19 -0
- package/schemas/common.schema.json +213 -0
- package/schemas/drift.schema.json +61 -0
- package/schemas/event.schema.json +36 -0
- package/schemas/init.schema.json +31 -0
- package/schemas/lint-rules.schema.json +54 -0
- package/schemas/lint.schema.json +294 -0
- package/schemas/mcp.schema.json +70 -0
- package/schemas/new.schema.json +71 -0
- package/schemas/plan.schema.json +489 -0
- package/schemas/rebase.schema.json +54 -0
- package/schemas/repair.schema.json +20 -0
- package/schemas/report.schema.json +114 -0
- package/schemas/revert.schema.json +69 -0
- package/schemas/status.schema.json +371 -0
package/dist/versioned/op.js
CHANGED
|
@@ -22,13 +22,14 @@
|
|
|
22
22
|
* `PATH="$PWD/node_modules/.bin:$PATH"`. When `yodel apply` runs it, yodel
|
|
23
23
|
* puts a `yodel` that runs itself first on the child's PATH.
|
|
24
24
|
*/
|
|
25
|
-
import { chmodSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
25
|
+
import { chmodSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
26
26
|
import { tmpdir } from "node:os";
|
|
27
27
|
import { delimiter, extname, join } from "node:path";
|
|
28
28
|
import { fileURLToPath } from "node:url";
|
|
29
29
|
import { YodelError } from "../project.js";
|
|
30
30
|
import { chantInstall, runChant } from "../chant/process.js";
|
|
31
|
-
import { GATED, readApplyRun } from "../chant/apply.js";
|
|
31
|
+
import { discoveryError, GATED, readApplyRun } from "../chant/apply.js";
|
|
32
|
+
import { REVERT_ENV, REVERT_STEP_ENV } from "./revert.js";
|
|
32
33
|
/** The env var the Apply step reads the approved digest from. */
|
|
33
34
|
export const APPROVED_PLAN_ENV = "YODEL_APPROVED_PLAN";
|
|
34
35
|
/** Passes `--allow-out-of-order` through `chant run` to the Op's steps. */
|
|
@@ -99,14 +100,16 @@ export function selectMigrateOp(ops, project, env, name) {
|
|
|
99
100
|
}
|
|
100
101
|
return { name: op.config.name, filePath: op.filePath, gate: op.parts.gate, quorum: op.parts.quorum };
|
|
101
102
|
}
|
|
102
|
-
export async function findMigrateOp(project,
|
|
103
|
+
export async function findMigrateOp(project, target, name) {
|
|
104
|
+
// A tenant (#56) is applied by its environment's Op.
|
|
105
|
+
const env = target.tenant ? { name: target.tenant.env, profile: target.profile } : target;
|
|
103
106
|
const { discoverOps } = await import("@intentius/chant/op/discover");
|
|
104
107
|
let found;
|
|
105
108
|
try {
|
|
106
109
|
found = await discoverOps({ cwd: project.dir });
|
|
107
110
|
}
|
|
108
111
|
catch (e) {
|
|
109
|
-
throw
|
|
112
|
+
throw discoveryError(project.dir, e);
|
|
110
113
|
}
|
|
111
114
|
if (found.errors.length > 0 && found.ops.size === 0)
|
|
112
115
|
throw new YodelError(`could not discover Ops in ${project.dir}:\n${found.errors.join("\n")}`);
|
|
@@ -127,24 +130,58 @@ export function yodelShim() {
|
|
|
127
130
|
chmodSync(path, 0o755);
|
|
128
131
|
return { dir, dispose: () => { rmSync(dir, { recursive: true, force: true }); } };
|
|
129
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Where `yodel apply --execute` (the Op's Apply step) writes its exit code,
|
|
135
|
+
* so the outer `yodel apply` exits with it (5 for the lock, 4 for a refusal)
|
|
136
|
+
* rather than with `chant run`'s 1.
|
|
137
|
+
*/
|
|
138
|
+
export const STEP_EXIT_ENV = "YODEL_STEP_EXIT_FILE";
|
|
139
|
+
/** Records an Op step's exit code where the outer `yodel apply` reads it. Never fails the step. */
|
|
140
|
+
export function recordStepExit(code, env = process.env) {
|
|
141
|
+
const file = env[STEP_EXIT_ENV];
|
|
142
|
+
if (!file)
|
|
143
|
+
return;
|
|
144
|
+
try {
|
|
145
|
+
writeFileSync(file, `${String(code)}\n`);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// The outer run then reports chant run's own exit.
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/** The exit code the Op's Apply step recorded, when it ran. */
|
|
152
|
+
export function readStepExit(file) {
|
|
153
|
+
try {
|
|
154
|
+
const n = Number(readFileSync(file, "utf8").trim());
|
|
155
|
+
return Number.isInteger(n) ? n : undefined;
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
130
161
|
/** Runs the migrations Op with `chant run`, with this yodel on PATH and `--allow-out-of-order` passed through. */
|
|
131
162
|
export async function runMigrateOp(project, op, options) {
|
|
132
163
|
const shim = yodelShim();
|
|
133
164
|
try {
|
|
134
165
|
const base = options.env ?? process.env;
|
|
135
166
|
// The approved digest only ever comes from the gate, never from the caller's environment.
|
|
136
|
-
|
|
167
|
+
// Nor is a revert ever taken from it: only yodel revert sets one.
|
|
168
|
+
const rest = Object.fromEntries(Object.entries(base).filter(([k]) => k !== APPROVED_PLAN_ENV && k !== ALLOW_OUT_OF_ORDER_ENV && k !== REVERT_ENV && k !== REVERT_STEP_ENV));
|
|
169
|
+
const exitFile = join(shim.dir, "step-exit");
|
|
137
170
|
const env = {
|
|
138
171
|
...rest,
|
|
172
|
+
[STEP_EXIT_ENV]: exitFile,
|
|
139
173
|
PATH: [shim.dir, base.PATH ?? ""].filter(Boolean).join(delimiter),
|
|
140
174
|
...(options.allowOutOfOrder ? { [ALLOW_OUT_OF_ORDER_ENV]: "1" } : {}),
|
|
175
|
+
...(options.revert ? { [REVERT_ENV]: options.revert.id, ...(options.revert.step ? { [REVERT_STEP_ENV]: options.revert.step } : {}) } : {}),
|
|
141
176
|
};
|
|
142
177
|
const result = await runChant(["run", op.name, "--gated-exit", String(GATED)], {
|
|
143
178
|
cwd: project.dir,
|
|
144
179
|
env,
|
|
145
180
|
...(options.onOutput ? { onStdout: options.onOutput, onStderr: options.onOutput } : {}),
|
|
146
181
|
});
|
|
147
|
-
|
|
182
|
+
const run = readApplyRun(result.code, `${result.stdout}\n${result.stderr}`);
|
|
183
|
+
const stepExit = readStepExit(exitFile);
|
|
184
|
+
return stepExit === undefined ? run : { ...run, stepExit };
|
|
148
185
|
}
|
|
149
186
|
finally {
|
|
150
187
|
shim.dispose();
|
package/dist/versioned/op.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"op.js","sourceRoot":"","sources":["../../src/versioned/op.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"op.js","sourceRoot":"","sources":["../../src/versioned/op.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy over the plan (#53): the rules `yodel.config.ts` `policy` declares
|
|
3
|
+
* (`../config/define.ts`), evaluated over the plan `yodel apply` would run,
|
|
4
|
+
* and the overrides recorded against them.
|
|
5
|
+
*
|
|
6
|
+
* `yodel plan` reports each rule's outcome; `yodel apply` refuses (exit 4)
|
|
7
|
+
* before the gate, and its Apply step again under the lock, a plan a rule
|
|
8
|
+
* denies. An override is a person's decision to run that plan anyway:
|
|
9
|
+
* `yodel override <env> --rule <id> --reason <text>` records it on chant's
|
|
10
|
+
* gate ledger (the `chant/lifecycle` branch) as an approval of the gate
|
|
11
|
+
* `override-<id>` of the migrations Op, for exactly the current plan digest,
|
|
12
|
+
* with the reason as its note. It counts only when the plan digest is the
|
|
13
|
+
* same, so it is refused once the plan moves, and only when
|
|
14
|
+
* `policy.overriders` lists who recorded it. The Apply step writes the
|
|
15
|
+
* overrides it relied on into the history (the `note` of each migration's
|
|
16
|
+
* `started` row).
|
|
17
|
+
*/
|
|
18
|
+
import type { GateLedgerPort } from "@intentius/chant/op/gate";
|
|
19
|
+
import type { PolicyConfig, PolicyPlan } from "../config/define.js";
|
|
20
|
+
import type { SqlDialect } from "../project.js";
|
|
21
|
+
import { YodelError } from "../project.js";
|
|
22
|
+
import type { MigrateOpRef } from "./op.js";
|
|
23
|
+
import type { PendingMigration } from "./state.js";
|
|
24
|
+
import type { RevertPlan } from "./revert.js";
|
|
25
|
+
/** The gate an override of `rule` is recorded as an approval of. */
|
|
26
|
+
export declare const overrideGate: (rule: string) => string;
|
|
27
|
+
/** An override that counts: who recorded it, when, why, and the digest it is for. */
|
|
28
|
+
export interface PolicyOverride {
|
|
29
|
+
rule: string;
|
|
30
|
+
by: string;
|
|
31
|
+
at: string;
|
|
32
|
+
reason: string;
|
|
33
|
+
digest: string;
|
|
34
|
+
}
|
|
35
|
+
export interface RuleResult {
|
|
36
|
+
id: string;
|
|
37
|
+
description?: string | undefined;
|
|
38
|
+
/** `denied` stands; `overridden` was denied, and an override counts. */
|
|
39
|
+
outcome: "allowed" | "denied" | "overridden";
|
|
40
|
+
/** Why it denies the plan, one line each. */
|
|
41
|
+
reasons: string[];
|
|
42
|
+
override?: PolicyOverride | undefined;
|
|
43
|
+
}
|
|
44
|
+
/** The plan a rule sees. */
|
|
45
|
+
export declare function policyPlan(environment: string, dialect: SqlDialect, toApply: readonly PendingMigration[], now?: Date): PolicyPlan;
|
|
46
|
+
/**
|
|
47
|
+
* The plan a rule sees for a revert (#97): the migration reverted is the one
|
|
48
|
+
* entry of `pending`, its steps the revert's statements in the order they
|
|
49
|
+
* run (a hand-written revert step's first), and `revert` says it is one. A
|
|
50
|
+
* rule that refuses drops refuses a revert that drops what the migration
|
|
51
|
+
* added.
|
|
52
|
+
*/
|
|
53
|
+
export declare function policyRevertPlan(environment: string, dialect: SqlDialect, plan: RevertPlan, now?: Date): PolicyPlan;
|
|
54
|
+
/** Each rule that applies to the plan's environment, allowed or denied. No overrides yet. */
|
|
55
|
+
export declare function evaluatePolicy(policy: PolicyConfig | undefined, plan: PolicyPlan): RuleResult[];
|
|
56
|
+
/** The overrides on the ledger that count for `digest`: of a rule's override gate, for that digest, with a reason, by someone `overriders` lists. The newest per rule. */
|
|
57
|
+
export declare function readOverrides(port: GateLedgerPort, op: MigrateOpRef, digest: string, overriders: readonly string[] | undefined): Promise<PolicyOverride[]>;
|
|
58
|
+
/** The results with each denied rule an override counts for marked overridden. */
|
|
59
|
+
export declare function withOverrides(results: readonly RuleResult[], overrides: readonly PolicyOverride[]): RuleResult[];
|
|
60
|
+
/** The refusal for the rules that deny the plan with no override, or `undefined`. `revert`: the plan is the revert of that migration (with that hand-written step, as given). */
|
|
61
|
+
export declare function policyRefusal(results: readonly RuleResult[], environment: string, digest: string | undefined, when: string, revert?: {
|
|
62
|
+
id: string;
|
|
63
|
+
step?: string | undefined;
|
|
64
|
+
}): YodelError | undefined;
|
|
65
|
+
/** The whole evaluation: the rules over the plan, with the overrides on the ledger for `digest`. Empty when the config declares no policy. */
|
|
66
|
+
export declare function judgePlan(input: {
|
|
67
|
+
policy: PolicyConfig | undefined;
|
|
68
|
+
environment: string;
|
|
69
|
+
dialect: SqlDialect;
|
|
70
|
+
toApply: readonly PendingMigration[];
|
|
71
|
+
digest: string | undefined;
|
|
72
|
+
ledger: () => Promise<{
|
|
73
|
+
port: GateLedgerPort;
|
|
74
|
+
op: MigrateOpRef;
|
|
75
|
+
} | undefined>;
|
|
76
|
+
now?: Date;
|
|
77
|
+
}): Promise<RuleResult[]>;
|
|
78
|
+
/**
|
|
79
|
+
* The policy over a revert (#97), as `yodel revert` judges it before the
|
|
80
|
+
* gate and its Apply step again under the lock: the rules over
|
|
81
|
+
* {@link policyRevertPlan}, and the overrides recorded for the revert's own
|
|
82
|
+
* digest (`yodel override <env> --revert <id>`). Empty when the config
|
|
83
|
+
* declares no policy, or the revert has no statement.
|
|
84
|
+
*/
|
|
85
|
+
export declare function judgeRevert(input: {
|
|
86
|
+
policy: PolicyConfig | undefined;
|
|
87
|
+
environment: string;
|
|
88
|
+
dialect: SqlDialect;
|
|
89
|
+
plan: RevertPlan;
|
|
90
|
+
digest: string | undefined;
|
|
91
|
+
ledger: () => Promise<{
|
|
92
|
+
port: GateLedgerPort;
|
|
93
|
+
op: MigrateOpRef;
|
|
94
|
+
} | undefined>;
|
|
95
|
+
now?: Date;
|
|
96
|
+
}): Promise<RuleResult[]>;
|
|
97
|
+
/** One line per rule, for text output. */
|
|
98
|
+
export declare function describeResults(results: readonly RuleResult[]): string[];
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy over the plan (#53): the rules `yodel.config.ts` `policy` declares
|
|
3
|
+
* (`../config/define.ts`), evaluated over the plan `yodel apply` would run,
|
|
4
|
+
* and the overrides recorded against them.
|
|
5
|
+
*
|
|
6
|
+
* `yodel plan` reports each rule's outcome; `yodel apply` refuses (exit 4)
|
|
7
|
+
* before the gate, and its Apply step again under the lock, a plan a rule
|
|
8
|
+
* denies. An override is a person's decision to run that plan anyway:
|
|
9
|
+
* `yodel override <env> --rule <id> --reason <text>` records it on chant's
|
|
10
|
+
* gate ledger (the `chant/lifecycle` branch) as an approval of the gate
|
|
11
|
+
* `override-<id>` of the migrations Op, for exactly the current plan digest,
|
|
12
|
+
* with the reason as its note. It counts only when the plan digest is the
|
|
13
|
+
* same, so it is refused once the plan moves, and only when
|
|
14
|
+
* `policy.overriders` lists who recorded it. The Apply step writes the
|
|
15
|
+
* overrides it relied on into the history (the `note` of each migration's
|
|
16
|
+
* `started` row).
|
|
17
|
+
*/
|
|
18
|
+
import { YodelError } from "../project.js";
|
|
19
|
+
import { EXIT_REFUSED } from "../exit.js";
|
|
20
|
+
import { silencesOf } from "../lint/index.js";
|
|
21
|
+
import { sameDigest } from "./digest.js";
|
|
22
|
+
/** The gate an override of `rule` is recorded as an approval of. */
|
|
23
|
+
export const overrideGate = (rule) => `override-${rule}`;
|
|
24
|
+
/** The plan a rule sees. */
|
|
25
|
+
export function policyPlan(environment, dialect, toApply, now = new Date()) {
|
|
26
|
+
return {
|
|
27
|
+
environment,
|
|
28
|
+
dialect,
|
|
29
|
+
now: now.toISOString(),
|
|
30
|
+
pending: toApply.map((p) => ({
|
|
31
|
+
id: p.id,
|
|
32
|
+
checksum: p.checksum,
|
|
33
|
+
outOfOrder: p.outOfOrder,
|
|
34
|
+
steps: p.migration.document.steps.map((s, index) => {
|
|
35
|
+
if (s.kind === "statement") {
|
|
36
|
+
return { index, kind: "statement", object: s.object, name: s.name, classes: [s.class], destructive: s.destructive === true, rules: [s.rule], sql: s.sql };
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
index,
|
|
40
|
+
kind: s.kind,
|
|
41
|
+
object: s.object,
|
|
42
|
+
name: s.name,
|
|
43
|
+
classes: [...new Set(s.changes.map((c) => c.class))],
|
|
44
|
+
destructive: s.changes.some((c) => c.destructive === true),
|
|
45
|
+
rules: [...new Set(s.changes.map((c) => c.rule))],
|
|
46
|
+
...(s.kind === "op" ? { op: s.op } : {}),
|
|
47
|
+
};
|
|
48
|
+
}),
|
|
49
|
+
silences: silencesOf(p.migration).map(({ step, rule, reason }) => ({ step, rule, reason })),
|
|
50
|
+
})),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The plan a rule sees for a revert (#97): the migration reverted is the one
|
|
55
|
+
* entry of `pending`, its steps the revert's statements in the order they
|
|
56
|
+
* run (a hand-written revert step's first), and `revert` says it is one. A
|
|
57
|
+
* rule that refuses drops refuses a revert that drops what the migration
|
|
58
|
+
* added.
|
|
59
|
+
*/
|
|
60
|
+
export function policyRevertPlan(environment, dialect, plan, now = new Date()) {
|
|
61
|
+
return {
|
|
62
|
+
environment,
|
|
63
|
+
dialect,
|
|
64
|
+
now: now.toISOString(),
|
|
65
|
+
revert: { id: plan.migration.id, to: plan.to },
|
|
66
|
+
pending: [
|
|
67
|
+
{
|
|
68
|
+
id: plan.migration.id,
|
|
69
|
+
checksum: plan.checksum,
|
|
70
|
+
outOfOrder: false,
|
|
71
|
+
steps: plan.statements.map(({ source, step }, index) => ({
|
|
72
|
+
index,
|
|
73
|
+
kind: "statement",
|
|
74
|
+
object: step.object,
|
|
75
|
+
name: source === "step" ? `${step.name} (${plan.step?.file ?? "the revert step"})` : step.name,
|
|
76
|
+
classes: [step.class],
|
|
77
|
+
destructive: step.destructive === true,
|
|
78
|
+
rules: [step.rule],
|
|
79
|
+
sql: step.sql,
|
|
80
|
+
})),
|
|
81
|
+
silences: [],
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const applies = (rule, environment) => rule.environments === undefined || rule.environments.includes(environment);
|
|
87
|
+
function denials(rule, plan) {
|
|
88
|
+
const out = [];
|
|
89
|
+
if (rule.refuse) {
|
|
90
|
+
const { classes = [], destructive = false } = rule.refuse;
|
|
91
|
+
for (const m of plan.pending) {
|
|
92
|
+
for (const s of m.steps) {
|
|
93
|
+
const cls = s.classes.filter((c) => classes.includes(c));
|
|
94
|
+
if (cls.length > 0)
|
|
95
|
+
out.push(`${m.id} step ${String(s.index)} (${s.name}) is ${cls.join(", ")}`);
|
|
96
|
+
else if (destructive && s.destructive)
|
|
97
|
+
out.push(`${m.id} step ${String(s.index)} (${s.name}) is destructive`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (rule.silences) {
|
|
102
|
+
const { rules, reason } = rule.silences;
|
|
103
|
+
for (const m of plan.pending) {
|
|
104
|
+
for (const s of m.silences) {
|
|
105
|
+
if (rules && !rules.includes(s.rule))
|
|
106
|
+
continue;
|
|
107
|
+
reason.lastIndex = 0;
|
|
108
|
+
if (!reason.test(s.reason))
|
|
109
|
+
out.push(`${m.id} step ${String(s.step)} silences ${s.rule} with a reason that does not match ${String(reason)}: ${JSON.stringify(s.reason)}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (rule.check) {
|
|
114
|
+
let said;
|
|
115
|
+
try {
|
|
116
|
+
said = rule.check(plan);
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
said = `its check threw: ${e instanceof Error ? e.message : String(e)}`;
|
|
120
|
+
}
|
|
121
|
+
if (said === false)
|
|
122
|
+
out.push(rule.description ?? "its check denies the plan");
|
|
123
|
+
else if (typeof said === "string")
|
|
124
|
+
out.push(said);
|
|
125
|
+
else if (Array.isArray(said))
|
|
126
|
+
out.push(...said);
|
|
127
|
+
}
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
130
|
+
/** Each rule that applies to the plan's environment, allowed or denied. No overrides yet. */
|
|
131
|
+
export function evaluatePolicy(policy, plan) {
|
|
132
|
+
return (policy?.rules ?? [])
|
|
133
|
+
.filter((r) => applies(r, plan.environment))
|
|
134
|
+
.map((r) => {
|
|
135
|
+
const reasons = denials(r, plan);
|
|
136
|
+
return { id: r.id, ...(r.description ? { description: r.description } : {}), outcome: reasons.length > 0 ? "denied" : "allowed", reasons };
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/** The overrides on the ledger that count for `digest`: of a rule's override gate, for that digest, with a reason, by someone `overriders` lists. The newest per rule. */
|
|
140
|
+
export async function readOverrides(port, op, digest, overriders) {
|
|
141
|
+
const { resolutions } = await port.read(op.name);
|
|
142
|
+
const byRule = new Map();
|
|
143
|
+
for (const r of resolutions) {
|
|
144
|
+
if (!r.gate.startsWith("override-") || !r.note || !(overriders ?? []).includes(r.resolvedBy))
|
|
145
|
+
continue;
|
|
146
|
+
if (!(await sameDigest(r.planDigest, digest)))
|
|
147
|
+
continue;
|
|
148
|
+
const rule = r.gate.slice("override-".length);
|
|
149
|
+
const prior = byRule.get(rule);
|
|
150
|
+
if (!prior || prior.at < r.timestamp)
|
|
151
|
+
byRule.set(rule, { rule, by: r.resolvedBy, at: r.timestamp, reason: r.note, digest });
|
|
152
|
+
}
|
|
153
|
+
return [...byRule.values()];
|
|
154
|
+
}
|
|
155
|
+
/** The results with each denied rule an override counts for marked overridden. */
|
|
156
|
+
export function withOverrides(results, overrides) {
|
|
157
|
+
return results.map((r) => {
|
|
158
|
+
const o = r.outcome === "denied" ? overrides.find((x) => x.rule === r.id) : undefined;
|
|
159
|
+
return o ? { ...r, outcome: "overridden", override: o } : r;
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
/** The refusal for the rules that deny the plan with no override, or `undefined`. `revert`: the plan is the revert of that migration (with that hand-written step, as given). */
|
|
163
|
+
export function policyRefusal(results, environment, digest, when, revert) {
|
|
164
|
+
const denied = results.filter((r) => r.outcome === "denied");
|
|
165
|
+
if (denied.length === 0)
|
|
166
|
+
return undefined;
|
|
167
|
+
const lines = denied.flatMap((r) => [` ${r.id}${r.description ? ` (${r.description})` : ""}:`, ...r.reasons.map((x) => ` ${x}`)]);
|
|
168
|
+
const ids = denied.map((r) => r.id).join(", ");
|
|
169
|
+
const what = revert ? `the revert of ${revert.id}` : "this plan";
|
|
170
|
+
const target = revert ? ` --revert ${revert.id}${revert.step !== undefined ? ` --step ${revert.step}` : ""}` : "";
|
|
171
|
+
return new YodelError(`refused by policy ${when}: ${denied.length === 1 ? "rule" : "rules"} ${ids} ${denied.length === 1 ? "denies" : "deny"} ${what}${digest ? ` (${digest})` : ""}. Nothing was ${revert ? "reverted" : "applied"}:\n${lines.join("\n")}\n` +
|
|
172
|
+
`To run it anyway, someone policy.overriders lists records why, for exactly this plan: ${denied.map((r) => `yodel override ${environment}${target} --rule ${r.id} --reason "<why>"`).join("; ")}`, EXIT_REFUSED);
|
|
173
|
+
}
|
|
174
|
+
/** The whole evaluation: the rules over the plan, with the overrides on the ledger for `digest`. Empty when the config declares no policy. */
|
|
175
|
+
export async function judgePlan(input) {
|
|
176
|
+
if (!input.policy || input.toApply.length === 0)
|
|
177
|
+
return [];
|
|
178
|
+
return judgePolicyPlan(input.policy, policyPlan(input.environment, input.dialect, input.toApply, input.now), input.digest, input.ledger);
|
|
179
|
+
}
|
|
180
|
+
/** The rules over `plan`, with the overrides on the ledger for `digest` marking the denials they answer. */
|
|
181
|
+
async function judgePolicyPlan(policy, plan, digest, ledger) {
|
|
182
|
+
const results = evaluatePolicy(policy, plan);
|
|
183
|
+
if (!digest || !results.some((r) => r.outcome === "denied"))
|
|
184
|
+
return results;
|
|
185
|
+
const at = await ledger();
|
|
186
|
+
if (!at)
|
|
187
|
+
return results;
|
|
188
|
+
return withOverrides(results, await readOverrides(at.port, at.op, digest, policy.overriders));
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* The policy over a revert (#97), as `yodel revert` judges it before the
|
|
192
|
+
* gate and its Apply step again under the lock: the rules over
|
|
193
|
+
* {@link policyRevertPlan}, and the overrides recorded for the revert's own
|
|
194
|
+
* digest (`yodel override <env> --revert <id>`). Empty when the config
|
|
195
|
+
* declares no policy, or the revert has no statement.
|
|
196
|
+
*/
|
|
197
|
+
export async function judgeRevert(input) {
|
|
198
|
+
if (!input.policy || input.plan.statements.length === 0)
|
|
199
|
+
return [];
|
|
200
|
+
return judgePolicyPlan(input.policy, policyRevertPlan(input.environment, input.dialect, input.plan, input.now), input.digest, input.ledger);
|
|
201
|
+
}
|
|
202
|
+
/** One line per rule, for text output. */
|
|
203
|
+
export function describeResults(results) {
|
|
204
|
+
return results.map((r) => {
|
|
205
|
+
if (r.outcome === "allowed")
|
|
206
|
+
return `policy ${r.id}: allowed`;
|
|
207
|
+
if (r.outcome === "overridden" && r.override)
|
|
208
|
+
return `policy ${r.id}: denied, overridden by ${r.override.by} at ${r.override.at}: ${r.override.reason}`;
|
|
209
|
+
return `policy ${r.id}: denied: ${r.reasons.join("; ")}`;
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/versioned/policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* and from `sql.profiles.<env>`, as chant's applier reads them:
|
|
13
13
|
*
|
|
14
|
-
* lockTimeoutMs lock_timeout for every statement (default 5000)
|
|
14
|
+
* lockTimeoutMs lock_timeout for every statement, and for the live-schema read (default 5000)
|
|
15
15
|
* statementTimeoutMs statement_timeout for a catalog change (default 60000)
|
|
16
16
|
* scanTimeoutMs statement_timeout for a statement that reads or rewrites rows (default none)
|
|
17
17
|
* schemas the schemas the plan digest's fingerprint covers (default every schema but the server's own)
|
|
@@ -65,5 +65,7 @@ export interface PostgresDriverInput {
|
|
|
65
65
|
store: PostgresHistoryStore;
|
|
66
66
|
sleep?: (ms: number) => Promise<void>;
|
|
67
67
|
retryBaseMs?: number;
|
|
68
|
+
/** Where a read held up by another session's lock says so; default stderr. */
|
|
69
|
+
log?: (line: string) => void;
|
|
68
70
|
}
|
|
69
71
|
export declare function postgresDriver(input: PostgresDriverInput): VersionedDriver;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* and from `sql.profiles.<env>`, as chant's applier reads them:
|
|
13
13
|
*
|
|
14
|
-
* lockTimeoutMs lock_timeout for every statement (default 5000)
|
|
14
|
+
* lockTimeoutMs lock_timeout for every statement, and for the live-schema read (default 5000)
|
|
15
15
|
* statementTimeoutMs statement_timeout for a catalog change (default 60000)
|
|
16
16
|
* scanTimeoutMs statement_timeout for a statement that reads or rewrites rows (default none)
|
|
17
17
|
* schemas the schemas the plan digest's fingerprint covers (default every schema but the server's own)
|
|
@@ -22,8 +22,9 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import { YodelError } from "../../project.js";
|
|
24
24
|
import { DEFAULT_HISTORY_DATABASE } from "../../history/index.js";
|
|
25
|
-
import { acquireAdvisoryLock, PostgresHistoryStore } from "../../history/postgres/index.js";
|
|
25
|
+
import { acquireAdvisoryLock, pgIdent, PostgresHistoryStore } from "../../history/postgres/index.js";
|
|
26
26
|
import { pgCatalogFingerprint, readPgCatalog } from "./catalog.js";
|
|
27
|
+
import { readUnderLockTimeout } from "./waits.js";
|
|
27
28
|
import { DEFAULT_LOCK_RETRIES, DEFAULT_PG_TIMEOUTS, PgStatementError, runPgStatement } from "./executor.js";
|
|
28
29
|
export function pgSettings(target, env = process.env, historySchema = env.YODEL_HISTORY_DATABASE || DEFAULT_HISTORY_DATABASE) {
|
|
29
30
|
const retries = env.YODEL_LOCK_RETRIES ? Number(env.YODEL_LOCK_RETRIES) : DEFAULT_LOCK_RETRIES;
|
|
@@ -83,7 +84,33 @@ export function postgresDriver(input) {
|
|
|
83
84
|
return acquireAdvisoryLock(await input.connect(), { schema: settings.historySchema, holder });
|
|
84
85
|
},
|
|
85
86
|
async liveFingerprint() {
|
|
86
|
-
|
|
87
|
+
const read = () => readPgCatalog(client, { schemas: input.schemas, historySchema: settings.historySchema });
|
|
88
|
+
const entries = await readUnderLockTimeout(client, read, {
|
|
89
|
+
lockTimeoutMs: settings.timeouts.lockTimeoutMs,
|
|
90
|
+
retries: settings.lockRetries,
|
|
91
|
+
schemas: input.schemas,
|
|
92
|
+
what: "the live schema",
|
|
93
|
+
log: input.log ?? ((line) => process.stderr.write(`yodel: ${line}\n`)),
|
|
94
|
+
...(input.sleep ? { sleep: input.sleep } : {}),
|
|
95
|
+
...(input.retryBaseMs !== undefined ? { retryBaseMs: input.retryBaseMs } : {}),
|
|
96
|
+
});
|
|
97
|
+
return pgCatalogFingerprint(entries);
|
|
98
|
+
},
|
|
99
|
+
async readCheck(sql, where) {
|
|
100
|
+
await client.query("BEGIN READ ONLY");
|
|
101
|
+
try {
|
|
102
|
+
if (where.defaultSchema)
|
|
103
|
+
await client.query(`SELECT pg_catalog.set_config('search_path', $1, true)`, [pgIdent(where.defaultSchema)]);
|
|
104
|
+
// A check reads rows: the scan timeout (default none), and the lock timeout every statement gets.
|
|
105
|
+
await client.query(`SELECT pg_catalog.set_config('statement_timeout', $1, true), pg_catalog.set_config('lock_timeout', $2, true)`, [
|
|
106
|
+
String(settings.timeouts.scanTimeoutMs),
|
|
107
|
+
String(settings.timeouts.lockTimeoutMs),
|
|
108
|
+
]);
|
|
109
|
+
return await client.query(sql);
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
await client.query("ROLLBACK").catch(() => undefined);
|
|
113
|
+
}
|
|
87
114
|
},
|
|
88
115
|
async runStatement(step, run) {
|
|
89
116
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../../../src/versioned/postgres/driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,EAAE,UAAU,EAAkC,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAyB,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../../../src/versioned/postgres/driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads of the live schema that another session's lock can block (#18): the
|
|
3
|
+
* fingerprint the plan digest covers, read before every apply and plan.
|
|
4
|
+
* chant's catalog reader calls `pg_get_viewdef()` and friends, which wait
|
|
5
|
+
* for a table's ACCESS SHARE lock, so a session holding ACCESS EXCLUSIVE on
|
|
6
|
+
* a declared table (a long `ALTER TABLE`, a `LOCK TABLE`) would hold the read
|
|
7
|
+
* up for as long as it holds the lock, with nothing printed.
|
|
8
|
+
*
|
|
9
|
+
* So the read runs under the profile's `lockTimeoutMs`, and when that passes
|
|
10
|
+
* (SQLSTATE 55P03) yodel says which lock it waited on and who holds it, and
|
|
11
|
+
* tries again with the same pauses and count as a statement (250 ms, then
|
|
12
|
+
* doubling, YODEL_LOCK_RETRIES more times). When the lock is still held after
|
|
13
|
+
* the last try, the read fails with the same description.
|
|
14
|
+
*/
|
|
15
|
+
import type { PgClient } from "../../history/postgres/index.js";
|
|
16
|
+
/** A session's ACCESS EXCLUSIVE lock on a relation, held or queued for. */
|
|
17
|
+
export interface LockHolder {
|
|
18
|
+
schema: string;
|
|
19
|
+
name: string;
|
|
20
|
+
pid: number;
|
|
21
|
+
granted: boolean;
|
|
22
|
+
application: string;
|
|
23
|
+
}
|
|
24
|
+
/** The ACCESS EXCLUSIVE locks other sessions hold (or wait for) on relations in `schemas` (every schema but the server's own when undefined). */
|
|
25
|
+
export declare function lockHolders(client: PgClient, schemas: readonly string[] | undefined): Promise<LockHolder[]>;
|
|
26
|
+
/** `a lock on shop.orders (held by pid 123, psql)`, or `a lock held by another session` when none could be named. */
|
|
27
|
+
export declare function describeHolders(holders: readonly LockHolder[]): string;
|
|
28
|
+
export interface LockedReadOptions {
|
|
29
|
+
lockTimeoutMs: number;
|
|
30
|
+
retries: number;
|
|
31
|
+
/** The schemas to look for the lock in. */
|
|
32
|
+
schemas: readonly string[] | undefined;
|
|
33
|
+
/** What is being read, for the messages: `the live schema`. */
|
|
34
|
+
what: string;
|
|
35
|
+
log: (line: string) => void;
|
|
36
|
+
retryBaseMs?: number;
|
|
37
|
+
sleep?: (ms: number) => Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
declare const seconds: (ms: number) => string;
|
|
40
|
+
/** Runs `read` on `client` with `lock_timeout` set, retrying (and saying why) when another session's lock holds it up. */
|
|
41
|
+
export declare function readUnderLockTimeout<T>(client: PgClient, read: () => Promise<T>, o: LockedReadOptions): Promise<T>;
|
|
42
|
+
/** The `PGOPTIONS` a chant child reads Postgres under, so a read blocked by a lock gives up after `lockTimeoutMs` (node-postgres passes it to the server). */
|
|
43
|
+
export declare function lockTimeoutOptions(lockTimeoutMs: number, existing: string | undefined): string;
|
|
44
|
+
/** Whether a read failed because the lock timeout passed. */
|
|
45
|
+
export declare const isLockTimeout: (text: string | undefined) => boolean;
|
|
46
|
+
export { seconds as describeMs };
|