okmodel 0.4.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.
Files changed (64) hide show
  1. package/README.md +86 -6
  2. package/dist/contracts/catalog/document.d.ts +20 -0
  3. package/dist/contracts/driver.d.ts +7 -0
  4. package/dist/dialects/pg/introspect.d.ts +6 -0
  5. package/dist/dialects/pg/role/sql.d.ts +10 -0
  6. package/dist/dialects/pg/schema.d.ts +15 -6
  7. package/dist/dialects/pg/view/index.d.ts +20 -6
  8. package/dist/dialects/pg/view/scratch.d.ts +2 -2
  9. package/dist/runtime/pg/bun.d.ts +12 -7
  10. package/dist/runtime/pg/bun.js +4 -1
  11. package/dist/runtime/pg/pg.d.ts +12 -6
  12. package/dist/runtime/pg/pg.js +4 -1
  13. package/dist/runtime/pg/pglite.d.ts +11 -3
  14. package/dist/runtime/pg/pglite.js +4 -1
  15. package/dist/runtime/pg/postgresjs.d.ts +12 -6
  16. package/dist/runtime/pg/postgresjs.js +4 -1
  17. package/dist/runtime/plan.d.ts +3 -1
  18. package/dist/runtime/tenancy/index.js +1 -1
  19. package/dist/runtime/topology.d.ts +191 -0
  20. package/dist/runtime/traits/index.js +6 -6
  21. package/dist/runtime/types.d.ts +57 -2
  22. package/dist/runtime/validate/index.js +1 -1
  23. package/dist/shared/{nxb42q7h.js → 47xzb9fc.js} +2 -2
  24. package/dist/shared/{6693j9rs.js → 5fqx9yh4.js} +6 -2
  25. package/dist/shared/{8jb4ymh2.js → 8bwbwy8h.js} +12 -1
  26. package/dist/shared/{41kv2xdm.js → 8xsbagad.js} +1 -1
  27. package/dist/shared/{sr5ms7b3.js → 922qbgnw.js} +3 -3
  28. package/dist/shared/{tny2t3sm.js → 990a291j.js} +4 -4
  29. package/dist/shared/{jns2wx4t.js → 9tgmr1gh.js} +1 -1
  30. package/dist/shared/{n5y9zyj1.js → ayz64vzj.js} +13 -12
  31. package/dist/shared/{kkzwp3d2.js → bt9sfq0z.js} +16 -14
  32. package/dist/shared/{c5g81ngb.js → bzsjtd7c.js} +7 -5
  33. package/dist/shared/{radd3z4g.js → ckjbyrt9.js} +1 -1
  34. package/dist/shared/{zg24x0hm.js → dxjp14rk.js} +10 -2
  35. package/dist/shared/{xghkt7a9.js → fancm5pt.js} +6 -233
  36. package/dist/shared/{yjw02enp.js → fyqkk1m0.js} +4 -4
  37. package/dist/shared/{ygem90rn.js → g516zdsb.js} +8 -3
  38. package/dist/shared/{v7tpnhnz.js → h4nqvjkp.js} +5 -3
  39. package/dist/shared/{edwqqryd.js → h8ne16fq.js} +1 -1
  40. package/dist/shared/{ady1ms74.js → jdgqqx31.js} +5 -5
  41. package/dist/shared/{kafaa5zv.js → k7cc9nzk.js} +24 -7
  42. package/dist/shared/{7nk68fj8.js → kdkxh3kb.js} +17 -10
  43. package/dist/shared/nkc9sfqb.js +1161 -0
  44. package/dist/shared/{awrsqrn7.js → p7pfx624.js} +2 -2
  45. package/dist/shared/{xrfnq5k8.js → qgvt8nx1.js} +11 -2
  46. package/dist/shared/{84ptn35q.js → qy9rdq0g.js} +6 -5
  47. package/dist/shared/{qn0srwwq.js → r6pj4fq2.js} +5 -3
  48. package/dist/shared/{2321avmn.js → r73pt594.js} +21 -13
  49. package/dist/shared/{kj680nxv.js → rasvvzgz.js} +8 -6
  50. package/dist/shared/{hcmdtwgh.js → szm0cksa.js} +4 -1
  51. package/dist/shared/{axhk06q1.js → tq9afp8d.js} +1 -1
  52. package/dist/shared/wxn4b7pp.js +252 -0
  53. package/dist/shared/{q6zsyh31.js → xdpj5kkm.js} +19 -8
  54. package/dist/shared/{s4mb6a4b.js → xhh1srw3.js} +54 -10
  55. package/dist/shared/{jgxzjzcz.js → xsq7v6wp.js} +2 -2
  56. package/dist/shared/{hqjsxnz7.js → ykv7wh5b.js} +5 -4
  57. package/dist/shared/{q795afwa.js → z2rnngj4.js} +3 -3
  58. package/dist/tooling/cli.js +12 -12
  59. package/dist/tooling/migrate/apply.d.ts +2 -0
  60. package/dist/tooling/migrate/files.d.ts +7 -0
  61. package/dist/tooling/migrate/index.js +8 -6
  62. package/dist/tooling/testing/facts.d.ts +3 -0
  63. package/dist/tooling/testing/index.js +3 -3
  64. package/package.json +1 -1
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Primary and replica endpoints (spec §15.1).
3
+ *
4
+ * Loaded only when `connect` is given a topology object. The string and pool
5
+ * paths do not import this module. An automatic read chooses among eligible
6
+ * replicas. One watermark on this handle covers the root, `for()`, `unscoped()`,
7
+ * `using()`, and `reserve()`.
8
+ */
9
+ import type { DriverPool, DriverTimeouts } from "../contracts/driver.js";
10
+ import type { QuerySchema } from "../dialects/pg/model.js";
11
+ import type { ConnectOptions, Connected } from "./types.js";
12
+ /** `"primary"` or `"replica"`. `using` and `route` accept only these. */
13
+ export type RouteName = "primary" | "replica";
14
+ /**
15
+ * One routing choice.
16
+ *
17
+ * `onRoute` receives this. `inspect()` does not, until the dev inspector (M2).
18
+ */
19
+ export type RouteEvent = {
20
+ /** What the statement was classified as. */
21
+ readonly op: "read" | "write" | "tx" | "lock";
22
+ /** Endpoint name. The primary is `"primary"`. */
23
+ readonly endpoint: string;
24
+ /**
25
+ * `primary-required`, `constraint:primary`, `constraint:replica`,
26
+ * `auto:<name>`, or `fallback:<no-replicas | unhealthy | position-unknown | saturated | behind>`.
27
+ */
28
+ readonly reason: string;
29
+ };
30
+ /**
31
+ * One replica passed to a custom `routing.select`.
32
+ *
33
+ * `lag` is the replica's byte lag, or `null` when the primary insert position
34
+ * or the replica replay position has not been seen. `latencyMs` stays `null`
35
+ * until a probe or a successful read has been timed.
36
+ */
37
+ export type ReplicaCandidate = {
38
+ /** Endpoint name. */
39
+ readonly name: string;
40
+ /** Configured weight. Zero and below are OKM1120 at connect. */
41
+ readonly weight: number;
42
+ /** In-flight statements this router is running on the replica. */
43
+ readonly inflight: number;
44
+ /** EWMA of observed round-trip time, in milliseconds, or `null`. */
45
+ readonly latencyMs: number | null;
46
+ /** Byte lag behind the primary, or `null` when either position is unknown. */
47
+ readonly lag: number | null;
48
+ };
49
+ /**
50
+ * A topology client.
51
+ *
52
+ * `using` returns a client that forces one route. That client has no `close`
53
+ * and no `using`. Only the root closes the pools.
54
+ */
55
+ export type RoutedClient<S extends QuerySchema> = Connected<S> & {
56
+ /**
57
+ * Forces later operations onto the primary or a replica.
58
+ *
59
+ * @param route - `"primary"` or `"replica"`
60
+ * @returns A client with no `close` and no `using`
61
+ */
62
+ using(route: RouteName): Omit<Connected<S>, "close">;
63
+ };
64
+ /**
65
+ * Replay position for one replica.
66
+ *
67
+ * Tests supply this over independent databases. The probe still runs `SELECT 1`
68
+ * on the replica's pool. The position does not come from a mocked driver.
69
+ */
70
+ export type ReplicaState = {
71
+ /**
72
+ * @param endpoint - The replica being probed
73
+ * @returns The replay LSN, or `null` when the replica has not replayed
74
+ */
75
+ replayLsn(endpoint: {
76
+ readonly name: string;
77
+ }): string | null | Promise<string | null>;
78
+ /**
79
+ * Replay timestamp for a time `maxLag`.
80
+ *
81
+ * Omitted, and with no seam, the probe reads `pg_last_xact_replay_timestamp()`
82
+ * only when `maxLag` is a duration.
83
+ *
84
+ * @param endpoint - The replica being probed
85
+ * @returns A timestamp, or `null` when the replica has not replayed a transaction
86
+ */
87
+ replayTime?(endpoint: {
88
+ readonly name: string;
89
+ }): Date | string | null | Promise<Date | string | null>;
90
+ };
91
+ /** One replica in `{ primary, replicas }`. A string is a URL with weight 1. */
92
+ export type ReplicaInput = {
93
+ readonly url: string;
94
+ readonly weight?: number;
95
+ readonly name?: string;
96
+ readonly pool?: {
97
+ readonly max?: number;
98
+ };
99
+ };
100
+ /** The first argument of `connect` when it is a topology. */
101
+ export type TopologyInput = {
102
+ readonly primary: string;
103
+ readonly replicas?: readonly (string | ReplicaInput)[];
104
+ };
105
+ /** Options only the topology module reads. */
106
+ export type TopologyOptions = {
107
+ /**
108
+ * Background probe interval. `"1s"` when omitted.
109
+ *
110
+ * `select` chooses among eligible replicas. The default is `"weighted"`.
111
+ * `consistency` is `"session"` (the default) or `"eventual"`. `maxLag` is a
112
+ * duration (`"5s"`, `"500ms"`, `"2m"`) or a size (`"16MB"`, `"512KB"`,
113
+ * `"1GB"`, `"4096B"`). `fallback` is `"primary"` (the default) or `"error"`.
114
+ */
115
+ readonly routing?: {
116
+ readonly probe?: string | number;
117
+ readonly select?: "weighted" | "roundRobin" | "leastConnections" | "latencyAware" | ((candidates: readonly ReplicaCandidate[], ctx: {
118
+ readonly op: "read";
119
+ }) => ReplicaCandidate | string);
120
+ readonly consistency?: "session" | "eventual";
121
+ readonly fallback?: "primary" | "error";
122
+ readonly maxLag?: string;
123
+ };
124
+ /**
125
+ * Called after an endpoint is chosen.
126
+ *
127
+ * A throw is swallowed. The operation still runs.
128
+ */
129
+ readonly onRoute?: (event: RouteEvent) => void;
130
+ /** Test seam for replay positions. Omitted, the probe reads `pg_last_wal_replay_lsn()`. */
131
+ readonly replicaState?: ReplicaState;
132
+ };
133
+ /** One endpoint after connect. Tests read this. It is not the query path. */
134
+ export type EndpointView = {
135
+ readonly name: string;
136
+ readonly role: "primary" | "replica";
137
+ readonly weight: number;
138
+ /** `max` passed to the driver. Absent when connect did not set one. */
139
+ readonly max: number | undefined;
140
+ /** Whether `replication.position` was detected on this endpoint. */
141
+ readonly position: boolean;
142
+ readonly circuit: "closed" | "open";
143
+ readonly failures: number;
144
+ readonly replayLsn: string | null;
145
+ /** Delay until the next probe. The primary is 0. */
146
+ readonly nextDelayMs: number;
147
+ };
148
+ /** The topology a client was built with. */
149
+ export type TopologyView = {
150
+ readonly endpoints: readonly EndpointView[];
151
+ };
152
+ /** Fields each driver's `open` may read. Extra keys are ignored by that driver. */
153
+ type EndpointConfig = {
154
+ readonly url: string;
155
+ readonly dataDir: string;
156
+ readonly max?: number;
157
+ readonly timeouts?: DriverTimeouts;
158
+ readonly prepared?: "named" | "unnamed";
159
+ readonly searchPath?: string;
160
+ readonly ssl?: unknown;
161
+ };
162
+ /** Opens one endpoint. postgres.js reads `url`. PGlite reads `dataDir`. */
163
+ export type EndpointOpen = (config: EndpointConfig) => DriverPool | Promise<DriverPool>;
164
+ /**
165
+ * Opens one pool per endpoint, detects `replication.position`, and starts replica probes.
166
+ *
167
+ * An automatic read runs the selection pipeline and `routing.select`.
168
+ * `close()` stops the probes and closes every pool this call opened,
169
+ * including clients from `using`.
170
+ *
171
+ * @param target - `{ primary, replicas }`
172
+ * @param options - Schema, pool default, probe interval, and the optional seam
173
+ * @param open - The driver's `open`
174
+ * @returns The client
175
+ */
176
+ export declare function connectTopology<S extends QuerySchema>(target: object, options: ConnectOptions<S> & TopologyOptions & {
177
+ readonly max?: number;
178
+ readonly prepared?: "named" | "unnamed";
179
+ readonly searchPath?: string;
180
+ readonly ssl?: unknown;
181
+ }, open: EndpointOpen): Promise<RoutedClient<S>>;
182
+ /**
183
+ * Reads the endpoints recorded for a client this module built.
184
+ *
185
+ * A string `connect` has no record. Routing does not call this.
186
+ *
187
+ * @param client - The value `connect` returned
188
+ * @returns The endpoints, or `undefined` when `client` is not a topology client
189
+ */
190
+ export declare function readTopology(client: object): TopologyView | undefined;
191
+ export default connectTopology;
@@ -1,4 +1,4 @@
1
- import"../../shared/8jb4ymh2.js";
1
+ import"../../shared/8bwbwy8h.js";
2
2
  import {
3
3
  checkPresetNames,
4
4
  duplicatePreset
@@ -8,7 +8,7 @@ import {
8
8
  } from "../../shared/n0dgs0pb.js";
9
9
  import {
10
10
  quoteIdent
11
- } from "../../shared/41kv2xdm.js";
11
+ } from "../../shared/8xsbagad.js";
12
12
  import {
13
13
  functionObject,
14
14
  triggerObject
@@ -38,10 +38,10 @@ import {
38
38
  queryHandle,
39
39
  attachHttp,
40
40
  settleCall
41
- } from "../../shared/kkzwp3d2.js";
41
+ } from "../../shared/bt9sfq0z.js";
42
42
  import {
43
43
  installArchiveInspect
44
- } from "../../shared/xrfnq5k8.js";
44
+ } from "../../shared/qgvt8nx1.js";
45
45
  import {
46
46
  fitIdentifier2
47
47
  } from "../../shared/nfzc5z0w.js";
