okmodel 0.2.1 → 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.
Files changed (108) hide show
  1. package/README.md +710 -36
  2. package/dist/contracts/catalog/enum.d.ts +31 -4
  3. package/dist/contracts/catalog/extension.d.ts +61 -0
  4. package/dist/contracts/catalog/privilege.d.ts +64 -0
  5. package/dist/contracts/catalog/routine.d.ts +56 -0
  6. package/dist/contracts/catalog/types.d.ts +164 -10
  7. package/dist/contracts/catalog/view.d.ts +73 -0
  8. package/dist/dialects/pg/column.d.ts +3 -1
  9. package/dist/dialects/pg/ddl.d.ts +65 -1
  10. package/dist/dialects/pg/enum.d.ts +10 -8
  11. package/dist/dialects/pg/ext/citext.d.ts +14 -0
  12. package/dist/dialects/pg/ext/citext.js +11 -0
  13. package/dist/dialects/pg/ext/index.d.ts +52 -0
  14. package/dist/dialects/pg/ext/index.js +6 -0
  15. package/dist/dialects/pg/ext/pg-trgm.d.ts +53 -0
  16. package/dist/dialects/pg/ext/pg-trgm.js +42 -0
  17. package/dist/dialects/pg/fn/index.d.ts +107 -0
  18. package/dist/dialects/pg/fn/index.js +175 -0
  19. package/dist/dialects/pg/fn/touch.d.ts +14 -0
  20. package/dist/dialects/pg/index.js +104 -19
  21. package/dist/dialects/pg/introspect.d.ts +10 -1
  22. package/dist/dialects/pg/operators.d.ts +8 -1
  23. package/dist/dialects/pg/role/check.d.ts +45 -0
  24. package/dist/dialects/pg/role/index.d.ts +50 -0
  25. package/dist/dialects/pg/role/sql.d.ts +44 -0
  26. package/dist/dialects/pg/table.d.ts +7 -0
  27. package/dist/dialects/pg/tenancy.d.ts +9 -0
  28. package/dist/dialects/pg/view/client.d.ts +30 -0
  29. package/dist/dialects/pg/view/depend.d.ts +35 -0
  30. package/dist/dialects/pg/view/index.d.ts +114 -0
  31. package/dist/dialects/pg/view/index.js +289 -0
  32. package/dist/dialects/pg/view/scratch.d.ts +21 -0
  33. package/dist/dialects/pg/where.d.ts +2 -2
  34. package/dist/runtime/pg/bun.js +3 -3
  35. package/dist/runtime/pg/pg.js +3 -3
  36. package/dist/runtime/pg/pglite.js +3 -3
  37. package/dist/runtime/pg/postgresjs.js +3 -3
  38. package/dist/runtime/tenancy/index.js +6 -3
  39. package/dist/runtime/traits/index.d.ts +7 -2
  40. package/dist/runtime/traits/index.js +149 -12
  41. package/dist/runtime/validate/index.js +4 -4
  42. package/dist/shared/{ytg3xf9p.js → 01yr20s5.js} +3 -3
  43. package/dist/shared/{cstgkzdx.js → 0jc3ffzf.js} +1 -1
  44. package/dist/shared/{xkz8g6by.js → 1g0drakv.js} +2 -2
  45. package/dist/shared/{eaxwrgby.js → 1tfdfvhh.js} +4 -3
  46. package/dist/shared/2ssqrv66.js +1576 -0
  47. package/dist/shared/{10tjenmd.js → 3ekj9x92.js} +1 -1
  48. package/dist/shared/49ypnfwt.js +1122 -0
  49. package/dist/shared/{sacqha1y.js → 4m9fn52z.js} +2 -2
  50. package/dist/shared/5nmdenb6.js +1229 -0
  51. package/dist/shared/{qa5dsc7z.js → 6bazvqwm.js} +3 -3
  52. package/dist/shared/{x9v1qgeb.js → 6w5j844a.js} +1 -1
  53. package/dist/shared/{0qkxbm1f.js → 75xkjv0t.js} +1 -1
  54. package/dist/shared/7fvtrkwr.js +84 -0
  55. package/dist/shared/94ez8kzh.js +19 -0
  56. package/dist/shared/{1dp5knt7.js → 999ade2q.js} +2 -2
  57. package/dist/shared/{3a5ne750.js → 9m80mkac.js} +2 -2
  58. package/dist/shared/9x25fxhc.js +150 -0
  59. package/dist/shared/{4b9da9d7.js → axhk06q1.js} +19 -1
  60. package/dist/shared/{38crxbgn.js → bqha5cg6.js} +3 -3
  61. package/dist/shared/{zd93g3rq.js → bryqk9k9.js} +1 -1
  62. package/dist/shared/{n47rd821.js → c8aghh05.js} +1 -1
  63. package/dist/shared/{dd4f8mnx.js → c9z5g0fm.js} +4 -2
  64. package/dist/shared/{eqmtn1bj.js → dbjej1tw.js} +71 -14
  65. package/dist/shared/{ps43134h.js → dyj86cmj.js} +4 -4
  66. package/dist/shared/{sfh4pk75.js → fptpmvxp.js} +3 -3
  67. package/dist/shared/{97g2jnrw.js → fs0ex00p.js} +3 -3
  68. package/dist/shared/{rtnaqre0.js → g4f5kcx9.js} +2 -2
  69. package/dist/shared/{yw5c610b.js → gjthds9j.js} +2 -2
  70. package/dist/shared/hcmdtwgh.js +102 -0
  71. package/dist/shared/{qxa0yb9j.js → jkc6ws1p.js} +2 -54
  72. package/dist/shared/{mxmcdsh5.js → k34e0xf2.js} +9 -9
  73. package/dist/shared/{py3nh7jy.js → kgnc8grt.js} +2 -2
  74. package/dist/shared/{g9f0zqce.js → m78s7898.js} +1 -1
  75. package/dist/shared/meck53jv.js +99 -0
  76. package/dist/shared/{v18jva5b.js → mt5wswjz.js} +1 -1
  77. package/dist/shared/{g1b5zzj9.js → n0dgs0pb.js} +1 -1
  78. package/dist/shared/{zt8y0wzb.js → n7mcc1gk.js} +1 -1
  79. package/dist/shared/ne02ng5c.js +68 -0
  80. package/dist/shared/{e7a268fy.js → p24x2334.js} +1 -1
  81. package/dist/shared/qbxzvwwc.js +88 -0
  82. package/dist/shared/{a1gdp7j9.js → qybh48nd.js} +1 -1
  83. package/dist/shared/{d04j53v8.js → scwxrpx2.js} +5 -4
  84. package/dist/shared/{d2whjz4k.js → t616ynfn.js} +530 -24
  85. package/dist/shared/th14ygv2.js +69 -0
  86. package/dist/shared/{xatfg0gn.js → tmbdywx0.js} +4 -19
  87. package/dist/shared/{ge03bfca.js → ty3v3hfk.js} +2 -2
  88. package/dist/shared/wekze34d.js +246 -0
  89. package/dist/shared/{7mht49yd.js → x6wysh83.js} +59 -18
  90. package/dist/shared/{4jzzghr6.js → xva8v7qk.js} +8 -8
  91. package/dist/shared/{ecdzej21.js → xw1d69vd.js} +7 -7
  92. package/dist/shared/y005b761.js +112 -0
  93. package/dist/shared/{mrq77sgw.js → ydaz1sv3.js} +1 -1
  94. package/dist/tooling/cli.js +32 -8
  95. package/dist/tooling/migrate/apply.d.ts +16 -0
  96. package/dist/tooling/migrate/commands.d.ts +2 -1
  97. package/dist/tooling/migrate/config.d.ts +8 -0
  98. package/dist/tooling/migrate/doctor.d.ts +25 -0
  99. package/dist/tooling/migrate/drift.d.ts +19 -0
  100. package/dist/tooling/migrate/ext.d.ts +17 -0
  101. package/dist/tooling/migrate/extensions.d.ts +51 -0
  102. package/dist/tooling/migrate/managed.d.ts +17 -0
  103. package/dist/tooling/migrate/plan.d.ts +14 -1
  104. package/dist/tooling/migrate/project.d.ts +25 -1
  105. package/dist/tooling/migrate/type-name.d.ts +19 -0
  106. package/package.json +22 -2
  107. package/dist/shared/5z4q2zda.js +0 -2073
  108. /package/dist/shared/{9k6vetvf.js → rrstp3kb.js} +0 -0
