okmodel 0.3.0 → 0.5.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 +263 -23
- package/dist/contracts/catalog/document.d.ts +26 -2
- package/dist/contracts/driver.d.ts +7 -0
- package/dist/dialects/pg/ext/citext.js +1 -1
- package/dist/dialects/pg/ext/index.js +1 -1
- package/dist/dialects/pg/ext/pg-trgm.js +1 -1
- package/dist/dialects/pg/index.js +3 -3
- package/dist/dialects/pg/introspect.d.ts +6 -0
- package/dist/dialects/pg/role/sql.d.ts +21 -4
- package/dist/dialects/pg/schema.d.ts +15 -6
- package/dist/dialects/pg/table.d.ts +17 -1
- package/dist/dialects/pg/view/index.d.ts +20 -6
- package/dist/dialects/pg/view/index.js +1 -1
- package/dist/dialects/pg/view/scratch.d.ts +2 -1
- 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.d.ts +12 -7
- package/dist/runtime/pg/bun.js +5 -2
- package/dist/runtime/pg/pg.d.ts +12 -6
- package/dist/runtime/pg/pg.js +5 -2
- package/dist/runtime/pg/pglite.d.ts +11 -3
- package/dist/runtime/pg/pglite.js +5 -2
- package/dist/runtime/pg/postgresjs.d.ts +12 -6
- package/dist/runtime/pg/postgresjs.js +5 -2
- package/dist/runtime/plan.d.ts +3 -1
- package/dist/runtime/tenancy/index.js +1 -1
- package/dist/runtime/topology.d.ts +191 -0
- package/dist/runtime/traits/index.js +7 -6
- package/dist/runtime/types.d.ts +59 -2
- package/dist/runtime/validate/index.js +2 -2
- package/dist/shared/{x6wysh83.js → 3p4b1fg0.js} +3 -5
- package/dist/shared/{ty3v3hfk.js → 47xzb9fc.js} +2 -2
- package/dist/shared/{fs0ex00p.js → 4ef7mmqf.js} +2 -2
- package/dist/shared/{qybh48nd.js → 5fqx9yh4.js} +6 -2
- package/dist/shared/5mtf6cj3.js +94 -0
- package/dist/shared/{999ade2q.js → 5vdm4sgp.js} +1 -1
- package/dist/shared/{bqha5cg6.js → 6p5k20sm.js} +2 -2
- package/dist/shared/{t616ynfn.js → 8bwbwy8h.js} +71 -13
- package/dist/shared/{th14ygv2.js → 8ktwd3rh.js} +29 -1
- package/dist/shared/{wekze34d.js → 8xsbagad.js} +74 -2
- package/dist/shared/{bryqk9k9.js → 922qbgnw.js} +3 -3
- package/dist/shared/{meck53jv.js → 990a291j.js} +6 -5
- package/dist/shared/{jns2wx4t.js → 9tgmr1gh.js} +1 -1
- package/dist/shared/9yn6a2vd.js +11 -0
- package/dist/shared/{2ssqrv66.js → ayz64vzj.js} +1037 -181
- package/dist/shared/{k34e0xf2.js → bt9sfq0z.js} +16 -14
- package/dist/shared/{scwxrpx2.js → bzsjtd7c.js} +84 -15
- package/dist/shared/{m9tv7xn7.js → ckjbyrt9.js} +4 -4
- package/dist/shared/{ydaz1sv3.js → dxjp14rk.js} +10 -2
- package/dist/shared/{49ypnfwt.js → fancm5pt.js} +24 -229
- package/dist/shared/{6bazvqwm.js → fb00y8fp.js} +2 -2
- package/dist/shared/{1tfdfvhh.js → fyqkk1m0.js} +6 -4
- package/dist/shared/g516zdsb.js +905 -0
- package/dist/shared/{jkc6ws1p.js → g7ez901n.js} +83 -2
- package/dist/shared/{kgnc8grt.js → gdh9mrtp.js} +1 -1
- package/dist/shared/{p24x2334.js → h4nqvjkp.js} +5 -3
- package/dist/shared/{edwqqryd.js → h8ne16fq.js} +1 -1
- package/dist/shared/htnaj77v.js +17 -0
- package/dist/shared/jdgqqx31.js +72 -0
- package/dist/shared/{6w5j844a.js → jsd07prz.js} +2 -2
- package/dist/shared/{m78s7898.js → k7cc9nzk.js} +24 -7
- package/dist/shared/kdkxh3kb.js +758 -0
- package/dist/shared/nkc9sfqb.js +1161 -0
- package/dist/shared/{xva8v7qk.js → p7pfx624.js} +5 -5
- package/dist/shared/{xrfnq5k8.js → qgvt8nx1.js} +11 -2
- package/dist/shared/{ne02ng5c.js → qy9rdq0g.js} +9 -5
- package/dist/shared/{3ekj9x92.js → r6pj4fq2.js} +5 -3
- package/dist/shared/r73pt594.js +426 -0
- package/dist/shared/rasvvzgz.js +21 -0
- package/dist/shared/{01yr20s5.js → sf8m6tfy.js} +2 -2
- package/dist/shared/{hcmdtwgh.js → szm0cksa.js} +4 -1
- package/dist/shared/{axhk06q1.js → tq9afp8d.js} +1 -1
- package/dist/shared/{xw1d69vd.js → wqem4jed.js} +6 -6
- package/dist/shared/wxn4b7pp.js +252 -0
- package/dist/shared/xdpj5kkm.js +2203 -0
- package/dist/shared/xhh1srw3.js +589 -0
- package/dist/shared/{mt5wswjz.js → xsq7v6wp.js} +2 -2
- package/dist/shared/{7fvtrkwr.js → ycatkxmq.js} +1 -1
- package/dist/shared/ykv7wh5b.js +14 -0
- package/dist/shared/{fptpmvxp.js → z2rnngj4.js} +26 -21
- package/dist/tooling/cli.js +46 -17
- package/dist/tooling/migrate/apply.d.ts +61 -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 -2
- package/dist/tooling/migrate/config.d.ts +22 -0
- package/dist/tooling/migrate/doctor.d.ts +3 -0
- package/dist/tooling/migrate/drift.d.ts +18 -2
- package/dist/tooling/migrate/estimate.d.ts +50 -0
- package/dist/tooling/migrate/extensions.d.ts +2 -0
- package/dist/tooling/migrate/files.d.ts +19 -0
- package/dist/tooling/migrate/index.d.ts +3 -2
- package/dist/tooling/migrate/index.js +69 -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 +1 -1
- package/dist/tooling/migrate/plan.d.ts +64 -9
- package/dist/tooling/migrate/project.d.ts +42 -7
- 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/testing/factories.d.ts +117 -0
- package/dist/tooling/testing/facts.d.ts +75 -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 +6 -2
- package/dist/shared/5nmdenb6.js +0 -1229
- package/dist/shared/dbjej1tw.js +0 -456
- package/dist/shared/g4f5kcx9.js +0 -37
- package/dist/shared/qbxzvwwc.js +0 -88
- package/dist/shared/zwmqxb0g.js +0 -79
- /package/dist/shared/{75xkjv0t.js → fa9vt245.js} +0 -0
- /package/dist/shared/{0jc3ffzf.js → zvbjc949.js} +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import"../../shared/8bwbwy8h.js";
|
|
1
2
|
import {
|
|
2
3
|
checkPresetNames,
|
|
3
4
|
duplicatePreset
|
|
@@ -7,7 +8,7 @@ import {
|
|
|
7
8
|
} from "../../shared/n0dgs0pb.js";
|
|
8
9
|
import {
|
|
9
10
|
quoteIdent
|
|
10
|
-
} from "../../shared/
|
|
11
|
+
} from "../../shared/8xsbagad.js";
|
|
11
12
|
import {
|
|
12
13
|
functionObject,
|
|
13
14
|
triggerObject
|
|
@@ -20,7 +21,7 @@ import {
|
|
|
20
21
|
} from "../../shared/dyj86cmj.js";
|
|
21
22
|
import {
|
|
22
23
|
snakeCase
|
|
23
|
-
} from "../../shared/
|
|
24
|
+
} from "../../shared/jsd07prz.js";
|
|
24
25
|
import {
|
|
25
26
|
ColumnBuilder2,
|
|
26
27
|
retarget
|
|
@@ -37,10 +38,10 @@ import {
|
|
|
37
38
|
queryHandle,
|
|
38
39
|
attachHttp,
|
|
39
40
|
settleCall
|
|
40
|
-
} from "../../shared/
|
|
41
|
+
} from "../../shared/bt9sfq0z.js";
|
|
41
42
|
import {
|
|
42
43
|
installArchiveInspect
|
|
43
|
-
} from "../../shared/
|
|
44
|
+
} from "../../shared/qgvt8nx1.js";
|
|
44
45
|
import {
|
|
45
46
|
fitIdentifier2
|
|
46
47
|
} from "../../shared/nfzc5z0w.js";
|
|
@@ -57,7 +58,7 @@ function rewriteArchivable(self, tables, casing, schemaTraits, cascade) {
|
|
|
57
58
|
const edges = foreignKeys(tables, casing, byName);
|
|
58
59
|
const archiveSql = casing === "snake" ? "archived_at" : "archivedAt";
|
|
59
60
|
const idSql = casing === "snake" ? "archive_id" : "archiveId";
|
|
60
|
-
const predicate =
|
|
61
|
+
const predicate = casing === "snake" ? "(archived_at IS NULL)" : '("archivedAt" IS NULL)';
|
|
61
62
|
return tables.map((item) => {
|
|
62
63
|
if (!applies(self, item, schemaTraits))
|
|
63
64
|
return item;
|
|
@@ -458,7 +459,7 @@ function refuse(host, table) {
|
|
|
458
459
|
}
|
|
459
460
|
var archiveMod;
|
|
460
461
|
function loadArchive() {
|
|
461
|
-
archiveMod ??= import("../../shared/
|
|
462
|
+
archiveMod ??= import("../../shared/ckjbyrt9.js");
|
|
462
463
|
return archiveMod;
|
|
463
464
|
}
|
|
464
465
|
async function settle(host, table, mods) {
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -99,6 +99,12 @@ export type CallOptions = {
|
|
|
99
99
|
readonly signal?: AbortSignal;
|
|
100
100
|
/** Milliseconds. The call fails as `timeout` when it runs longer. */
|
|
101
101
|
readonly timeout?: number;
|
|
102
|
+
/**
|
|
103
|
+
* Forces this read onto the primary or a replica.
|
|
104
|
+
*
|
|
105
|
+
* Absent, a topology client chooses. A single endpoint serves either value.
|
|
106
|
+
*/
|
|
107
|
+
readonly route?: "primary" | "replica";
|
|
102
108
|
};
|
|
103
109
|
/** Options shared by reads. */
|
|
104
110
|
export type ReadOptions<S extends QuerySchema, K extends keyof S["~byName"]> = CallOptions & {
|
|
@@ -602,6 +608,55 @@ export type TxClient<S extends QuerySchema, Root extends boolean = false> = {
|
|
|
602
608
|
*/
|
|
603
609
|
advisoryLock(key: string | number | bigint, options?: CallOptions): Promise<void>;
|
|
604
610
|
} & TxApi<S, Root>;
|
|
611
|
+
/** A view field: its column name in camel case, as the client publishes it. */
|
|
612
|
+
type CamelName<N extends string> = N extends `_${infer Rest}` ? CamelName<Rest> : N extends `${infer Head}_${infer Tail}` ? `${Head}${Capitalize<CamelName<Tail>>}` : N;
|
|
613
|
+
/** One view row. Every column is decoded as text, so each field is a string or null. */
|
|
614
|
+
type ViewRow<D> = D extends {
|
|
615
|
+
readonly "~columns"?: infer C extends readonly {
|
|
616
|
+
readonly name: string;
|
|
617
|
+
}[];
|
|
618
|
+
} ? {
|
|
619
|
+
readonly [Col in C[number] as CamelName<Col["name"]>]: string | null;
|
|
620
|
+
} : never;
|
|
621
|
+
/** Options `find` and `one` take on a view. */
|
|
622
|
+
type ViewReadOptions<Row> = CallOptions & {
|
|
623
|
+
readonly where?: FieldWhere<Row>;
|
|
624
|
+
readonly select?: readonly (keyof Row & string)[];
|
|
625
|
+
readonly orderBy?: OrderBy<Row>;
|
|
626
|
+
readonly limit?: number;
|
|
627
|
+
};
|
|
628
|
+
/** The read-only handle `db.views` holds for one view. */
|
|
629
|
+
type ViewApi<Row> = {
|
|
630
|
+
find<const O extends ViewReadOptions<Row> & {
|
|
631
|
+
readonly limit: number;
|
|
632
|
+
}>(options: O): Read<readonly Show<Selected<Row, O extends {
|
|
633
|
+
readonly select: infer Sel;
|
|
634
|
+
} ? Sel : undefined>>[]>;
|
|
635
|
+
find<const O extends ViewReadOptions<Row>>(options: O): {
|
|
636
|
+
all(reason: string): Read<readonly Show<Selected<Row, O extends {
|
|
637
|
+
readonly select: infer Sel;
|
|
638
|
+
} ? Sel : undefined>>[]>;
|
|
639
|
+
};
|
|
640
|
+
one<const O extends ViewReadOptions<Row>>(options?: O): Read<Show<Selected<Row, O extends {
|
|
641
|
+
readonly select: infer Sel;
|
|
642
|
+
} ? Sel : undefined>> | null>;
|
|
643
|
+
count(options?: CallOptions & {
|
|
644
|
+
readonly where?: FieldWhere<Row>;
|
|
645
|
+
}): Read<number>;
|
|
646
|
+
exists(options?: CallOptions & {
|
|
647
|
+
readonly where?: FieldWhere<Row>;
|
|
648
|
+
}): Read<boolean>;
|
|
649
|
+
};
|
|
650
|
+
/** `db.views`, typed from `schema({ views })`. Absent when the schema declares none. */
|
|
651
|
+
type ViewsClient<S> = S extends {
|
|
652
|
+
readonly "~views": infer V extends readonly unknown[];
|
|
653
|
+
} ? {
|
|
654
|
+
readonly views: {
|
|
655
|
+
readonly [D in V[number] as D extends {
|
|
656
|
+
readonly name: infer N extends string;
|
|
657
|
+
} ? CamelName<N> : never]: ViewApi<Show<ViewRow<D>>>;
|
|
658
|
+
};
|
|
659
|
+
} : unknown;
|
|
605
660
|
/** A client whose tables are already inside one tenant or an unscoped reason. */
|
|
606
661
|
type ScopedClient<S extends QuerySchema> = {
|
|
607
662
|
readonly [K in keyof S["~byName"] & string]: TableApi<S, K>;
|
|
@@ -612,7 +667,7 @@ type ScopedClient<S extends QuerySchema> = {
|
|
|
612
667
|
close(): Promise<void>;
|
|
613
668
|
/** Resolves when the dialect and `requires` checks have finished. */
|
|
614
669
|
readonly connected: Promise<void>;
|
|
615
|
-
} & TxApi<S, false> & IfAsyncDisposable<typeof Symbol>;
|
|
670
|
+
} & TxApi<S, false> & ViewsClient<S> & IfAsyncDisposable<typeof Symbol>;
|
|
616
671
|
/** `for` and `unscoped` on a schema that set tenancy. */
|
|
617
672
|
type ScopeMethods<S extends QuerySchema> = TenantKeyOf<S> extends never ? object : {
|
|
618
673
|
/**
|
|
@@ -650,7 +705,7 @@ export type Connected<S extends QuerySchema> = {
|
|
|
650
705
|
close(): Promise<void>;
|
|
651
706
|
/** Resolves when the dialect and `requires` checks have finished. */
|
|
652
707
|
readonly connected: Promise<void>;
|
|
653
|
-
} & TxApi<S, true> & ScopeMethods<S> & IfAsyncDisposable<typeof Symbol>;
|
|
708
|
+
} & TxApi<S, true> & ScopeMethods<S> & ViewsClient<S> & IfAsyncDisposable<typeof Symbol>;
|
|
654
709
|
/**
|
|
655
710
|
* A catalog `okm build` wrote.
|
|
656
711
|
*
|
|
@@ -672,6 +727,8 @@ export type ConnectOptions<S extends QuerySchema> = {
|
|
|
672
727
|
* Directory of `catalog.hash` and `catalog.json`.
|
|
673
728
|
*
|
|
674
729
|
* When omitted, `connect` reads `.okm` under the process cwd if that hash file exists.
|
|
730
|
+
* The hash file is the fast path. A mismatch then reads `catalog.json` once
|
|
731
|
+
* per process and does not rebuild the catalog from the schema.
|
|
675
732
|
*/
|
|
676
733
|
readonly catalogDir?: string;
|
|
677
734
|
readonly logger?: {
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
} from "../../shared/9m80mkac.js";
|
|
4
4
|
import {
|
|
5
5
|
addSchemaHook
|
|
6
|
-
} from "../../shared/
|
|
6
|
+
} from "../../shared/3p4b1fg0.js";
|
|
7
7
|
import {
|
|
8
8
|
queryHandle
|
|
9
|
-
} from "../../shared/
|
|
9
|
+
} from "../../shared/bt9sfq0z.js";
|
|
10
10
|
import {
|
|
11
11
|
OkmError2
|
|
12
12
|
} from "../../shared/52szzakm.js";
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
catalog
|
|
3
|
-
} from "./jkc6ws1p.js";
|
|
4
|
-
import {
|
|
2
|
+
catalog,
|
|
5
3
|
enumType,
|
|
6
4
|
sameEnumLabels
|
|
7
|
-
} from "./
|
|
5
|
+
} from "./g7ez901n.js";
|
|
8
6
|
import {
|
|
9
7
|
snakeCase,
|
|
10
8
|
emittedTypeName,
|
|
11
9
|
rejectLater
|
|
12
|
-
} from "./
|
|
10
|
+
} from "./jsd07prz.js";
|
|
13
11
|
import {
|
|
14
12
|
withLocation
|
|
15
13
|
} from "./k7dwkhvq.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
withHttp,
|
|
3
3
|
attachHttp
|
|
4
|
-
} from "./
|
|
4
|
+
} from "./bt9sfq0z.js";
|
|
5
5
|
import {
|
|
6
6
|
OkmError2
|
|
7
7
|
} from "./52szzakm.js";
|
|
@@ -31,7 +31,7 @@ async function acceptServer(pool, schema, rows, http, requireMeta, options, sour
|
|
|
31
31
|
}));
|
|
32
32
|
}
|
|
33
33
|
} else {
|
|
34
|
-
const { assertCompatible } = await import("./
|
|
34
|
+
const { assertCompatible } = await import("./z2rnngj4.js");
|
|
35
35
|
try {
|
|
36
36
|
await assertCompatible(pool, schema, recorded, source, options);
|
|
37
37
|
} catch (error) {
|
|
@@ -2,13 +2,13 @@ import {
|
|
|
2
2
|
send2,
|
|
3
3
|
reserve,
|
|
4
4
|
park
|
|
5
|
-
} from "./
|
|
5
|
+
} from "./sf8m6tfy.js";
|
|
6
6
|
import {
|
|
7
7
|
isConnectionLost
|
|
8
8
|
} from "./tbszx8mz.js";
|
|
9
9
|
import {
|
|
10
10
|
WireSession
|
|
11
|
-
} from "./
|
|
11
|
+
} from "./zvbjc949.js";
|
|
12
12
|
import {
|
|
13
13
|
rejectClosed,
|
|
14
14
|
runCall
|
|
@@ -4,9 +4,11 @@ import {
|
|
|
4
4
|
renameTable2,
|
|
5
5
|
serializeCatalog2,
|
|
6
6
|
catalogHash2,
|
|
7
|
+
startupCatalog2,
|
|
8
|
+
startupHash2,
|
|
7
9
|
loadTrustedCatalog2,
|
|
8
10
|
parseCatalog2
|
|
9
|
-
} from "./
|
|
11
|
+
} from "./8bwbwy8h.js";
|
|
10
12
|
export {
|
|
11
13
|
catalogHash2 as catalogHash,
|
|
12
14
|
creationOrder2 as creationOrder,
|
|
@@ -14,5 +16,7 @@ export {
|
|
|
14
16
|
parseCatalog2 as parseCatalog,
|
|
15
17
|
renameColumn2 as renameColumn,
|
|
16
18
|
renameTable2 as renameTable,
|
|
17
|
-
serializeCatalog2 as serializeCatalog
|
|
19
|
+
serializeCatalog2 as serializeCatalog,
|
|
20
|
+
startupCatalog2 as startupCatalog,
|
|
21
|
+
startupHash2 as startupHash
|
|
18
22
|
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BEHIND_EXPAND,
|
|
3
|
+
BEHIND_CONTRACT,
|
|
4
|
+
AHEAD_CONTRACT
|
|
5
|
+
} from "./9yn6a2vd.js";
|
|
6
|
+
import {
|
|
7
|
+
OkmError2
|
|
8
|
+
} from "./52szzakm.js";
|
|
9
|
+
|
|
10
|
+
// src/runtime/drift-detail.ts
|
|
11
|
+
function driftVerdict(codeHash, recordedHash, migrations) {
|
|
12
|
+
const codeAt = indexOfHash(migrations, codeHash);
|
|
13
|
+
const recordedAt = indexOfHash(migrations, recordedHash);
|
|
14
|
+
if (codeAt >= 0 && recordedAt >= codeAt) {
|
|
15
|
+
for (let index = codeAt + 1;index <= recordedAt; index += 1) {
|
|
16
|
+
const migration = migrations[index];
|
|
17
|
+
if (migration !== undefined && migration.expand !== true) {
|
|
18
|
+
return { state: "ahead by contract", migrationId: migration.id };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return { state: "ok" };
|
|
22
|
+
}
|
|
23
|
+
if (codeAt >= 0 && recordedAt >= 0 && recordedAt < codeAt) {
|
|
24
|
+
const next = migrations[recordedAt + 1];
|
|
25
|
+
if (next !== undefined) {
|
|
26
|
+
return {
|
|
27
|
+
state: next.expand ? "behind by expand" : "behind by contract",
|
|
28
|
+
migrationId: next.id
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (recordedAt >= 0) {
|
|
33
|
+
const at = migrations[recordedAt];
|
|
34
|
+
if (at !== undefined)
|
|
35
|
+
return { state: "behind", migrationId: at.id };
|
|
36
|
+
}
|
|
37
|
+
const last = migrations.at(-1);
|
|
38
|
+
return { state: "behind", migrationId: last?.id ?? "" };
|
|
39
|
+
}
|
|
40
|
+
async function assertDrift(pool, codeHash, recordedHash, options) {
|
|
41
|
+
let rows;
|
|
42
|
+
try {
|
|
43
|
+
const result = await pool.execute("select migration_id, class, catalog_hash from okm_history order by migration_id, step_index", undefined, options);
|
|
44
|
+
rows = result.rows;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
throw gapError({ state: "behind", migrationId: "" }, error);
|
|
47
|
+
}
|
|
48
|
+
const verdict = driftVerdict(codeHash, recordedHash, groupMigrations(rows));
|
|
49
|
+
if (verdict.state === "ok")
|
|
50
|
+
return;
|
|
51
|
+
throw gapError(verdict);
|
|
52
|
+
}
|
|
53
|
+
function indexOfHash(migrations, hash) {
|
|
54
|
+
let found = -1;
|
|
55
|
+
for (let index = 0;index < migrations.length; index += 1) {
|
|
56
|
+
if (migrations[index]?.catalogHash === hash)
|
|
57
|
+
found = index;
|
|
58
|
+
}
|
|
59
|
+
return found;
|
|
60
|
+
}
|
|
61
|
+
function groupMigrations(rows) {
|
|
62
|
+
const grouped = [];
|
|
63
|
+
for (const row of rows) {
|
|
64
|
+
const id = row[0];
|
|
65
|
+
const stepClass = row[1];
|
|
66
|
+
const hash = row[2];
|
|
67
|
+
if (id == null || stepClass == null || hash == null)
|
|
68
|
+
continue;
|
|
69
|
+
const expand = stepClass === "expand";
|
|
70
|
+
const last = grouped.at(-1);
|
|
71
|
+
if (last !== undefined && last.id === id) {
|
|
72
|
+
grouped[grouped.length - 1] = {
|
|
73
|
+
id,
|
|
74
|
+
catalogHash: hash,
|
|
75
|
+
expand: last.expand && expand
|
|
76
|
+
};
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
grouped.push({ id, catalogHash: hash, expand });
|
|
80
|
+
}
|
|
81
|
+
return grouped;
|
|
82
|
+
}
|
|
83
|
+
function gapError(verdict, cause) {
|
|
84
|
+
const named = verdict.migrationId;
|
|
85
|
+
const phrase = verdict.state === "ahead by contract" ? `${AHEAD_CONTRACT} migration ${named}` : verdict.state === "behind by expand" ? `${BEHIND_EXPAND} migration ${named}` : verdict.state === "behind by contract" ? `${BEHIND_CONTRACT} migration ${named}` : named.length > 0 ? `behind the app at migration ${named}` : "behind the app";
|
|
86
|
+
const fix = named.length > 0 ? `Apply ${named}, or change the deploy order.` : "Apply migrations, or change the deploy order.";
|
|
87
|
+
return new OkmError2("OKM1520", `The database is ${phrase}.`, {
|
|
88
|
+
...cause === undefined ? {} : { cause },
|
|
89
|
+
fix: { summary: fix }
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
export {
|
|
93
|
+
assertDrift
|
|
94
|
+
};
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
noticeBuffer,
|
|
4
4
|
WireSession,
|
|
5
5
|
cursorStream
|
|
6
|
-
} from "./
|
|
6
|
+
} from "./zvbjc949.js";
|
|
7
7
|
import {
|
|
8
8
|
NODE_POSTGRES_CAPABILITIES,
|
|
9
9
|
driverErrors,
|
|
@@ -53,7 +53,7 @@ function open4(config) {
|
|
|
53
53
|
counters.busy = Math.max(0, counters.busy - 1);
|
|
54
54
|
}, inflight);
|
|
55
55
|
const held = { pool, acquireMs, counters, notices, named, isClosed };
|
|
56
|
-
const checkout = () => closed ? rejectClosed() : import("./
|
|
56
|
+
const checkout = () => closed ? rejectClosed() : import("./fb00y8fp.js").then((mod) => mod.checkout(held));
|
|
57
57
|
return {
|
|
58
58
|
capabilities: NODE_POSTGRES_CAPABILITIES,
|
|
59
59
|
execute(text, params, options) {
|
|
@@ -9,16 +9,14 @@ import {
|
|
|
9
9
|
} from "./y005b761.js";
|
|
10
10
|
import {
|
|
11
11
|
extensionObject
|
|
12
|
-
} from "./
|
|
12
|
+
} from "./8ktwd3rh.js";
|
|
13
13
|
import {
|
|
14
14
|
dependencyOrder,
|
|
15
|
-
catalog
|
|
16
|
-
} from "./jkc6ws1p.js";
|
|
17
|
-
import {
|
|
15
|
+
catalog,
|
|
18
16
|
enumType,
|
|
19
17
|
domainType,
|
|
20
18
|
isDomain
|
|
21
|
-
} from "./
|
|
19
|
+
} from "./g7ez901n.js";
|
|
22
20
|
import {
|
|
23
21
|
canonicalJson,
|
|
24
22
|
staticNamespace2,
|
|
@@ -46,7 +44,8 @@ import {
|
|
|
46
44
|
} from "./4e4c6vq2.js";
|
|
47
45
|
import {
|
|
48
46
|
sha2562,
|
|
49
|
-
assertIdentifier2
|
|
47
|
+
assertIdentifier2,
|
|
48
|
+
fitIdentifier2
|
|
50
49
|
} from "./nfzc5z0w.js";
|
|
51
50
|
import {
|
|
52
51
|
catalogError2
|
|
@@ -201,7 +200,7 @@ function renameTable2(source, change) {
|
|
|
201
200
|
if (!found) {
|
|
202
201
|
catalogError2("OKM1020", `Table ${change.from} is not in the catalog.`);
|
|
203
202
|
}
|
|
204
|
-
const next = source.objects.map((object) => rewriteTableName(object, change, fromKey, toIdentity));
|
|
203
|
+
const next = source.objects.map((object) => rewriteTableName(object, change, fromKey, toIdentity, source));
|
|
205
204
|
return catalog(next);
|
|
206
205
|
}
|
|
207
206
|
var serializedText = new WeakMap;
|
|
@@ -230,6 +229,17 @@ function catalogHash2(source) {
|
|
|
230
229
|
serializedHash.set(source, hash);
|
|
231
230
|
return hash;
|
|
232
231
|
}
|
|
232
|
+
function startupCatalog2(source) {
|
|
233
|
+
if (!source.objects.some(isPrivilege))
|
|
234
|
+
return source;
|
|
235
|
+
return { version: source.version, objects: source.objects.filter((item) => !isPrivilege(item)) };
|
|
236
|
+
}
|
|
237
|
+
function startupHash2(source) {
|
|
238
|
+
return catalogHash2(startupCatalog2(source));
|
|
239
|
+
}
|
|
240
|
+
function isPrivilege(object) {
|
|
241
|
+
return object.kind === "role" || object.kind === "grant" || object.kind === "defaultPrivilege";
|
|
242
|
+
}
|
|
233
243
|
function loadTrustedCatalog2(text, hash) {
|
|
234
244
|
if (sha2562(text) !== hash) {
|
|
235
245
|
catalogError2("OKM1027", "Catalog hash does not match the build artifact.");
|
|
@@ -473,8 +483,8 @@ function rewriteExpr(text, change, active) {
|
|
|
473
483
|
return text;
|
|
474
484
|
return replaceIdentifier(text, change.from, change.to);
|
|
475
485
|
}
|
|
476
|
-
function rewriteTableName(object, change, fromKey, toIdentity) {
|
|
477
|
-
const dependencies = retarget(object.dependencies, fromKey, toIdentity);
|
|
486
|
+
function rewriteTableName(object, change, fromKey, toIdentity, source) {
|
|
487
|
+
const dependencies = retarget(object.dependencies, fromKey, toIdentity, change);
|
|
478
488
|
const named = object.kind === "table" && object.identity.name === change.from && sameNamespace2(object.identity.namespace, change.namespace);
|
|
479
489
|
if (object.kind === "table") {
|
|
480
490
|
return table3({
|
|
@@ -579,9 +589,19 @@ function rewriteTableName(object, change, fromKey, toIdentity) {
|
|
|
579
589
|
});
|
|
580
590
|
return rewriteView(object, dependencies, rewriteExpr(object.definition.query, { from: change.from, to: change.to }, local));
|
|
581
591
|
}
|
|
582
|
-
if (object.kind === "role" || object.kind === "
|
|
592
|
+
if (object.kind === "role" || object.kind === "defaultPrivilege") {
|
|
583
593
|
return retargeted(object, dependencies);
|
|
584
594
|
}
|
|
595
|
+
if (object.kind === "grant") {
|
|
596
|
+
return grantObject({
|
|
597
|
+
role: object.identity.role,
|
|
598
|
+
object: movedGrantRef(object.identity.object, change, source),
|
|
599
|
+
privilege: object.identity.privilege,
|
|
600
|
+
owner: object.owner,
|
|
601
|
+
provenance: object.provenance,
|
|
602
|
+
dependencies
|
|
603
|
+
});
|
|
604
|
+
}
|
|
585
605
|
if (object.kind === "trigger") {
|
|
586
606
|
const parent = movedParent(object.identity.parent, change);
|
|
587
607
|
const local = parent.name !== object.identity.parent.name;
|
|
@@ -644,8 +664,46 @@ function rewriteSequence(object, dependencies) {
|
|
|
644
664
|
function renameList(names, from, to) {
|
|
645
665
|
return names.map((name) => name === from ? to : name);
|
|
646
666
|
}
|
|
647
|
-
function retarget(edges, fromKey, to) {
|
|
648
|
-
return edges.map((edge) =>
|
|
667
|
+
function retarget(edges, fromKey, to, change) {
|
|
668
|
+
return edges.map((edge) => {
|
|
669
|
+
if (identityKey2(edge.target) === fromKey)
|
|
670
|
+
return to;
|
|
671
|
+
if (change === undefined)
|
|
672
|
+
return edge.target;
|
|
673
|
+
return movedChild(edge.target, change);
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
function movedChild(target, change) {
|
|
677
|
+
if (!("parent" in target))
|
|
678
|
+
return target;
|
|
679
|
+
if (target.parent.name !== change.from || !sameNamespace2(target.parent.namespace, change.namespace)) {
|
|
680
|
+
return target;
|
|
681
|
+
}
|
|
682
|
+
return { ...target, parent: { namespace: target.parent.namespace, name: change.to } };
|
|
683
|
+
}
|
|
684
|
+
function movedGrantRef(object, change, source) {
|
|
685
|
+
if (object.kind === "table" && object.name === change.from && sameNamespace2(object.namespace, change.namespace)) {
|
|
686
|
+
return { ...object, name: change.to };
|
|
687
|
+
}
|
|
688
|
+
if (object.kind !== "sequence")
|
|
689
|
+
return object;
|
|
690
|
+
const next = renamedIdentitySequence(source, change, object.name);
|
|
691
|
+
if (next === undefined)
|
|
692
|
+
return object;
|
|
693
|
+
return { ...object, name: next };
|
|
694
|
+
}
|
|
695
|
+
function renamedIdentitySequence(source, change, sequenceName) {
|
|
696
|
+
for (const object of source.objects) {
|
|
697
|
+
if (object.kind !== "column" || object.definition.identity === undefined)
|
|
698
|
+
continue;
|
|
699
|
+
if (object.identity.parent.name !== change.from || !sameNamespace2(object.identity.parent.namespace, change.namespace)) {
|
|
700
|
+
continue;
|
|
701
|
+
}
|
|
702
|
+
if (fitIdentifier2(`${change.from}_${object.identity.name}_seq`) !== sequenceName)
|
|
703
|
+
continue;
|
|
704
|
+
return fitIdentifier2(`${change.to}_${object.identity.name}_seq`);
|
|
705
|
+
}
|
|
706
|
+
return;
|
|
649
707
|
}
|
|
650
708
|
function dependencyJson(edges) {
|
|
651
709
|
const indexed = edges.map((edge) => ({
|
|
@@ -1397,4 +1455,4 @@ function assertNeverKind(value) {
|
|
|
1397
1455
|
return catalogError2("OKM1020", `Unexpected kind ${JSON.stringify(value)}.`);
|
|
1398
1456
|
}
|
|
1399
1457
|
|
|
1400
|
-
export { roleObject, grantObject, defaultPrivilegeObject, creationOrder2, renameColumn2, renameTable2, serializeCatalog2, catalogHash2, loadTrustedCatalog2, parseCatalog2 };
|
|
1458
|
+
export { roleObject, grantObject, defaultPrivilegeObject, creationOrder2, renameColumn2, renameTable2, serializeCatalog2, catalogHash2, startupCatalog2, startupHash2, loadTrustedCatalog2, parseCatalog2 };
|
|
@@ -50,11 +50,39 @@ function sameExtensionDefinition(before, after) {
|
|
|
50
50
|
return false;
|
|
51
51
|
return sameVersion(before.definition.version, after.definition.version);
|
|
52
52
|
}
|
|
53
|
+
function alignExtensionVersions(source, other) {
|
|
54
|
+
const loose = looseNames(source, other);
|
|
55
|
+
if (loose.size === 0)
|
|
56
|
+
return source;
|
|
57
|
+
let changed = false;
|
|
58
|
+
const objects = source.objects.map((object) => {
|
|
59
|
+
if (object.kind !== "extension" || object.definition.version === undefined)
|
|
60
|
+
return object;
|
|
61
|
+
if (!loose.has(object.identity.name))
|
|
62
|
+
return object;
|
|
63
|
+
changed = true;
|
|
64
|
+
const { version: _version, ...definition } = object.definition;
|
|
65
|
+
return { ...object, definition };
|
|
66
|
+
});
|
|
67
|
+
return changed ? { version: source.version, objects } : source;
|
|
68
|
+
}
|
|
53
69
|
function sameVersion(before, after) {
|
|
54
70
|
if (!isExactVersion(after) || !isExactVersion(before))
|
|
55
71
|
return true;
|
|
56
72
|
return before === after;
|
|
57
73
|
}
|
|
74
|
+
function looseNames(source, other) {
|
|
75
|
+
const names = new Set;
|
|
76
|
+
for (const catalog of [source, other]) {
|
|
77
|
+
for (const object of catalog.objects) {
|
|
78
|
+
if (object.kind !== "extension")
|
|
79
|
+
continue;
|
|
80
|
+
if (!isExactVersion(object.definition.version))
|
|
81
|
+
names.add(object.identity.name);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return names;
|
|
85
|
+
}
|
|
58
86
|
function assertVersion(version) {
|
|
59
87
|
if (version === undefined)
|
|
60
88
|
return;
|
|
@@ -66,4 +94,4 @@ function parts(version) {
|
|
|
66
94
|
return version.split(".").map((part) => Number(part));
|
|
67
95
|
}
|
|
68
96
|
|
|
69
|
-
export { extensionObject, isExactVersion, compareExtensionVersions, sameExtensionDefinition };
|
|
97
|
+
export { extensionObject, isExactVersion, compareExtensionVersions, sameExtensionDefinition, alignExtensionVersions };
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
creationOrder2
|
|
3
|
+
} from "./8bwbwy8h.js";
|
|
1
4
|
import {
|
|
2
5
|
isDomain
|
|
3
|
-
} from "./
|
|
6
|
+
} from "./g7ez901n.js";
|
|
4
7
|
import {
|
|
5
8
|
quoteLiteral
|
|
6
9
|
} from "./94ez8kzh.js";
|
|
@@ -15,6 +18,61 @@ import {
|
|
|
15
18
|
function quoteIdent(name) {
|
|
16
19
|
return `"${name.replaceAll('"', '""')}"`;
|
|
17
20
|
}
|
|
21
|
+
function renderCatalog(source, schema) {
|
|
22
|
+
const folded = foldedKeys(source);
|
|
23
|
+
const statements = [];
|
|
24
|
+
const ordered = creationOrder2(source);
|
|
25
|
+
for (const object of ordered) {
|
|
26
|
+
if (object.kind !== "type" || object.owner === "ignored")
|
|
27
|
+
continue;
|
|
28
|
+
const sql = createObjectSql(object, schema);
|
|
29
|
+
if (sql !== undefined)
|
|
30
|
+
statements.push(sql);
|
|
31
|
+
}
|
|
32
|
+
for (const object of ordered) {
|
|
33
|
+
if (object.kind === "type" || object.kind === "function" || object.kind === "trigger" || object.kind === "view" || object.kind === "materializedView" || ownedByView(object)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (object.owner === "ignored")
|
|
37
|
+
continue;
|
|
38
|
+
const key = identityKey2(object.identity);
|
|
39
|
+
if (object.kind === "table") {
|
|
40
|
+
statements.push(createTableSql(object, source, schema));
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (folded.has(key))
|
|
44
|
+
continue;
|
|
45
|
+
const sql = createObjectSql(object, schema);
|
|
46
|
+
if (sql !== undefined)
|
|
47
|
+
statements.push(sql);
|
|
48
|
+
}
|
|
49
|
+
for (const kind of ["function", "trigger"]) {
|
|
50
|
+
for (const object of ordered) {
|
|
51
|
+
if (object.kind !== kind || object.owner === "ignored")
|
|
52
|
+
continue;
|
|
53
|
+
const sql = createObjectSql(object, schema);
|
|
54
|
+
if (sql !== undefined)
|
|
55
|
+
statements.push(sql);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
for (const kind of ["view", "materializedView"]) {
|
|
59
|
+
for (const object of ordered) {
|
|
60
|
+
if (object.kind !== kind || object.owner === "ignored")
|
|
61
|
+
continue;
|
|
62
|
+
const sql = createObjectSql(object, schema);
|
|
63
|
+
if (sql !== undefined)
|
|
64
|
+
statements.push(sql);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
for (const object of ordered) {
|
|
68
|
+
if (!ownedByView(object) || object.owner === "ignored")
|
|
69
|
+
continue;
|
|
70
|
+
const sql = createObjectSql(object, schema);
|
|
71
|
+
if (sql !== undefined)
|
|
72
|
+
statements.push(sql);
|
|
73
|
+
}
|
|
74
|
+
return statements;
|
|
75
|
+
}
|
|
18
76
|
function ownedByView(object) {
|
|
19
77
|
if (object.kind !== "index")
|
|
20
78
|
return false;
|
|
@@ -145,6 +203,20 @@ function identitySequence(sequence, source) {
|
|
|
145
203
|
return object.dependencies.some((edge) => identityKey2(edge.target) === key);
|
|
146
204
|
});
|
|
147
205
|
}
|
|
206
|
+
function foldedKeys(source) {
|
|
207
|
+
const keys = new Set;
|
|
208
|
+
for (const object of source.objects) {
|
|
209
|
+
if (object.kind === "column")
|
|
210
|
+
keys.add(identityKey2(object.identity));
|
|
211
|
+
if (object.kind === "constraint" && object.definition.constraintKind === "primaryKey") {
|
|
212
|
+
keys.add(identityKey2(object.identity));
|
|
213
|
+
}
|
|
214
|
+
if (object.kind === "sequence" && identitySequence(object, source)) {
|
|
215
|
+
keys.add(identityKey2(object.identity));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return keys;
|
|
219
|
+
}
|
|
148
220
|
function createTableSql(tableObject, source, schema) {
|
|
149
221
|
const parent = tableObject.identity.name;
|
|
150
222
|
const columns = source.objects.filter((object) => object.kind === "column" && object.identity.parent.name === parent);
|
|
@@ -243,4 +315,4 @@ function qualify(schema, name) {
|
|
|
243
315
|
return `${quoteIdent(schema)}.${quoteIdent(name)}`;
|
|
244
316
|
}
|
|
245
317
|
|
|
246
|
-
export { quoteIdent, ownedByView, dropObjectSql, createObjectSql, functionSql, viewSql, refreshMaterializedViewSql, alterColumnSql, identitySequence, createTableSql, qualify };
|
|
318
|
+
export { quoteIdent, renderCatalog, ownedByView, dropObjectSql, createObjectSql, functionSql, viewSql, refreshMaterializedViewSql, alterColumnSql, identitySequence, createTableSql, qualify };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
withHttp
|
|
3
|
-
} from "./
|
|
3
|
+
} from "./bt9sfq0z.js";
|
|
4
4
|
import {
|
|
5
5
|
decodeResult
|
|
6
|
-
} from "./
|
|
6
|
+
} from "./qgvt8nx1.js";
|
|
7
7
|
import {
|
|
8
8
|
OkmError2
|
|
9
9
|
} from "./52szzakm.js";
|
|
@@ -17,7 +17,7 @@ async function* streamRows(session, call, prepare, log) {
|
|
|
17
17
|
})));
|
|
18
18
|
}
|
|
19
19
|
const { plan, params } = await prepare();
|
|
20
|
-
const decode = plan.outputs.includes.length === 0 ? decodeResult : (await import("./
|
|
20
|
+
const decode = plan.outputs.includes.length === 0 ? decodeResult : (await import("./h8ne16fq.js")).decodeIncluded;
|
|
21
21
|
for await (const chunk of session.pool.stream(plan.text, params)) {
|
|
22
22
|
const decoded = decode(plan, chunk, call.table);
|
|
23
23
|
if (!Array.isArray(decoded))
|