@intentius/sql-yodeler 0.0.0-stage → 0.1.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 +202 -0
- package/README.md +110 -2
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +14 -0
- package/dist/bin.js.map +1 -0
- package/dist/chant/apply.d.ts +51 -0
- package/dist/chant/apply.js +104 -0
- package/dist/chant/apply.js.map +1 -0
- package/dist/chant/build.d.ts +34 -0
- package/dist/chant/build.js +48 -0
- package/dist/chant/build.js.map +1 -0
- package/dist/chant/drift.d.ts +44 -0
- package/dist/chant/drift.js +91 -0
- package/dist/chant/drift.js.map +1 -0
- package/dist/chant/plan.d.ts +45 -0
- package/dist/chant/plan.js +61 -0
- package/dist/chant/plan.js.map +1 -0
- package/dist/chant/process.d.ts +41 -0
- package/dist/chant/process.js +87 -0
- package/dist/chant/process.js.map +1 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +59 -0
- package/dist/cli.js.map +1 -0
- package/dist/command.d.ts +17 -0
- package/dist/command.js +13 -0
- package/dist/command.js.map +1 -0
- package/dist/commands/apply.d.ts +3 -0
- package/dist/commands/apply.js +306 -0
- package/dist/commands/apply.js.map +1 -0
- package/dist/commands/drift.d.ts +3 -0
- package/dist/commands/drift.js +38 -0
- package/dist/commands/drift.js.map +1 -0
- package/dist/commands/index.d.ts +3 -0
- package/dist/commands/index.js +22 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.js +135 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/lint.d.ts +3 -0
- package/dist/commands/lint.js +193 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/new.d.ts +3 -0
- package/dist/commands/new.js +168 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/plan.d.ts +3 -0
- package/dist/commands/plan.js +171 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/rebase.d.ts +3 -0
- package/dist/commands/rebase.js +167 -0
- package/dist/commands/rebase.js.map +1 -0
- package/dist/commands/repair.d.ts +3 -0
- package/dist/commands/repair.js +117 -0
- package/dist/commands/repair.js.map +1 -0
- package/dist/commands/status.d.ts +7 -0
- package/dist/commands/status.js +54 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/config/define.d.ts +50 -0
- package/dist/config/define.js +20 -0
- package/dist/config/define.js.map +1 -0
- package/dist/config/index.d.ts +11 -0
- package/dist/config/index.js +12 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/load.d.ts +17 -0
- package/dist/config/load.js +102 -0
- package/dist/config/load.js.map +1 -0
- package/dist/config/settings.d.ts +40 -0
- package/dist/config/settings.js +88 -0
- package/dist/config/settings.js.map +1 -0
- package/dist/env-args.d.ts +18 -0
- package/dist/env-args.js +62 -0
- package/dist/env-args.js.map +1 -0
- package/dist/history/client.d.ts +17 -0
- package/dist/history/client.js +19 -0
- package/dist/history/client.js.map +1 -0
- package/dist/history/ddl.d.ts +58 -0
- package/dist/history/ddl.js +100 -0
- package/dist/history/ddl.js.map +1 -0
- package/dist/history/index.d.ts +25 -0
- package/dist/history/index.js +26 -0
- package/dist/history/index.js.map +1 -0
- package/dist/history/lock.d.ts +100 -0
- package/dist/history/lock.js +224 -0
- package/dist/history/lock.js.map +1 -0
- package/dist/history/postgres/ddl.d.ts +22 -0
- package/dist/history/postgres/ddl.js +47 -0
- package/dist/history/postgres/ddl.js.map +1 -0
- package/dist/history/postgres/index.d.ts +12 -0
- package/dist/history/postgres/index.js +13 -0
- package/dist/history/postgres/index.js.map +1 -0
- package/dist/history/postgres/lock.d.ts +48 -0
- package/dist/history/postgres/lock.js +95 -0
- package/dist/history/postgres/lock.js.map +1 -0
- package/dist/history/postgres/store.d.ts +39 -0
- package/dist/history/postgres/store.js +68 -0
- package/dist/history/postgres/store.js.map +1 -0
- package/dist/history/rows.d.ts +96 -0
- package/dist/history/rows.js +73 -0
- package/dist/history/rows.js.map +1 -0
- package/dist/history/store.d.ts +72 -0
- package/dist/history/store.js +134 -0
- package/dist/history/store.js.map +1 -0
- package/dist/history/topology.d.ts +41 -0
- package/dist/history/topology.js +54 -0
- package/dist/history/topology.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/init/adopt.d.ts +70 -0
- package/dist/init/adopt.js +138 -0
- package/dist/init/adopt.js.map +1 -0
- package/dist/init/baseline.d.ts +61 -0
- package/dist/init/baseline.js +88 -0
- package/dist/init/baseline.js.map +1 -0
- package/dist/init/files.d.ts +23 -0
- package/dist/init/files.js +77 -0
- package/dist/init/files.js.map +1 -0
- package/dist/init/index.d.ts +16 -0
- package/dist/init/index.js +17 -0
- package/dist/init/index.js.map +1 -0
- package/dist/init/live.d.ts +28 -0
- package/dist/init/live.js +45 -0
- package/dist/init/live.js.map +1 -0
- package/dist/lint/check.d.ts +81 -0
- package/dist/lint/check.js +208 -0
- package/dist/lint/check.js.map +1 -0
- package/dist/lint/config.d.ts +21 -0
- package/dist/lint/config.js +43 -0
- package/dist/lint/config.js.map +1 -0
- package/dist/lint/index.d.ts +31 -0
- package/dist/lint/index.js +43 -0
- package/dist/lint/index.js.map +1 -0
- package/dist/lint/project-rules.d.ts +19 -0
- package/dist/lint/project-rules.js +32 -0
- package/dist/lint/project-rules.js.map +1 -0
- package/dist/lint/report.d.ts +7 -0
- package/dist/lint/report.js +48 -0
- package/dist/lint/report.js.map +1 -0
- package/dist/lint/rules.d.ts +53 -0
- package/dist/lint/rules.js +42 -0
- package/dist/lint/rules.js.map +1 -0
- package/dist/lint/silences.d.ts +49 -0
- package/dist/lint/silences.js +91 -0
- package/dist/lint/silences.js.map +1 -0
- package/dist/lint/statements.d.ts +38 -0
- package/dist/lint/statements.js +120 -0
- package/dist/lint/statements.js.map +1 -0
- package/dist/migrations/checksum.d.ts +56 -0
- package/dist/migrations/checksum.js +72 -0
- package/dist/migrations/checksum.js.map +1 -0
- package/dist/migrations/create.d.ts +73 -0
- package/dist/migrations/create.js +119 -0
- package/dist/migrations/create.js.map +1 -0
- package/dist/migrations/directory.d.ts +119 -0
- package/dist/migrations/directory.js +225 -0
- package/dist/migrations/directory.js.map +1 -0
- package/dist/migrations/document.d.ts +83 -0
- package/dist/migrations/document.js +82 -0
- package/dist/migrations/document.js.map +1 -0
- package/dist/migrations/index.d.ts +20 -0
- package/dist/migrations/index.js +21 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/pr/comment.d.ts +32 -0
- package/dist/pr/comment.js +99 -0
- package/dist/pr/comment.js.map +1 -0
- package/dist/pr/forge.d.ts +50 -0
- package/dist/pr/forge.js +105 -0
- package/dist/pr/forge.js.map +1 -0
- package/dist/pr/model.d.ts +91 -0
- package/dist/pr/model.js +113 -0
- package/dist/pr/model.js.map +1 -0
- package/dist/pr/render.d.ts +27 -0
- package/dist/pr/render.js +246 -0
- package/dist/pr/render.js.map +1 -0
- package/dist/project.d.ts +62 -0
- package/dist/project.js +92 -0
- package/dist/project.js.map +1 -0
- package/dist/rebase/index.d.ts +121 -0
- package/dist/rebase/index.js +390 -0
- package/dist/rebase/index.js.map +1 -0
- package/dist/rebase/repair.d.ts +41 -0
- package/dist/rebase/repair.js +68 -0
- package/dist/rebase/repair.js.map +1 -0
- package/dist/replay/clickhouse.d.ts +33 -0
- package/dist/replay/clickhouse.js +106 -0
- package/dist/replay/clickhouse.js.map +1 -0
- package/dist/replay/index.d.ts +36 -0
- package/dist/replay/index.js +54 -0
- package/dist/replay/index.js.map +1 -0
- package/dist/replay/postgres.d.ts +31 -0
- package/dist/replay/postgres.js +140 -0
- package/dist/replay/postgres.js.map +1 -0
- package/dist/replay/replay.d.ts +114 -0
- package/dist/replay/replay.js +98 -0
- package/dist/replay/replay.js.map +1 -0
- package/dist/replay/report.d.ts +18 -0
- package/dist/replay/report.js +72 -0
- package/dist/replay/report.js.map +1 -0
- package/dist/steps/backfill.d.ts +128 -0
- package/dist/steps/backfill.js +307 -0
- package/dist/steps/backfill.js.map +1 -0
- package/dist/steps/index.d.ts +52 -0
- package/dist/steps/index.js +52 -0
- package/dist/steps/index.js.map +1 -0
- package/dist/steps/kinds.d.ts +101 -0
- package/dist/steps/kinds.js +143 -0
- package/dist/steps/kinds.js.map +1 -0
- package/dist/steps/postgres-migration.d.ts +95 -0
- package/dist/steps/postgres-migration.js +149 -0
- package/dist/steps/postgres-migration.js.map +1 -0
- package/dist/steps/rebuild.d.ts +97 -0
- package/dist/steps/rebuild.js +162 -0
- package/dist/steps/rebuild.js.map +1 -0
- package/dist/steps/run.d.ts +45 -0
- package/dist/steps/run.js +72 -0
- package/dist/steps/run.js.map +1 -0
- package/dist/topology/render.d.ts +17 -0
- package/dist/topology/render.js +17 -0
- package/dist/topology/render.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/dist/versioned/approval.d.ts +35 -0
- package/dist/versioned/approval.js +53 -0
- package/dist/versioned/approval.js.map +1 -0
- package/dist/versioned/clickhouse.d.ts +24 -0
- package/dist/versioned/clickhouse.js +34 -0
- package/dist/versioned/clickhouse.js.map +1 -0
- package/dist/versioned/digest.d.ts +77 -0
- package/dist/versioned/digest.js +69 -0
- package/dist/versioned/digest.js.map +1 -0
- package/dist/versioned/driver.d.ts +41 -0
- package/dist/versioned/driver.js +13 -0
- package/dist/versioned/driver.js.map +1 -0
- package/dist/versioned/engine.d.ts +152 -0
- package/dist/versioned/engine.js +277 -0
- package/dist/versioned/engine.js.map +1 -0
- package/dist/versioned/explain.d.ts +123 -0
- package/dist/versioned/explain.js +289 -0
- package/dist/versioned/explain.js.map +1 -0
- package/dist/versioned/index.d.ts +37 -0
- package/dist/versioned/index.js +54 -0
- package/dist/versioned/index.js.map +1 -0
- package/dist/versioned/op.d.ts +62 -0
- package/dist/versioned/op.js +153 -0
- package/dist/versioned/op.js.map +1 -0
- package/dist/versioned/postgres/catalog.d.ts +33 -0
- package/dist/versioned/postgres/catalog.js +34 -0
- package/dist/versioned/postgres/catalog.js.map +1 -0
- package/dist/versioned/postgres/driver.d.ts +69 -0
- package/dist/versioned/postgres/driver.js +113 -0
- package/dist/versioned/postgres/driver.js.map +1 -0
- package/dist/versioned/postgres/executor.d.ts +104 -0
- package/dist/versioned/postgres/executor.js +172 -0
- package/dist/versioned/postgres/executor.js.map +1 -0
- package/dist/versioned/postgres/index.d.ts +11 -0
- package/dist/versioned/postgres/index.js +12 -0
- package/dist/versioned/postgres/index.js.map +1 -0
- package/dist/versioned/report.d.ts +22 -0
- package/dist/versioned/report.js +81 -0
- package/dist/versioned/report.js.map +1 -0
- package/dist/versioned/state.d.ts +108 -0
- package/dist/versioned/state.js +153 -0
- package/dist/versioned/state.js.map +1 -0
- package/package.json +51 -4
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `ClickHouseRebuildOp` step: the change ClickHouse cannot make with
|
|
3
|
+
* `ALTER` (a sort key, an engine, a key column's type or name), run inside
|
|
4
|
+
* the migration as chant's rebuild Op.
|
|
5
|
+
*
|
|
6
|
+
* The Op is chant's own (`ClickHouseRebuildOp` from the sql lexicon), built
|
|
7
|
+
* from the step's options with the apply's environment, and run by chant's
|
|
8
|
+
* local executor with the lexicon's rebuild activities:
|
|
9
|
+
*
|
|
10
|
+
* Plan, Create, Dual write (materialized-view mode), Backfill, Verify, Swap, Retain
|
|
11
|
+
*
|
|
12
|
+
* Three things differ from running the Op with `chant run`:
|
|
13
|
+
*
|
|
14
|
+
* - The declaration is the migration's recorded schema (`migration.json`'s
|
|
15
|
+
* `schema`), written to a temporary build file, not a fresh `chant build`:
|
|
16
|
+
* the table is rebuilt as this migration declares it, however far the
|
|
17
|
+
* declared schema has moved on since.
|
|
18
|
+
* - Its gates are left out. The swap gate's approval is the migration's:
|
|
19
|
+
* the step's options are in the migration's checksum, which is in the plan
|
|
20
|
+
* digest the migrations Op's gate approved. The verification still runs
|
|
21
|
+
* before the swap, and a difference fails the step with nothing swapped.
|
|
22
|
+
* The old table is kept, `<table>__chant_old`, until its retention date
|
|
23
|
+
* (7 days); the Op's drop gate and Drop phase are not part of the step.
|
|
24
|
+
* - Its onFailure (which drops the new table) is left out, so a step that
|
|
25
|
+
* failed or was killed part way resumes from the backfill's receipts on
|
|
26
|
+
* the next `yodel apply`: every partition with a receipt is skipped. To
|
|
27
|
+
* start the rebuild over instead, drop `<table>__chant_new` and
|
|
28
|
+
* `<table>__chant_dual`.
|
|
29
|
+
*
|
|
30
|
+
* The activities render their DDL for the topology chant resolves from
|
|
31
|
+
* `sql.profiles.<env>.topology`. When the environment's topology comes from
|
|
32
|
+
* elsewhere (`yodel.config.ts`, or `YODEL_TOPOLOGY`, #9), the step hands
|
|
33
|
+
* every rebuild activity chant's config with that topology set on the
|
|
34
|
+
* profile ({@link rebuildChantConfig}), so the rebuild renders for the same
|
|
35
|
+
* topology as the migration's statements.
|
|
36
|
+
*/
|
|
37
|
+
import type { OpConfig, PhaseDefinition } from "@intentius/chant/op/types";
|
|
38
|
+
import type { ActivityFn } from "@intentius/chant/op/activity-registry";
|
|
39
|
+
import type { StepRecord } from "@intentius/chant/op/local-executor";
|
|
40
|
+
import type { Topology } from "@intentius/chant-lexicon-sql/clickhouse/topology";
|
|
41
|
+
import type { RebuildOptions } from "./kinds.js";
|
|
42
|
+
import { type ProjectConfig } from "../project.js";
|
|
43
|
+
import { type RunOpOptions } from "./run.js";
|
|
44
|
+
/** `config` with `sql.profiles.<environment>.topology` set to `topology`. Pure; `config` is not changed. */
|
|
45
|
+
export declare function withProfileTopology(config: ProjectConfig, environment: string, topology: Topology): ProjectConfig;
|
|
46
|
+
/**
|
|
47
|
+
* The chant config a rebuild step's activities bind with: the project's,
|
|
48
|
+
* with the environment's resolved topology on its profile when chant would
|
|
49
|
+
* not find it there itself. `undefined` when chant's own resolution already
|
|
50
|
+
* gives the same topology (set in the profile, or no topology anywhere).
|
|
51
|
+
*/
|
|
52
|
+
export declare function rebuildChantConfig(projectDir: string, environment: string, env?: NodeJS.ProcessEnv): Promise<ProjectConfig | undefined>;
|
|
53
|
+
/** `ClickHouseRebuildOp`'s phases as a step runs them: no gates, no Drop, no onFailure. */
|
|
54
|
+
export declare function stepPhases(config: OpConfig): PhaseDefinition[];
|
|
55
|
+
/** The Op a rebuild step runs. `buildPath` is the recorded schema's file; `projectDir` holds chant.config.ts. */
|
|
56
|
+
export declare function rebuildOpConfig(options: RebuildOptions, ctx: {
|
|
57
|
+
environment: string;
|
|
58
|
+
projectDir: string;
|
|
59
|
+
buildPath: string;
|
|
60
|
+
}): Promise<OpConfig>;
|
|
61
|
+
export interface RebuildSummary {
|
|
62
|
+
op: "ClickHouseRebuildOp";
|
|
63
|
+
table: string;
|
|
64
|
+
/** The Plan's state when the step began: `rebuild`, or `swapped` / `done` when an earlier run got that far. */
|
|
65
|
+
state?: string;
|
|
66
|
+
partitions?: number;
|
|
67
|
+
/** Partitions copied in this run. */
|
|
68
|
+
copied?: number;
|
|
69
|
+
/** Partitions skipped: their receipt matched (copied by an earlier run). */
|
|
70
|
+
skipped?: number;
|
|
71
|
+
/** Partitions found partly copied and cleared before copying again. */
|
|
72
|
+
cleared?: number;
|
|
73
|
+
/** Rows copied by both the backfill and the dual-write view, deleted and copied again. */
|
|
74
|
+
repaired?: number;
|
|
75
|
+
/** Rows compared in the whole table, old against new. */
|
|
76
|
+
verifiedRows?: number;
|
|
77
|
+
swapped?: boolean;
|
|
78
|
+
oldTable?: string;
|
|
79
|
+
retainUntil?: string;
|
|
80
|
+
}
|
|
81
|
+
/** Folds one rebuild activity's result into the summary. */
|
|
82
|
+
export declare function summarize(summary: RebuildSummary, fn: string, result: unknown): void;
|
|
83
|
+
export interface RunRebuildOptions extends Omit<RunOpOptions, "activities" | "cwd"> {
|
|
84
|
+
projectDir: string;
|
|
85
|
+
/** The migration's recorded schema: the `chant build` output after it. */
|
|
86
|
+
schema: unknown;
|
|
87
|
+
/** Activities to use in place of the lexicon's, for a test. */
|
|
88
|
+
activities?: Record<string, ActivityFn>;
|
|
89
|
+
log?: (line: string) => void;
|
|
90
|
+
/** The chant config the rebuild activities bind with (see {@link rebuildChantConfig}). Default: they load chant.config.ts. */
|
|
91
|
+
config?: ProjectConfig | undefined;
|
|
92
|
+
}
|
|
93
|
+
/** Runs a rebuild step to the end. The summary is filled in as the activities return, so a failure still says how far it got. */
|
|
94
|
+
export declare function runRebuild(options: RebuildOptions, run: RunRebuildOptions, summary?: RebuildSummary): Promise<{
|
|
95
|
+
summary: RebuildSummary;
|
|
96
|
+
records: StepRecord[];
|
|
97
|
+
}>;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `ClickHouseRebuildOp` step: the change ClickHouse cannot make with
|
|
3
|
+
* `ALTER` (a sort key, an engine, a key column's type or name), run inside
|
|
4
|
+
* the migration as chant's rebuild Op.
|
|
5
|
+
*
|
|
6
|
+
* The Op is chant's own (`ClickHouseRebuildOp` from the sql lexicon), built
|
|
7
|
+
* from the step's options with the apply's environment, and run by chant's
|
|
8
|
+
* local executor with the lexicon's rebuild activities:
|
|
9
|
+
*
|
|
10
|
+
* Plan, Create, Dual write (materialized-view mode), Backfill, Verify, Swap, Retain
|
|
11
|
+
*
|
|
12
|
+
* Three things differ from running the Op with `chant run`:
|
|
13
|
+
*
|
|
14
|
+
* - The declaration is the migration's recorded schema (`migration.json`'s
|
|
15
|
+
* `schema`), written to a temporary build file, not a fresh `chant build`:
|
|
16
|
+
* the table is rebuilt as this migration declares it, however far the
|
|
17
|
+
* declared schema has moved on since.
|
|
18
|
+
* - Its gates are left out. The swap gate's approval is the migration's:
|
|
19
|
+
* the step's options are in the migration's checksum, which is in the plan
|
|
20
|
+
* digest the migrations Op's gate approved. The verification still runs
|
|
21
|
+
* before the swap, and a difference fails the step with nothing swapped.
|
|
22
|
+
* The old table is kept, `<table>__chant_old`, until its retention date
|
|
23
|
+
* (7 days); the Op's drop gate and Drop phase are not part of the step.
|
|
24
|
+
* - Its onFailure (which drops the new table) is left out, so a step that
|
|
25
|
+
* failed or was killed part way resumes from the backfill's receipts on
|
|
26
|
+
* the next `yodel apply`: every partition with a receipt is skipped. To
|
|
27
|
+
* start the rebuild over instead, drop `<table>__chant_new` and
|
|
28
|
+
* `<table>__chant_dual`.
|
|
29
|
+
*
|
|
30
|
+
* The activities render their DDL for the topology chant resolves from
|
|
31
|
+
* `sql.profiles.<env>.topology`. When the environment's topology comes from
|
|
32
|
+
* elsewhere (`yodel.config.ts`, or `YODEL_TOPOLOGY`, #9), the step hands
|
|
33
|
+
* every rebuild activity chant's config with that topology set on the
|
|
34
|
+
* profile ({@link rebuildChantConfig}), so the rebuild renders for the same
|
|
35
|
+
* topology as the migration's statements.
|
|
36
|
+
*/
|
|
37
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
38
|
+
import { tmpdir } from "node:os";
|
|
39
|
+
import { join } from "node:path";
|
|
40
|
+
import { environmentSettings } from "../config/settings.js";
|
|
41
|
+
import { loadProject } from "../project.js";
|
|
42
|
+
import { runOp, StepOpFailed } from "./run.js";
|
|
43
|
+
/** The rebuild activities whose results the history's summary keeps. */
|
|
44
|
+
const SUMMARIZED = ["clickhouseRebuildPlan", "clickhouseRebuildBackfill", "clickhouseRebuildVerify", "clickhouseRebuildSwap", "clickhouseRebuildRetain"];
|
|
45
|
+
/** `config` with `sql.profiles.<environment>.topology` set to `topology`. Pure; `config` is not changed. */
|
|
46
|
+
export function withProfileTopology(config, environment, topology) {
|
|
47
|
+
const profiles = config.sql?.profiles ?? {};
|
|
48
|
+
const profile = profiles[environment];
|
|
49
|
+
if (!profile)
|
|
50
|
+
return config;
|
|
51
|
+
return { ...config, sql: { ...config.sql, profiles: { ...profiles, [environment]: { ...profile, topology } } } };
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The chant config a rebuild step's activities bind with: the project's,
|
|
55
|
+
* with the environment's resolved topology on its profile when chant would
|
|
56
|
+
* not find it there itself. `undefined` when chant's own resolution already
|
|
57
|
+
* gives the same topology (set in the profile, or no topology anywhere).
|
|
58
|
+
*/
|
|
59
|
+
export async function rebuildChantConfig(projectDir, environment, env = process.env) {
|
|
60
|
+
const project = await loadProject(projectDir);
|
|
61
|
+
const settings = environmentSettings(project, environment, env);
|
|
62
|
+
if (settings.topologySource === "default" || settings.topologySource === `sql.profiles.${environment}.topology`)
|
|
63
|
+
return undefined;
|
|
64
|
+
return withProfileTopology(project.config, environment, settings.topology);
|
|
65
|
+
}
|
|
66
|
+
/** The activity of the phase left out: the old table's drop, which waits for its retention and its own gate. */
|
|
67
|
+
const LEFT_OUT = new Set(["clickhouseRebuildDrop"]);
|
|
68
|
+
/** `ClickHouseRebuildOp`'s phases as a step runs them: no gates, no Drop, no onFailure. */
|
|
69
|
+
export function stepPhases(config) {
|
|
70
|
+
return config.phases
|
|
71
|
+
.map((p) => ({ ...p, steps: p.steps.filter((s) => s.kind !== "gate" && !(s.kind === "activity" && LEFT_OUT.has(s.fn))) }))
|
|
72
|
+
.filter((p) => p.steps.length > 0);
|
|
73
|
+
}
|
|
74
|
+
/** The Op a rebuild step runs. `buildPath` is the recorded schema's file; `projectDir` holds chant.config.ts. */
|
|
75
|
+
export async function rebuildOpConfig(options, ctx) {
|
|
76
|
+
const { ClickHouseRebuildOp } = await import("@intentius/chant-lexicon-sql/clickhouse/rebuild/op");
|
|
77
|
+
const { op } = ClickHouseRebuildOp({
|
|
78
|
+
name: options.name,
|
|
79
|
+
env: ctx.environment,
|
|
80
|
+
table: options.table,
|
|
81
|
+
dualWrite: options.dualWrite,
|
|
82
|
+
build: false,
|
|
83
|
+
output: ctx.buildPath,
|
|
84
|
+
path: ctx.projectDir,
|
|
85
|
+
});
|
|
86
|
+
const full = op.props;
|
|
87
|
+
const rest = { ...full, phases: stepPhases(full) };
|
|
88
|
+
delete rest.onFailure;
|
|
89
|
+
return rest;
|
|
90
|
+
}
|
|
91
|
+
const num = (v) => (typeof v === "number" ? v : undefined);
|
|
92
|
+
const str = (v) => (typeof v === "string" ? v : undefined);
|
|
93
|
+
/** Folds one rebuild activity's result into the summary. */
|
|
94
|
+
export function summarize(summary, fn, result) {
|
|
95
|
+
const r = (typeof result === "object" && result !== null ? result : {});
|
|
96
|
+
const put = (k, v) => {
|
|
97
|
+
if (v !== undefined)
|
|
98
|
+
summary[k] = v;
|
|
99
|
+
};
|
|
100
|
+
if (fn === "clickhouseRebuildPlan")
|
|
101
|
+
put("state", str(r.state));
|
|
102
|
+
if (fn === "clickhouseRebuildBackfill") {
|
|
103
|
+
put("partitions", num(r.partitions));
|
|
104
|
+
put("copied", num(r.copied));
|
|
105
|
+
put("skipped", num(r.skipped));
|
|
106
|
+
put("cleared", num(r.cleared));
|
|
107
|
+
put("repaired", num(r.repaired));
|
|
108
|
+
}
|
|
109
|
+
if (fn === "clickhouseRebuildVerify")
|
|
110
|
+
put("verifiedRows", num(r.rows));
|
|
111
|
+
if (fn === "clickhouseRebuildSwap") {
|
|
112
|
+
put("swapped", typeof r.swapped === "boolean" ? r.swapped : undefined);
|
|
113
|
+
put("oldTable", str(r.oldTable));
|
|
114
|
+
put("retainUntil", str(r.retainUntil));
|
|
115
|
+
}
|
|
116
|
+
if (fn === "clickhouseRebuildRetain") {
|
|
117
|
+
put("oldTable", str(r.oldTable));
|
|
118
|
+
put("retainUntil", str(r.retainUntil));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** Runs a rebuild step to the end. The summary is filled in as the activities return, so a failure still says how far it got. */
|
|
122
|
+
export async function runRebuild(options, run, summary = { op: "ClickHouseRebuildOp", table: options.table }) {
|
|
123
|
+
const dir = mkdtempSync(join(tmpdir(), "yodel-rebuild-"));
|
|
124
|
+
try {
|
|
125
|
+
const buildPath = join(dir, "schema.json");
|
|
126
|
+
writeFileSync(buildPath, JSON.stringify(run.schema));
|
|
127
|
+
const config = await rebuildOpConfig(options, { environment: run.environment, projectDir: run.projectDir, buildPath });
|
|
128
|
+
const lexicon = run.activities ?? (await import("@intentius/chant-lexicon-sql/op/activities"));
|
|
129
|
+
const wrapped = {};
|
|
130
|
+
// A rebuild activity takes its config as a third argument (chant's ClickHouseRebuildDeps).
|
|
131
|
+
const deps = run.config ? { config: run.config } : undefined;
|
|
132
|
+
const summarized = SUMMARIZED;
|
|
133
|
+
for (const fn of Object.keys(lexicon).filter((f) => f.startsWith("clickhouseRebuild") && (deps !== undefined || summarized.includes(f)))) {
|
|
134
|
+
const inner = lexicon[fn];
|
|
135
|
+
if (!inner)
|
|
136
|
+
continue;
|
|
137
|
+
wrapped[fn] = async (args, signal) => {
|
|
138
|
+
const result = await (deps ? inner(args, signal, deps) : inner(args, signal));
|
|
139
|
+
if (summarized.includes(fn))
|
|
140
|
+
summarize(summary, fn, result);
|
|
141
|
+
return result;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const records = await runOp(config, {
|
|
145
|
+
cwd: run.projectDir,
|
|
146
|
+
environment: run.environment,
|
|
147
|
+
activities: { ...(run.activities ?? {}), ...wrapped },
|
|
148
|
+
...(run.base ? { base: run.base } : {}),
|
|
149
|
+
...(run.signal ? { signal: run.signal } : {}),
|
|
150
|
+
...(run.onRecord ? { onRecord: run.onRecord } : {}),
|
|
151
|
+
}).catch((e) => {
|
|
152
|
+
if (e instanceof StepOpFailed)
|
|
153
|
+
e.summary = summary;
|
|
154
|
+
throw e;
|
|
155
|
+
});
|
|
156
|
+
return { summary, records };
|
|
157
|
+
}
|
|
158
|
+
finally {
|
|
159
|
+
rmSync(dir, { recursive: true, force: true });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=rebuild.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rebuild.js","sourceRoot":"","sources":["../../src/steps/rebuild.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Running an Op step's Op in this process, with chant's local executor
|
|
3
|
+
* (`runOpLocally`, the executor `chant run` uses), inside the versioned
|
|
4
|
+
* apply that holds the lock.
|
|
5
|
+
*
|
|
6
|
+
* The activities are the ones `chant run` loads for a sql project (core's,
|
|
7
|
+
* and the sql lexicon's, the rebuild's among them), plus what the step adds
|
|
8
|
+
* (a backfill's receipt store and its `yodelSql`). Nothing is written to the
|
|
9
|
+
* run ledger: the history table is the record of what ran.
|
|
10
|
+
*
|
|
11
|
+
* A step's Op has no gate of its own here. The migration it is part of was
|
|
12
|
+
* approved under the plan digest, which covers the step through the
|
|
13
|
+
* migration's checksum; a gate left in the Op is refused before it runs.
|
|
14
|
+
*/
|
|
15
|
+
import type { OpConfig } from "@intentius/chant/op/types";
|
|
16
|
+
import type { ActivityFn } from "@intentius/chant/op/activity-registry";
|
|
17
|
+
import type { StepRecord } from "@intentius/chant/op/local-executor";
|
|
18
|
+
import { YodelError } from "../project.js";
|
|
19
|
+
/** A step's Op stopped part way. The history records it failed; the next run resumes it. */
|
|
20
|
+
export declare class StepOpFailed extends YodelError {
|
|
21
|
+
readonly op: string;
|
|
22
|
+
readonly detail: string;
|
|
23
|
+
readonly records: StepRecord[];
|
|
24
|
+
/** How far it got, for the history's note: set by the step that ran it. */
|
|
25
|
+
summary: unknown;
|
|
26
|
+
constructor(op: string, detail: string, records: StepRecord[]);
|
|
27
|
+
}
|
|
28
|
+
/** The gates in an Op, by name. */
|
|
29
|
+
export declare const gatesOf: (config: Pick<OpConfig, "phases" | "onFailure">) => string[];
|
|
30
|
+
/** The first failing record's error, for the message. */
|
|
31
|
+
export declare function failureOf(records: readonly StepRecord[]): string;
|
|
32
|
+
export interface RunOpOptions {
|
|
33
|
+
/** The project directory: chant's config is read from it. */
|
|
34
|
+
cwd: string;
|
|
35
|
+
/** The environment, handed to the activities through the run context. */
|
|
36
|
+
environment: string;
|
|
37
|
+
/** Activities added to (or replacing) the ones chant loads. */
|
|
38
|
+
activities?: Record<string, ActivityFn>;
|
|
39
|
+
/** The activities to use instead of loading chant's, for a test. */
|
|
40
|
+
base?: Map<string, ActivityFn>;
|
|
41
|
+
signal?: AbortSignal;
|
|
42
|
+
onRecord?: (record: StepRecord) => void;
|
|
43
|
+
}
|
|
44
|
+
/** Runs `config` to the end. Resolves with its records; throws {@link StepOpFailed} when it fails, or stops at a gate or a decision point. */
|
|
45
|
+
export declare function runOp(config: OpConfig, options: RunOpOptions): Promise<StepRecord[]>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Running an Op step's Op in this process, with chant's local executor
|
|
3
|
+
* (`runOpLocally`, the executor `chant run` uses), inside the versioned
|
|
4
|
+
* apply that holds the lock.
|
|
5
|
+
*
|
|
6
|
+
* The activities are the ones `chant run` loads for a sql project (core's,
|
|
7
|
+
* and the sql lexicon's, the rebuild's among them), plus what the step adds
|
|
8
|
+
* (a backfill's receipt store and its `yodelSql`). Nothing is written to the
|
|
9
|
+
* run ledger: the history table is the record of what ran.
|
|
10
|
+
*
|
|
11
|
+
* A step's Op has no gate of its own here. The migration it is part of was
|
|
12
|
+
* approved under the plan digest, which covers the step through the
|
|
13
|
+
* migration's checksum; a gate left in the Op is refused before it runs.
|
|
14
|
+
*/
|
|
15
|
+
import { YodelError } from "../project.js";
|
|
16
|
+
/** A step's Op stopped part way. The history records it failed; the next run resumes it. */
|
|
17
|
+
export class StepOpFailed extends YodelError {
|
|
18
|
+
op;
|
|
19
|
+
detail;
|
|
20
|
+
records;
|
|
21
|
+
/** How far it got, for the history's note: set by the step that ran it. */
|
|
22
|
+
summary;
|
|
23
|
+
constructor(op, detail, records) {
|
|
24
|
+
super(`${op}: ${detail}`, 1);
|
|
25
|
+
this.op = op;
|
|
26
|
+
this.detail = detail;
|
|
27
|
+
this.records = records;
|
|
28
|
+
this.name = "StepOpFailed";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const allSteps = (config) => [...config.phases, ...(config.onFailure ?? [])].flatMap((p) => p.steps.flatMap((s) => (s.kind === "effect" ? [s, ...s.steps] : [s])));
|
|
32
|
+
/** The gates in an Op, by name. */
|
|
33
|
+
export const gatesOf = (config) => allSteps(config).flatMap((s) => (s.kind === "gate" ? [s.gate ?? "unnamed"] : []));
|
|
34
|
+
/** The first failing record's error, for the message. */
|
|
35
|
+
export function failureOf(records) {
|
|
36
|
+
const failed = records.find((r) => r.status === "fail");
|
|
37
|
+
return failed ? `${failed.phase} / ${failed.fn} failed: ${failed.error ?? "no error given"}` : "the Op failed";
|
|
38
|
+
}
|
|
39
|
+
/** Runs `config` to the end. Resolves with its records; throws {@link StepOpFailed} when it fails, or stops at a gate or a decision point. */
|
|
40
|
+
export async function runOp(config, options) {
|
|
41
|
+
const gates = gatesOf(config);
|
|
42
|
+
if (gates.length > 0) {
|
|
43
|
+
throw new StepOpFailed(config.name, `it has a gate (${gates.join(", ")}); a step's Op runs behind the migration's own gate and may not have one of its own`, []);
|
|
44
|
+
}
|
|
45
|
+
const { loadActivities, loadProfiles } = await import("@intentius/chant/op/activity-registry");
|
|
46
|
+
const { runOpLocally, OpRunFailure } = await import("@intentius/chant/op/local-executor");
|
|
47
|
+
const activities = options.base ? new Map(options.base) : await loadActivities(["sql"]);
|
|
48
|
+
for (const [name, fn] of Object.entries(options.activities ?? {}))
|
|
49
|
+
activities.set(name, fn);
|
|
50
|
+
const profiles = await loadProfiles();
|
|
51
|
+
try {
|
|
52
|
+
const result = await runOpLocally(config, activities, profiles, options.signal, {
|
|
53
|
+
cwd: options.cwd,
|
|
54
|
+
env: options.environment,
|
|
55
|
+
...(options.onRecord ? { onRecord: options.onRecord } : {}),
|
|
56
|
+
});
|
|
57
|
+
if (result.status !== "ok")
|
|
58
|
+
throw new StepOpFailed(config.name, `it stopped (${result.status}) instead of running to the end`, result.records);
|
|
59
|
+
return result.records;
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
if (e instanceof StepOpFailed)
|
|
63
|
+
throw e;
|
|
64
|
+
if (e instanceof OpRunFailure) {
|
|
65
|
+
const cause = e.cause instanceof Error ? e.cause.message : typeof e.cause === "string" ? e.cause : undefined;
|
|
66
|
+
const failedStep = e.result.records.some((r) => r.status === "fail");
|
|
67
|
+
throw new StepOpFailed(config.name, failedStep ? failureOf(e.result.records) : (cause ?? "the Op failed"), e.result.records);
|
|
68
|
+
}
|
|
69
|
+
throw new StepOpFailed(config.name, e instanceof Error ? e.message : String(e), []);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/steps/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A migration's statements as one environment runs them. The source is
|
|
3
|
+
* topology-neutral: `yodel new` writes each statement for a single node,
|
|
4
|
+
* and at apply time each is rendered for the environment's topology with
|
|
5
|
+
* chant's renderer (`ON CLUSTER` added or removed, the replicated engine
|
|
6
|
+
* written). Pure.
|
|
7
|
+
*
|
|
8
|
+
* The history records a statement by the neutral statement's sha, so a
|
|
9
|
+
* migration resumes the same way on every topology; the topology it was
|
|
10
|
+
* sent for goes in the row's note ({@link topologyNote}).
|
|
11
|
+
*/
|
|
12
|
+
import { type Topology } from "@intentius/chant-lexicon-sql/clickhouse/topology";
|
|
13
|
+
export type { Topology };
|
|
14
|
+
/** One neutral statement, as `topology` runs it. */
|
|
15
|
+
export declare const renderForEnvironment: (sql: string, topology: Topology) => string;
|
|
16
|
+
/** The `note` a statement row carries: the topology the statement was rendered for. */
|
|
17
|
+
export declare const topologyNote: (topology: Topology) => string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A migration's statements as one environment runs them. The source is
|
|
3
|
+
* topology-neutral: `yodel new` writes each statement for a single node,
|
|
4
|
+
* and at apply time each is rendered for the environment's topology with
|
|
5
|
+
* chant's renderer (`ON CLUSTER` added or removed, the replicated engine
|
|
6
|
+
* written). Pure.
|
|
7
|
+
*
|
|
8
|
+
* The history records a statement by the neutral statement's sha, so a
|
|
9
|
+
* migration resumes the same way on every topology; the topology it was
|
|
10
|
+
* sent for goes in the row's note ({@link topologyNote}).
|
|
11
|
+
*/
|
|
12
|
+
import { renderStatement, topologyLabel } from "@intentius/chant-lexicon-sql/clickhouse/topology";
|
|
13
|
+
/** One neutral statement, as `topology` runs it. */
|
|
14
|
+
export const renderForEnvironment = (sql, topology) => renderStatement(sql, topology);
|
|
15
|
+
/** The `note` a statement row carries: the topology the statement was rendered for. */
|
|
16
|
+
export const topologyNote = (topology) => `topology=${topologyLabel(topology)}`;
|
|
17
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/topology/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAiB,MAAM,kDAAkD,CAAC;AAIjH,oDAAoD;AACpD,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAW,EAAE,QAAkB,EAAU,EAAE,CAAC,eAAe,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AAEhH,uFAAuF;AACvF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,QAAkB,EAAU,EAAE,CAAC,YAAY,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
/** The package version, read from package.json (one level above both src/ and dist/). */
|
|
3
|
+
export function version() {
|
|
4
|
+
const url = new URL("../package.json", import.meta.url);
|
|
5
|
+
const pkg = JSON.parse(readFileSync(url, "utf8"));
|
|
6
|
+
if (typeof pkg.version !== "string") {
|
|
7
|
+
throw new Error(`no version in ${url.pathname}`);
|
|
8
|
+
}
|
|
9
|
+
return pkg.version;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,yFAAyF;AACzF,MAAM,UAAU,OAAO;IACrB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAA0B,CAAC;IAC3E,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,iBAAiB,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,GAAG,CAAC,OAAO,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The approval check `yodel apply <env> --execute` makes itself, against
|
|
3
|
+
* chant's gate ledger, before it sends anything.
|
|
4
|
+
*
|
|
5
|
+
* `YODEL_APPROVED_PLAN` is how the Op hands the digest to the Apply step, but
|
|
6
|
+
* it is never enough on its own: anyone can set an environment variable.
|
|
7
|
+
* `--execute` reads the ledger the gate step reads (the `chant/lifecycle`
|
|
8
|
+
* branch, through chant's `gitGateLedgerPort`) for the environment's
|
|
9
|
+
* migrations Op, and requires an approval of its gate for exactly the digest
|
|
10
|
+
* it computes under the lock, by the rule chant's gate applies
|
|
11
|
+
* (`evaluateGate`):
|
|
12
|
+
*
|
|
13
|
+
* - the resolution is for this gate and for this plan digest
|
|
14
|
+
* (`latestResolutionForPlan`; one recorded before plan-bound gates never
|
|
15
|
+
* counts);
|
|
16
|
+
* - it is newer than the newest pending fact for the gate, so an approval
|
|
17
|
+
* from before the gate last asked does not answer it;
|
|
18
|
+
* - the workspace's approval rule for the gate (`identity.gates`), when one
|
|
19
|
+
* applies, accepts it.
|
|
20
|
+
*
|
|
21
|
+
* A gate with a quorum or policy (`approval`) is refused here: counting a
|
|
22
|
+
* quorum is the gate step's, and `--execute` fails closed rather than
|
|
23
|
+
* approximate it.
|
|
24
|
+
*/
|
|
25
|
+
import type { GateLedgerPort } from "@intentius/chant/op/gate";
|
|
26
|
+
import type { MigrateOpRef } from "./op.js";
|
|
27
|
+
/** Exit code of a refusal for want of an approval: the same as a run stopped at the gate. */
|
|
28
|
+
export declare const NOT_APPROVED = 3;
|
|
29
|
+
/** Throws unless the ledger holds an approval of `op`'s gate for `digest`. Returns who approved it. */
|
|
30
|
+
export declare function verifyApproval(port: GateLedgerPort, op: MigrateOpRef, digest: string): Promise<{
|
|
31
|
+
resolvedBy: string;
|
|
32
|
+
timestamp: string;
|
|
33
|
+
}>;
|
|
34
|
+
/** The ledger as the gate step reads it, in the project's checkout. */
|
|
35
|
+
export declare function gitLedger(cwd: string): Promise<GateLedgerPort>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The approval check `yodel apply <env> --execute` makes itself, against
|
|
3
|
+
* chant's gate ledger, before it sends anything.
|
|
4
|
+
*
|
|
5
|
+
* `YODEL_APPROVED_PLAN` is how the Op hands the digest to the Apply step, but
|
|
6
|
+
* it is never enough on its own: anyone can set an environment variable.
|
|
7
|
+
* `--execute` reads the ledger the gate step reads (the `chant/lifecycle`
|
|
8
|
+
* branch, through chant's `gitGateLedgerPort`) for the environment's
|
|
9
|
+
* migrations Op, and requires an approval of its gate for exactly the digest
|
|
10
|
+
* it computes under the lock, by the rule chant's gate applies
|
|
11
|
+
* (`evaluateGate`):
|
|
12
|
+
*
|
|
13
|
+
* - the resolution is for this gate and for this plan digest
|
|
14
|
+
* (`latestResolutionForPlan`; one recorded before plan-bound gates never
|
|
15
|
+
* counts);
|
|
16
|
+
* - it is newer than the newest pending fact for the gate, so an approval
|
|
17
|
+
* from before the gate last asked does not answer it;
|
|
18
|
+
* - the workspace's approval rule for the gate (`identity.gates`), when one
|
|
19
|
+
* applies, accepts it.
|
|
20
|
+
*
|
|
21
|
+
* A gate with a quorum or policy (`approval`) is refused here: counting a
|
|
22
|
+
* quorum is the gate step's, and `--execute` fails closed rather than
|
|
23
|
+
* approximate it.
|
|
24
|
+
*/
|
|
25
|
+
import { YodelError } from "../project.js";
|
|
26
|
+
const EPOCH = new Date(0).toISOString();
|
|
27
|
+
/** Exit code of a refusal for want of an approval: the same as a run stopped at the gate. */
|
|
28
|
+
export const NOT_APPROVED = 3;
|
|
29
|
+
/** Throws unless the ledger holds an approval of `op`'s gate for `digest`. Returns who approved it. */
|
|
30
|
+
export async function verifyApproval(port, op, digest) {
|
|
31
|
+
if (op.quorum) {
|
|
32
|
+
throw new YodelError(`--execute cannot check gate "${op.gate}" of ${op.name}: it declares an approval quorum or policy, which only the gate step counts; run yodel apply without --execute`, NOT_APPROVED);
|
|
33
|
+
}
|
|
34
|
+
const { latestPendingGate, latestResolutionForPlan } = await import("@intentius/chant/lifecycle/gate-ledger");
|
|
35
|
+
const ledger = await port.read(op.name);
|
|
36
|
+
const rule = (await port.approvalRule?.(op.gate)) ?? null;
|
|
37
|
+
const resolutions = ledger.resolutions.filter((r) => r.gate !== op.gate || rule === null || rule.refuses(r) === null);
|
|
38
|
+
const since = latestPendingGate(ledger.pending, op.gate)?.timestamp ?? EPOCH;
|
|
39
|
+
const found = latestResolutionForPlan(resolutions, op.gate, since, digest);
|
|
40
|
+
if (found.resolution)
|
|
41
|
+
return { resolvedBy: found.resolution.resolvedBy, timestamp: found.resolution.timestamp };
|
|
42
|
+
const other = found.mismatched
|
|
43
|
+
? ` (the newest approval of that gate is for ${found.mismatched.planDigest ?? "no plan"}, by ${found.mismatched.resolvedBy} at ${found.mismatched.timestamp})`
|
|
44
|
+
: "";
|
|
45
|
+
throw new YodelError(`refused: chant's gate ledger holds no approval of ${op.name} / ${op.gate} for plan ${digest}${other}. Nothing was applied. ` +
|
|
46
|
+
`Run yodel apply without --execute; it stops at the gate and prints the chant approve command.`, NOT_APPROVED);
|
|
47
|
+
}
|
|
48
|
+
/** The ledger as the gate step reads it, in the project's checkout. */
|
|
49
|
+
export async function gitLedger(cwd) {
|
|
50
|
+
const { gitGateLedgerPort } = await import("@intentius/chant/op/gate");
|
|
51
|
+
return gitGateLedgerPort({ cwd });
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=approval.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval.js","sourceRoot":"","sources":["../../src/versioned/approval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;AAExC,6FAA6F;AAC7F,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC;AAE9B,uGAAuG;AACvG,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAoB,EAAE,EAAgB,EAAE,MAAc;IACzF,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;QACd,MAAM,IAAI,UAAU,CAAC,gCAAgC,EAAE,CAAC,IAAI,QAAQ,EAAE,CAAC,IAAI,gHAAgH,EAAE,YAAY,CAAC,CAAC;IAC7M,CAAC;IACD,MAAM,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,GAAG,MAAM,MAAM,CAAC,wCAAwC,CAAC,CAAC;IAC9G,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC;IAC1D,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IACtH,MAAM,KAAK,GAAG,iBAAiB,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,SAAS,IAAI,KAAK,CAAC;IAC7E,MAAM,KAAK,GAAG,uBAAuB,CAAC,WAAW,EAAE,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC3E,IAAI,KAAK,CAAC,UAAU;QAAE,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC;IAChH,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU;QAC5B,CAAC,CAAC,6CAA6C,KAAK,CAAC,UAAU,CAAC,UAAU,IAAI,SAAS,QAAQ,KAAK,CAAC,UAAU,CAAC,UAAU,OAAO,KAAK,CAAC,UAAU,CAAC,SAAS,GAAG;QAC9J,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,IAAI,UAAU,CAClB,qDAAqD,EAAE,CAAC,IAAI,MAAM,EAAE,CAAC,IAAI,aAAa,MAAM,GAAG,KAAK,yBAAyB;QAC3H,+FAA+F,EACjG,YAAY,CACb,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW;IACzC,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;IACvE,OAAO,iBAAiB,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The versioned apply's ClickHouse driver: the Keeper (or local) lock
|
|
3
|
+
* (`../history/lock.ts`), the catalog fingerprint over `system.tables`
|
|
4
|
+
* (`./digest.ts`), and each statement rendered for the environment's
|
|
5
|
+
* topology (#9) and sent, then its `succeeded` row appended. ClickHouse DDL
|
|
6
|
+
* is not transactional, so the row follows the statement; a runner killed
|
|
7
|
+
* between the two leaves the statement's latest row `started`, and the next
|
|
8
|
+
* run sends it again.
|
|
9
|
+
*/
|
|
10
|
+
import type { ClickHouseEndpoint } from "@intentius/chant-lexicon-sql/clickhouse/http";
|
|
11
|
+
import { type ClickHousePort, type HistoryLocation } from "../history/index.js";
|
|
12
|
+
import { type Topology } from "../topology/render.js";
|
|
13
|
+
import { type LiveScope } from "./digest.js";
|
|
14
|
+
import type { VersionedDriver } from "./driver.js";
|
|
15
|
+
export interface ClickHouseDriverInput {
|
|
16
|
+
port: ClickHousePort;
|
|
17
|
+
location: HistoryLocation;
|
|
18
|
+
scope: LiveScope;
|
|
19
|
+
serverKey: string;
|
|
20
|
+
lockTtlMs: number;
|
|
21
|
+
endpoint?: ClickHouseEndpoint | undefined;
|
|
22
|
+
topology?: Topology | undefined;
|
|
23
|
+
}
|
|
24
|
+
export declare function clickhouseDriver(input: ClickHouseDriverInput): VersionedDriver;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The versioned apply's ClickHouse driver: the Keeper (or local) lock
|
|
3
|
+
* (`../history/lock.ts`), the catalog fingerprint over `system.tables`
|
|
4
|
+
* (`./digest.ts`), and each statement rendered for the environment's
|
|
5
|
+
* topology (#9) and sent, then its `succeeded` row appended. ClickHouse DDL
|
|
6
|
+
* is not transactional, so the row follows the statement; a runner killed
|
|
7
|
+
* between the two leaves the statement's latest row `started`, and the next
|
|
8
|
+
* run sends it again.
|
|
9
|
+
*/
|
|
10
|
+
import { acquireLock, SINGLE, serverMessage } from "../history/index.js";
|
|
11
|
+
import { renderForEnvironment, topologyNote } from "../topology/render.js";
|
|
12
|
+
import { catalogFingerprint, readLiveCatalog } from "./digest.js";
|
|
13
|
+
export function clickhouseDriver(input) {
|
|
14
|
+
const { port } = input;
|
|
15
|
+
const topology = input.topology ?? SINGLE;
|
|
16
|
+
return {
|
|
17
|
+
dialect: "clickhouse",
|
|
18
|
+
rowNote: topologyNote(topology),
|
|
19
|
+
acquireLock: (holder) => acquireLock(port, { database: input.location.database, topology: input.location.topology, holder, ttlMs: input.lockTtlMs, serverKey: input.serverKey }),
|
|
20
|
+
liveFingerprint: async () => catalogFingerprint(await readLiveCatalog(port, input.scope)),
|
|
21
|
+
async runStatement(step, run) {
|
|
22
|
+
try {
|
|
23
|
+
await port.query(renderForEnvironment(step.sql, topology), step.waitsForMutation ? { settings: { mutations_sync: "2" } } : {});
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
throw new Error(serverMessage(e), { cause: e });
|
|
27
|
+
}
|
|
28
|
+
await run.succeeded("");
|
|
29
|
+
},
|
|
30
|
+
stepContext: () => ({ port, endpoint: input.endpoint }),
|
|
31
|
+
close: () => Promise.resolve(),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=clickhouse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickhouse.js","sourceRoot":"","sources":["../../src/versioned/clickhouse.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAA6C,MAAM,qBAAqB,CAAC;AACpH,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAiB,MAAM,uBAAuB,CAAC;AAC1F,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAkB,MAAM,aAAa,CAAC;AAalF,MAAM,UAAU,gBAAgB,CAAC,KAA4B;IAC3D,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IACvB,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,MAAM,CAAC;IAC1C,OAAO;QACL,OAAO,EAAE,YAAY;QACrB,OAAO,EAAE,YAAY,CAAC,QAAQ,CAAC;QAC/B,WAAW,EAAE,CAAC,MAAM,EAAE,EAAE,CACtB,WAAW,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC;QACzJ,eAAe,EAAE,KAAK,IAAI,EAAE,CAAC,kBAAkB,CAAC,MAAM,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACzF,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,GAAG;YAC1B,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,cAAc,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACjI,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;YAClD,CAAC;YACD,MAAM,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAC1B,CAAC;QACD,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;QACvD,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;KAC/B,CAAC;AACJ,CAAC"}
|