@@ -0,0 +1,112 @@
1
+ import {
2
+ staticNamespace2,
3
+ assertNamespace2,
4
+ normaliseEdges,
5
+ assertProvenance
6
+ } from "./t4tbsy9h.js";
7
+ import {
8
+ assertIdentifier2,
9
+ fitIdentifier2,
10
+ deterministicName2
11
+ } from "./nfzc5z0w.js";
12
+ import {
13
+ catalogError2
14
+ } from "./52szzakm.js";
15
+
16
+ // src/contracts/catalog/view.ts
17
+ function normaliseViewQuery(query) {
18
+ return query.trim().replace(/;\s*$/, "");
19
+ }
20
+ function viewObject(input) {
21
+ const namespace = input.namespace ?? staticNamespace2("public");
22
+ const columns = readColumns(input.name, input.columns);
23
+ const query = readQuery(input.name, input.query);
24
+ assertNamespace2(namespace);
25
+ assertProvenance(input.provenance);
26
+ const definition = { columns, query };
27
+ return {
28
+ kind: "view",
29
+ identity: { kind: "view", namespace, name: input.name },
30
+ owner: input.owner ?? "managed",
31
+ definition,
32
+ dependencies: normaliseEdges(input.dependencies ?? []),
33
+ provenance: input.provenance
34
+ };
35
+ }
36
+ function materializedViewObject(input) {
37
+ const namespace = input.namespace ?? staticNamespace2("public");
38
+ const columns = readColumns(input.name, input.columns);
39
+ const query = readQuery(input.name, input.query);
40
+ assertNamespace2(namespace);
41
+ assertProvenance(input.provenance);
42
+ const definition = {
43
+ columns,
44
+ query,
45
+ ...input.refresh === "concurrently" ? { refresh: "concurrently" } : {}
46
+ };
47
+ return {
48
+ kind: "materializedView",
49
+ identity: { kind: "materializedView", namespace, name: input.name },
50
+ owner: input.owner ?? "managed",
51
+ definition,
52
+ dependencies: normaliseEdges(input.dependencies ?? []),
53
+ provenance: input.provenance
54
+ };
55
+ }
56
+ function materializedViewIndex(input) {
57
+ assertNamespace2(input.parent.namespace);
58
+ assertIdentifier2(input.parent.name, "index parent");
59
+ assertProvenance(input.provenance);
60
+ const columns = [...input.columns];
61
+ for (const name of columns)
62
+ assertIdentifier2(name, "index column");
63
+ if (columns.length === 0 && input.expression === undefined) {
64
+ catalogError2("OKM1020", `Index on ${input.parent.name} needs a column or an expression.`);
65
+ }
66
+ const nameKey = input.nameKey ?? (columns.length > 0 ? columns.join("_") : "expr");
67
+ const name = input.name === undefined ? deterministicName2({ parent: input.parent.name, purpose: "index", nameKey }) : fitIdentifier2(input.name);
68
+ const parentView = {
69
+ kind: "materializedView",
70
+ namespace: input.parent.namespace,
71
+ name: input.parent.name
72
+ };
73
+ return {
74
+ kind: "index",
75
+ identity: { kind: "index", parent: input.parent, name },
76
+ owner: input.owner ?? "managed",
77
+ definition: {
78
+ columns,
79
+ unique: input.unique === true,
80
+ nameKey,
81
+ ...input.expression !== undefined ? { expression: input.expression } : {},
82
+ ...input.predicate !== undefined ? { predicate: input.predicate } : {}
83
+ },
84
+ dependencies: normaliseEdges(input.dependencies ?? [parentView]),
85
+ provenance: input.provenance
86
+ };
87
+ }
88
+ function readColumns(view, columns) {
89
+ assertIdentifier2(view, "view");
90
+ if (columns.length === 0)
91
+ catalogError2("OKM1020", `View ${view} needs a column.`);
92
+ const seen = new Set;
93
+ return columns.map((column) => {
94
+ assertIdentifier2(column.name, `view ${view} column`);
95
+ if (seen.has(column.name)) {
96
+ catalogError2("OKM1020", `View ${view} lists column ${column.name} twice.`);
97
+ }
98
+ seen.add(column.name);
99
+ if (column.dataType.length === 0 || /[;'"\\]/.test(column.dataType)) {
100
+ catalogError2("OKM1020", `View ${view} column ${column.name} type is not a type name.`);
101
+ }
102
+ return { name: column.name, dataType: column.dataType };
103
+ });
104
+ }
105
+ function readQuery(view, query) {
106
+ const text = normaliseViewQuery(query);
107
+ if (text.length === 0)
108
+ catalogError2("OKM1020", `View ${view} needs a query.`);
109
+ return text;
110
+ }
111
+
112
+ export { normaliseViewQuery, viewObject, materializedViewObject, materializedViewIndex };
@@ -3,7 +3,7 @@ import {
3
3
  readHandle,
4
4
  readCall,
5
5
  attachHttp
6
- } from "./mxmcdsh5.js";
6
+ } from "./k34e0xf2.js";
7
7
  import {
8
8
  fail
9
9
  } from "./xrfnq5k8.js";