@@ -58,7 +58,7 @@ function rewriteArchivable(self, tables, casing, schemaTraits, cascade) {
58
58
  const edges = foreignKeys(tables, casing, byName);
59
59
  const archiveSql = casing === "snake" ? "archived_at" : "archivedAt";
60
60
  const idSql = casing === "snake" ? "archive_id" : "archiveId";
61
- const predicate = `"${archiveSql.replaceAll('"', '""')}" is null`;
61
+ const predicate = casing === "snake" ? "(archived_at IS NULL)" : '("archivedAt" IS NULL)';
62
62
  return tables.map((item) => {
63
63
  if (!applies(self, item, schemaTraits))
64
64
  return item;
@@ -459,7 +459,7 @@ function refuse(host, table) {
459
459
  }
460
460
  var archiveMod;
461
461
  function loadArchive() {
462
- archiveMod ??= import("../../shared/radd3z4g.js");
462
+ archiveMod ??= import("../../shared/ckjbyrt9.js");
463
463
  return archiveMod;
464
464
  }
465
465
  async function settle(host, table, mods) {
@@ -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
  *
@@ -6,7 +6,7 @@ import {
6
6
  } from "../../shared/3p4b1fg0.js";
7
7
  import {
8
8
  queryHandle
9
- } from "../../shared/kkzwp3d2.js";
9
+ } from "../../shared/bt9sfq0z.js";
10
10
  import {
11
11
  OkmError2
12
12
  } from "../../shared/52szzakm.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  withHttp,
3
3
  attachHttp
4
- } from "./kkzwp3d2.js";
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("./q795afwa.js");
34
+ const { assertCompatible } = await import("./z2rnngj4.js");
35
35
  try {
36
36
  await assertCompatible(pool, schema, recorded, source, options);
37
37
  } catch (error) {
@@ -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 "./8jb4ymh2.js";
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
  };
@@ -229,6 +229,17 @@ function catalogHash2(source) {
229
229
  serializedHash.set(source, hash);
230
230
  return hash;
231
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
+ }
232
243
  function loadTrustedCatalog2(text, hash) {
233
244
  if (sha2562(text) !== hash) {
234
245
  catalogError2("OKM1027", "Catalog hash does not match the build artifact.");
@@ -1444,4 +1455,4 @@ function assertNeverKind(value) {
1444
1455
  return catalogError2("OKM1020", `Unexpected kind ${JSON.stringify(value)}.`);
1445
1456
  }
1446
1457
 
1447
- 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 };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  creationOrder2
3
- } from "./8jb4ymh2.js";
3
+ } from "./8bwbwy8h.js";
4
4
  import {
5
5
  isDomain
6
6
  } from "./g7ez901n.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  withHttp
3
- } from "./kkzwp3d2.js";
3
+ } from "./bt9sfq0z.js";
4
4
  import {
5
5
  decodeResult
6
- } from "./xrfnq5k8.js";
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("./edwqqryd.js")).decodeIncluded;
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))
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  open2
3
3
  } from "./wqem4jed.js";
