okmodel 0.2.1 → 0.4.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 +882 -48
- package/dist/contracts/catalog/document.d.ts +6 -2
- package/dist/contracts/catalog/enum.d.ts +31 -4
- package/dist/contracts/catalog/extension.d.ts +61 -0
- package/dist/contracts/catalog/privilege.d.ts +64 -0
- package/dist/contracts/catalog/routine.d.ts +56 -0
- package/dist/contracts/catalog/types.d.ts +164 -10
- package/dist/contracts/catalog/view.d.ts +73 -0
- package/dist/dialects/pg/column.d.ts +3 -1
- package/dist/dialects/pg/ddl.d.ts +65 -1
- package/dist/dialects/pg/enum.d.ts +10 -8
- package/dist/dialects/pg/ext/citext.d.ts +14 -0
- package/dist/dialects/pg/ext/citext.js +11 -0
- package/dist/dialects/pg/ext/index.d.ts +52 -0
- package/dist/dialects/pg/ext/index.js +6 -0
- package/dist/dialects/pg/ext/pg-trgm.d.ts +53 -0
- package/dist/dialects/pg/ext/pg-trgm.js +42 -0
- package/dist/dialects/pg/fn/index.d.ts +107 -0
- package/dist/dialects/pg/fn/index.js +175 -0
- package/dist/dialects/pg/fn/touch.d.ts +14 -0
- package/dist/dialects/pg/index.js +104 -19
- package/dist/dialects/pg/introspect.d.ts +10 -1
- package/dist/dialects/pg/operators.d.ts +8 -1
- package/dist/dialects/pg/role/check.d.ts +45 -0
- package/dist/dialects/pg/role/index.d.ts +50 -0
- package/dist/dialects/pg/role/sql.d.ts +51 -0
- package/dist/dialects/pg/table.d.ts +24 -1
- package/dist/dialects/pg/tenancy.d.ts +9 -0
- package/dist/dialects/pg/view/client.d.ts +30 -0
- package/dist/dialects/pg/view/depend.d.ts +35 -0
- package/dist/dialects/pg/view/index.d.ts +114 -0
- package/dist/dialects/pg/view/index.js +289 -0
- package/dist/dialects/pg/view/scratch.d.ts +22 -0
- package/dist/dialects/pg/where.d.ts +2 -2
- package/dist/runtime/catalog-cache.d.ts +17 -0
- package/dist/runtime/compat-words.d.ts +23 -0
- package/dist/runtime/drift-detail.d.ts +20 -4
- package/dist/runtime/drift.d.ts +4 -2
- package/dist/runtime/pg/bun.js +3 -3
- package/dist/runtime/pg/pg.js +3 -3
- package/dist/runtime/pg/pglite.js +3 -3
- package/dist/runtime/pg/postgresjs.js +3 -3
- package/dist/runtime/tenancy/index.js +6 -3
- package/dist/runtime/traits/index.d.ts +7 -2
- package/dist/runtime/traits/index.js +151 -13
- package/dist/runtime/types.d.ts +2 -0
- package/dist/runtime/validate/index.js +4 -4
- package/dist/shared/{xkz8g6by.js → 1g0drakv.js} +2 -2
- package/dist/shared/2321avmn.js +418 -0
- package/dist/shared/{7mht49yd.js → 3p4b1fg0.js} +57 -18
- package/dist/shared/41kv2xdm.js +318 -0
- package/dist/shared/{97g2jnrw.js → 4ef7mmqf.js} +3 -3
- package/dist/shared/{sacqha1y.js → 4m9fn52z.js} +2 -2
- package/dist/shared/5mtf6cj3.js +94 -0
- package/dist/shared/{1dp5knt7.js → 5vdm4sgp.js} +2 -2
- package/dist/shared/{a1gdp7j9.js → 6693j9rs.js} +1 -1
- package/dist/shared/{38crxbgn.js → 6p5k20sm.js} +3 -3
- package/dist/shared/7nk68fj8.js +751 -0
- package/dist/shared/84ptn35q.js +71 -0
- package/dist/shared/{d2whjz4k.js → 8jb4ymh2.js} +581 -28
- package/dist/shared/8ktwd3rh.js +97 -0
- package/dist/shared/94ez8kzh.js +19 -0
- package/dist/shared/{3a5ne750.js → 9m80mkac.js} +2 -2
- package/dist/shared/9x25fxhc.js +150 -0
- package/dist/shared/9yn6a2vd.js +11 -0
- package/dist/shared/ady1ms74.js +72 -0
- package/dist/shared/{4jzzghr6.js → awrsqrn7.js} +6 -6
- package/dist/shared/{4b9da9d7.js → axhk06q1.js} +19 -1
- package/dist/shared/{d04j53v8.js → c5g81ngb.js} +82 -14
- package/dist/shared/{n47rd821.js → c8aghh05.js} +1 -1
- package/dist/shared/{dd4f8mnx.js → c9z5g0fm.js} +4 -2
- package/dist/shared/{ps43134h.js → dyj86cmj.js} +4 -4
- package/dist/shared/{0qkxbm1f.js → fa9vt245.js} +1 -1
- package/dist/shared/{qa5dsc7z.js → fb00y8fp.js} +3 -3
- package/dist/shared/{qxa0yb9j.js → g7ez901n.js} +30 -1
- package/dist/shared/{py3nh7jy.js → gdh9mrtp.js} +2 -2
- package/dist/shared/{yw5c610b.js → gjthds9j.js} +2 -2
- package/dist/shared/hcmdtwgh.js +102 -0
- package/dist/shared/hqjsxnz7.js +13 -0
- package/dist/shared/htnaj77v.js +17 -0
- package/dist/shared/{v18jva5b.js → jgxzjzcz.js} +1 -1
- package/dist/shared/{x9v1qgeb.js → jsd07prz.js} +3 -3
- package/dist/shared/{g9f0zqce.js → kafaa5zv.js} +1 -1
- package/dist/shared/kj680nxv.js +19 -0
- package/dist/shared/{mxmcdsh5.js → kkzwp3d2.js} +9 -9
- package/dist/shared/{g1b5zzj9.js → n0dgs0pb.js} +1 -1
- package/dist/shared/n5y9zyj1.js +2431 -0
- package/dist/shared/{zt8y0wzb.js → n7mcc1gk.js} +1 -1
- package/dist/shared/{ge03bfca.js → nxb42q7h.js} +2 -2
- package/dist/shared/q6zsyh31.js +2192 -0
- package/dist/shared/{sfh4pk75.js → q795afwa.js} +26 -21
- package/dist/shared/{10tjenmd.js → qn0srwwq.js} +1 -1
- package/dist/shared/s4mb6a4b.js +545 -0
- package/dist/shared/{ytg3xf9p.js → sf8m6tfy.js} +3 -3
- package/dist/shared/{zd93g3rq.js → sr5ms7b3.js} +1 -1
- package/dist/shared/{xatfg0gn.js → tmbdywx0.js} +4 -19
- package/dist/shared/tny2t3sm.js +100 -0
- package/dist/shared/{e7a268fy.js → v7tpnhnz.js} +1 -1
- package/dist/shared/{ecdzej21.js → wqem4jed.js} +7 -7
- package/dist/shared/xghkt7a9.js +1144 -0
- package/dist/shared/y005b761.js +112 -0
- package/dist/shared/ycatkxmq.js +84 -0
- package/dist/shared/ygem90rn.js +900 -0
- package/dist/shared/{eaxwrgby.js → yjw02enp.js} +6 -3
- package/dist/shared/{mrq77sgw.js → zg24x0hm.js} +1 -1
- package/dist/shared/{cstgkzdx.js → zvbjc949.js} +1 -1
- package/dist/tooling/cli.js +66 -13
- package/dist/tooling/migrate/apply.d.ts +75 -5
- package/dist/tooling/migrate/backfill.d.ts +136 -0
- package/dist/tooling/migrate/check.d.ts +65 -0
- package/dist/tooling/migrate/classify.d.ts +108 -0
- package/dist/tooling/migrate/commands.d.ts +2 -1
- package/dist/tooling/migrate/config.d.ts +30 -0
- package/dist/tooling/migrate/doctor.d.ts +28 -0
- package/dist/tooling/migrate/drift.d.ts +35 -0
- package/dist/tooling/migrate/estimate.d.ts +50 -0
- package/dist/tooling/migrate/ext.d.ts +17 -0
- package/dist/tooling/migrate/extensions.d.ts +53 -0
- package/dist/tooling/migrate/files.d.ts +12 -0
- package/dist/tooling/migrate/index.d.ts +3 -2
- package/dist/tooling/migrate/index.js +67 -1
- package/dist/tooling/migrate/lint-rules.d.ts +51 -0
- package/dist/tooling/migrate/lint.d.ts +71 -0
- package/dist/tooling/migrate/managed.d.ts +17 -0
- package/dist/tooling/migrate/plan.d.ts +78 -10
- package/dist/tooling/migrate/project.d.ts +64 -5
- package/dist/tooling/migrate/provision.d.ts +18 -0
- package/dist/tooling/migrate/reference.d.ts +40 -0
- package/dist/tooling/migrate/runner.d.ts +108 -0
- package/dist/tooling/migrate/safe.d.ts +77 -0
- package/dist/tooling/migrate/seed.d.ts +20 -0
- package/dist/tooling/migrate/snapshot.d.ts +78 -0
- package/dist/tooling/migrate/status.d.ts +25 -6
- package/dist/tooling/migrate/type-name.d.ts +19 -0
- package/dist/tooling/testing/factories.d.ts +117 -0
- package/dist/tooling/testing/facts.d.ts +72 -0
- package/dist/tooling/testing/index.d.ts +89 -0
- package/dist/tooling/testing/index.js +8 -0
- package/dist/tooling/testing/isolation.d.ts +30 -0
- package/dist/tooling/testing/random.d.ts +40 -0
- package/dist/tooling/testing/record.d.ts +38 -0
- package/package.json +26 -2
- package/dist/shared/5z4q2zda.js +0 -2073
- package/dist/shared/eqmtn1bj.js +0 -399
- package/dist/shared/rtnaqre0.js +0 -37
- package/dist/shared/zwmqxb0g.js +0 -79
- package/dist/shared/{m9tv7xn7.js → radd3z4g.js} +3 -3
- /package/dist/shared/{9k6vetvf.js → rrstp3kb.js} +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `provision(target)` for one configured target (D198).
|
|
3
|
+
*
|
|
4
|
+
* Same rules as `okm migrate apply` on an empty target, including
|
|
5
|
+
* {@link assertTargetPolicy}. A target that is not empty is OKM1851.
|
|
6
|
+
* Tenant registry creation is M5.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Provisions one configured target from the head snapshot.
|
|
10
|
+
*
|
|
11
|
+
* The target must be empty. Reference rows are inserted if missing. History
|
|
12
|
+
* records `provisioned@<migration id>` and no migration step.
|
|
13
|
+
*
|
|
14
|
+
* @param target - Configured target name. `default` is the `database` target
|
|
15
|
+
* @param cwd - Project directory. Defaults to the process working directory
|
|
16
|
+
* @returns The same text `okm migrate apply` prints for that run
|
|
17
|
+
*/
|
|
18
|
+
export declare function provision(target: string, cwd?: string): Promise<string>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reference rows declared on a table (D198).
|
|
3
|
+
*
|
|
4
|
+
* The rows live on the schema, not as a catalog diff. Apply inserts a row
|
|
5
|
+
* when its key is missing and does not update or delete. The statements are
|
|
6
|
+
* not migration steps, so OKM1542 does not see them.
|
|
7
|
+
*/
|
|
8
|
+
import type { Catalog } from "../../contracts/catalog/types.js";
|
|
9
|
+
import { type AnyTable } from "../../dialects/pg/table.js";
|
|
10
|
+
/** One value a reference row may store. */
|
|
11
|
+
export type ReferenceValue = string | number | boolean | null;
|
|
12
|
+
/** One table's reference declaration, in SQL names. */
|
|
13
|
+
export type ReferenceTable = {
|
|
14
|
+
readonly table: string;
|
|
15
|
+
readonly key: readonly string[];
|
|
16
|
+
readonly rows: readonly (readonly (readonly [string, ReferenceValue])[])[];
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Reads `reference` from the schema and checks it against the head catalog.
|
|
20
|
+
*
|
|
21
|
+
* A key must be a primary key, a unique constraint, or a unique index, in
|
|
22
|
+
* that column order. The catalog is not given a copy of the rows.
|
|
23
|
+
*
|
|
24
|
+
* @param tables - Tables the schema built
|
|
25
|
+
* @param casing - Schema casing. Absent means names are used as written
|
|
26
|
+
* @param head - Head snapshot the rows will be inserted into
|
|
27
|
+
* @returns One entry per table that declares rows
|
|
28
|
+
*/
|
|
29
|
+
export declare function readReference(tables: readonly AnyTable[], casing: "snake" | undefined, head: Catalog): readonly ReferenceTable[];
|
|
30
|
+
/**
|
|
31
|
+
* Insert-if-missing statements for one schema.
|
|
32
|
+
*
|
|
33
|
+
* Each row is its own `INSERT … ON CONFLICT DO NOTHING`. There is no
|
|
34
|
+
* `UPDATE` and no `DELETE`.
|
|
35
|
+
*
|
|
36
|
+
* @param tables - Declarations from {@link readReference}
|
|
37
|
+
* @param schema - Schema the statements write
|
|
38
|
+
* @returns SQL in declaration order
|
|
39
|
+
*/
|
|
40
|
+
export declare function referenceInserts(tables: readonly ReferenceTable[], schema: string): readonly string[];
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-target apply runner (D195).
|
|
3
|
+
*
|
|
4
|
+
* `okm migrate apply` calls {@link runTarget} with the units of one target.
|
|
5
|
+
* Bounded concurrency, several targets, canaries, and class flags are M5.
|
|
6
|
+
* A backfill step is one transaction per batch, with a checkpoint in
|
|
7
|
+
* `okm_backfill` after each commit.
|
|
8
|
+
*/
|
|
9
|
+
import type { DriverConnection } from "../../contracts/driver.js";
|
|
10
|
+
import type { PlanStep } from "./plan.js";
|
|
11
|
+
/** One step with its index in the migration file. */
|
|
12
|
+
export type RunnableStep = {
|
|
13
|
+
readonly index: number;
|
|
14
|
+
readonly step: PlanStep;
|
|
15
|
+
};
|
|
16
|
+
/** Steps that commit together, or one step that cannot. */
|
|
17
|
+
export type RunnableUnit = {
|
|
18
|
+
readonly migrationId: string;
|
|
19
|
+
readonly catalogHash: string;
|
|
20
|
+
/** True when this unit is the last step of its migration. */
|
|
21
|
+
readonly finishes: boolean;
|
|
22
|
+
readonly transactional: boolean;
|
|
23
|
+
readonly steps: readonly RunnableStep[];
|
|
24
|
+
};
|
|
25
|
+
/** What one committed backfill batch recorded. */
|
|
26
|
+
export type BackfillBatch = {
|
|
27
|
+
readonly migrationId: string;
|
|
28
|
+
readonly stepIndex: number;
|
|
29
|
+
readonly batch: number;
|
|
30
|
+
readonly rows: number;
|
|
31
|
+
readonly lastKey: string | null;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Protection and timeouts the runner reads on every batch.
|
|
35
|
+
*
|
|
36
|
+
* `protected` is read again at each batch, so a caller can change it between
|
|
37
|
+
* batches.
|
|
38
|
+
*/
|
|
39
|
+
export type RunPolicy = {
|
|
40
|
+
readonly target: string;
|
|
41
|
+
readonly protected: boolean;
|
|
42
|
+
readonly allowProtected?: boolean;
|
|
43
|
+
};
|
|
44
|
+
/** One target's units, retries, and checkpoints. */
|
|
45
|
+
export type TargetRun = {
|
|
46
|
+
readonly policy: RunPolicy;
|
|
47
|
+
readonly units: readonly RunnableUnit[];
|
|
48
|
+
readonly retries: number;
|
|
49
|
+
readonly lockTimeoutMs: number;
|
|
50
|
+
readonly statementTimeoutMs: number;
|
|
51
|
+
readonly backfillPauseMs?: number;
|
|
52
|
+
readonly backfillStatementTimeoutMs?: number;
|
|
53
|
+
readonly migrationRole?: string;
|
|
54
|
+
readonly schema?: string;
|
|
55
|
+
readonly onProgress?: (line: string) => void;
|
|
56
|
+
readonly afterBatch?: (batch: BackfillBatch) => void | Promise<void>;
|
|
57
|
+
};
|
|
58
|
+
/** What {@link runTarget} finished on this target. */
|
|
59
|
+
export type TargetRunReport = {
|
|
60
|
+
readonly target: string;
|
|
61
|
+
readonly applied: readonly string[];
|
|
62
|
+
readonly setRole?: string;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Runs one target's units in order.
|
|
66
|
+
*
|
|
67
|
+
* A finished step is skipped by the caller before it is placed in `units`.
|
|
68
|
+
* Lock timeout retries that step. A backfill retries the current batch only
|
|
69
|
+
* and resumes from `okm_backfill`.
|
|
70
|
+
*
|
|
71
|
+
* @param connection - Reserved connection. The caller holds the advisory lock
|
|
72
|
+
* @param run - Units, retries, and the protection flag
|
|
73
|
+
* @param session - Role assumed for the rest of the connection
|
|
74
|
+
* @returns The target and the migration ids that ran at least one unit
|
|
75
|
+
*/
|
|
76
|
+
export declare function runTarget(connection: DriverConnection, run: TargetRun, session: {
|
|
77
|
+
setRole?: string;
|
|
78
|
+
}): Promise<TargetRunReport>;
|
|
79
|
+
/**
|
|
80
|
+
* Assumes `role` for the rest of this connection.
|
|
81
|
+
*
|
|
82
|
+
* A second call with the same role does nothing.
|
|
83
|
+
*
|
|
84
|
+
* @param connection - Reserved connection
|
|
85
|
+
* @param role - Migration role
|
|
86
|
+
* @param session - Remembers the role already assumed
|
|
87
|
+
*/
|
|
88
|
+
export declare function assumeRole(connection: DriverConnection, role: string, session: {
|
|
89
|
+
setRole?: string;
|
|
90
|
+
}): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Lets a new migration role create objects in `schema`.
|
|
93
|
+
*
|
|
94
|
+
* @param connection - Reserved connection, before `SET ROLE`
|
|
95
|
+
* @param schema - Schema the migration writes
|
|
96
|
+
* @param role - Role that was just created
|
|
97
|
+
*/
|
|
98
|
+
export declare function grantSchema(connection: DriverConnection, schema: string, role: string): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Reports whether Postgres refuses to run `sql` inside a transaction.
|
|
101
|
+
*
|
|
102
|
+
* `VACUUM`, `ALTER TYPE … ADD VALUE`, and concurrent index create or drop
|
|
103
|
+
* each need their own unit.
|
|
104
|
+
*
|
|
105
|
+
* @param sql - One statement
|
|
106
|
+
* @returns `true` when the statement cannot share a transaction
|
|
107
|
+
*/
|
|
108
|
+
export declare function statementOutsideTransaction(sql: string): boolean;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe DDL for a table that already exists (D193).
|
|
3
|
+
*
|
|
4
|
+
* A new table keeps the plain statements from `ddl.ts`. These shapes are only
|
|
5
|
+
* for a table in the before-catalog: concurrent indexes, `NOT VALID` plus
|
|
6
|
+
* `VALIDATE`, `SET NOT NULL` through a validated check, a volatile default
|
|
7
|
+
* split from column creation, and a unique or primary key built from a
|
|
8
|
+
* concurrent unique index.
|
|
9
|
+
*
|
|
10
|
+
* The volatile-default fill is a backfill: one idempotent `UPDATE` per batch,
|
|
11
|
+
* limited to rows where the new column is still null (D195).
|
|
12
|
+
*/
|
|
13
|
+
import type { Catalog, CatalogObject, ColumnObject } from "../../contracts/catalog/types.js";
|
|
14
|
+
import { type BackfillSpec } from "./backfill.js";
|
|
15
|
+
import type { StepKind } from "./classify.js";
|
|
16
|
+
/** One statement the planner emits instead of the plain form. */
|
|
17
|
+
export type SafeStep = {
|
|
18
|
+
readonly sql: string;
|
|
19
|
+
readonly kind: StepKind;
|
|
20
|
+
readonly action: "ddl" | "backfill";
|
|
21
|
+
readonly lock: string;
|
|
22
|
+
readonly transactional: boolean;
|
|
23
|
+
/** Set on the volatile-default fill. The statement is one batch. */
|
|
24
|
+
readonly backfill?: BackfillSpec;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Safe steps for one object on a table that already exists.
|
|
28
|
+
*
|
|
29
|
+
* Returns `undefined` when the plain statement is already safe: a stable or
|
|
30
|
+
* constant column default, or an object this rewrite does not cover.
|
|
31
|
+
*
|
|
32
|
+
* @param object - Object the plan is creating
|
|
33
|
+
* @param schema - Concrete schema name
|
|
34
|
+
* @param catalogs - Before and after catalogs, for volatility and name clashes
|
|
35
|
+
* @param batchSize - Rows per batch written on a volatile-default fill
|
|
36
|
+
* @returns The replacement steps, or `undefined` to keep the plain statement
|
|
37
|
+
*/
|
|
38
|
+
export declare function stepsForExistingTable(object: CatalogObject, schema: string, catalogs: readonly Catalog[], batchSize: number): readonly SafeStep[] | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* `SET NOT NULL` through a validated check (Postgres 12+, always on the floor of 15).
|
|
41
|
+
*
|
|
42
|
+
* Postgres skips the table scan when a validated `CHECK (col IS NOT NULL)`
|
|
43
|
+
* already exists. The temporary check is dropped after `SET NOT NULL`.
|
|
44
|
+
*
|
|
45
|
+
* @param column - Column that must become `NOT NULL`
|
|
46
|
+
* @param schema - Concrete schema name
|
|
47
|
+
* @param setKind - `set-not-null` when the column already existed; `add-column` when this finishes a new column and the plan stays expand
|
|
48
|
+
* @param catalogs - Catalogs whose constraint names the temporary check must not reuse
|
|
49
|
+
* @returns Add `NOT VALID`, validate, set not null, drop the check
|
|
50
|
+
*/
|
|
51
|
+
export declare function notNullSteps(column: ColumnObject, schema: string, setKind: "set-not-null" | "add-column", catalogs: readonly Catalog[]): readonly SafeStep[];
|
|
52
|
+
/**
|
|
53
|
+
* Inserts `CONCURRENTLY` into a `CREATE INDEX` statement.
|
|
54
|
+
*
|
|
55
|
+
* @param sql - Plain `create index` or `create unique index` from `ddl.ts`
|
|
56
|
+
* @returns The same statement, concurrent
|
|
57
|
+
*/
|
|
58
|
+
export declare function concurrentIndexSql(sql: string): string;
|
|
59
|
+
/**
|
|
60
|
+
* Inserts `CONCURRENTLY` into a `DROP INDEX` statement.
|
|
61
|
+
*
|
|
62
|
+
* @param sql - Plain `drop index` from `ddl.ts`
|
|
63
|
+
* @returns The same statement, concurrent
|
|
64
|
+
*/
|
|
65
|
+
export declare function concurrentDropIndexSql(sql: string): string;
|
|
66
|
+
/**
|
|
67
|
+
* Reports whether a default expression is volatile.
|
|
68
|
+
*
|
|
69
|
+
* A constant has no call. `now()` and the other stable builtins stay plain.
|
|
70
|
+
* `gen_random_uuid()`, `uuidv7()`, and any other call the catalog marks
|
|
71
|
+
* volatile are split. A call the catalog does not know is left plain.
|
|
72
|
+
*
|
|
73
|
+
* @param expression - Column `defaultExpression`, when the column has one
|
|
74
|
+
* @param catalogs - Catalogs that may hold the called function
|
|
75
|
+
* @returns `true` when adding the column with this default would rewrite existing rows
|
|
76
|
+
*/
|
|
77
|
+
export declare function volatileDefault(expression: string | undefined, catalogs: readonly Catalog[]): boolean;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `okm seed <file>` (spec §20, D199).
|
|
3
|
+
*
|
|
4
|
+
* The file's default export receives the testing harness for the selected
|
|
5
|
+
* target. Protection is `assertTargetPolicy`, the same gate as every other
|
|
6
|
+
* command. The target is already migrated: this command does not apply DDL.
|
|
7
|
+
*/
|
|
8
|
+
import { type InvokeFlags } from "./policy.js";
|
|
9
|
+
/**
|
|
10
|
+
* Runs a seed file against the selected target.
|
|
11
|
+
*
|
|
12
|
+
* Policy and target selection run before the pool opens, so a protected
|
|
13
|
+
* target is refused without a connection.
|
|
14
|
+
*
|
|
15
|
+
* @param cwd - Project directory
|
|
16
|
+
* @param file - Seed module, relative to `cwd`
|
|
17
|
+
* @param flags - `--target`, `--allow-protected`, and `--allow-pooler`
|
|
18
|
+
* @returns Text for stdout
|
|
19
|
+
*/
|
|
20
|
+
export declare function seedProject(cwd: string, file: string, flags: InvokeFlags): Promise<string>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Head snapshot install and the comparison with a replayed history (D198).
|
|
3
|
+
*
|
|
4
|
+
* Provision plans the head catalog from an empty catalog and runs that SQL.
|
|
5
|
+
* It does not replay migration files. OKM1521 is the difference between that
|
|
6
|
+
* result and a full replay, after {@link canonicalTypeName} (D191).
|
|
7
|
+
*/
|
|
8
|
+
import type { Catalog } from "../../contracts/catalog/types.js";
|
|
9
|
+
import type { DriverConnection } from "../../contracts/driver.js";
|
|
10
|
+
import type { ReferenceTable } from "./reference.js";
|
|
11
|
+
/** History id prefix for a target installed from the head snapshot. */
|
|
12
|
+
export declare const PROVISION_PREFIX = "provisioned@";
|
|
13
|
+
/**
|
|
14
|
+
* History id written when a target is provisioned at `migrationId`.
|
|
15
|
+
*
|
|
16
|
+
* @param migrationId - Head migration id
|
|
17
|
+
* @returns `provisioned@` plus that id
|
|
18
|
+
*/
|
|
19
|
+
export declare function provisionMark(migrationId: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Migration id stored inside a provision mark.
|
|
22
|
+
*
|
|
23
|
+
* @param migrationId - A history migration id
|
|
24
|
+
* @returns The id after the prefix, or `undefined` when it is not a mark
|
|
25
|
+
*/
|
|
26
|
+
export declare function provisionedMigrationId(migrationId: string): string | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Marks every step up through a provisioned migration as done.
|
|
29
|
+
*
|
|
30
|
+
* A later file stays pending. A mark whose id is not in `migrations` is left
|
|
31
|
+
* for the caller to treat as history this project does not contain.
|
|
32
|
+
*
|
|
33
|
+
* @param migrations - Files in apply order
|
|
34
|
+
* @param done - Keys `${id}:${step}` already in history
|
|
35
|
+
* @param historyIds - `migration_id` values in history
|
|
36
|
+
* @returns A set the applier can skip
|
|
37
|
+
*/
|
|
38
|
+
export declare function expandProvisioned(migrations: readonly {
|
|
39
|
+
readonly id: string;
|
|
40
|
+
readonly steps: readonly unknown[];
|
|
41
|
+
}[], done: ReadonlySet<string>, historyIds: readonly string[]): Set<string>;
|
|
42
|
+
/**
|
|
43
|
+
* Reports whether a history id belongs to this project's files.
|
|
44
|
+
*
|
|
45
|
+
* A `provisioned@` mark belongs when the id after the prefix is a file.
|
|
46
|
+
*
|
|
47
|
+
* @param migrationId - History migration id
|
|
48
|
+
* @param known - File ids
|
|
49
|
+
* @returns `true` when status should not call the row ahead
|
|
50
|
+
*/
|
|
51
|
+
export declare function provisionHistoryIsKnown(migrationId: string, known: ReadonlySet<string>): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Installs `head` into an empty schema and inserts reference rows.
|
|
54
|
+
*
|
|
55
|
+
* The plan is from an empty catalog, so no expand, backfill, or contract
|
|
56
|
+
* file is replayed. An existing role is left in place. The caller records
|
|
57
|
+
* history.
|
|
58
|
+
*
|
|
59
|
+
* @param connection - Reserved connection, after the advisory lock
|
|
60
|
+
* @param head - Head snapshot
|
|
61
|
+
* @param schema - Schema that receives the objects
|
|
62
|
+
* @param reference - Rows to insert if missing
|
|
63
|
+
* @param migrationRole - Role assumed after this run creates it
|
|
64
|
+
*/
|
|
65
|
+
export declare function installSnapshot(connection: DriverConnection, head: Catalog, schema: string, reference: readonly ReferenceTable[], session: {
|
|
66
|
+
setRole?: string;
|
|
67
|
+
}, migrationRole?: string): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Names the first object that differs between two introspected catalogs.
|
|
70
|
+
*
|
|
71
|
+
* Type names are compared with {@link canonicalTypeName}. Managed history
|
|
72
|
+
* tables are omitted. `undefined` means the catalogs match.
|
|
73
|
+
*
|
|
74
|
+
* @param left - One introspection
|
|
75
|
+
* @param right - The other introspection
|
|
76
|
+
* @returns The object, and the statement that would change it, when they differ
|
|
77
|
+
*/
|
|
78
|
+
export declare function snapshotDifference(left: Catalog, right: Catalog): string | undefined;
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
* `okm migrate status`.
|
|
3
3
|
*
|
|
4
4
|
* One row per target: version, catalog hash, state, and a separate protected
|
|
5
|
-
* column. The state is current, behind by expand, behind by contract, ahead
|
|
6
|
-
* or failed at a step.
|
|
5
|
+
* column. The state is current, behind by expand, behind by contract, ahead
|
|
6
|
+
* by expand, ahead by contract, or failed at a step with a resume hint. An
|
|
7
|
+
* unfinished backfill is a later section: migration, step, rows so far, last
|
|
8
|
+
* key, and state.
|
|
7
9
|
*/
|
|
8
10
|
import type { MigrationClass } from "./plan.js";
|
|
9
11
|
import type { StoredMigration } from "./files.js";
|
|
@@ -15,6 +17,18 @@ export type TargetStatus = {
|
|
|
15
17
|
readonly catalogHash: string;
|
|
16
18
|
readonly state: string;
|
|
17
19
|
readonly protected: boolean;
|
|
20
|
+
/** Unfinished `okm_backfill` rows for this target. A finished step is absent. */
|
|
21
|
+
readonly backfills: readonly BackfillProgress[];
|
|
22
|
+
};
|
|
23
|
+
/** One backfill that has committed at least one batch and is not done. */
|
|
24
|
+
export type BackfillProgress = {
|
|
25
|
+
readonly migrationId: string;
|
|
26
|
+
readonly stepIndex: number;
|
|
27
|
+
/** Rows the committed batches changed. */
|
|
28
|
+
readonly rows: string;
|
|
29
|
+
/** Last committed boundary, or `-` when the first batch is still open. */
|
|
30
|
+
readonly lastKey: string;
|
|
31
|
+
readonly state: string;
|
|
18
32
|
};
|
|
19
33
|
/** A checkpoint row the state function reads. */
|
|
20
34
|
export type StatusHistory = {
|
|
@@ -25,9 +39,11 @@ export type StatusHistory = {
|
|
|
25
39
|
/**
|
|
26
40
|
* Decides the status state from files and history.
|
|
27
41
|
*
|
|
28
|
-
* A partial migration is `failed at step
|
|
29
|
-
*
|
|
30
|
-
*
|
|
42
|
+
* A partial migration is `failed at step` plus the resume hint. History the
|
|
43
|
+
* files do not contain is ahead by expand, or ahead by contract when a stored
|
|
44
|
+
* class is not expand. Pending files are behind by expand, or by contract
|
|
45
|
+
* when any pending step is not expand. The class is the one stored on the
|
|
46
|
+
* file or in `okm_history`.
|
|
31
47
|
*
|
|
32
48
|
* @param migrations - Files in apply order
|
|
33
49
|
* @param history - Checkpoint rows
|
|
@@ -68,7 +84,10 @@ export declare function statusProject(cwd: string, flags: InvokeFlags): Promise<
|
|
|
68
84
|
/**
|
|
69
85
|
* Prints status rows.
|
|
70
86
|
*
|
|
87
|
+
* The target columns stay `target`, `version`, `catalog`, `state`, and
|
|
88
|
+
* `protected`. Unfinished backfills follow as their own section.
|
|
89
|
+
*
|
|
71
90
|
* @param rows - One per target
|
|
72
|
-
* @returns Header plus one line per target
|
|
91
|
+
* @returns Header plus one line per target, then unfinished backfills
|
|
73
92
|
*/
|
|
74
93
|
export declare function formatStatus(rows: readonly TargetStatus[]): string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One spelling for a SQL type name in a diff (D191).
|
|
3
|
+
*
|
|
4
|
+
* The catalog keeps the spelling the schema wrote. Introspection keeps
|
|
5
|
+
* `format_type`. Both sides of a comparison pass through here, so
|
|
6
|
+
* `timestamptz` and `timestamp with time zone` are one type. A different
|
|
7
|
+
* length, precision, or type stays different. An unknown name is returned
|
|
8
|
+
* as written.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Maps a schema spelling or a `format_type` spelling to the long form.
|
|
12
|
+
*
|
|
13
|
+
* Modifiers and array ranks stay. `varchar(20)[]` becomes
|
|
14
|
+
* `character varying(20)[]`.
|
|
15
|
+
*
|
|
16
|
+
* @param typeName - Type name from a catalog definition
|
|
17
|
+
* @returns The Postgres long spelling
|
|
18
|
+
*/
|
|
19
|
+
export declare function canonicalTypeName(typeName: string): string;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factories: `create`, `createMany`, `with({ child: n })`, and `x.ref`.
|
|
3
|
+
*
|
|
4
|
+
* A required column the definition leaves out is filled from its type (D199).
|
|
5
|
+
* `x.ref` reuses the latest row of that table in the same tenant, or creates one.
|
|
6
|
+
*/
|
|
7
|
+
import type { Connected } from "../../runtime/types.js";
|
|
8
|
+
import { type TableFacts, type TestingSchema } from "./facts.js";
|
|
9
|
+
import type { Rng } from "./random.js";
|
|
10
|
+
declare const REF: unique symbol;
|
|
11
|
+
/** A `x.ref("table")` marker. Resolved when the row is inserted. */
|
|
12
|
+
type FactoryRef = {
|
|
13
|
+
readonly [REF]: string;
|
|
14
|
+
};
|
|
15
|
+
/** Values a factory definition may return. */
|
|
16
|
+
export type FactoryContext = {
|
|
17
|
+
/** `userN@example.com`. N increases for each call. */
|
|
18
|
+
email(): string;
|
|
19
|
+
/** A first and last name from a fixed list. */
|
|
20
|
+
name(): string;
|
|
21
|
+
/** `count` words from a fixed list. */
|
|
22
|
+
words(count: number): string;
|
|
23
|
+
/** An integer in `[0, bound)`. `bound` defaults to 10_000. */
|
|
24
|
+
int(bound?: number): number;
|
|
25
|
+
/** A number in `[0, 1)`. */
|
|
26
|
+
float(): number;
|
|
27
|
+
/** A boolean. */
|
|
28
|
+
boolean(): boolean;
|
|
29
|
+
/** An ISO date `YYYY-MM-DD` in January 2020. */
|
|
30
|
+
date(): string;
|
|
31
|
+
/** A UUID from the seed. */
|
|
32
|
+
uuid(): string;
|
|
33
|
+
/** One entry of `list`. */
|
|
34
|
+
pick<T>(list: readonly T[]): T;
|
|
35
|
+
/**
|
|
36
|
+
* The primary key of `table`.
|
|
37
|
+
*
|
|
38
|
+
* The first call creates the row. A later call in the same tenant reuses it.
|
|
39
|
+
* A `create` of that table replaces the reused row.
|
|
40
|
+
*/
|
|
41
|
+
ref(table: string): FactoryRef;
|
|
42
|
+
};
|
|
43
|
+
/** One table's factory. */
|
|
44
|
+
export type TableFactory = {
|
|
45
|
+
/**
|
|
46
|
+
* Inserts one row.
|
|
47
|
+
*
|
|
48
|
+
* @param overrides - Column values. A tenant key here is the scope, not a column.
|
|
49
|
+
* @returns The inserted row
|
|
50
|
+
*/
|
|
51
|
+
create(overrides?: Readonly<Record<string, unknown>>): Promise<Record<string, unknown>>;
|
|
52
|
+
/**
|
|
53
|
+
* Inserts `count` rows. Each row draws new generated values.
|
|
54
|
+
*
|
|
55
|
+
* @param count - How many rows
|
|
56
|
+
* @param overrides - Column values applied to every row
|
|
57
|
+
* @returns The inserted rows
|
|
58
|
+
*/
|
|
59
|
+
createMany(count: number, overrides?: Readonly<Record<string, unknown>>): Promise<readonly Record<string, unknown>[]>;
|
|
60
|
+
/**
|
|
61
|
+
* Creates `count` rows of `child` after the parent, linked by the foreign key.
|
|
62
|
+
*
|
|
63
|
+
* @param children - Child table name to how many rows
|
|
64
|
+
* @returns A factory that still inserts this table
|
|
65
|
+
*/
|
|
66
|
+
with(children: Readonly<Record<string, number>>): TableFactory;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Remembers `host` for the harness object `okm seed` prints from.
|
|
70
|
+
*
|
|
71
|
+
* @param harness - The object returned by `testing()`
|
|
72
|
+
* @param host - Its factory state
|
|
73
|
+
*/
|
|
74
|
+
export declare function attachHost(harness: object, host: FactoryHost): void;
|
|
75
|
+
/**
|
|
76
|
+
* Rows inserted through factories, summed by table name.
|
|
77
|
+
*
|
|
78
|
+
* @param harness - The object returned by `testing()`
|
|
79
|
+
* @returns Counts in table-name order
|
|
80
|
+
*/
|
|
81
|
+
export declare function createdOf(harness: object): readonly {
|
|
82
|
+
readonly table: string;
|
|
83
|
+
readonly count: number;
|
|
84
|
+
}[];
|
|
85
|
+
/** Shared state for one harness. */
|
|
86
|
+
export type FactoryHost = {
|
|
87
|
+
readonly schema: TestingSchema;
|
|
88
|
+
readonly db: Connected<TestingSchema>;
|
|
89
|
+
readonly facts: ReadonlyMap<string, TableFacts>;
|
|
90
|
+
readonly rng: Rng;
|
|
91
|
+
/** Latest row of a table in one tenant. Isolation uses its own map. */
|
|
92
|
+
cache: Map<string, Record<string, unknown>>;
|
|
93
|
+
/** Tables currently being inserted. A repeat is a factory cycle. */
|
|
94
|
+
readonly creating: Set<string>;
|
|
95
|
+
readonly created: Map<string, number>;
|
|
96
|
+
readonly definitions: Map<string, (context: FactoryContext) => Readonly<Record<string, unknown>>>;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Builds the factory object for `definitions`.
|
|
100
|
+
*
|
|
101
|
+
* @param host - Schema, client, and seed
|
|
102
|
+
* @param definitions - One function per table
|
|
103
|
+
* @returns A factory per definition
|
|
104
|
+
*/
|
|
105
|
+
export declare function bindFactories(host: FactoryHost, definitions: Readonly<Record<string, (context: FactoryContext) => Readonly<Record<string, unknown>>>>): Record<string, TableFactory>;
|
|
106
|
+
/**
|
|
107
|
+
* Inserts one row, filling required columns. Used by factories and by isolation.
|
|
108
|
+
*
|
|
109
|
+
* @param host - Schema, client, and seed
|
|
110
|
+
* @param table - Table name
|
|
111
|
+
* @param overrides - Column values and the tenant key
|
|
112
|
+
* @param children - Child counts from `with`
|
|
113
|
+
* @param inherited - Tenant from the parent row, when this row is a child
|
|
114
|
+
* @returns The inserted row
|
|
115
|
+
*/
|
|
116
|
+
export declare function insertRow(host: FactoryHost, table: string, overrides: Readonly<Record<string, unknown>> | undefined, children: Readonly<Record<string, number>> | undefined, inherited: string | undefined): Promise<Record<string, unknown>>;
|
|
117
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a factory needs from a compiled schema: required columns, foreign keys,
|
|
3
|
+
* and which tables are tenant or global.
|
|
4
|
+
*
|
|
5
|
+
* Column tenancy is the only strategy in this version. A table is tenant when
|
|
6
|
+
* its predicate binds a scope, and global when `global("reason")` opted it out.
|
|
7
|
+
* `schemaPerTenant` and `databasePerTenant` are not in 0.4.
|
|
8
|
+
*/
|
|
9
|
+
import type { Catalog } from "../../contracts/catalog/types.js";
|
|
10
|
+
import type { QuerySchema, RelationModel } from "../../dialects/pg/model.js";
|
|
11
|
+
/** A schema `testing()` can open. `schema()` returns this shape. */
|
|
12
|
+
export type TestingSchema = QuerySchema & {
|
|
13
|
+
readonly catalog: Catalog;
|
|
14
|
+
};
|
|
15
|
+
/** One foreign key, SQL names, child columns aligned with the target columns. */
|
|
16
|
+
export type ForeignKey = {
|
|
17
|
+
readonly columns: readonly string[];
|
|
18
|
+
readonly target: string;
|
|
19
|
+
readonly targetColumns: readonly string[];
|
|
20
|
+
};
|
|
21
|
+
/** One column, with the catalog facts the factory uses to fill a default. */
|
|
22
|
+
export type ColumnFacts = {
|
|
23
|
+
readonly field: string;
|
|
24
|
+
readonly sql: string;
|
|
25
|
+
readonly dataType: string;
|
|
26
|
+
readonly nullable: boolean;
|
|
27
|
+
readonly databaseDefault: boolean;
|
|
28
|
+
readonly identity: boolean;
|
|
29
|
+
readonly generated: boolean;
|
|
30
|
+
readonly guarded: boolean;
|
|
31
|
+
readonly writable: boolean;
|
|
32
|
+
readonly fill: boolean;
|
|
33
|
+
readonly accepts: readonly string[] | undefined;
|
|
34
|
+
readonly encode: (value: unknown) => string;
|
|
35
|
+
};
|
|
36
|
+
/** One table. */
|
|
37
|
+
export type TableFacts = {
|
|
38
|
+
readonly name: string;
|
|
39
|
+
readonly sql: string;
|
|
40
|
+
readonly primary: readonly string[];
|
|
41
|
+
readonly columns: readonly ColumnFacts[];
|
|
42
|
+
readonly relations: readonly RelationModel[];
|
|
43
|
+
readonly foreignKeys: readonly ForeignKey[];
|
|
44
|
+
/** Column tenancy applies a predicate. */
|
|
45
|
+
readonly tenant: boolean;
|
|
46
|
+
/** `global("reason")`. Absent on a tenant table and on a schema with no tenancy. */
|
|
47
|
+
readonly globalReason: string | undefined;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Scope value used to ask a tenancy object whether a table is tenant.
|
|
51
|
+
*
|
|
52
|
+
* A test tenancy can recognise this probe and still omit the predicate on a
|
|
53
|
+
* real query. That is how the isolation check is shown to fail.
|
|
54
|
+
*/
|
|
55
|
+
export declare const tenantProbe = "00000000-0000-4000-8000-000000000001";
|
|
56
|
+
/**
|
|
57
|
+
* Reads every table in declaration order.
|
|
58
|
+
*
|
|
59
|
+
* @param schema - Compiled schema
|
|
60
|
+
* @returns One facts object per table
|
|
61
|
+
*/
|
|
62
|
+
export declare function readFacts(schema: TestingSchema): readonly TableFacts[];
|
|
63
|
+
/**
|
|
64
|
+
* A column the factory must set when the definition and the overrides omit it.
|
|
65
|
+
*
|
|
66
|
+
* Nullable, a database default, identity, a generated expression, a client
|
|
67
|
+
* fill, and a guarded column are left to the database or the scope (D199).
|
|
68
|
+
*
|
|
69
|
+
* @param column - Column facts
|
|
70
|
+
* @returns Whether the factory fills it
|
|
71
|
+
*/
|
|
72
|
+
export declare function isRequired(column: ColumnFacts): boolean;
|