@@ -1,12 +1,14 @@
1
- import"../shared/d2whjz4k.js";
1
+ import"../shared/t616ynfn.js";
2
2
  import"../shared/n442h54c.js";
3
3
  import {
4
- formatPlan,
5
4
  buildProject,
6
5
  generateProject,
7
6
  planProject,
8
7
  checkProject
9
- } from "../shared/5z4q2zda.js";
8
+ } from "../shared/5nmdenb6.js";
9
+ import {
10
+ formatPlan
11
+ } from "../shared/2ssqrv66.js";
10
12
  import {
11
13
  OkmError2
12
14
  } from "../shared/52szzakm.js";
@@ -33,7 +35,7 @@ async function run(argv, io) {
33
35
  return;
34
36
  }
35
37
  if (command === "check") {
36
- await checkProject(cwd);
38
+ await checkProject(cwd, invoke(splitFlags(rest)));
37
39
  stdout(`ok
38
40
  `);
39
41
  return;
@@ -47,12 +49,12 @@ async function run(argv, io) {
47
49
  return;
48
50
  }
49
51
  if (command === "dev") {
50
- const { devProject } = await import("../shared/eaxwrgby.js");
52
+ const { devProject } = await import("../shared/1tfdfvhh.js");
51
53
  stdout(await devProject(cwd));
52
54
  return;
53
55
  }
54
56
  if (command === "push") {
55
- const { pushProject } = await import("../shared/eqmtn1bj.js");
57
+ const { pushProject } = await import("../shared/dbjej1tw.js");
56
58
  stdout(await pushProject(cwd, invoke(splitFlags(rest))));
57
59
  return;
58
60
  }
@@ -67,16 +69,38 @@ async function run(argv, io) {
67
69
  return;
68
70
  }
69
71
  if (sub === "apply") {
70
- const { applyProject } = await import("../shared/eqmtn1bj.js");
72
+ const { applyProject } = await import("../shared/dbjej1tw.js");
71
73
  stdout(await applyProject(cwd, invoke(parsed)));
72
74
  return;
73
75
  }
74
76
  if (sub === "status") {
75
- const { statusProject } = await import("../shared/d04j53v8.js");
77
+ const { statusProject } = await import("../shared/scwxrpx2.js");
76
78
  stdout(await statusProject(cwd, invoke(parsed)));
77
79
  return;
78
80
  }
79
81
  }