4
- import"./8jb4ymh2.js";
4
+ import"./8bwbwy8h.js";
5
5
  import"./n442h54c.js";
6
6
  import {
7
7
  assertTargetPolicy,
8
8
  selectTarget,
9
9
  openProject
10
- } from "./q6zsyh31.js";
11
- import"./n5y9zyj1.js";
12
- import"./41kv2xdm.js";
10
+ } from "./xdpj5kkm.js";
11
+ import"./ayz64vzj.js";
12
+ import"./8xsbagad.js";
13
13
  import {
14
14
  isExactVersion,
15
15
  compareExtensionVersions
@@ -9,7 +9,7 @@ import {
9
9
  isRecord,
10
10
  registerFailFix,
11
11
  fail
12
- } from "./xrfnq5k8.js";
12
+ } from "./qgvt8nx1.js";
13
13
  import {
14
14
  throwNamed2
15
15
  } from "./52szzakm.js";
@@ -2,7 +2,7 @@ import {
2
2
  creationOrder2,
3
3
  renameColumn2,
4
4
  renameTable2
5
- } from "./8jb4ymh2.js";
5
+ } from "./8bwbwy8h.js";
6
6
  import {
7
7
  quoteIdent,
8
8
  ownedByView,
@@ -15,7 +15,7 @@ import {
15
15
  identitySequence,
16
16
  createTableSql,
17
17
  qualify
18
- } from "./41kv2xdm.js";
18
+ } from "./8xsbagad.js";
19
19
  import {
20
20
  isExactVersion,
21
21
  compareExtensionVersions,
@@ -122,7 +122,7 @@ function privilegeSql(before, after, schema, recreated = new Set) {
122
122
  revoke.push({ sql: grantStatement(object, schema, true), kind: "revoke" });
123
123
  }
124
124
  if (object.kind === "defaultPrivilege") {
125
- revoke.push({ sql: defaultStatement(object, true), kind: "revoke-default" });
125
+ revoke.push({ sql: defaultStatement(object, schema, true), kind: "revoke-default" });
126
126
  }
127
127
  }
