okmodel 0.9.0 → 0.9.1
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 +9 -1
- package/dist/adapters/pg/bunsql-extra.d.ts +5 -5
- package/dist/adapters/pg/bunsql.d.ts +6 -2
- package/dist/adapters/pg/nodepostgres.d.ts +16 -1
- package/dist/adapters/pg/postgres-extra.d.ts +3 -17
- package/dist/adapters/pg/postgresjs.d.ts +2 -1
- package/dist/contracts/driver.d.ts +3 -2
- package/dist/contracts/error.d.ts +1 -1
- package/dist/dialects/pg/errors.d.ts +2 -0
- package/dist/dialects/pg/ext/fuzzystrmatch.js +1 -1
- package/dist/dialects/pg/ext/hstore.js +1 -1
- package/dist/dialects/pg/ext/ltree.js +1 -1
- package/dist/dialects/pg/ext/pgcrypto.js +1 -1
- package/dist/dialects/pg/ext/unaccent.js +1 -1
- package/dist/dialects/pg/filters.d.ts +2 -2
- package/dist/dialects/pg/fn/index.js +1 -1
- package/dist/dialects/pg/index.js +3 -3
- package/dist/dialects/pg/introspect.d.ts +12 -0
- package/dist/dialects/pg/view/index.js +2 -2
- package/dist/runtime/param-limit.d.ts +20 -0
- package/dist/runtime/pg/bun.js +3 -3
- package/dist/runtime/pg/neon.js +3 -3
- package/dist/runtime/pg/pg.js +3 -3
- package/dist/runtime/pg/pglite.js +2 -2
- package/dist/runtime/pg/postgresjs.js +10 -10
- package/dist/runtime/tenancy/index.js +1 -1
- package/dist/runtime/traits/index.js +2 -2
- package/dist/runtime/validate/index.js +2 -2
- package/dist/runtime/write.d.ts +1 -1
- package/dist/shared/{5kyb3tqx.js → 1h5h1rf5.js} +1 -1
- package/dist/shared/{4vbf83xx.js → 2vcnpf0n.js} +1 -1
- package/dist/shared/{8n688yjg.js → 3ap5hxvj.js} +2 -1
- package/dist/shared/{wvtjg5m3.js → 3d7a80fq.js} +1 -1
- package/dist/shared/{bphrgwz9.js → 3dr444ny.js} +57 -78
- package/dist/shared/{yvabyg9k.js → 3vvpcphd.js} +7 -6
- package/dist/shared/{760ppr76.js → 4a3mmhhe.js} +2 -2
- package/dist/shared/{90sg0w5a.js → 4pkz5nvw.js} +65 -10
- package/dist/shared/{mazpbcdj.js → 4te76xc5.js} +1 -1
- package/dist/shared/{xwhdcrm4.js → 60y4ahmw.js} +1 -1
- package/dist/shared/{9dtgn1z2.js → 63qjmhnp.js} +100 -17
- package/dist/shared/{s7he5e5d.js → 67w3kn71.js} +1 -1
- package/dist/shared/{n306gqkd.js → 6vfvsdkt.js} +9 -7
- package/dist/shared/{jpybhf98.js → 6xqvesa5.js} +1 -1
- package/dist/shared/{n5whk3mt.js → 8gdbty5v.js} +8 -8
- package/dist/shared/{ccsmhv9r.js → 8ma6drzr.js} +194 -31
- package/dist/shared/{3456242y.js → 8p2bgye0.js} +110 -18
- package/dist/shared/{ebhz8vh6.js → 8qwqrxed.js} +11 -3
- package/dist/shared/{ss2kv2rs.js → 8v7vzpgt.js} +10 -7
- package/dist/shared/{8qzkd9f3.js → ak61ye1f.js} +3 -3
- package/dist/shared/{6nae0spm.js → bdekbvmt.js} +69 -7
- package/dist/shared/{tw1nvvfj.js → bxjq6xqv.js} +2 -2
- package/dist/shared/{rbxt795q.js → c7dqd3gk.js} +81 -41
- package/dist/shared/ddh72ym5.js +20 -0
- package/dist/shared/e1c55v04.js +10 -0
- package/dist/shared/{8jesqsrk.js → ekhq3ytz.js} +1 -1
- package/dist/shared/{7ba5h6pb.js → esy4dyxe.js} +5 -5
- package/dist/shared/{gcefca6p.js → f9t9g54z.js} +22 -9
- package/dist/shared/fkjne6gx.js +8 -0
- package/dist/shared/{ds229x4r.js → fne90dvz.js} +4 -1
- package/dist/shared/{cexb7z6b.js → gr9sn4za.js} +1 -1
- package/dist/shared/{mvmm3xpb.js → gzgfsspx.js} +1 -1
- package/dist/shared/{fdsz3w80.js → hgt69zjf.js} +2 -2
- package/dist/shared/{dd5pmnky.js → jvxcp1qk.js} +70 -86
- package/dist/shared/{yybhre6n.js → k73e8n9d.js} +3 -3
- package/dist/shared/{mgaq2sd3.js → kzgrcy8s.js} +8 -7
- package/dist/shared/{myk8fswx.js → mz48rs74.js} +14 -3
- package/dist/shared/{62b603gr.js → n6je5b28.js} +10 -23
- package/dist/shared/{2szgv6yj.js → ns35jqz0.js} +71 -45
- package/dist/shared/{xtsydxjg.js → nstwgzn8.js} +1 -1
- package/dist/shared/{stfa9xcw.js → py2zrrm6.js} +7 -6
- package/dist/shared/{9dr2qnx7.js → qqm3ze6q.js} +1 -1
- package/dist/shared/{cf8zdz5p.js → rcjm0yn7.js} +27 -34
- package/dist/shared/{ckz05z15.js → rged92v6.js} +7 -4
- package/dist/shared/{qvwwp1mp.js → rw4tpcd0.js} +30 -21
- package/dist/shared/{bsek72fg.js → s5qe47a6.js} +3 -0
- package/dist/shared/{1d9q9cv2.js → smxzjz60.js} +2 -2
- package/dist/shared/{c3mvnq7a.js → th5rnaxw.js} +1 -1
- package/dist/shared/{1mxm04fy.js → tyqapcgk.js} +71 -8
- package/dist/shared/{zdqf8k5d.js → vsna85qf.js} +1 -1
- package/dist/shared/{63qtkrca.js → vy47ryqa.js} +55 -5
- package/dist/shared/{xv8qj97g.js → wbdh9qbg.js} +3 -1
- package/dist/shared/{2zdxkt7b.js → wp7y8q3y.js} +41 -9
- package/dist/shared/{pg4ezgyf.js → xbd9xs6p.js} +2 -2
- package/dist/shared/{npdftanb.js → xbvz446k.js} +16 -13
- package/dist/shared/{aksb89mn.js → y6tfjk9q.js} +2 -2
- package/dist/shared/{3bb7wsqt.js → ycnft340.js} +1 -1
- package/dist/shared/{z7s6fpxv.js → ymenf259.js} +1 -1
- package/dist/shared/{71n0jmhc.js → ysdw2fg3.js} +10 -2
- package/dist/shared/{xqacq37x.js → zecrwdk9.js} +1 -1
- package/dist/shared/{3t6kw83m.js → zm2rzqba.js} +2 -1
- package/dist/tooling/cli.js +122 -44
- package/dist/tooling/driver-run.js +107 -24
- package/dist/tooling/github/comment.d.ts +8 -2
- package/dist/tooling/migrate/apply.d.ts +17 -2
- package/dist/tooling/migrate/drift.d.ts +12 -0
- package/dist/tooling/migrate/driver-url.d.ts +17 -0
- package/dist/tooling/migrate/index.js +9 -7
- package/dist/tooling/migrate/policy.d.ts +17 -5
- package/dist/tooling/migrate/pooler-probe.d.ts +23 -0
- package/dist/tooling/migrate/pull.d.ts +3 -0
- package/dist/tooling/migrate/runner.d.ts +24 -1
- package/dist/tooling/shared/{0j0jtse1.js → 09a6vsys.js} +1 -1
- package/dist/tooling/shared/{68tf18v4.js → 0v9ptnxp.js} +8 -8
- package/dist/tooling/shared/{qartgazh.js → 0wtzps9p.js} +6 -6
- package/dist/tooling/shared/{1800eymw.js → 0yhf1db4.js} +6 -6
- package/dist/tooling/shared/{s6qha57m.js → 19msgrsc.js} +2 -2
- package/dist/tooling/shared/{3yn79q5m.js → 1fwfm5m3.js} +1 -1
- package/dist/tooling/shared/{hfq3n3bd.js → 2jdn09e2.js} +55 -5
- package/dist/tooling/shared/{v6j1ep6w.js → 2qrte2ct.js} +5 -5
- package/dist/tooling/shared/{yb4kd19s.js → 2v4nwnkb.js} +1 -1
- package/dist/tooling/shared/{ezqn88nj.js → 33z39trp.js} +106 -23
- package/dist/tooling/shared/{0r05zhyq.js → 353vnw9z.js} +5 -5
- package/dist/tooling/shared/{m4hhb8aa.js → 390kry9g.js} +2 -2
- package/dist/tooling/shared/{rcywj2w8.js → 3f6etb9z.js} +18 -31
- package/dist/tooling/shared/{9wsnsvbf.js → 3t2cqmsx.js} +1 -1
- package/dist/tooling/shared/{5zrzffnk.js → 4dzvjtpy.js} +1 -1
- package/dist/tooling/shared/{am04v8na.js → 4ec0nxvw.js} +10 -10
- package/dist/tooling/shared/{04svnxxj.js → 4tg2bn41.js} +59 -78
- package/dist/tooling/shared/{829fjxyw.js → 5rah55z0.js} +2 -2
- package/dist/tooling/shared/{c0xevn1h.js → 804w1t69.js} +4 -4
- package/dist/tooling/shared/{dhatassp.js → 8g0m0rvd.js} +6 -6
- package/dist/tooling/shared/{zx3v9phv.js → 8msbtw5s.js} +1 -1
- package/dist/tooling/shared/{7pxncnzs.js → 8t22h3h7.js} +2 -2
- package/dist/tooling/shared/{wbwq1jsa.js → 91c59b7b.js} +2 -2
- package/dist/tooling/shared/{a2xe04bm.js → adk9k6va.js} +1 -1
- package/dist/tooling/shared/{w17sj05d.js → ajjd5cwz.js} +2 -2
- package/dist/tooling/shared/{35zemrmf.js → angjck01.js} +1 -1
- package/dist/tooling/shared/{jsjjz875.js → asnnc3v5.js} +1 -1
- package/dist/tooling/shared/{5bmksndh.js → bj1kyqc8.js} +2 -2
- package/dist/tooling/shared/{kbqnrs1x.js → bt3tjemb.js} +11 -3
- package/dist/tooling/shared/{vwr2y833.js → chk2bh4f.js} +2 -2
- package/dist/tooling/shared/{ybdew6j7.js → ckq4z5ax.js} +5 -2
- package/dist/tooling/shared/{3rmaz3pq.js → d3rhb24q.js} +1 -1
- package/dist/tooling/shared/{mw5npye0.js → d8q00vxg.js} +4 -4
- package/dist/tooling/shared/{j664qjrt.js → dx188rxs.js} +2 -2
- package/dist/tooling/shared/{8yr7ges1.js → efq6p9df.js} +35 -42
- package/dist/tooling/shared/{yhp829bx.js → en6rwzq0.js} +3 -3
- package/dist/tooling/shared/{f77nnfqy.js → f2r5g0fs.js} +2 -2
- package/dist/tooling/shared/{zs9aymcp.js → f4gep0nk.js} +1 -1
- package/dist/tooling/shared/{kz715295.js → f8a010fm.js} +13 -11
- package/dist/tooling/shared/{w5d89rb4.js → fdsek6pa.js} +1 -1
- package/dist/tooling/shared/fvmrxsd1.js +8 -0
- package/dist/tooling/shared/{jpgmjsx3.js → g3xybeqf.js} +4 -3
- package/dist/tooling/shared/{wezxf3h8.js → gefmpwsa.js} +1 -1
- package/dist/tooling/shared/{jr2nmr81.js → gjj71hfh.js} +23 -20
- package/dist/tooling/shared/{9sfbtwsk.js → jgzt69pa.js} +5 -5
- package/dist/tooling/shared/{a4pzghha.js → jm30k2ca.js} +10 -8
- package/dist/tooling/shared/{shjs0379.js → kayqzpbk.js} +6 -3
- package/dist/tooling/shared/{tcwpjvxe.js → kvw1672d.js} +1 -1
- package/dist/tooling/shared/{stebqyyd.js → mr1kcgpw.js} +3 -3
- package/dist/tooling/shared/{tpssp7ac.js → mwbdf409.js} +1 -1
- package/dist/tooling/shared/{fh07z1dt.js → ns9207v3.js} +1 -1
- package/dist/tooling/shared/{5p8km5jb.js → p6tjv97k.js} +3 -3
- package/dist/tooling/shared/{ytk1tjs0.js → p73evwf0.js} +1 -1
- package/dist/tooling/shared/{8m5znpdt.js → phc1nc4g.js} +1 -1
- package/dist/tooling/shared/{asgr07mp.js → ppybjw50.js} +79 -16
- package/dist/tooling/shared/{t4xveemq.js → qdrn8ghn.js} +5 -4
- package/dist/tooling/shared/rd8h01ta.js +20 -0
- package/dist/tooling/shared/{7aews1zg.js → rwg8y90m.js} +3 -3
- package/dist/tooling/shared/{5x3pf400.js → ry2f3w8p.js} +3 -3
- package/dist/tooling/shared/{m3xt8b1h.js → ryc5sa58.js} +8 -8
- package/dist/tooling/shared/{57btdkgm.js → ss87qxwv.js} +2 -2
- package/dist/tooling/shared/{6vk28rjp.js → vg68k11z.js} +3 -3
- package/dist/tooling/shared/{62fxpc1p.js → vms9dta5.js} +73 -89
- package/dist/tooling/shared/{gqwevek4.js → xchpnbdv.js} +1 -1
- package/dist/tooling/shared/{t6zjeake.js → xn6p01fh.js} +5 -5
- package/dist/tooling/shared/{7b3xp9gc.js → xwr6q618.js} +3 -3
- package/dist/tooling/shared/{yfedr1zb.js → xx3gmq94.js} +1 -1
- package/dist/tooling/shared/{9qr9rkbh.js → y2bd7yfx.js} +21 -13
- package/dist/tooling/shared/{nxq95eb6.js → y4gq9rbe.js} +11 -11
- package/dist/tooling/shared/{76pv6qff.js → y4vwft92.js} +2 -2
- package/dist/tooling/shared/{sjwkt1pg.js → yz68xcmc.js} +1 -1
- package/dist/tooling/testing/factories.d.ts +1 -3
- package/dist/tooling/testing/index.js +1 -1
- package/package.json +2 -1
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
NODE_POSTGRES_CAPABILITIES,
|
|
7
7
|
driverErrors,
|
|
8
8
|
rejectClosed,
|
|
9
|
+
rejectCancelled,
|
|
10
|
+
rejectTimedOut,
|
|
9
11
|
mapFailure,
|
|
10
12
|
runCall
|
|
11
13
|
} from "./mfvx6kjx.js";
|
|
@@ -14,10 +16,20 @@ import {
|
|
|
14
16
|
import net from "node:net";
|
|
15
17
|
import pg from "pg";
|
|
16
18
|
var CANCEL_CODE = 80877102;
|
|
19
|
+
var ABORT_GRACE_MS = 250;
|
|
17
20
|
var identity = (value) => value;
|
|
18
21
|
function armDriverError(source, handle = () => {}) {
|
|
19
22
|
source.on("error", handle);
|
|
20
23
|
}
|
|
24
|
+
function logClientError(notices, error) {
|
|
25
|
+
const message = error instanceof Error ? error.message : typeof error === "string" ? error : "client error";
|
|
26
|
+
const code = typeof error === "object" && error !== null && "code" in error ? Reflect.get(error, "code") : undefined;
|
|
27
|
+
notices.push({
|
|
28
|
+
severity: "ERROR",
|
|
29
|
+
message,
|
|
30
|
+
...typeof code === "string" && code.length > 0 ? { code } : {}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
21
33
|
var WIRE = {
|
|
22
34
|
getTypeParser() {
|
|
23
35
|
return identity;
|
|
@@ -25,7 +37,7 @@ var WIRE = {
|
|
|
25
37
|
};
|
|
26
38
|
function open4(config) {
|
|
27
39
|
const max = config.max ?? 10;
|
|
28
|
-
const acquireMs = config.timeouts?.acquire;
|
|
40
|
+
const acquireMs = config.timeouts?.acquire ?? 1e4;
|
|
29
41
|
const counters = { reserved: 0, busy: 0, reservedBusy: 0, waiting: 0 };
|
|
30
42
|
const inflight = new Set;
|
|
31
43
|
const notices = noticeBuffer();
|
|
@@ -43,11 +55,16 @@ function open4(config) {
|
|
|
43
55
|
...config.ssl !== undefined ? { ssl: config.ssl } : {},
|
|
44
56
|
...config.searchPath !== undefined ? { options: `-c search_path=${config.searchPath}` } : {}
|
|
45
57
|
});
|
|
46
|
-
armDriverError(pool)
|
|
58
|
+
armDriverError(pool, (error) => {
|
|
59
|
+
logClientError(notices, error);
|
|
60
|
+
});
|
|
47
61
|
pool.on("connect", (client) => {
|
|
48
62
|
client.on("notice", (notice) => {
|
|
49
63
|
notices.push(notice);
|
|
50
64
|
});
|
|
65
|
+
armDriverError(client, (error) => {
|
|
66
|
+
logClientError(notices, error);
|
|
67
|
+
});
|
|
51
68
|
});
|
|
52
69
|
const root = new WireSession((text, params) => send(pool, text, params, named, undefined), notices, isClosed, true, () => {
|
|
53
70
|
counters.busy += 1;
|
|
@@ -55,7 +72,7 @@ function open4(config) {
|
|
|
55
72
|
counters.busy = Math.max(0, counters.busy - 1);
|
|
56
73
|
}, inflight);
|
|
57
74
|
const held = { pool, acquireMs, counters, notices, named, isClosed };
|
|
58
|
-
const checkout = () => closed ? rejectClosed() : import("./
|
|
75
|
+
const checkout = () => closed ? rejectClosed() : import("./8qwqrxed.js").then((mod) => mod.checkout(held));
|
|
59
76
|
return {
|
|
60
77
|
capabilities: NODE_POSTGRES_CAPABILITIES,
|
|
61
78
|
execute(text, params, options) {
|
|
@@ -63,17 +80,31 @@ function open4(config) {
|
|
|
63
80
|
if (watch === undefined)
|
|
64
81
|
return root.query(text, params, undefined);
|
|
65
82
|
const client = await connectClient(pool, acquireMs, counters);
|
|
83
|
+
if (watch.signal.aborted) {
|
|
84
|
+
client.release();
|
|
85
|
+
return watch.reason() === "cancelled" ? rejectCancelled() : rejectTimedOut();
|
|
86
|
+
}
|
|
66
87
|
counters.busy += 1;
|
|
88
|
+
const slot = trackCheckout(client, () => {
|
|
89
|
+
counters.busy = Math.max(0, counters.busy - 1);
|
|
90
|
+
});
|
|
67
91
|
const session = new WireSession((statement, values) => send(client, statement, values, named, client), notices, isClosed, true, () => {
|
|
68
92
|
return;
|
|
69
93
|
}, () => {
|
|
70
94
|
return;
|
|
71
95
|
}, inflight);
|
|
96
|
+
const onAbort = () => {
|
|
97
|
+
slot.abandon();
|
|
98
|
+
};
|
|
99
|
+
if (watch.signal.aborted)
|
|
100
|
+
onAbort();
|
|
101
|
+
else
|
|
102
|
+
watch.signal.addEventListener("abort", onAbort, { once: true });
|
|
72
103
|
try {
|
|
73
104
|
return await session.query(text, params, watch);
|
|
74
105
|
} finally {
|
|
75
|
-
|
|
76
|
-
|
|
106
|
+
watch.signal.removeEventListener("abort", onAbort);
|
|
107
|
+
slot.release();
|
|
77
108
|
}
|
|
78
109
|
});
|
|
79
110
|
},
|
|
@@ -88,14 +119,14 @@ function open4(config) {
|
|
|
88
119
|
reserve: () => checkout(),
|
|
89
120
|
stream(text, params) {
|
|
90
121
|
return async function* () {
|
|
91
|
-
const { streamRows } = await import("./
|
|
122
|
+
const { streamRows } = await import("./8qwqrxed.js");
|
|
92
123
|
yield* streamRows(checkout, text, params);
|
|
93
124
|
}();
|
|
94
125
|
},
|
|
95
126
|
listen(channel, onNotify) {
|
|
96
127
|
if (closed)
|
|
97
128
|
return rejectClosed();
|
|
98
|
-
return import("./
|
|
129
|
+
return import("./8qwqrxed.js").then((mod) => mod.listen(held, channel, onNotify));
|
|
99
130
|
},
|
|
100
131
|
cancel() {
|
|
101
132
|
for (const pending of inflight)
|
|
@@ -149,6 +180,38 @@ function cancelBackend(client) {
|
|
|
149
180
|
socket.end(bytes);
|
|
150
181
|
});
|
|
151
182
|
}
|
|
183
|
+
function trackCheckout(client, done) {
|
|
184
|
+
let dead = false;
|
|
185
|
+
let released = false;
|
|
186
|
+
let grace;
|
|
187
|
+
const onError = () => {
|
|
188
|
+
dead = true;
|
|
189
|
+
};
|
|
190
|
+
const events = client;
|
|
191
|
+
events.on("error", onError);
|
|
192
|
+
const release = () => {
|
|
193
|
+
if (released)
|
|
194
|
+
return;
|
|
195
|
+
released = true;
|
|
196
|
+
if (grace !== undefined)
|
|
197
|
+
clearTimeout(grace);
|
|
198
|
+
events.removeListener("error", onError);
|
|
199
|
+
done();
|
|
200
|
+
client.release(dead ? true : undefined);
|
|
201
|
+
};
|
|
202
|
+
return {
|
|
203
|
+
abandon() {
|
|
204
|
+
if (released || grace !== undefined)
|
|
205
|
+
return;
|
|
206
|
+
grace = setTimeout(() => {
|
|
207
|
+
dead = true;
|
|
208
|
+
release();
|
|
209
|
+
}, ABORT_GRACE_MS);
|
|
210
|
+
grace.unref();
|
|
211
|
+
},
|
|
212
|
+
release
|
|
213
|
+
};
|
|
214
|
+
}
|
|
152
215
|
function connectClient(pool, acquireMs, counters) {
|
|
153
216
|
counters.waiting += 1;
|
|
154
217
|
let settled = false;
|
|
@@ -191,4 +254,4 @@ function statsOf(counters, size) {
|
|
|
191
254
|
};
|
|
192
255
|
}
|
|
193
256
|
|
|
194
|
-
export { armDriverError, open4, send, connectClient };
|
|
257
|
+
export { armDriverError, logClientError, open4, send, connectClient };
|
|
@@ -14,7 +14,7 @@ function mapPostgresError(error, options) {
|
|
|
14
14
|
return error;
|
|
15
15
|
if (!isDriverError(error))
|
|
16
16
|
return OkmError2.from(error);
|
|
17
|
-
const search = searchInputError(error);
|
|
17
|
+
const search = searchInputError(error, options);
|
|
18
18
|
if (search !== undefined)
|
|
19
19
|
return search;
|
|
20
20
|
const kind = kindOf(error);
|
|
@@ -23,6 +23,7 @@ function mapPostgresError(error, options) {
|
|
|
23
23
|
const fieldReason = hint?.reason ?? (kind === "not_null" ? "not_null" : reasonOf(kind, error.table, error.constraint, columns, options?.schema));
|
|
24
24
|
const values = options?.includeValues === true ? valuesOf(error.detail, columns) : undefined;
|
|
25
25
|
const code = kind === "outcome_unknown" ? "OKM1401" : kind;
|
|
26
|
+
const redactCause = options?.includeValues !== true && needsSafeCause(options?.schema, error.table, columns);
|
|
26
27
|
return new OkmError2(code, summaryOf(kind, error, columns, fieldReason), {
|
|
27
28
|
kind,
|
|
28
29
|
fieldReason,
|
|
@@ -32,11 +33,59 @@ function mapPostgresError(error, options) {
|
|
|
32
33
|
...error.constraint !== undefined ? { constraint: error.constraint } : {},
|
|
33
34
|
...error.sqlstate !== undefined ? { sqlstate: error.sqlstate } : {},
|
|
34
35
|
batchIndex: error.batchIndex,
|
|
35
|
-
cause: error.cause ?? error,
|
|
36
|
+
cause: redactCause ? safeCause(error) : error.cause ?? error,
|
|
36
37
|
...options?.includeValues === true && values !== undefined ? { includeValues: true, values } : {},
|
|
37
38
|
...options?.http !== undefined ? { http: options.http } : {}
|
|
38
39
|
});
|
|
39
40
|
}
|
|
41
|
+
function needsSafeCause(schema, table, columns) {
|
|
42
|
+
if (schema === undefined)
|
|
43
|
+
return false;
|
|
44
|
+
const model = modelForTable(schema, table);
|
|
45
|
+
if (model !== undefined && model.columns.some((column) => column.sensitive === true)) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
if (columns.length === 0)
|
|
49
|
+
return false;
|
|
50
|
+
for (const item of Object.values(schema.model)) {
|
|
51
|
+
for (const column of item.columns) {
|
|
52
|
+
if (column.sensitive !== true)
|
|
53
|
+
continue;
|
|
54
|
+
for (const name of columns) {
|
|
55
|
+
if (column.sql === name || column.field === name)
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
function safeCause(error) {
|
|
63
|
+
const out = { name: "DriverError" };
|
|
64
|
+
if (error.sqlstate !== undefined)
|
|
65
|
+
out.sqlstate = error.sqlstate;
|
|
66
|
+
if (error.constraint !== undefined)
|
|
67
|
+
out.constraint = error.constraint;
|
|
68
|
+
if (error.table !== undefined)
|
|
69
|
+
out.table = error.table;
|
|
70
|
+
if (error.column !== undefined)
|
|
71
|
+
out.column = error.column;
|
|
72
|
+
const nested = error.cause;
|
|
73
|
+
if (typeof nested === "object" && nested !== null) {
|
|
74
|
+
const code = Reflect.get(nested, "code");
|
|
75
|
+
if (typeof code === "string" && code.length > 0 && code.length <= 64)
|
|
76
|
+
out.code = code;
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
function modelForTable(schema, table) {
|
|
81
|
+
if (table === undefined)
|
|
82
|
+
return;
|
|
83
|
+
for (const item of Object.values(schema.model)) {
|
|
84
|
+
if (item.sql === table)
|
|
85
|
+
return item;
|
|
86
|
+
}
|
|
87
|
+
return schema.model[table];
|
|
88
|
+
}
|
|
40
89
|
var TLS_CODE = /^(ERR_TLS_|ERR_POSTGRES_TLS_|SELF_SIGNED_CERT_|DEPTH_ZERO_SELF_SIGNED_CERT$|UNABLE_TO_VERIFY_LEAF_SIGNATURE$)/;
|
|
41
90
|
function isTlsFailure(error) {
|
|
42
91
|
const cause = error.cause;
|
|
@@ -55,14 +104,15 @@ function searchQuery(error) {
|
|
|
55
104
|
const query = Reflect.get(cause, "query");
|
|
56
105
|
return typeof query === "string" && query.includes("to_tsquery");
|
|
57
106
|
}
|
|
58
|
-
function searchInputError(error) {
|
|
107
|
+
function searchInputError(error, options) {
|
|
59
108
|
const sqlstate = error.sqlstate;
|
|
60
109
|
const message = error.message;
|
|
110
|
+
const cause = options?.includeValues !== true && needsSafeCause(options?.schema, error.table, columnsOf(error)) ? safeCause(error) : error.cause ?? error;
|
|
61
111
|
if (sqlstate === "42601" && (message.includes("tsquery") || searchQuery(error))) {
|
|
62
112
|
return new OkmError2("OKM1120", `Search input is not valid. ${stripRowValues(message)}`, {
|
|
63
113
|
kind: "invalid",
|
|
64
114
|
sqlstate,
|
|
65
|
-
cause
|
|
115
|
+
cause,
|
|
66
116
|
fix: { summary: "Fix the advanced search text, or use natural, all-words, or phrase." }
|
|
67
117
|
});
|
|
68
118
|
}
|
|
@@ -70,7 +120,7 @@ function searchInputError(error) {
|
|
|
70
120
|
return new OkmError2("OKM1122", stripRowValues(message), {
|
|
71
121
|
kind: "invalid",
|
|
72
122
|
sqlstate,
|
|
73
|
-
cause
|
|
123
|
+
cause,
|
|
74
124
|
fix: {
|
|
75
125
|
summary: "Use a text search configuration that exists, such as english, or omit language."
|
|
76
126
|
}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
connectClient2,
|
|
6
6
|
send3
|
|
7
|
-
} from "./
|
|
7
|
+
} from "./4te76xc5.js";
|
|
8
8
|
import {
|
|
9
9
|
resetSession2
|
|
10
10
|
} from "./99qp9vtg.js";
|
|
@@ -80,6 +80,8 @@ async function checkout(held) {
|
|
|
80
80
|
try {
|
|
81
81
|
if (!lost)
|
|
82
82
|
await reset(session, client);
|
|
83
|
+
} catch {
|
|
84
|
+
lost = true;
|
|
83
85
|
} finally {
|
|
84
86
|
counters.reserved = Math.max(0, counters.reserved - 1);
|
|
85
87
|
events.removeListener("error", onError);
|
|
@@ -18,8 +18,9 @@ import {
|
|
|
18
18
|
} from "./n442h54c.js";
|
|
19
19
|
import {
|
|
20
20
|
open2
|
|
21
|
-
} from "./
|
|
21
|
+
} from "./jvxcp1qk.js";
|
|
22
22
|
import {
|
|
23
|
+
driverUrl,
|
|
23
24
|
sqlStatements,
|
|
24
25
|
transactionControl,
|
|
25
26
|
canonicalTypeName,
|
|
@@ -39,7 +40,7 @@ import {
|
|
|
39
40
|
assertTargetAlias,
|
|
40
41
|
listTargets,
|
|
41
42
|
selectTarget
|
|
42
|
-
} from "./
|
|
43
|
+
} from "./bdekbvmt.js";
|
|
43
44
|
import {
|
|
44
45
|
contributedFields
|
|
45
46
|
} from "./n0dgs0pb.js";
|
|
@@ -58,7 +59,7 @@ import {
|
|
|
58
59
|
import {
|
|
59
60
|
snakeCase,
|
|
60
61
|
emittedTypeName
|
|
61
|
-
} from "./
|
|
62
|
+
} from "./f9t9g54z.js";
|
|
62
63
|
import {
|
|
63
64
|
ColumnBuilder2
|
|
64
65
|
} from "./606g0nbf.js";
|
|
@@ -182,7 +183,12 @@ async function assertLiveExternal(url, source, snapshots) {
|
|
|
182
183
|
if (snapshots.length === 0 && externalTables(source).length === 0)
|
|
183
184
|
return;
|
|
184
185
|
const postgres = (await import("postgres")).default;
|
|
185
|
-
const sql = postgres(url, {
|
|
186
|
+
const sql = postgres(driverUrl(url), {
|
|
187
|
+
max: 1,
|
|
188
|
+
connect_timeout: 5,
|
|
189
|
+
idle_timeout: 1,
|
|
190
|
+
onnotice: () => {}
|
|
191
|
+
});
|
|
186
192
|
try {
|
|
187
193
|
const current = await sql`select current_database() as name`;
|
|
188
194
|
const database = current[0]?.name;
|
|
@@ -581,7 +587,7 @@ var ERROR_DOCS = [
|
|
|
581
587
|
{
|
|
582
588
|
code: "OKM1120",
|
|
583
589
|
title: "Unknown field",
|
|
584
|
-
summary: "The name is not a field or an option. timeout and signal go in the second argument of update. Options go first: tx(options, fn).",
|
|
590
|
+
summary: "The name is not a field or an option on a write, read, or update. An unknown key on insert, update, upsert, or first-or-create is refused and names the key and the table. timeout and signal go in the second argument of update. Options go first: tx(options, fn).",
|
|
585
591
|
fix: "Use a field from the catalog, or move the option. The error includes a nearest-name hint when one is close."
|
|
586
592
|
},
|
|
587
593
|
{
|
|
@@ -611,8 +617,14 @@ var ERROR_DOCS = [
|
|
|
611
617
|
{
|
|
612
618
|
code: "OKM1125",
|
|
613
619
|
title: "Bad SQL fragment",
|
|
614
|
-
summary: "A composed fragment is empty, unbalanced, or interpolates a value it cannot bind. A select fragment that is not a number is the same code.",
|
|
615
|
-
fix: "Interpolate a string, number, boolean, null, ident(name), fragment.column, or another fragment. Keep parentheses and quotes balanced. A select fragment is a numeric expression named with as()."
|
|
620
|
+
summary: "A composed fragment is empty, unbalanced, includes a backslash, or interpolates a value it cannot bind. A select fragment that is not a number is the same code.",
|
|
621
|
+
fix: "Interpolate a string, number, boolean, null, ident(name), fragment.column, or another fragment. Keep parentheses and quotes balanced. Pass a value that needs a backslash as an interpolation. A select fragment is a numeric expression named with as()."
|
|
622
|
+
},
|
|
623
|
+
{
|
|
624
|
+
code: "OKM1126",
|
|
625
|
+
title: "Parameter limit",
|
|
626
|
+
summary: "The finished statement has more than 65,535 parameters. The limit is for the whole statement (filters, inList, limit, values), not for inList alone.",
|
|
627
|
+
fix: "Chunk the work, or filter with = any(array) instead of a long inList."
|
|
616
628
|
},
|
|
617
629
|
{
|
|
618
630
|
code: "OKM1130",
|
|
@@ -1578,10 +1590,30 @@ function foreignKeyWithoutNotValid(input) {
|
|
|
1578
1590
|
function validatingCheck(input) {
|
|
1579
1591
|
if (widenValidate(input))
|
|
1580
1592
|
return false;
|
|
1593
|
+
if (notNullFloorValidate(input))
|
|
1594
|
+
return false;
|
|
1581
1595
|
if (validates(input, "check"))
|
|
1582
1596
|
return true;
|
|
1583
1597
|
return checkWithoutNotValid(input);
|
|
1584
1598
|
}
|
|
1599
|
+
function notNullFloorValidate(input) {
|
|
1600
|
+
const text = normalizedSql(input.step.sql);
|
|
1601
|
+
const name = /^alter table\s+(\S+)\s+validate constraint\s+(\S+)/.exec(text);
|
|
1602
|
+
if (name === null)
|
|
1603
|
+
return false;
|
|
1604
|
+
const table = name[1];
|
|
1605
|
+
const constraint = name[2];
|
|
1606
|
+
if (table === undefined || constraint === undefined)
|
|
1607
|
+
return false;
|
|
1608
|
+
return input.earlier.some((step) => {
|
|
1609
|
+
const prior = normalizedSql(step.sql);
|
|
1610
|
+
if (!prior.startsWith(`alter table ${table} `))
|
|
1611
|
+
return false;
|
|
1612
|
+
if (!prior.includes(`add constraint ${constraint} `))
|
|
1613
|
+
return false;
|
|
1614
|
+
return /check\s*\(\s*\S+\s+is not null\s*\)\s*not valid/.test(prior);
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1585
1617
|
function widenValidate(input) {
|
|
1586
1618
|
const text = normalizedSql(input.step.sql);
|
|
1587
1619
|
if (!/^alter table\s+\S+\s+validate constraint\b/.test(text))
|
|
@@ -2910,7 +2942,7 @@ var ESTIMATE_SQL = `
|
|
|
2910
2942
|
and c.relkind in ('r', 'p', 'f', 'm')
|
|
2911
2943
|
`;
|
|
2912
2944
|
async function readRowEstimates(url, schema, tables) {
|
|
2913
|
-
const pool = open2({ url, max: 1 });
|
|
2945
|
+
const pool = open2({ url: driverUrl(url), max: 1 });
|
|
2914
2946
|
try {
|
|
2915
2947
|
const connection = await pool.reserve?.();
|
|
2916
2948
|
if (connection === undefined) {
|
|
@@ -3182,7 +3214,7 @@ async function checkProject(cwd, flags) {
|
|
|
3182
3214
|
const target = selectTarget(opened.config, named);
|
|
3183
3215
|
assertTargetPolicy(target, "check", flags?.allowProtected ?? false);
|
|
3184
3216
|
assertTargetPolicy(target, "drift", flags?.allowProtected ?? false);
|
|
3185
|
-
const { assertAuthorDrift } = await import("./
|
|
3217
|
+
const { assertAuthorDrift } = await import("./rged92v6.js");
|
|
3186
3218
|
const allowPooler = flags?.allowPooler === true || opened.config.allowPooler === true;
|
|
3187
3219
|
await assertLiveExternal(target.url, opened.built.catalog, loadSnapshots(cwd, opened.config));
|
|
3188
3220
|
await assertAuthorDrift(target.url, opened.built.catalog, opened.config.roles, allowPooler);
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
artifactDir,
|
|
6
6
|
readText
|
|
7
|
-
} from "./
|
|
7
|
+
} from "./k73e8n9d.js";
|
|
8
8
|
import {
|
|
9
9
|
OkmError2
|
|
10
10
|
} from "./52szzakm.js";
|
|
@@ -36,7 +36,7 @@ async function assertCompatible(pool, schema, recordedHash, source, options, nam
|
|
|
36
36
|
loadTrustedCatalog(text, code.hash);
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
|
-
const { assertDrift } = await import("./
|
|
39
|
+
const { assertDrift } = await import("./gzgfsspx.js");
|
|
40
40
|
await assertDrift(pool, code.hash, recordedHash, options, namespace);
|
|
41
41
|
}
|
|
42
42
|
async function codeHash(schema, source) {
|
|
@@ -86,7 +86,7 @@ function openClient(session) {
|
|
|
86
86
|
},
|
|
87
87
|
close,
|
|
88
88
|
connected: session.connected,
|
|
89
|
-
tx: (...args) => import("./
|
|
89
|
+
tx: (...args) => import("./3d7a80fq.js").then((mod) => mod.tx(session, args)),
|
|
90
90
|
batch: (ops, options) => batchHandle(session, ops, options),
|
|
91
91
|
...session.tx?.extras
|
|
92
92
|
};
|
|
@@ -121,7 +121,7 @@ function tableApi(session, table, view, uses) {
|
|
|
121
121
|
const api = {
|
|
122
122
|
find(options = {}) {
|
|
123
123
|
if ("lock" in options) {
|
|
124
|
-
return lazyRead(session, () => import("./
|
|
124
|
+
return lazyRead(session, () => import("./ekhq3ytz.js"), table, options, base, view);
|
|
125
125
|
}
|
|
126
126
|
return start(session, "find", table, options, base, view);
|
|
127
127
|
},
|
|
@@ -135,10 +135,10 @@ function tableApi(session, table, view, uses) {
|
|
|
135
135
|
return start(session, "exists", table, options, base, view);
|
|
136
136
|
},
|
|
137
137
|
page(options) {
|
|
138
|
-
return lazyRead(session, () => import("./
|
|
138
|
+
return lazyRead(session, () => import("./1h5h1rf5.js"), table, options, base, view);
|
|
139
139
|
},
|
|
140
140
|
aggregate(options = {}) {
|
|
141
|
-
return lazyRead(session, () => import("./
|
|
141
|
+
return lazyRead(session, () => import("./nstwgzn8.js"), table, options, base, view);
|
|
142
142
|
},
|
|
143
143
|
insert(data, options = {}) {
|
|
144
144
|
return writeHandle(session, "insert", table, data, options, mods);
|
|
@@ -151,9 +151,9 @@ function tableApi(session, table, view, uses) {
|
|
|
151
151
|
}
|
|
152
152
|
};
|
|
153
153
|
for (const walk of ["descendants", "ancestors"]) {
|
|
154
|
-
api[walk] = (id, options) => lazyRead(session, () => import("./
|
|
154
|
+
api[walk] = (id, options) => lazyRead(session, () => import("./th5rnaxw.js"), table, { id, walk, options }, base, view);
|
|
155
155
|
}
|
|
156
|
-
api.sync = (id, relation, ids, options) => lazyRead(session, () => import("./
|
|
156
|
+
api.sync = (id, relation, ids, options) => lazyRead(session, () => import("./y6tfjk9q.js"), table, { id, relation, ids, options }, base, view, true);
|
|
157
157
|
const hooks = session.schema.hooks;
|
|
158
158
|
if (hooks !== undefined) {
|
|
159
159
|
for (const hook of hooks) {
|
|
@@ -173,13 +173,13 @@ function tableApi(session, table, view, uses) {
|
|
|
173
173
|
return api;
|
|
174
174
|
}
|
|
175
175
|
function batchHandle(session, ops, options, replica) {
|
|
176
|
-
return queryHandle(() => import("./
|
|
176
|
+
return queryHandle(() => import("./fne90dvz.js").then((mod) => mod.batch(session, ops, options, replica)), {
|
|
177
177
|
replica: () => batchHandle(session, ops, options, true)
|
|
178
178
|
});
|
|
179
179
|
}
|
|
180
180
|
var writers;
|
|
181
181
|
function loadWrite() {
|
|
182
|
-
writers ??= import("./
|
|
182
|
+
writers ??= import("./3ap5hxvj.js");
|
|
183
183
|
return writers;
|
|
184
184
|
}
|
|
185
185
|
function queryHandle(run, extra) {
|
|
@@ -309,7 +309,7 @@ function readHandle(session, table, call, mods, decode, extra) {
|
|
|
309
309
|
await loadOperatorSql();
|
|
310
310
|
}
|
|
311
311
|
if (call.build === undefined && selectHasWindow(call.select)) {
|
|
312
|
-
call = (await import("./
|
|
312
|
+
call = (await import("./smxzjz60.js")).attach(session.schema, call);
|
|
313
313
|
}
|
|
314
314
|
const bound = bindCall(session.schema, call, hooks);
|
|
315
315
|
let plan = session.cache.get(bound.key);
|
|
@@ -329,6 +329,9 @@ function readHandle(session, table, call, mods, decode, extra) {
|
|
|
329
329
|
const run = async () => {
|
|
330
330
|
await session.connected;
|
|
331
331
|
const { plan, params } = await prepare();
|
|
332
|
+
if (params.length > 65535) {
|
|
333
|
+
(await import("./fkjne6gx.js")).refuseParamLimit(params.length);
|
|
334
|
+
}
|
|
332
335
|
try {
|
|
333
336
|
const result = await session.pool.execute(plan.text, params, callOptions(call, session.timeouts?.statement));
|
|
334
337
|
if (session.hookm && result.notices.length) {
|
|
@@ -372,7 +375,7 @@ function readHandle(session, table, call, mods, decode, extra) {
|
|
|
372
375
|
}
|
|
373
376
|
function streamLazy(session, call, mods, view, batch) {
|
|
374
377
|
return async function* () {
|
|
375
|
-
const { streamRows } = await import("./
|
|
378
|
+
const { streamRows } = await import("./bxjq6xqv.js");
|
|
376
379
|
yield* streamRows(session, call, mods, view, batch, (error) => logged(session, error));
|
|
377
380
|
}();
|
|
378
381
|
}
|
|
@@ -405,14 +408,14 @@ function readCall(op, table, options, all, scope, model, schema, view) {
|
|
|
405
408
|
};
|
|
406
409
|
}
|
|
407
410
|
async function checkServer(pool, schema, http, requireMeta, options, source) {
|
|
408
|
-
const { acceptServer } = await import("./
|
|
411
|
+
const { acceptServer } = await import("./vsna85qf.js");
|
|
409
412
|
await acceptServer(pool, schema, http, requireMeta, options, source);
|
|
410
413
|
}
|
|
411
414
|
async function mapError(session, error) {
|
|
412
415
|
if (error instanceof OkmError2) {
|
|
413
416
|
return session.http === undefined ? error : new OkmError2(error.code, error.message, { ...errorFields(error), http: session.http });
|
|
414
417
|
}
|
|
415
|
-
const { mapPostgresError } = await import("./
|
|
418
|
+
const { mapPostgresError } = await import("./vy47ryqa.js");
|
|
416
419
|
return mapPostgresError(error, mapOptions(session.http, session.includeValues, session.schema));
|
|
417
420
|
}
|
|
418
421
|
function errorFields(error) {
|
|
@@ -426,7 +429,7 @@ function errorFields(error) {
|
|
|
426
429
|
var includeHooks;
|
|
427
430
|
var operatorSql;
|
|
428
431
|
function loadOperatorSql() {
|
|
429
|
-
operatorSql ??= import("./
|
|
432
|
+
operatorSql ??= import("./2vcnpf0n.js").then(() => {
|
|
430
433
|
return;
|
|
431
434
|
});
|
|
432
435
|
return operatorSql;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
identityColumn2
|
|
3
|
-
} from "./
|
|
3
|
+
} from "./67w3kn71.js";
|
|
4
4
|
import {
|
|
5
5
|
runWrite
|
|
6
6
|
} from "./n4jqhpqz.js";
|
|
7
7
|
import {
|
|
8
8
|
queryHandle,
|
|
9
9
|
settleCall
|
|
10
|
-
} from "./
|
|
10
|
+
} from "./xbvz446k.js";
|
|
11
11
|
import {
|
|
12
12
|
withRowFilters,
|
|
13
13
|
archiveRules,
|
|
@@ -39,7 +39,7 @@ async function refreshView(session, name, concurrently) {
|
|
|
39
39
|
throw error;
|
|
40
40
|
}
|
|
41
41
|
} catch (error) {
|
|
42
|
-
const { mapPostgresError } = await import("./
|
|
42
|
+
const { mapPostgresError } = await import("./vy47ryqa.js");
|
|
43
43
|
const mapped = mapPostgresError(error, {
|
|
44
44
|
...host.http !== undefined ? { http: host.http } : {},
|
|
45
45
|
...host.includeValues === true ? { includeValues: true } : {},
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./cnkky55j.js";
|
|
5
5
|
import {
|
|
6
6
|
createClient
|
|
7
|
-
} from "./
|
|
7
|
+
} from "./xbvz446k.js";
|
|
8
8
|
import {
|
|
9
9
|
OkmError2
|
|
10
10
|
} from "./52szzakm.js";
|
|
@@ -1168,7 +1168,15 @@ function fromSelect(handle, select, candidates) {
|
|
|
1168
1168
|
lag: byteLagNumber(handle, endpoint)
|
|
1169
1169
|
});
|
|
1170
1170
|
}
|
|
1171
|
-
|
|
1171
|
+
let returned;
|
|
1172
|
+
try {
|
|
1173
|
+
returned = select(offered, { op: "read" });
|
|
1174
|
+
} catch (error) {
|
|
1175
|
+
if (error instanceof OkmError2)
|
|
1176
|
+
throw error;
|
|
1177
|
+
const message = error instanceof Error ? error.message : "routing.select threw.";
|
|
1178
|
+
throw new OkmError2("invalid", message, { kind: "invalid", cause: error });
|
|
1179
|
+
}
|
|
1172
1180
|
if (typeof returned === "string") {
|
|
1173
1181
|
const endpoint = endpoints.find((item) => item.name === returned);
|
|
1174
1182
|
if (endpoint !== undefined)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
stack2
|
|
3
3
|
} from "./mss6ctgv.js";
|
|
4
|
+
import"./ddh72ym5.js";
|
|
4
5
|
import {
|
|
5
6
|
updateSliceBody2,
|
|
6
7
|
rejectDuplicateTargets2,
|
|
@@ -15,7 +16,7 @@ import {
|
|
|
15
16
|
expectOf2,
|
|
16
17
|
allowSet2,
|
|
17
18
|
noteGuarded2
|
|
18
|
-
} from "./
|
|
19
|
+
} from "./63qjmhnp.js";
|
|
19
20
|
import {
|
|
20
21
|
emitWhere,
|
|
21
22
|
projectExpr,
|