82
+ if (command === "doctor") {
83
+ const parsed = splitFlags(rest);
84
+ const { doctorProject } = await import("../shared/ne02ng5c.js");
85
+ stdout(await doctorProject(cwd, parsed.name, invoke(parsed)));
86
+ return;
87
+ }
88
+ if (command === "ext") {
89
+ const sub = rest[0];
90
+ if (sub === "test" || sub === "scaffold") {
91
+ throw new OkmError2("invalid", `okm ext ${sub} is not available yet.`, {
92
+ fix: { summary: "okm ext list and okm ext check are the commands in this version." }
93
+ });
94
+ }
95
+ if (sub === "list" || sub === "check") {
96
+ const { extProject } = await import("../shared/meck53jv.js");
97
+ stdout(await extProject(cwd, sub, invoke(splitFlags(rest.slice(1)))));
98
+ return;
99
+ }
100
+ throw new OkmError2("invalid", `Unknown command ext ${sub ?? ""}.`, {
101
+ fix: { summary: "Use okm ext list or okm ext check." }
102
+ });
103
+ }
80
104
  throw new OkmError2("invalid", `Unknown command ${command ?? ""}.`);
81
105
  }
82
106
  function invoke(parsed) {
@@ -37,11 +37,27 @@ export type ApplyRequest = {
37
37
  readonly migrations: readonly StoredMigration[];
38
38
  /** Runs after the advisory lock is held and before the first step. */
39
39
  readonly onLocked?: () => void;
40
+ /**
41
+ * Role that runs the migration.
42
+ *
43
+ * When it already exists and is not `current_user`, the runner issues one
44
+ * `SET ROLE` before any statement. That statement is not a plan step.
45
+ */
46
+ readonly migrationRole?: string;
47
+ /**
48
+ * Schema the migration role may create in.
49
+ *
50
+ * When this run creates that role, the runner grants `USAGE` and `CREATE`
51
+ * on this schema before `SET ROLE`. The default is `public`.
52
+ */
53
+ readonly schema?: string;
40
54
  };
41
55
  /** Migrations that ran at least one step in this invocation. */
42
56
  export type ApplyReport = {
43
57
  readonly target: string;
44
58
  readonly applied: readonly string[];
59
+ /** Set when the runner issued `SET ROLE` at session start. */
60
+ readonly setRole?: string;
45
61
  };
46
62
  /**
47
63
  * Groups pending steps into the transactions apply will run.
@@ -23,7 +23,8 @@ export declare function formatFailure(error: OkmError): string;
23
23
  * Runs one `okm` invocation.
24
24
  *
25
25
  * `--version` stays in the bin. This function handles `build`, `check`,
26
- * `generate`, `dev`, `push`, and `migrate plan`, `apply`, and `status`.
26
+ * `generate`, `dev`, `push`, `ext list`, `ext check`, `doctor`, and `migrate plan`,
27
+ * `apply`, and `status`.
27
28
  *
28
29
  * @param argv - Arguments after the program name
29
30
  * @param io - Working directory and stdout. Defaults to the process
@@ -9,6 +9,7 @@ export type TargetInput = string | {
9
9
  /** Refuses contract, push, and other non-expand work unless `--allow-protected`. */
10
10
  readonly protected?: boolean;
11
11
  };