128
128
  for (const [key, object] of afterBy) {
@@ -151,7 +151,7 @@ function privilegeSql(before, after, schema, recreated = new Set) {
151
151
  if (previous !== undefined)
152
152
  continue;
153
153
  if (object.kind === "defaultPrivilege") {
154
- defaults.push({ sql: defaultStatement(object, false), kind: "grant-default" });
154
+ defaults.push({ sql: defaultStatement(object, schema, false), kind: "grant-default" });
155
155
  }
156
156
  }
157
157
  return { revoke, prepare: [...roles, ...defaults], grant };
@@ -163,6 +163,9 @@ function createdRoleName(sql) {
163
163
  return quoted.replaceAll('""', '"');
164
164
  return match?.[2];
165
165
  }
166
+ function createRoleOnce(sql) {
167
+ return `do $okm$ begin ${sql}; exception when duplicate_object or unique_violation then null; end $okm$`;
168
+ }
166
169
  function changesRole(sql) {
167
170
  return /^\s*(create|alter)\s+role\b/i.test(sql);
168
171
  }
@@ -195,13 +198,12 @@ function grantStatement(object, schema, revoke) {
195
198
  const direction = revoke ? "from" : "to";
196
199
  return `${verb} ${privilege} on ${grantTarget(object.identity.object, schema)} ${direction} ${quoteIdent(object.identity.role)}`;
197
200
  }
198
- function defaultStatement(object, revoke) {
201
+ function defaultStatement(object, schema, revoke) {
199
202
  const privilege = object.identity.privilege.toLowerCase();
200
203
  assertPrivilege(privilege);
201
204
  const verb = revoke ? "revoke" : "grant";
202
205
  const direction = revoke ? "from" : "to";
203
- const namespace = object.identity.namespace.form === "static" ? object.identity.namespace.name : "public";
204
- return `alter default privileges for role ${quoteIdent(object.identity.forRole)} in schema ${quoteIdent(namespace)} ${verb} ${privilege} on ${objectKindSql(object.identity.objectKind)} ${direction} ${quoteIdent(object.identity.grantee)}`;
206
+ return `alter default privileges for role ${quoteIdent(object.identity.forRole)} in schema ${quoteIdent(schema)} ${verb} ${privilege} on ${objectKindSql(object.identity.objectKind)} ${direction} ${quoteIdent(object.identity.grantee)}`;
205
207
  }
206
208
  function grantTargetKey(object) {
207
209
  if (object.kind === "table" || object.kind === "view" || object.kind === "materializedView" || object.kind === "sequence") {
@@ -222,14 +224,13 @@ function grantTargetKey(object) {
222
224
  });
223
225
  }
224
226
  function grantTarget(object, schema) {
225
- const name = object.namespace.form === "static" ? object.namespace.name : schema;
226
227
  if (object.kind === "sequence")
227
- return `sequence ${qualify(name, object.name)}`;
228
+ return `sequence ${qualify(schema, object.name)}`;
228
229
  if (object.kind === "function")
229
- return functionTarget(object.name, name);
230
+ return functionTarget(object.name, schema);
230
231
  if (object.kind === "namespace")
231
232
  return `schema ${quoteIdent(object.name)}`;
232
- return `table ${qualify(name, object.name)}`;
233
+ return `table ${qualify(schema, object.name)}`;
233
234
  }
234
235
  function functionTarget(name, schema) {
235
236
  const open = name.lastIndexOf("(");
@@ -2428,4 +2429,4 @@ function order(value) {
2428
2429
  return value;
2429
2430
  }
2430
2431
 
2431
- export { canonicalTypeName, createdRoleName, changesRole, DEFAULT_BACKFILL_PAUSE_MS, DEFAULT_BACKFILL_STATEMENT_TIMEOUT_MS, batchSizeField, aboutBatchCount, boundaryQuery, checkedCast, classOf, strictestClass, assertExtensionsAvailable, omitManagedObjects, parseReplace, planMigration, formatPlan, parsePlan, staleRenames };
2432
+ export { canonicalTypeName, createdRoleName, createRoleOnce, changesRole, DEFAULT_BACKFILL_PAUSE_MS, DEFAULT_BACKFILL_STATEMENT_TIMEOUT_MS, batchSizeField, aboutBatchCount, boundaryQuery, checkedCast, classOf, strictestClass, assertExtensionsAvailable, omitManagedObjects, parseReplace, planMigration, formatPlan, parsePlan, staleRenames };
@@ -7,7 +7,7 @@ import {
7
7
  decodeResult,
8
8
  logicalIntent,
9
9
  appliedRules
10
- } from "./xrfnq5k8.js";
10
+ } from "./qgvt8nx1.js";
11
11
  import {
12
12
  OkmError2,
13
13
  safe2,
@@ -72,7 +72,7 @@ function openClient(session) {
72
72
  },
73
73
  close,
74
74
  connected: session.connected,
75
- tx: (...args) => import("./kafaa5zv.js").then((mod) => mod.tx(session, args)),
75
+ tx: (...args) => import("./k7cc9nzk.js").then((mod) => mod.tx(session, args)),
76
76
  batch: (ops, options) => batchHandle(session, ops, options),
77
77
  ...session.tx?.extras
78
78
  };
@@ -107,7 +107,7 @@ function tableApi(session, table, view, uses) {
107
107
  const api = {
108
108
  find(options = {}) {
109
109
  if ("lock" in options) {
110
- return lazyRead(session, () => import("./zg24x0hm.js"), table, options, base, view);
110
+ return lazyRead(session, () => import("./dxjp14rk.js"), table, options, base, view);
111
111
  }
112
112
  return start(session, "find", table, options, base, view);
113
113
  },
@@ -121,10 +121,10 @@ function tableApi(session, table, view, uses) {
121
121
  return start(session, "exists", table, options, base, view);
122
122
  },
123
123
  page(options) {
124
- return lazyRead(session, () => import("./v7tpnhnz.js"), table, options, base, view);
124
+ return lazyRead(session, () => import("./h4nqvjkp.js"), table, options, base, view);
125
125
  },
126
126
  aggregate(options = {}) {
127
- return lazyRead(session, () => import("./qn0srwwq.js"), table, options, base, view);
127
+ return lazyRead(session, () => import("./r6pj4fq2.js"), table, options, base, view);
128
128
  },
129
129
  insert(data, options = {}) {
130
130
  return writeHandle(session, "insert", table, data, options, mods);
@@ -154,13 +154,13 @@ function tableApi(session, table, view, uses) {
154
154
  return api;
155
155
  }
156
156
  function batchHandle(session, ops, options, replica) {
157
- return queryHandle(() => import("./jgxzjzcz.js").then((mod) => mod.batch(session, ops, options, replica)), {
157
+ return queryHandle(() => import("./xsq7v6wp.js").then((mod) => mod.batch(session, ops, options, replica)), {
158
158
  replica: () => batchHandle(session, ops, options, true)
159
159
  });
160
160
  }
161
161
  var writers;
162
162
  function loadWrite() {
163
- writers ??= import("./awrsqrn7.js");
163
+ writers ??= import("./p7pfx624.js");
164
164
  return writers;
165
165
  }
166
166
  function queryHandle(run, extra) {
@@ -245,7 +245,7 @@ function lazyRead(session, load, table, options, mods, view) {
245
245
  });
246
246
  }
247
247
  async function decodeRows(plan, rows, table) {
248
- return plan.outputs.includes.length === 0 ? decodeResult(plan, rows, table) : (await import("./edwqqryd.js")).decodeIncluded(plan, rows, table);
248
+ return plan.outputs.includes.length === 0 ? decodeResult(plan, rows, table) : (await import("./h8ne16fq.js")).decodeIncluded(plan, rows, table);
249
249
  }
250
250
  function readHandle(session, table, call, mods, decode, extra) {
251
251
  let prepared;
@@ -320,7 +320,7 @@ function readHandle(session, table, call, mods, decode, extra) {
320
320
  }
321
321
  function streamLazy(session, call, prepare) {
322
322
  return async function* () {
323
- const { streamRows } = await import("./sr5ms7b3.js");
323
+ const { streamRows } = await import("./922qbgnw.js");
324
324
  yield* streamRows(session, call, prepare, (error) => logged(session, error));
325
325
  }();
326
326
  }
@@ -357,7 +357,7 @@ function readCall(op, table, options, all, scope, model, schema, view) {
357
357
  };
358
358
  }
359
359
  async function checkServer(pool, schema, http, requireMeta, options, source) {
360
- const server = await import("./nxb42q7h.js");
360
+ const server = await import("./47xzb9fc.js");
361
361
  let rows;
362
362
  try {
363
363
  const result = await pool.execute(server.versionQuery, undefined, options);
@@ -386,7 +386,7 @@ function errorFields(error) {
386
386
  var includeHooks;
387
387
  var operatorSql;
388
388
  function loadOperatorSql() {
389
- operatorSql ??= import("./axhk06q1.js").then(() => {
389
+ operatorSql ??= import("./tq9afp8d.js").then(() => {
390
390
  return;
391
391
  });
392
392
  return operatorSql;
@@ -394,7 +394,7 @@ function loadOperatorSql() {
394
394
  function hooksFor(call) {
395
395
  if (call.include === undefined)
396
396
  return Promise.resolve(undefined);
397
- includeHooks ??= import("./edwqqryd.js").then((mod) => mod.includeHooks);
397
+ includeHooks ??= import("./h8ne16fq.js").then((mod) => mod.includeHooks);
398
398
  return includeHooks;
399
399
  }
400
400
  function bindNow(schema, call) {
@@ -426,11 +426,13 @@ function attachHttp(http, error) {
426
426
  }
427
427
  function callOptions(input, statement) {
428
428
  const timeout = input.timeout ?? statement;
429
- if (input.signal === undefined && timeout === undefined)
429
+ const route = input.route;
430
+ if (input.signal === undefined && timeout === undefined && route === undefined)
430
431
  return;
431
432
  return {
432
433
  ...input.signal !== undefined ? { signal: input.signal } : {},
433
- ...timeout !== undefined ? { timeout } : {}
434
+ ...timeout !== undefined ? { timeout } : {},
435
+ ...route !== undefined ? { route } : {}
434
436
  };
435
437
  }
436
438
  function mapOptions(http, includeValues) {