12
+ import type { RolesInput } from "../../dialects/pg/role/index.js";
12
13
  /** Paths and targets `okm` reads. */
13
14
  export type MigrateConfig = {
14
15
  /** Module that exports the built schema. */
@@ -35,6 +36,13 @@ export type MigrateConfig = {
35
36
  readonly lock?: number;
36
37
  readonly statement?: number;
37
38
  };
39
+ /**
40
+ * Migration role and application role.
41
+ *
42
+ * A name is external unless it is also listed in `managed`. The plan creates
43
+ * a managed role and never drops one.
44
+ */
45
+ readonly roles?: RolesInput;
38
46
  };
39
47
  /**
40
48
  * Returns the config unchanged.
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `okm doctor`.
3
+ *
4
+ * A code prints the registry entry. With no code, the project is loaded and
5
+ * each table's triggers are listed. When `roles` is set, the command also
6
+ * connects and checks that those roles exist, that a managed role can be
7
+ * created, and that the application role can reach each managed object.
8
+ */
9
+ import type { CatalogObject } from "../../contracts/catalog/types.js";
10
+ import { type InvokeFlags } from "./policy.js";
11
+ /**
12
+ * Explains one code, or lists the triggers on each table.
13
+ *
14
+ * @param cwd - Project directory
15
+ * @param code - Spec code, when the caller passed one
16
+ * @returns Text for stdout, including the trailing newline
17
+ */
18
+ export declare function doctorProject(cwd: string, code: string | undefined, flags?: InvokeFlags): Promise<string>;
19
+ /**
20
+ * One line per table that has a trigger.
21
+ *
22
+ * @param objects - Catalog objects
23
+ * @returns The listing, or `no triggers` when none are present
24
+ */
25
+ export declare function formatTriggers(objects: readonly CatalogObject[]): string;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Live drift for `okm check`.
3
+ *
4
+ * A database that has never been pushed has no `okm_meta` and is left alone.
5
+ * After push, the introspected catalog is planned back to the schema. Each
6
+ * view is reprinted on this server first, so a `pg_get_viewdef` spelling is
7
+ * not drift. Any remaining statement is OKM1520. `okm_meta` and `okm_history`
8
+ * are omitted by the planner.
9
+ */
10
+ import type { Catalog } from "../../contracts/catalog/types.js";
11
+ import type { RolesInput } from "../../dialects/pg/role/index.js";
12
+ /**
13
+ * Refuses when the connected database differs from the schema.
14
+ *
15
+ * @param url - Target URL
16
+ * @param author - Schema catalog, including roles when the config names them
17
+ * @param roles - `defineConfig({ roles })`, when set
18
+ */
19
+ export declare function assertAuthorDrift(url: string, author: Catalog, roles?: RolesInput): Promise<void>;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `okm ext list` and `okm ext check`.
3
+ *
4
+ * Both talk to the selected target. List prints every extension the server
5
+ * can install, and the installed version when one is present. Check compares
6
+ * the schema's declarations with what is installed.
7
+ */
8
+ import { type InvokeFlags } from "./policy.js";
9
+ /**
10
+ * Runs `list` or `check` against the selected target.
11
+ *
12
+ * @param cwd - Project directory
13
+ * @param command - `list` or `check`
14
+ * @param flags - Target and protection flags
15
+ * @returns Text for stdout, including the trailing newline
16
+ */
17
+ export declare function extProject(cwd: string, command: "list" | "check", flags: InvokeFlags): Promise<string>;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Extension alters and the apply preflight.
3
+ *
4
+ * Create and drop SQL come from the dialect. An upgrade is `ALTER EXTENSION
5
+ * … UPDATE`, marked `path-unverified` until apply checks
6
+ * `pg_extension_update_paths`. A move is `SET SCHEMA` and only when the
7
+ * declaration is relocatable.
8
+ */
9
+ import type { CatalogObject } from "../../contracts/catalog/types.js";
10
+ import type { DriverConnection } from "../../contracts/driver.js";
11
+ /** One extension alter. The planner stores it as a plan step. */
12
+ export type ExtensionStep = {
13
+ readonly sql: string;
14
+ readonly class: "expand" | "contract";
15
+ readonly action: "ddl";
16
+ readonly lock: string;
17
+ readonly transactional: boolean;
18
+ readonly path?: "unverified";
19
+ };
20
+ /** Migrations the preflight reads. Only the statement text is used. */
21
+ type MigrationSql = {
22
+ readonly steps: readonly {
23
+ readonly sql: string;
24
+ }[];
25
+ };
26
+ /**
27
+ * Upgrade and move steps for extensions whose definition changed.
28
+ *
29
+ * Exact downgrades and moves of a non-relocatable extension are OKM1814.
30
+ * Dropping an extension that an object in the next catalog still uses is
31
+ * OKM1814. `DROP` is never `CASCADE`.
32
+ *
33
+ * @param beforeBy - Previous objects, keyed by identity
34
+ * @param afterBy - Next objects, keyed by identity
35
+ * @param dropKeys - Identities the plan drops
36
+ * @returns Alter steps. Creates and drops stay in the main planner
37
+ */
38
+ export declare function extensionAlterSteps(beforeBy: ReadonlyMap<string, CatalogObject>, afterBy: ReadonlyMap<string, CatalogObject>, dropKeys: ReadonlySet<string>): ExtensionStep[];
39
+ /**
40
+ * Refuses a migration that names an extension the server cannot install,
41
+ * or an upgrade with no path.
42
+ *
43
+ * The server is asked only when a step creates or upgrades an extension.
44
+ * The check runs before any statement.
45
+ *
46
+ * @param connection - The reserved apply connection
47
+ * @param migrations - Migrations in apply order
48
+ * @throws OkmError OKM1811 when the extension is not available, OKM1814 when the update path is missing
49
+ */
50
+ export declare function assertExtensionsAvailable(connection: DriverConnection, migrations: readonly MigrationSql[]): Promise<void>;
51
+ export {};
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Tables OKModel owns: `okm_meta` and `okm_history`.
3
+ *
4
+ * Apply creates them. They are not part of the author schema. Plan, push,
5
+ * check, and doctor omit them on both sides, so a diff neither drops them
6
+ * nor creates them.
7
+ */
8
+ import type { Catalog } from "../../contracts/catalog/types.js";
9
+ /**
10
+ * Removes the migration history tables and the objects that belong to them.
11
+ *
12
+ * A catalog that has neither is returned as itself.
13
+ *
14
+ * @param source - Catalog about to be diffed or diagnosed
15
+ * @returns The catalog without OKModel's own tables
16
+ */
17
+ export declare function omitManagedObjects(source: Catalog): Catalog;
@@ -26,6 +26,19 @@ export type PlanStep = {
26
26
  readonly action: "ddl" | "backfill";
27
27
  readonly lock: string;
28
28
  readonly transactional: boolean;
29
+ /**
30
+ * Set on an extension upgrade the planner could not check.
31
+ *
32
+ * Apply reads `pg_extension_update_paths` before any statement and refuses
33
+ * a missing path. Offline `okm migrate plan` leaves this unverified.
34
+ */
35
+ readonly path?: "unverified";
36
+ /**
37
+ * Set on `CREATE OR REPLACE` of a function whose signature did not change.
38
+ *
39
+ * The statement is expand. The flag says the body or the settings changed.
40
+ */
41
+ readonly behavior?: "change";
29
42
  };
30
43
  /** A named plan and the class of its strictest step. */
31
44
  export type MigrationPlan = {
@@ -49,7 +62,7 @@ export type PlanRequest = {
49
62
  * @param request - Catalogs, declared renames, and `--replace` flags
50
63
  * @returns Steps in apply order, with one class for the plan
51
64
  */
52
- export declare function planMigration(request: PlanRequest): MigrationPlan;
65
+ export declare function planMigration(input: PlanRequest): MigrationPlan;
53
66
  /**
54
67
  * Prints a plan. The text is SQL plus class comments, never TypeScript.
55
68
  *
@@ -5,9 +5,13 @@
5
5
  * `.catalog`, which runs that validation. Generate writes SQL only.
6
6
  */
7
7
  import { type DeclaredRename } from "../../dialects/pg/declarations.js";
8
+ import type { BuiltSchema } from "../../dialects/pg/schema.js";
9
+ import type { AnyTable } from "../../dialects/pg/table.js";
8
10
  import type { Catalog } from "../../contracts/catalog/types.js";
9
11
  import { type MigrateConfig } from "./config.js";
12
+ import { type InvokeFlags } from "./policy.js";
10
13
  import { type MigrationPlan } from "./plan.js";
14
+ type Built = BuiltSchema<readonly AnyTable[]>;
11
15
  /**
12
16
  * Validates the schema and writes `.okm/`.
13
17
  *
@@ -38,9 +42,14 @@ export declare function planProject(cwd: string, name: string, flags: readonly s
38
42
  /**
39
43
  * Validates the schema, then reports stale renames and unlisted table files.
40
44
  *
45
+ * When exactly one target is configured, or `--target` names one, a database
46
+ * that already has `okm_meta` is compared with the schema. A difference is
47
+ * OKM1520. Several targets and no `--target` skip that comparison.
48
+ *
41
49
  * @param cwd - Project directory
50
+ * @param flags - `--target`, when the caller passed one
42
51
  */
43
- export declare function checkProject(cwd: string): Promise<void>;
52
+ export declare function checkProject(cwd: string, flags?: InvokeFlags): Promise<void>;
44
53
  /**
45
54
  * Table files whose names do not appear in the schema module.
46
55
  *
@@ -60,6 +69,20 @@ export declare function projectHead(cwd: string): Promise<{
60
69
  readonly catalog: Catalog;
61
70
  readonly renames: readonly DeclaredRename[];
62
71
  }>;
72
+ /**
73
+ * Loads the config, the schema, and the previous catalog snapshot.
74
+ *
75
+ * A `renamedFrom` that the previous catalog does not contain is OKM1020.
76
+ *
77
+ * @param cwd - Project directory
78
+ * @returns The loaded project
79
+ */
80
+ export declare function openProject(cwd: string): Promise<{
81
+ readonly config: MigrateConfig;
82
+ readonly built: Built;
83
+ readonly previous: Catalog;
84
+ readonly renames: readonly DeclaredRename[];
85
+ }>;
63
86
  /**
64
87
  * Loads `okmodel.config.ts`.
65
88
  *
@@ -67,3 +90,4 @@ export declare function projectHead(cwd: string): Promise<{
67
90
  * @returns The config object
68
91
  */
69
92
  export declare function loadConfig(cwd: string): Promise<MigrateConfig>;
93
+ export {};
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okmodel",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "okmodel is a catalog-first TypeScript ORM, PostgreSQL first.",
5
5
  "keywords": [
6
6
  "migrations",
@@ -85,10 +85,30 @@
85
85
  "./validate": {
86
86
  "types": "./dist/runtime/validate/index.d.ts",
87
87
  "import": "./dist/runtime/validate/index.js"
88
+ },
89
+ "./ext": {
90
+ "types": "./dist/dialects/pg/ext/index.d.ts",
91
+ "import": "./dist/dialects/pg/ext/index.js"
92
+ },
93
+ "./fn": {
94
+ "types": "./dist/dialects/pg/fn/index.d.ts",
95
+ "import": "./dist/dialects/pg/fn/index.js"
96
+ },
97
+ "./view": {
98
+ "types": "./dist/dialects/pg/view/index.d.ts",
99
+ "import": "./dist/dialects/pg/view/index.js"
100
+ },
101
+ "./pg/citext": {
102
+ "types": "./dist/dialects/pg/ext/citext.d.ts",
103
+ "import": "./dist/dialects/pg/ext/citext.js"
104
+ },
105
+ "./pg/pg_trgm": {
106
+ "types": "./dist/dialects/pg/ext/pg-trgm.d.ts",
107
+ "import": "./dist/dialects/pg/ext/pg-trgm.js"
88
108
  }
89
109
  },
90
110
  "scripts": {
91
- "build": "rm -rf dist && bun build ./src/contracts/index.ts ./src/contracts/internal.ts ./src/dialects/pg/index.ts ./src/runtime/pg/postgresjs.ts ./src/runtime/pg/pglite.ts ./src/runtime/pg/pg.ts ./src/runtime/pg/bun.ts ./src/runtime/ids/index.ts ./src/runtime/safety/index.ts ./src/runtime/traits/index.ts ./src/runtime/tenancy/index.ts ./src/runtime/validate/index.ts ./src/tooling/migrate/index.ts ./src/tooling/cli.ts --outdir ./dist --root ./src --format esm --target node --splitting --chunk-naming=shared/[hash].js --external postgres --external @electric-sql/pglite --external pg --external bun && bunx tsc -p tsconfig.build.json && bun ./scripts/write-bin-wrappers.ts",
111
+ "build": "rm -rf dist && bun build ./src/contracts/index.ts ./src/contracts/internal.ts ./src/dialects/pg/index.ts ./src/runtime/pg/postgresjs.ts ./src/runtime/pg/pglite.ts ./src/runtime/pg/pg.ts ./src/runtime/pg/bun.ts ./src/runtime/ids/index.ts ./src/runtime/safety/index.ts ./src/runtime/traits/index.ts ./src/runtime/tenancy/index.ts ./src/runtime/validate/index.ts ./src/dialects/pg/ext/index.ts ./src/dialects/pg/fn/index.ts ./src/dialects/pg/view/index.ts ./src/dialects/pg/ext/citext.ts ./src/dialects/pg/ext/pg-trgm.ts ./src/tooling/migrate/index.ts ./src/tooling/cli.ts --outdir ./dist --root ./src --format esm --target node --splitting --chunk-naming=shared/[hash].js --external postgres --external @electric-sql/pglite --external pg --external bun && bunx tsc -p tsconfig.build.json && bun ./scripts/write-bin-wrappers.ts",
92
112
  "driver-bench": "bun ./scripts/driver-bench.ts",
93
113
  "typecheck": "bunx tsc --noEmit -p tsconfig.json",
94
114
  "editor-check": "bun ./scripts/editor-check.ts",