@oxy-hq/sdk 2.13.0 → 2.16.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 (44) hide show
  1. package/README.md +67 -0
  2. package/dist/{function-context-D8eyZuw_.d.cts → function-context-BNpL5bFb.d.cts} +223 -20
  3. package/dist/function-context-BNpL5bFb.d.cts.map +1 -0
  4. package/dist/{function-context-D8eyZuw_.d.mts → function-context-BNpL5bFb.d.mts} +223 -20
  5. package/dist/function-context-BNpL5bFb.d.mts.map +1 -0
  6. package/dist/index.cjs +19 -16
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.cts +3 -3
  9. package/dist/index.d.cts.map +1 -1
  10. package/dist/index.d.mts +3 -3
  11. package/dist/index.d.mts.map +1 -1
  12. package/dist/index.mjs +17 -15
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/ops.d.cts +1 -1
  15. package/dist/ops.d.mts +1 -1
  16. package/dist/{react-D-Sf973d.d.mts → react-CljeXJuw.d.cts} +56 -7
  17. package/dist/react-CljeXJuw.d.cts.map +1 -0
  18. package/dist/{react-D-Sf973d.d.cts → react-CljeXJuw.d.mts} +56 -7
  19. package/dist/react-CljeXJuw.d.mts.map +1 -0
  20. package/dist/{react-CkAQg9wB.cjs → react-Dvkv2deI.cjs} +46 -55
  21. package/dist/react-Dvkv2deI.cjs.map +1 -0
  22. package/dist/{react-Cq3xULOr.mjs → react-OW1t_J0M.mjs} +39 -22
  23. package/dist/react-OW1t_J0M.mjs.map +1 -0
  24. package/dist/rolldown-runtime-KC0qvQup.cjs +34 -0
  25. package/dist/shell.cjs +4 -3
  26. package/dist/shell.cjs.map +1 -1
  27. package/dist/shell.d.cts +2 -2
  28. package/dist/shell.d.mts +2 -2
  29. package/dist/shell.mjs +1 -1
  30. package/dist/testing.cjs +4431 -0
  31. package/dist/testing.cjs.map +1 -0
  32. package/dist/testing.d.cts +656 -0
  33. package/dist/testing.d.cts.map +1 -0
  34. package/dist/testing.d.mts +656 -0
  35. package/dist/testing.d.mts.map +1 -0
  36. package/dist/testing.mjs +4395 -0
  37. package/dist/testing.mjs.map +1 -0
  38. package/package.json +22 -9
  39. package/dist/function-context-D8eyZuw_.d.cts.map +0 -1
  40. package/dist/function-context-D8eyZuw_.d.mts.map +0 -1
  41. package/dist/react-CkAQg9wB.cjs.map +0 -1
  42. package/dist/react-Cq3xULOr.mjs.map +0 -1
  43. package/dist/react-D-Sf973d.d.cts.map +0 -1
  44. package/dist/react-D-Sf973d.d.mts.map +0 -1
@@ -0,0 +1,4395 @@
1
+ // @oxy/sdk - TypeScript SDK for Oxy data platform
2
+ import * as nodeCryptoImport from "node:crypto";
3
+
4
+ //#region src/testing/host-contract.ts
5
+ /**
6
+ * The host's words, gates, op names and rules, as `@oxy-hq/sdk/testing`
7
+ * enforces them on an app's unit tests.
8
+ *
9
+ * ONE SOURCE OF TRUTH, AND IT IS NOT THIS FILE. Every string below is quoted
10
+ * from the host's source — `host.rs`, `host/destinations.rs`,
11
+ * `host/airhouse_ops.rs`, `upsert_support.rs`, `tx.rs`, `runtime.rs` under
12
+ * `crates/app/src/server/api/custom_apps_functions/`, and the connector's
13
+ * `transaction.rs` / `postgres_tx/convert.rs` — never paraphrased.
14
+ * `{placeholder}`s stand for what the host formats in (`{database}`,
15
+ * `{dialect}`, …) and use the host's own names.
16
+ *
17
+ * HELD TO THE HOST BY A RUST TEST. `sdk_testing_drift.rs`, beside `host.rs`,
18
+ * `include_str!`s this file and fails when a `refusal:` here is no longer a
19
+ * sentence its `source:` file contains, when `HOST_OPS` differs from the
20
+ * host's closed list, when `GATES` stops naming exactly the fields of
21
+ * `FunctionCapabilities`, when `ABSENT_GLOBALS` differs from `oxyc`'s lint
22
+ * list, or when `FETCH_RULES` differs from `is_safe_outbound`. One direction
23
+ * only: this file is checked against the host, the host is never checked
24
+ * against this file (`internal-docs/sdk-testing-context.md` §7, answer 9).
25
+ *
26
+ * THE RUST TEST READS TEXT, NOT TYPESCRIPT: after stripping comments it takes
27
+ * the block from `export const HOST_OPS` to `] as const;`, every object whose
28
+ * key line ends `: {` and carries `source:` and `refusal:` lines, the
29
+ * `hostField:` / `ops:` lines of `GATES`, the `name:` / `member:` lines of
30
+ * `ABSENT_GLOBALS`, and every quoted string in `FETCH_RULES`. Keep those keys
31
+ * spelled as they are, each `refusal:` a single string literal, and none of
32
+ * them behind a comment that is not a full-line one.
33
+ *
34
+ * NO `contractVersion` (§7, answer 10): a reworded refusal reaches an app on
35
+ * its next SDK bump, which is the right moment to see it; a version field
36
+ * with no consumer is a mechanism nobody reads.
37
+ */
38
+ /**
39
+ * Every name the host pages an op under — `HOST_OPS` in `host_call_attrs.rs`,
40
+ * "pinned by unit tests to `host_op_name` and `runtime::host_call_span`". The
41
+ * `HostOp` type is this list, so `"warehouse.inserts"` does not compile.
42
+ */
43
+ const HOST_OPS = [
44
+ "query",
45
+ "query_stream",
46
+ "fetch",
47
+ "semantic.query",
48
+ "airway.run",
49
+ "warehouse.insert",
50
+ "warehouse.exec",
51
+ "warehouse.upsert",
52
+ "warehouse.query",
53
+ "tx.begin",
54
+ "tx.begin_oltp",
55
+ "tx.query",
56
+ "tx.exec",
57
+ "tx.commit",
58
+ "tx.rollback",
59
+ "oltp.query",
60
+ "oltp.exec",
61
+ "airhouse.query",
62
+ "airhouse.exec",
63
+ "airhouse.append",
64
+ "storage.getUploadUrl",
65
+ "storage.getDownloadUrl",
66
+ "storage.put",
67
+ "storage.get",
68
+ "storage.head",
69
+ "storage.list",
70
+ "storage.delete",
71
+ "storage.copy",
72
+ "secrets.set",
73
+ "email.send",
74
+ "org.people",
75
+ "org.places",
76
+ "org.assignments"
77
+ ];
78
+ /**
79
+ * The surface `reply_json` prefixes a refusal with (`runtime.rs`): a thrown
80
+ * `HostError`'s message is `"<surface>: <host message>"`. Every `tx.*` verb —
81
+ * `begin_oltp` included — answers under `ctx.tx`, because one op carries all
82
+ * six.
83
+ */
84
+ const SURFACES = {
85
+ query: "ctx.query",
86
+ queryStream: "ctx.queryStream",
87
+ fetch: "ctx.fetch",
88
+ warehouse: "ctx.warehouse",
89
+ tx: "ctx.tx",
90
+ oltp: "ctx.oltp",
91
+ airhouse: "ctx.airhouse",
92
+ secretsSet: "ctx.secrets.set",
93
+ emailSend: "ctx.email.send",
94
+ storage: "ctx.storage",
95
+ orgPeople: "ctx.org.people",
96
+ orgPlaces: "ctx.org.places",
97
+ orgAssignments: "ctx.org.assignments",
98
+ semanticQuery: "ctx.semantic.query",
99
+ airwayRun: "ctx.airway.run"
100
+ };
101
+ /**
102
+ * Every refusal the context throws, quoted from the host. The context renders
103
+ * a template by substituting its `{placeholder}`s and prefixing the surface.
104
+ */
105
+ const REFUSALS = {
106
+ secretsWrite: {
107
+ source: "host.rs",
108
+ refusal: "ctx.secrets.set: this function has not declared the `secrets.write` capability (add it to oxy-app.json to permit writes)"
109
+ },
110
+ emailSend: {
111
+ source: "host.rs",
112
+ refusal: "EmailCapabilityMissing: this function has not declared the `email.send` capability (add \"email\": { \"send\": true } to its oxy-app.json entry)"
113
+ },
114
+ orgPeople: {
115
+ source: "host.rs",
116
+ refusal: "OrgCapabilityMissing: this function has not declared the `org.read` capability (add \"org\": { \"read\": true } to its oxy-app.json entry)"
117
+ },
118
+ orgMember: {
119
+ source: "host.rs",
120
+ refusal: "OrgCapabilityMissing: this function has not declared the `org.read` capability (add \"org\": { \"read\": true } to its oxy-app.json entry) — ctx.org.{member}"
121
+ },
122
+ storageWrite: {
123
+ source: "host.rs",
124
+ refusal: "StorageCapabilityMissing: this function has not declared the `storage.write` capability (add \"storage\": { \"write\": true } to its oxy-app.json entry)"
125
+ },
126
+ storageRead: {
127
+ source: "host.rs",
128
+ refusal: "StorageCapabilityMissing: this function has not declared the `storage.read` capability (add \"storage\": { \"read\": true } to its oxy-app.json entry)"
129
+ },
130
+ oltp: {
131
+ source: "host.rs",
132
+ refusal: "OltpCapabilityMissing: this function has not declared the `oltp` capability (add \"oltp\": { \"enabled\": true } to its oxy-app.json entry). The schema it writes is derived from the app's own slug — the manifest only enables access."
133
+ },
134
+ airhouse: {
135
+ source: "host/airhouse_ops.rs",
136
+ refusal: "AirhouseCapabilityMissing: this function has not declared the `airhouse` capability (add \"airhouse\": { \"enabled\": true } to its oxy-app.json entry). The schema it writes is derived from the app's own slug — the manifest only enables access."
137
+ },
138
+ destinationNotDeclared: {
139
+ source: "host.rs",
140
+ refusal: "database '{database}' is not in this function's `destinations` allowlist (declare it in oxy-app.json to permit writes)"
141
+ },
142
+ databaseNotConfigured: {
143
+ source: "host.rs",
144
+ refusal: "database '{database}' is not configured for this project"
145
+ },
146
+ managedOltpWrite: {
147
+ source: "host/destinations.rs",
148
+ refusal: "database '{database}' is the org's OLTP store, which this surface reaches as the read-only analyst — write this app's own records with ctx.oltp"
149
+ },
150
+ customerWarehouseWrite: {
151
+ source: "host/destinations.rs",
152
+ refusal: "database '{database}' is a customer warehouse, and customer warehouses are read-only to apps. Facts this app records belong in Airhouse (ctx.airhouse); records it edits belong in ctx.oltp. If this write has to stay, say why on the function in oxy-app.json: \"customerWarehouseWrites\": { \"{database}\": \"<reason>\" }"
153
+ },
154
+ customerWarehouseTransaction: {
155
+ source: "host/destinations.rs",
156
+ refusal: ". A ctx.tx transaction counts as a write even when it only reads — read with ctx.warehouse.query instead"
157
+ },
158
+ upsertUnsupported: {
159
+ source: "upsert_support.rs",
160
+ refusal: "warehouse.upsert is not supported on {dialect}: it compiles to `INSERT … ON CONFLICT … DO UPDATE`, which only Postgres and DuckDB parse. Use warehouse.insert, or warehouse.exec with this warehouse's own upsert statement."
161
+ },
162
+ transactionOpen: {
163
+ source: "host.rs",
164
+ refusal: "could not open a transaction on '{database}': {e}"
165
+ },
166
+ transactionUnsupported: {
167
+ source: "transaction.rs",
168
+ refusal: "{backend} does not support multi-statement transactions — ctx.tx() requires a Postgres-backed database (`type: postgres`). Use ctx.warehouse.{insert,exec,upsert} for single-statement writes."
169
+ },
170
+ transactionsOpen: {
171
+ source: "tx.rs",
172
+ refusal: "this invocation already has {MAX_OPEN} transactions open. Commit or roll one back before opening another."
173
+ },
174
+ transactionFinished: {
175
+ source: "runtime.rs",
176
+ refusal: "{label}: this transaction is already finished — {what} was called after the callback returned"
177
+ },
178
+ transactionFnNotFunction: {
179
+ source: "runtime.rs",
180
+ refusal: "{signature}: fn must be a function"
181
+ },
182
+ btoaBytes: {
183
+ source: "runtime.rs",
184
+ refusal: "btoa: expected a string. For bytes use bytesToBase64() from @oxy-hq/sdk"
185
+ },
186
+ atobPadding: {
187
+ source: "runtime.rs",
188
+ refusal: "atob: '=' may only appear as trailing padding"
189
+ },
190
+ atobLength: {
191
+ source: "runtime.rs",
192
+ refusal: "atob: invalid base64 length"
193
+ },
194
+ fetchInvalidUrl: {
195
+ source: "host.rs",
196
+ refusal: "invalid url: {e}"
197
+ },
198
+ fetchBlocked: {
199
+ source: "host.rs",
200
+ refusal: "fetch to '{url}' blocked by SSRF allowlist"
201
+ },
202
+ fetchInvalidHeaderName: {
203
+ source: "host.rs",
204
+ refusal: "InvalidFetchHeader: `{k}` is not a header name"
205
+ },
206
+ fetchInvalidHeaderValue: {
207
+ source: "host.rs",
208
+ refusal: "InvalidFetchHeader: the value of `{k}` is not a header value"
209
+ },
210
+ fetchTooLarge: {
211
+ source: "host.rs",
212
+ refusal: "response too large ({len} bytes > {max_bytes} cap)"
213
+ },
214
+ slugCannotBackASchema: {
215
+ source: "host.rs",
216
+ refusal: "the capability is enabled, but this app's slug '{slug}' cannot back an {store} schema: to do so a slug must start with a letter, be at most {max} characters, and use only lowercase letters, digits and hyphens (a `_` is refused — it would collide with the hyphenated form). A leading digit is a legal app slug but not a legal schema name. Rename the app to one that qualifies."
217
+ },
218
+ oltpParamsNotArray: {
219
+ source: "host.rs",
220
+ refusal: "`params` must be an array of values. Pass positional arguments for $1, $2, … — e.g. [name, partySize]."
221
+ },
222
+ noDefaultDatabase: {
223
+ source: "host.rs",
224
+ refusal: "this project has no databases configured"
225
+ },
226
+ oltpUnsupportedColumn: {
227
+ source: "postgres_tx/convert.rs",
228
+ refusal: "result column `{name}` has Postgres type `{ty}`, which cannot be returned directly. Cast it to text in the SELECT list and parse it in your function — cast the whole expression, not the output name (`avg(qty)::text`, `amount::text`). Note `avg`/`sum` over any numeric type, and a bare decimal literal, are all `numeric`. (Supported as-is: bool, int2/4/8, float4/8, text/varchar/char/name, json/jsonb, uuid, timestamptz/timestamp, date, time.)"
229
+ }
230
+ };
231
+ /**
232
+ * Every gate in `FunctionCapabilities`, in the struct's order. `storage_read`
233
+ * and `storage_write` list `check_storage_capability`'s arms (`copy` needs
234
+ * both); `customer_warehouse_writes` is decided per database by
235
+ * `destination_write_policy`, after the `destinations` allowlist.
236
+ * `storage_retention` and `fetch_max_bytes` are fields of the struct and
237
+ * deliberately absent: they shape an allowed call, they never refuse one.
238
+ */
239
+ const GATES = [
240
+ {
241
+ hostField: "secrets_write",
242
+ manifest: "secrets.write",
243
+ ops: ["secrets.set"]
244
+ },
245
+ {
246
+ hostField: "email_send",
247
+ manifest: "email.send",
248
+ ops: ["email.send"]
249
+ },
250
+ {
251
+ hostField: "org_read",
252
+ manifest: "org.read",
253
+ ops: [
254
+ "org.people",
255
+ "org.places",
256
+ "org.assignments"
257
+ ]
258
+ },
259
+ {
260
+ hostField: "storage_read",
261
+ manifest: "storage.read",
262
+ ops: [
263
+ "storage.getDownloadUrl",
264
+ "storage.get",
265
+ "storage.head",
266
+ "storage.list",
267
+ "storage.copy"
268
+ ]
269
+ },
270
+ {
271
+ hostField: "storage_write",
272
+ manifest: "storage.write",
273
+ ops: [
274
+ "storage.getUploadUrl",
275
+ "storage.put",
276
+ "storage.delete",
277
+ "storage.copy"
278
+ ]
279
+ },
280
+ {
281
+ hostField: "oltp",
282
+ manifest: "oltp.enabled",
283
+ ops: [
284
+ "oltp.query",
285
+ "oltp.exec",
286
+ "tx.begin_oltp"
287
+ ]
288
+ },
289
+ {
290
+ hostField: "airhouse",
291
+ manifest: "airhouse.enabled",
292
+ ops: [
293
+ "airhouse.query",
294
+ "airhouse.exec",
295
+ "airhouse.append"
296
+ ]
297
+ },
298
+ {
299
+ hostField: "customer_warehouse_writes",
300
+ manifest: "customerWarehouseWrites",
301
+ ops: [
302
+ "warehouse.insert",
303
+ "warehouse.exec",
304
+ "warehouse.upsert",
305
+ "tx.begin"
306
+ ]
307
+ }
308
+ ];
309
+ /**
310
+ * The globals the isolate does not define, as `oxyc`'s `isolate-global` lint
311
+ * names them (`ABSENT_GLOBALS` in `sdk/cli/src/publish/function-lint.ts`).
312
+ * `member` narrows an entry to `<name>.<member>`; an empty `member` is the
313
+ * whole of `process.*`. The isolate's bootstrap defines `Response`, `btoa`,
314
+ * `atob`, `console` and `__buildCtx` and nothing else (`runtime.rs`), so it has
315
+ * no `crypto` global at all; the lint singles out `subtle` because that is what
316
+ * an author reaches for, and `run()` removes the whole global as production
317
+ * does.
318
+ */
319
+ const ABSENT_GLOBALS = [
320
+ { name: "Buffer" },
321
+ { name: "TextEncoder" },
322
+ { name: "TextDecoder" },
323
+ { name: "Blob" },
324
+ { name: "File" },
325
+ { name: "FormData" },
326
+ {
327
+ name: "crypto",
328
+ member: "subtle"
329
+ },
330
+ {
331
+ name: "process",
332
+ member: ""
333
+ }
334
+ ];
335
+ /**
336
+ * `is_safe_outbound` in `host.rs`, the first-layer check every `ctx.fetch`
337
+ * URL meets before anything is sent: the scheme, the host names refused by
338
+ * name, and the suffixes an internal name ends with. The IP rules (loopback,
339
+ * unspecified, private, link-local, broadcast, documentation, v4-mapped and
340
+ * embedded v6) are code, in `fetch-rules.ts`. What no unit test can reproduce
341
+ * is the second layer — a public name that RESOLVES to a private address is
342
+ * caught at connect time by `PublicOnlyDnsResolver` — so the context does not
343
+ * pretend to.
344
+ */
345
+ const FETCH_RULES = {
346
+ scheme: "https",
347
+ literalHosts: [
348
+ "localhost",
349
+ "ip6-localhost",
350
+ "ip6-loopback"
351
+ ],
352
+ internalSuffixes: [
353
+ ".internal",
354
+ ".local",
355
+ ".localdomain",
356
+ ".svc",
357
+ ".cluster.local"
358
+ ]
359
+ };
360
+ /** `FETCH_MAX_BYTES` in `host.rs`: the default `ctx.fetch` response ceiling. */
361
+ const FETCH_MAX_BYTES = 10485760;
362
+ /** `MAX_OPEN` in `tx.rs`: transactions one invocation may hold open at once. */
363
+ const MAX_OPEN_TRANSACTIONS = 4;
364
+ /**
365
+ * How each dialect names itself in a refusal — `SqlDialect::as_str` in the
366
+ * connector crate, which `upsert_support::check` and `transaction::unsupported`
367
+ * format in. Only Postgres, DuckDB and SQLite parse `ON CONFLICT`
368
+ * (`parses_on_conflict`), and only the Postgres connector opens a transaction.
369
+ */
370
+ const DIALECTS = {
371
+ clickhouse: {
372
+ name: "ClickHouse",
373
+ parsesOnConflict: false,
374
+ opensTransactions: false
375
+ },
376
+ postgres: {
377
+ name: "PostgreSQL",
378
+ parsesOnConflict: true,
379
+ opensTransactions: true
380
+ },
381
+ duckdb: {
382
+ name: "DuckDB",
383
+ parsesOnConflict: true,
384
+ opensTransactions: false
385
+ }
386
+ };
387
+
388
+ //#endregion
389
+ //#region src/testing/fetch-rules.ts
390
+ /** The host's verdict on a URL: allowed, or refused before sending. */
391
+ function isSafeOutbound(url) {
392
+ if (url.protocol !== `${FETCH_RULES.scheme}:`) return false;
393
+ const host = url.hostname;
394
+ if (host === "") return false;
395
+ const ip = parseIp(host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host);
396
+ if (ip) return isPublicIp(ip);
397
+ const lower = host.toLowerCase();
398
+ if (FETCH_RULES.literalHosts.includes(lower)) return false;
399
+ return !FETCH_RULES.internalSuffixes.some((suffix) => lower.endsWith(suffix));
400
+ }
401
+ /** A literal IPv4 or IPv6 address, or `null` when `s` is a name. */
402
+ function parseIp(s) {
403
+ const v4 = parseV4(s);
404
+ if (v4) return { v4 };
405
+ const v6 = parseV6(s);
406
+ return v6 ? { v6 } : null;
407
+ }
408
+ function parseV4(s) {
409
+ const m = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(s);
410
+ if (!m) return null;
411
+ const parts = m.slice(1).map(Number);
412
+ if (parts.some((p) => p > 255)) return null;
413
+ return parts;
414
+ }
415
+ /** Eight 16-bit segments, or `null`. Accepts `::`, and a dotted v4 tail. */
416
+ function parseV6(s) {
417
+ if (!s.includes(":")) return null;
418
+ const zone = s.indexOf("%");
419
+ const halves = (zone >= 0 ? s.slice(0, zone) : s).split("::");
420
+ if (halves.length > 2) return null;
421
+ const head = halves[0] === "" ? [] : halves[0].split(":");
422
+ const tail = halves.length === 2 && halves[1] !== "" ? halves[1].split(":") : [];
423
+ const words = (groups) => {
424
+ const out = [];
425
+ for (const [i, g] of groups.entries()) if (g.includes(".")) {
426
+ if (i !== groups.length - 1) return null;
427
+ const v4 = parseV4(g);
428
+ if (!v4) return null;
429
+ out.push(v4[0] << 8 | v4[1], v4[2] << 8 | v4[3]);
430
+ } else {
431
+ if (!/^[0-9a-fA-F]{1,4}$/.test(g)) return null;
432
+ out.push(Number.parseInt(g, 16));
433
+ }
434
+ return out;
435
+ };
436
+ const h = words(head);
437
+ const t = words(tail);
438
+ if (!h || !t) return null;
439
+ if (halves.length === 1) return h.length === 8 ? h : null;
440
+ const fill = 8 - h.length - t.length;
441
+ if (fill < 1) return null;
442
+ return [
443
+ ...h,
444
+ ...new Array(fill).fill(0),
445
+ ...t
446
+ ];
447
+ }
448
+ /** `is_public_ip` in `host.rs`. */
449
+ function isPublicIp(ip) {
450
+ const canonical = "v6" in ip ? mappedV4(ip.v6) ?? ip : ip;
451
+ if ("v4" in canonical) return isPublicV4(canonical.v4);
452
+ const seg = canonical.v6;
453
+ if (seg.every((w) => w === 0)) return false;
454
+ if (seg.slice(0, 7).every((w) => w === 0) && seg[7] === 1) return false;
455
+ const embedded = embeddedV4(seg);
456
+ if (embedded) return isPublicV4(embedded);
457
+ const first = seg[0];
458
+ const linkLocal = (first & 65472) === 65152;
459
+ const uniqueLocal = (first & 65024) === 64512;
460
+ return !linkLocal && !uniqueLocal;
461
+ }
462
+ function isPublicV4([a, b, c, d]) {
463
+ if (a === 127) return false;
464
+ if (a === 0 && b === 0 && c === 0 && d === 0) return false;
465
+ return !(a === 10 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168) && !(a === 169 && b === 254) && !(a === 255 && b === 255 && c === 255 && d === 255) && !(a === 192 && b === 0 && c === 2 || a === 198 && b === 51 && c === 100 || a === 203 && b === 0 && c === 113);
466
+ }
467
+ /** `to_canonical()`: an IPv4-mapped address (`::ffff:a.b.c.d`) as its v4. */
468
+ function mappedV4(seg) {
469
+ if (seg.slice(0, 5).every((w) => w === 0) && seg[5] === 65535) return { v4: [
470
+ seg[6] >> 8,
471
+ seg[6] & 255,
472
+ seg[7] >> 8,
473
+ seg[7] & 255
474
+ ] };
475
+ return null;
476
+ }
477
+ /** `embedded_ipv4`: the v4 in a `::/96` or `64:ff9b::/96` address. */
478
+ function embeddedV4(seg) {
479
+ const compatible = seg.slice(0, 6).every((w) => w === 0);
480
+ const nat64 = seg[0] === 100 && seg[1] === 65435 && seg.slice(2, 6).every((w) => w === 0);
481
+ if (!compatible && !nat64) return null;
482
+ return [
483
+ seg[6] >> 8,
484
+ seg[6] & 255,
485
+ seg[7] >> 8,
486
+ seg[7] & 255
487
+ ];
488
+ }
489
+
490
+ //#endregion
491
+ //#region src/testing/host-error.ts
492
+ /** The `name` the runtime gives every refusal it unwraps. */
493
+ const HOST_ERROR_NAME = "HostError";
494
+ /**
495
+ * Render a refusal template: every `{placeholder}` replaced by `vars[name]`.
496
+ * A placeholder the caller did not supply is a bug in the context, not in the
497
+ * app under test, so it throws rather than leaking `{database}` into a message
498
+ * a test might then match on.
499
+ */
500
+ function render(template, vars = {}) {
501
+ return template.refusal.replace(/\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (whole, name) => {
502
+ const value = vars[name];
503
+ if (value === void 0) throw new Error(`test context bug: refusal template leaves {${name}} unfilled: ${whole}`);
504
+ return String(value);
505
+ });
506
+ }
507
+ /**
508
+ * The error a function sees when the host refuses: `name` `"HostError"`,
509
+ * message `"<surface>: <message>"`.
510
+ */
511
+ function hostError(surface, message) {
512
+ const err = /* @__PURE__ */ new Error(`${surface}: ${message}`);
513
+ err.name = HOST_ERROR_NAME;
514
+ return err;
515
+ }
516
+ /** `hostError` over a rendered template. */
517
+ function refuse(surface, template, vars = {}) {
518
+ return hostError(surface, render(template, vars));
519
+ }
520
+ /** Whether `err` is a refusal the context (or the runtime) threw. */
521
+ function isHostError(err) {
522
+ return err instanceof Error && err.name === "HostError";
523
+ }
524
+ /**
525
+ * An error in the context's OWN words — never the host's. Thrown where the
526
+ * context cannot model what the host would do (an unrecognised statement, an
527
+ * unregistered `fetch` answer) and says so, rather than answering something
528
+ * production would not. Its `name` is `"TestContextError"` so a test can never
529
+ * mistake it for a refusal.
530
+ */
531
+ function contextError(message) {
532
+ const err = /* @__PURE__ */ new Error(`@oxy-hq/sdk/testing: ${message}`);
533
+ err.name = "TestContextError";
534
+ return err;
535
+ }
536
+
537
+ //#endregion
538
+ //#region src/testing/gates.ts
539
+ const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
540
+ /** `spec.<a>.<b> === true` — `flag` in `capabilities.ts`. */
541
+ function flag(spec, a, b) {
542
+ const block = spec[a];
543
+ return isObject(block) && block[b] === true;
544
+ }
545
+ /**
546
+ * `MAX_NAME_LEN` in `crates/oltp/src/schema.rs`: 63 (Postgres) less `app_` and
547
+ * the longest role suffix `_rw`.
548
+ */
549
+ const MAX_SCHEMA_NAME_LEN = 56;
550
+ /**
551
+ * `app_writer_name` + `WriterRef::schema_name`: the schema an app's slug
552
+ * derives, or `null` when it derives none.
553
+ *
554
+ * Both halves matter. `app_writer_name` refuses a slug containing `_` outright
555
+ * — `my_app` would otherwise alias the hyphenated sibling `my-app` onto one
556
+ * schema and role — and then runs the derived name through `validate_name`,
557
+ * which is what rejects a leading digit, an over-long name, and any character
558
+ * outside `[a-z0-9_]`. Skipping that second half handed back a schema for slugs
559
+ * the host answers `None` for, which is the difference between a green test and
560
+ * a closed `ctx.oltp` in production.
561
+ */
562
+ function writerSchema(slug) {
563
+ if (slug.includes("_")) return null;
564
+ const name = slug.replace(/-/g, "_");
565
+ if (name === "" || name.length > 56) return null;
566
+ if (!/^[a-z]/.test(name)) return null;
567
+ if (!/^[a-z0-9_]+$/.test(name)) return null;
568
+ return `app_${name}`;
569
+ }
570
+ /** Read the gates for `functionName` from `manifest`, or throw naming what is missing. */
571
+ function readGates(manifest, functionName) {
572
+ const spec = manifest.functions?.[functionName];
573
+ if (!isObject(spec)) {
574
+ const known = Object.keys(manifest.functions ?? {});
575
+ throw contextError(`oxy-app.json declares no function "${functionName}" (functions: ${known.length ? known.join(", ") : "none"})`);
576
+ }
577
+ const slug = typeof manifest.slug === "string" ? manifest.slug : "";
578
+ const destinations = Array.isArray(spec.destinations) ? spec.destinations.filter((d) => typeof d === "string") : [];
579
+ const customerWarehouseWrites = {};
580
+ if (isObject(spec.customerWarehouseWrites)) {
581
+ for (const [db, reason] of Object.entries(spec.customerWarehouseWrites)) if (typeof reason === "string" && reason.trim() !== "") customerWarehouseWrites[db] = reason;
582
+ }
583
+ const fetch = isObject(spec.fetch) ? spec.fetch : {};
584
+ return {
585
+ functionName,
586
+ slug,
587
+ writerSchema: writerSchema(slug),
588
+ secretsWrite: flag(spec, "secrets", "write"),
589
+ emailSend: flag(spec, "email", "send"),
590
+ orgRead: flag(spec, "org", "read"),
591
+ storageRead: flag(spec, "storage", "read"),
592
+ storageWrite: flag(spec, "storage", "write"),
593
+ oltp: flag(spec, "oltp", "enabled"),
594
+ airhouse: flag(spec, "airhouse", "enabled"),
595
+ destinations,
596
+ customerWarehouseWrites,
597
+ fetchMaxBytes: typeof fetch.maxResponseBytes === "number" ? fetch.maxResponseBytes : null
598
+ };
599
+ }
600
+
601
+ //#endregion
602
+ //#region src/testing/run.ts
603
+ const B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
604
+ const B64R = (/* @__PURE__ */ new Uint8Array(256)).fill(255);
605
+ for (let i = 0; i < 64; i++) B64R[B64.charCodeAt(i)] = i;
606
+ /** `globalThis.btoa` as the isolate defines it: strings only, Latin1 only. */
607
+ function isolateBtoa(input) {
608
+ if (input instanceof ArrayBuffer || ArrayBuffer.isView(input)) throw new TypeError(render(REFUSALS.btoaBytes));
609
+ const s = String(input);
610
+ let out = "";
611
+ for (let i = 0; i < s.length; i += 3) {
612
+ const c0 = s.charCodeAt(i);
613
+ const c1 = i + 1 < s.length ? s.charCodeAt(i + 1) : 0;
614
+ const c2 = i + 2 < s.length ? s.charCodeAt(i + 2) : 0;
615
+ if (c0 > 255 || c1 > 255 || c2 > 255) throw new TypeError("btoa: input contains characters outside the Latin1 range; for text pass it directly with { encoding: \"utf8\" }");
616
+ const n = c0 << 16 | c1 << 8 | c2;
617
+ out += B64[n >> 18 & 63] + B64[n >> 12 & 63] + (i + 1 < s.length ? B64[n >> 6 & 63] : "=") + (i + 2 < s.length ? B64[n & 63] : "=");
618
+ }
619
+ return out;
620
+ }
621
+ /** `globalThis.atob` as the isolate defines it: WHATWG forgiving-base64. */
622
+ function isolateAtob(input) {
623
+ let s = String(input).replace(/[ \t\n\f\r]/g, "");
624
+ if (s.length % 4 === 0) {
625
+ let pad = 0;
626
+ while (pad < 2 && s.charCodeAt(s.length - 1) === 61) {
627
+ s = s.slice(0, -1);
628
+ pad++;
629
+ }
630
+ }
631
+ if (s.indexOf("=") >= 0) throw new TypeError(render(REFUSALS.atobPadding));
632
+ if (s.length % 4 === 1) throw new TypeError(render(REFUSALS.atobLength));
633
+ let out = "";
634
+ let buf = 0;
635
+ let bits = 0;
636
+ for (let i = 0; i < s.length; i++) {
637
+ const code = s.charCodeAt(i);
638
+ const v = code < 256 ? B64R[code] : 255;
639
+ if (v === 255) throw new TypeError(`atob: invalid base64 character '${s[i]}'`);
640
+ buf = buf << 6 | v;
641
+ bits += 6;
642
+ if (bits >= 8) {
643
+ bits -= 8;
644
+ out += String.fromCharCode(buf >> bits & 255);
645
+ }
646
+ }
647
+ return out;
648
+ }
649
+ let running = false;
650
+ /**
651
+ * Evaluate `fn` with every `ABSENT_GLOBALS` entry removed from `globalThis` and
652
+ * `btoa` / `atob` replaced by the isolate's, restoring all of them afterwards
653
+ * — whether `fn` resolves or throws.
654
+ */
655
+ async function runWithoutIsolateGlobals(fn) {
656
+ if (running) throw contextError("t.run(fn) calls must not overlap — one at a time per test");
657
+ running = true;
658
+ const saved = [];
659
+ const g = globalThis;
660
+ const shadow = (name, value) => {
661
+ saved.push([name, Object.getOwnPropertyDescriptor(globalThis, name)]);
662
+ if (value === void 0) delete g[name];
663
+ else Object.defineProperty(globalThis, name, {
664
+ value,
665
+ configurable: true,
666
+ writable: true
667
+ });
668
+ };
669
+ try {
670
+ for (const entry of ABSENT_GLOBALS) shadow(entry.name, void 0);
671
+ shadow("btoa", isolateBtoa);
672
+ shadow("atob", isolateAtob);
673
+ return await fn();
674
+ } finally {
675
+ for (const [name, descriptor] of saved.reverse()) if (descriptor) Object.defineProperty(globalThis, name, descriptor);
676
+ else delete g[name];
677
+ running = false;
678
+ }
679
+ }
680
+
681
+ //#endregion
682
+ //#region src/testing/sql.ts
683
+ const STOP_WORDS = /^(DEFAULT|NOT|NULL|PRIMARY|UNIQUE|REFERENCES|CHECK|GENERATED|CODEC|COMMENT|TTL)$/i;
684
+ const CONSTRAINT_HEAD = /^(PRIMARY|UNIQUE|CONSTRAINT|FOREIGN|CHECK|KEY|INDEX)\b/i;
685
+ /** `sql` without its leading line and block comments and whitespace. */
686
+ function stripLeadingComments(sql) {
687
+ let s = sql;
688
+ for (;;) {
689
+ const before = s;
690
+ s = s.replace(/^\s+/, "").replace(/^--[^\n]*\n?/, "").replace(/^\/\*[\s\S]*?\*\//, "");
691
+ if (s === before) return s;
692
+ }
693
+ }
694
+ /** Parse one statement, or throw in the context's own words. */
695
+ function parse(sql) {
696
+ const text = stripLeadingComments(sql).replace(/;\s*$/, "");
697
+ switch (/^(\w+)/.exec(text)?.[1]?.toUpperCase() ?? "") {
698
+ case "CREATE": return parseCreate(text);
699
+ case "INSERT": return parseInsert(text);
700
+ case "SELECT":
701
+ case "WITH": return parseSelect(text);
702
+ case "DELETE": return parseDelete(text);
703
+ case "UPDATE": return parseUpdate(text);
704
+ default: throw unsupported(text);
705
+ }
706
+ }
707
+ function unsupported(sql) {
708
+ const head = sql.trim().slice(0, 60).replace(/\s+/g, " ");
709
+ return contextError(`the test context cannot evaluate this statement: "${head}…". It reads CREATE TABLE, INSERT … VALUES, SELECT <columns|count(*)|literals> FROM <table> [WHERE col = value AND …] [ORDER BY col] [LIMIT n], DELETE FROM and UPDATE … SET. Answer the call with t.override(op, …), or seed the rows it should find with t.state.<store>.raw(table, rows).`);
710
+ }
711
+ /** Strip the quotes an identifier was written with. */
712
+ function ident(raw) {
713
+ const s = raw.trim();
714
+ if (s.startsWith("\"") && s.endsWith("\"") || s.startsWith("`") && s.endsWith("`")) return s.slice(1, -1);
715
+ return s;
716
+ }
717
+ /** Split `text` on top-level commas, respecting parentheses, brackets and quotes. */
718
+ function splitTopLevel(text, separator = ",") {
719
+ const out = [];
720
+ let depth = 0;
721
+ let quote = null;
722
+ let start = 0;
723
+ for (let i = 0; i < text.length; i++) {
724
+ const c = text[i];
725
+ if (quote) {
726
+ if (c === quote) {
727
+ if (text[i + 1] === quote) i++;
728
+ else quote = null;
729
+ }
730
+ continue;
731
+ }
732
+ if (c === "'" || c === "\"" || c === "`") quote = c;
733
+ else if (c === "(" || c === "[") depth++;
734
+ else if (c === ")" || c === "]") depth--;
735
+ else if (depth === 0 && text.startsWith(separator, i)) {
736
+ out.push(text.slice(start, i).trim());
737
+ i += separator.length - 1;
738
+ start = i + 1;
739
+ }
740
+ }
741
+ out.push(text.slice(start).trim());
742
+ return out.filter((s) => s !== "");
743
+ }
744
+ /** The index just past the `)` matching the `(` at `open`. */
745
+ function closeParen(text, open) {
746
+ let depth = 0;
747
+ let quote = null;
748
+ for (let i = open; i < text.length; i++) {
749
+ const c = text[i];
750
+ if (quote) {
751
+ if (c === quote) {
752
+ if (text[i + 1] === quote) i++;
753
+ else quote = null;
754
+ }
755
+ continue;
756
+ }
757
+ if (c === "'" || c === "\"") quote = c;
758
+ else if (c === "(") depth++;
759
+ else if (c === ")" && --depth === 0) return i + 1;
760
+ }
761
+ throw unsupported(text);
762
+ }
763
+ function parseCreate(text) {
764
+ const m = /^CREATE\s+TABLE\s+(IF\s+NOT\s+EXISTS\s+)?([\w."`]+)\s*\(/i.exec(text);
765
+ if (!m) throw unsupported(text);
766
+ const open = m[0].length - 1;
767
+ const end = closeParen(text, open);
768
+ const columns = [];
769
+ for (const def of splitTopLevel(text.slice(open + 1, end - 1))) {
770
+ if (CONSTRAINT_HEAD.test(def)) continue;
771
+ const words = splitTopLevel(def, " ");
772
+ const name = ident(words[0] ?? "");
773
+ const typeWords = splitTopLevel(def.slice(def.indexOf(words[0] ?? "") + (words[0]?.length ?? 0)).trim(), " ");
774
+ const stop = typeWords.findIndex((w) => STOP_WORDS.test(w));
775
+ const type = (stop < 0 ? typeWords : typeWords.slice(0, stop)).join(" ");
776
+ if (name) columns.push({
777
+ name,
778
+ type
779
+ });
780
+ }
781
+ return {
782
+ kind: "create",
783
+ table: ident(m[2]),
784
+ ifNotExists: Boolean(m[1]),
785
+ columns
786
+ };
787
+ }
788
+ function parseInsert(text) {
789
+ const m = /^INSERT\s+INTO\s+([\w."`]+)\s*(\(([^)]*)\))?\s*VALUES\s*/i.exec(text);
790
+ if (!m) throw unsupported(text);
791
+ const columns = m[3] ? splitTopLevel(m[3]).map(ident) : null;
792
+ const tuples = [];
793
+ let at = m[0].length;
794
+ while (at < text.length) {
795
+ if (text[at] !== "(") throw unsupported(text);
796
+ const end = closeParen(text, at);
797
+ tuples.push(splitTopLevel(text.slice(at + 1, end - 1)));
798
+ at = end;
799
+ const gap = /^\s*,?\s*/.exec(text.slice(at))?.[0] ?? "";
800
+ at += gap.length;
801
+ }
802
+ return {
803
+ kind: "insert",
804
+ table: ident(m[1]),
805
+ columns,
806
+ tuples
807
+ };
808
+ }
809
+ /** `a = 1 AND b = 'x' AND c IN (1, 2)` → predicates; anything else throws. */
810
+ function parseWhere(text, whole) {
811
+ if (!text) return [];
812
+ return splitTopLevel(text, " AND ").map((clause) => {
813
+ const eq = /^([\w."`]+)\s*=\s*(.+)$/s.exec(clause);
814
+ if (eq) return {
815
+ column: ident(eq[1]),
816
+ values: [eq[2].trim()]
817
+ };
818
+ const inList = /^([\w."`]+)\s+IN\s*\((.*)\)$/is.exec(clause);
819
+ if (inList) return {
820
+ column: ident(inList[1]),
821
+ values: splitTopLevel(inList[2])
822
+ };
823
+ throw contextError(`the test context cannot evaluate this WHERE clause: "${clause}". It reads "col = value" and "col IN (…)" joined by AND. Answer the call with t.override(op, …) instead: ${whole.slice(0, 80)}`);
824
+ });
825
+ }
826
+ /**
827
+ * Whether `literal()` will read this expression as a value rather than hand it
828
+ * back as its own SQL text. The two must agree: a projection the parser accepts
829
+ * as a literal but `literal()` cannot read comes back to the caller as the SQL
830
+ * they wrote — a column named `sum(amount)` holding the string `"sum(amount)"`,
831
+ * which is the one thing this module promises never to do.
832
+ */
833
+ function isReadableLiteral(expr) {
834
+ const s = expr.trim();
835
+ return /^\$\d+$/.test(s) || /^(NULL|TRUE|FALSE)$/i.test(s) || s.startsWith("'") && s.endsWith("'") && s.length >= 2 || /^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(s);
836
+ }
837
+ /**
838
+ * The statement with every quoted string blanked, so a keyword scan reads the
839
+ * SQL and not the data: `WHERE label = 'GROUP BY'` is a row, not a grouping.
840
+ */
841
+ function withoutStringLiterals(text) {
842
+ return text.replace(/'(?:[^']|'')*'/g, "''");
843
+ }
844
+ function parseSelect(text) {
845
+ if (/\bGROUP\s+BY\b/is.test(withoutStringLiterals(text))) throw contextError(`the test context cannot evaluate GROUP BY: "${text.trim().slice(0, 60).replace(/\s+/g, " ")}…". It would have to aggregate, and a wrong aggregate reads like a right one. Answer the call with t.override(op, …) and assert on the arguments instead.`);
846
+ const m = /^SELECT\s+(.*?)(?:\s+FROM\s+([\w."`]+))?(?:\s+WHERE\s+(.*?))?(?:\s+ORDER\s+BY\s+([\w."`]+)(?:\s+(ASC|DESC))?)?(?:\s+LIMIT\s+(\d+))?\s*$/is.exec(text);
847
+ if (!m || !m[2] && /\bFROM\b/i.test(m[1])) throw unsupported(text);
848
+ const items = splitTopLevel(m[1]).map((item) => {
849
+ if (item === "*") return { kind: "all" };
850
+ const aliased = /^(.*?)\s+AS\s+([\w"`]+)$/is.exec(item);
851
+ const expr = (aliased ? aliased[1] : item).trim();
852
+ const alias = aliased ? ident(aliased[2]) : null;
853
+ if (/^count\s*\(\s*\*\s*\)$/i.test(expr)) return {
854
+ kind: "count",
855
+ alias: alias ?? "count(*)"
856
+ };
857
+ if (/^[\w."`]+$/.test(expr) && !/^\d/.test(expr) && !/^(true|false|null)$/i.test(expr)) return {
858
+ kind: "column",
859
+ column: ident(expr),
860
+ alias: alias ?? ident(expr)
861
+ };
862
+ if (!isReadableLiteral(expr)) throw unsupported(text);
863
+ return {
864
+ kind: "literal",
865
+ raw: expr,
866
+ alias: alias ?? expr
867
+ };
868
+ });
869
+ return {
870
+ kind: "select",
871
+ table: m[2] ? ident(m[2]) : null,
872
+ items,
873
+ where: parseWhere(m[3], text),
874
+ orderBy: m[4] ? {
875
+ column: ident(m[4]),
876
+ desc: (m[5] ?? "").toUpperCase() === "DESC"
877
+ } : null,
878
+ limit: m[6] ? Number(m[6]) : null
879
+ };
880
+ }
881
+ function parseDelete(text) {
882
+ const m = /^DELETE\s+FROM\s+([\w."`]+)(?:\s+WHERE\s+(.*))?\s*$/is.exec(text);
883
+ if (!m) throw unsupported(text);
884
+ return {
885
+ kind: "delete",
886
+ table: ident(m[1]),
887
+ where: parseWhere(m[2], text)
888
+ };
889
+ }
890
+ function parseUpdate(text) {
891
+ const m = /^UPDATE\s+([\w."`]+)\s+SET\s+(.*?)(?:\s+WHERE\s+(.*))?\s*$/is.exec(text);
892
+ if (!m) throw unsupported(text);
893
+ const set = splitTopLevel(m[2]).map((assignment) => {
894
+ const eq = /^([\w."`]+)\s*=\s*(.+)$/s.exec(assignment);
895
+ if (!eq) throw unsupported(text);
896
+ const raw = eq[2].trim();
897
+ if (!isReadableLiteral(raw)) throw unsupported(text);
898
+ return {
899
+ column: ident(eq[1]),
900
+ raw
901
+ };
902
+ });
903
+ return {
904
+ kind: "update",
905
+ table: ident(m[1]),
906
+ set,
907
+ where: parseWhere(m[3], text)
908
+ };
909
+ }
910
+ /**
911
+ * A raw SQL value as a JS value, with no engine's rendering applied: a quoted
912
+ * string, a number, NULL, TRUE/FALSE, or a `$n` bound parameter. Anything else
913
+ * (a function call, a cast, an array literal) stays as its SQL text.
914
+ */
915
+ function literal(raw, params = []) {
916
+ const s = raw.trim();
917
+ const param = /^\$(\d+)$/.exec(s);
918
+ if (param) return params[Number(param[1]) - 1];
919
+ if (/^NULL$/i.test(s)) return null;
920
+ if (/^TRUE$/i.test(s)) return true;
921
+ if (/^FALSE$/i.test(s)) return false;
922
+ if (s.startsWith("'") && s.endsWith("'")) return s.slice(1, -1).replace(/''/g, "'");
923
+ if (/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(s)) return Number(s);
924
+ return s;
925
+ }
926
+
927
+ //#endregion
928
+ //#region src/testing/shape-zoo.json
929
+ var shape_zoo_default = {
930
+ version: 1,
931
+ engines: {
932
+ "clickhouse": { "cases": [
933
+ {
934
+ "key": "clickhouse/Bool/plain",
935
+ "native_type": "Bool",
936
+ "class": "plain",
937
+ "value_sql": "true",
938
+ "expect": { "warehouse": true }
939
+ },
940
+ {
941
+ "key": "clickhouse/Nullable(Bool)/null",
942
+ "native_type": "Nullable(Bool)",
943
+ "class": "null",
944
+ "value_sql": "NULL",
945
+ "expect": { "warehouse": null }
946
+ },
947
+ {
948
+ "key": "clickhouse/Boolean/plain",
949
+ "native_type": "Boolean",
950
+ "class": "plain",
951
+ "value_sql": "false",
952
+ "expect": { "warehouse": false }
953
+ },
954
+ {
955
+ "key": "clickhouse/Int8/plain",
956
+ "native_type": "Int8",
957
+ "class": "plain",
958
+ "value_sql": "42",
959
+ "expect": { "warehouse": 42 }
960
+ },
961
+ {
962
+ "key": "clickhouse/Int8/negative",
963
+ "native_type": "Int8",
964
+ "class": "negative",
965
+ "value_sql": "-128",
966
+ "expect": { "warehouse": -128 }
967
+ },
968
+ {
969
+ "key": "clickhouse/Int8/zero",
970
+ "native_type": "Int8",
971
+ "class": "zero",
972
+ "value_sql": "0",
973
+ "expect": { "warehouse": 0 }
974
+ },
975
+ {
976
+ "key": "clickhouse/Nullable(Int8)/null",
977
+ "native_type": "Nullable(Int8)",
978
+ "class": "null",
979
+ "value_sql": "NULL",
980
+ "expect": { "warehouse": null }
981
+ },
982
+ {
983
+ "key": "clickhouse/Int16/plain",
984
+ "native_type": "Int16",
985
+ "class": "plain",
986
+ "value_sql": "42",
987
+ "expect": { "warehouse": 42 }
988
+ },
989
+ {
990
+ "key": "clickhouse/Int16/negative",
991
+ "native_type": "Int16",
992
+ "class": "negative",
993
+ "value_sql": "-32768",
994
+ "expect": { "warehouse": -32768 }
995
+ },
996
+ {
997
+ "key": "clickhouse/Int16/zero",
998
+ "native_type": "Int16",
999
+ "class": "zero",
1000
+ "value_sql": "0",
1001
+ "expect": { "warehouse": 0 }
1002
+ },
1003
+ {
1004
+ "key": "clickhouse/Nullable(Int16)/null",
1005
+ "native_type": "Nullable(Int16)",
1006
+ "class": "null",
1007
+ "value_sql": "NULL",
1008
+ "expect": { "warehouse": null }
1009
+ },
1010
+ {
1011
+ "key": "clickhouse/Int32/plain",
1012
+ "native_type": "Int32",
1013
+ "class": "plain",
1014
+ "value_sql": "42",
1015
+ "expect": { "warehouse": 42 }
1016
+ },
1017
+ {
1018
+ "key": "clickhouse/Int32/negative",
1019
+ "native_type": "Int32",
1020
+ "class": "negative",
1021
+ "value_sql": "-2147483648",
1022
+ "expect": { "warehouse": -2147483648 }
1023
+ },
1024
+ {
1025
+ "key": "clickhouse/Int32/zero",
1026
+ "native_type": "Int32",
1027
+ "class": "zero",
1028
+ "value_sql": "0",
1029
+ "expect": { "warehouse": 0 }
1030
+ },
1031
+ {
1032
+ "key": "clickhouse/Nullable(Int32)/null",
1033
+ "native_type": "Nullable(Int32)",
1034
+ "class": "null",
1035
+ "value_sql": "NULL",
1036
+ "expect": { "warehouse": null }
1037
+ },
1038
+ {
1039
+ "key": "clickhouse/Int64/plain",
1040
+ "native_type": "Int64",
1041
+ "class": "plain",
1042
+ "value_sql": "42",
1043
+ "expect": { "warehouse": 42 }
1044
+ },
1045
+ {
1046
+ "key": "clickhouse/Int64/negative",
1047
+ "native_type": "Int64",
1048
+ "class": "negative",
1049
+ "value_sql": "-9007199254740991",
1050
+ "expect": { "warehouse": -9007199254740991 }
1051
+ },
1052
+ {
1053
+ "key": "clickhouse/Int64/zero",
1054
+ "native_type": "Int64",
1055
+ "class": "zero",
1056
+ "value_sql": "0",
1057
+ "expect": { "warehouse": 0 }
1058
+ },
1059
+ {
1060
+ "key": "clickhouse/Int64/precision_gt_18",
1061
+ "native_type": "Int64",
1062
+ "class": "precision_gt_18",
1063
+ "value_sql": "9223372036854775807",
1064
+ "expect": { "warehouse": 0x8000000000000000 }
1065
+ },
1066
+ {
1067
+ "key": "clickhouse/Nullable(Int64)/null",
1068
+ "native_type": "Nullable(Int64)",
1069
+ "class": "null",
1070
+ "value_sql": "NULL",
1071
+ "expect": { "warehouse": null }
1072
+ },
1073
+ {
1074
+ "key": "clickhouse/UInt8/plain",
1075
+ "native_type": "UInt8",
1076
+ "class": "plain",
1077
+ "value_sql": "42",
1078
+ "expect": { "warehouse": 42 }
1079
+ },
1080
+ {
1081
+ "key": "clickhouse/UInt8/zero",
1082
+ "native_type": "UInt8",
1083
+ "class": "zero",
1084
+ "value_sql": "0",
1085
+ "expect": { "warehouse": 0 }
1086
+ },
1087
+ {
1088
+ "key": "clickhouse/Nullable(UInt8)/null",
1089
+ "native_type": "Nullable(UInt8)",
1090
+ "class": "null",
1091
+ "value_sql": "NULL",
1092
+ "expect": { "warehouse": null }
1093
+ },
1094
+ {
1095
+ "key": "clickhouse/UInt16/plain",
1096
+ "native_type": "UInt16",
1097
+ "class": "plain",
1098
+ "value_sql": "42",
1099
+ "expect": { "warehouse": 42 }
1100
+ },
1101
+ {
1102
+ "key": "clickhouse/UInt16/zero",
1103
+ "native_type": "UInt16",
1104
+ "class": "zero",
1105
+ "value_sql": "0",
1106
+ "expect": { "warehouse": 0 }
1107
+ },
1108
+ {
1109
+ "key": "clickhouse/Nullable(UInt16)/null",
1110
+ "native_type": "Nullable(UInt16)",
1111
+ "class": "null",
1112
+ "value_sql": "NULL",
1113
+ "expect": { "warehouse": null }
1114
+ },
1115
+ {
1116
+ "key": "clickhouse/UInt32/plain",
1117
+ "native_type": "UInt32",
1118
+ "class": "plain",
1119
+ "value_sql": "42",
1120
+ "expect": { "warehouse": 42 }
1121
+ },
1122
+ {
1123
+ "key": "clickhouse/UInt32/zero",
1124
+ "native_type": "UInt32",
1125
+ "class": "zero",
1126
+ "value_sql": "0",
1127
+ "expect": { "warehouse": 0 }
1128
+ },
1129
+ {
1130
+ "key": "clickhouse/Nullable(UInt32)/null",
1131
+ "native_type": "Nullable(UInt32)",
1132
+ "class": "null",
1133
+ "value_sql": "NULL",
1134
+ "expect": { "warehouse": null }
1135
+ },
1136
+ {
1137
+ "key": "clickhouse/UInt64/plain",
1138
+ "native_type": "UInt64",
1139
+ "class": "plain",
1140
+ "value_sql": "42",
1141
+ "expect": { "warehouse": 42 }
1142
+ },
1143
+ {
1144
+ "key": "clickhouse/UInt64/zero",
1145
+ "native_type": "UInt64",
1146
+ "class": "zero",
1147
+ "value_sql": "0",
1148
+ "expect": { "warehouse": 0 }
1149
+ },
1150
+ {
1151
+ "key": "clickhouse/UInt64/precision_gt_18",
1152
+ "native_type": "UInt64",
1153
+ "class": "precision_gt_18",
1154
+ "value_sql": "18446744073709551615",
1155
+ "expect": { "warehouse": "18446744073709551615" }
1156
+ },
1157
+ {
1158
+ "key": "clickhouse/Nullable(UInt64)/null",
1159
+ "native_type": "Nullable(UInt64)",
1160
+ "class": "null",
1161
+ "value_sql": "NULL",
1162
+ "expect": { "warehouse": null }
1163
+ },
1164
+ {
1165
+ "key": "clickhouse/Int128/plain",
1166
+ "native_type": "Int128",
1167
+ "class": "plain",
1168
+ "value_sql": "42",
1169
+ "expect": { "warehouse": "42" }
1170
+ },
1171
+ {
1172
+ "key": "clickhouse/Int128/negative",
1173
+ "native_type": "Int128",
1174
+ "class": "negative",
1175
+ "value_sql": "-42",
1176
+ "expect": { "warehouse": "-42" }
1177
+ },
1178
+ {
1179
+ "key": "clickhouse/Int128/zero",
1180
+ "native_type": "Int128",
1181
+ "class": "zero",
1182
+ "value_sql": "0",
1183
+ "expect": { "warehouse": "0" }
1184
+ },
1185
+ {
1186
+ "key": "clickhouse/Int128/precision_gt_18",
1187
+ "native_type": "Int128",
1188
+ "class": "precision_gt_18",
1189
+ "value_sql": "toInt128('-170141183460469231731687303715884105728')",
1190
+ "expect": { "warehouse": "-170141183460469231731687303715884105728" }
1191
+ },
1192
+ {
1193
+ "key": "clickhouse/Nullable(Int128)/null",
1194
+ "native_type": "Nullable(Int128)",
1195
+ "class": "null",
1196
+ "value_sql": "NULL",
1197
+ "expect": { "warehouse": null }
1198
+ },
1199
+ {
1200
+ "key": "clickhouse/UInt128/plain",
1201
+ "native_type": "UInt128",
1202
+ "class": "plain",
1203
+ "value_sql": "42",
1204
+ "expect": { "warehouse": "42" }
1205
+ },
1206
+ {
1207
+ "key": "clickhouse/UInt128/zero",
1208
+ "native_type": "UInt128",
1209
+ "class": "zero",
1210
+ "value_sql": "0",
1211
+ "expect": { "warehouse": "0" }
1212
+ },
1213
+ {
1214
+ "key": "clickhouse/UInt128/precision_gt_18",
1215
+ "native_type": "UInt128",
1216
+ "class": "precision_gt_18",
1217
+ "value_sql": "toUInt128('340282366920938463463374607431768211455')",
1218
+ "expect": { "warehouse": "340282366920938463463374607431768211455" }
1219
+ },
1220
+ {
1221
+ "key": "clickhouse/Nullable(UInt128)/null",
1222
+ "native_type": "Nullable(UInt128)",
1223
+ "class": "null",
1224
+ "value_sql": "NULL",
1225
+ "expect": { "warehouse": null }
1226
+ },
1227
+ {
1228
+ "key": "clickhouse/Int256/plain",
1229
+ "native_type": "Int256",
1230
+ "class": "plain",
1231
+ "value_sql": "42",
1232
+ "expect": { "warehouse": "42" }
1233
+ },
1234
+ {
1235
+ "key": "clickhouse/Int256/negative",
1236
+ "native_type": "Int256",
1237
+ "class": "negative",
1238
+ "value_sql": "-42",
1239
+ "expect": { "warehouse": "-42" }
1240
+ },
1241
+ {
1242
+ "key": "clickhouse/Int256/zero",
1243
+ "native_type": "Int256",
1244
+ "class": "zero",
1245
+ "value_sql": "0",
1246
+ "expect": { "warehouse": "0" }
1247
+ },
1248
+ {
1249
+ "key": "clickhouse/Int256/precision_gt_18",
1250
+ "native_type": "Int256",
1251
+ "class": "precision_gt_18",
1252
+ "value_sql": "toInt256('-57896044618658097711785492504343953926634992332820282019728792003956564819968')",
1253
+ "expect": { "warehouse": "-57896044618658097711785492504343953926634992332820282019728792003956564819968" }
1254
+ },
1255
+ {
1256
+ "key": "clickhouse/Nullable(Int256)/null",
1257
+ "native_type": "Nullable(Int256)",
1258
+ "class": "null",
1259
+ "value_sql": "NULL",
1260
+ "expect": { "warehouse": null }
1261
+ },
1262
+ {
1263
+ "key": "clickhouse/UInt256/plain",
1264
+ "native_type": "UInt256",
1265
+ "class": "plain",
1266
+ "value_sql": "42",
1267
+ "expect": { "warehouse": "42" }
1268
+ },
1269
+ {
1270
+ "key": "clickhouse/UInt256/zero",
1271
+ "native_type": "UInt256",
1272
+ "class": "zero",
1273
+ "value_sql": "0",
1274
+ "expect": { "warehouse": "0" }
1275
+ },
1276
+ {
1277
+ "key": "clickhouse/UInt256/precision_gt_18",
1278
+ "native_type": "UInt256",
1279
+ "class": "precision_gt_18",
1280
+ "value_sql": "toUInt256('115792089237316195423570985008687907853269984665640564039457584007913129639935')",
1281
+ "expect": { "warehouse": "115792089237316195423570985008687907853269984665640564039457584007913129639935" }
1282
+ },
1283
+ {
1284
+ "key": "clickhouse/Nullable(UInt256)/null",
1285
+ "native_type": "Nullable(UInt256)",
1286
+ "class": "null",
1287
+ "value_sql": "NULL",
1288
+ "expect": { "warehouse": null }
1289
+ },
1290
+ {
1291
+ "key": "clickhouse/Float32/plain",
1292
+ "native_type": "Float32",
1293
+ "class": "plain",
1294
+ "value_sql": "0.1",
1295
+ "expect": { "warehouse": .1 }
1296
+ },
1297
+ {
1298
+ "key": "clickhouse/Float32/negative",
1299
+ "native_type": "Float32",
1300
+ "class": "negative",
1301
+ "value_sql": "-1.5",
1302
+ "expect": { "warehouse": -1.5 }
1303
+ },
1304
+ {
1305
+ "key": "clickhouse/Float32/zero",
1306
+ "native_type": "Float32",
1307
+ "class": "zero",
1308
+ "value_sql": "0",
1309
+ "expect": { "warehouse": 0 }
1310
+ },
1311
+ {
1312
+ "key": "clickhouse/Float32/nan_inf",
1313
+ "native_type": "Float32",
1314
+ "class": "nan_inf",
1315
+ "value_sql": "nan",
1316
+ "expect": { "warehouse": null }
1317
+ },
1318
+ {
1319
+ "key": "clickhouse/Nullable(Float32)/null",
1320
+ "native_type": "Nullable(Float32)",
1321
+ "class": "null",
1322
+ "value_sql": "NULL",
1323
+ "expect": { "warehouse": null }
1324
+ },
1325
+ {
1326
+ "key": "clickhouse/Float64/plain",
1327
+ "native_type": "Float64",
1328
+ "class": "plain",
1329
+ "value_sql": "0.1",
1330
+ "expect": { "warehouse": .1 }
1331
+ },
1332
+ {
1333
+ "key": "clickhouse/Float64/negative",
1334
+ "native_type": "Float64",
1335
+ "class": "negative",
1336
+ "value_sql": "-1.5",
1337
+ "expect": { "warehouse": -1.5 }
1338
+ },
1339
+ {
1340
+ "key": "clickhouse/Float64/zero",
1341
+ "native_type": "Float64",
1342
+ "class": "zero",
1343
+ "value_sql": "0",
1344
+ "expect": { "warehouse": 0 }
1345
+ },
1346
+ {
1347
+ "key": "clickhouse/Float64/nan_inf",
1348
+ "native_type": "Float64",
1349
+ "class": "nan_inf",
1350
+ "value_sql": "inf",
1351
+ "expect": { "warehouse": null }
1352
+ },
1353
+ {
1354
+ "key": "clickhouse/Nullable(Float64)/null",
1355
+ "native_type": "Nullable(Float64)",
1356
+ "class": "null",
1357
+ "value_sql": "NULL",
1358
+ "expect": { "warehouse": null }
1359
+ },
1360
+ {
1361
+ "key": "clickhouse/Decimal(18, 4)/plain",
1362
+ "native_type": "Decimal(18, 4)",
1363
+ "class": "plain",
1364
+ "value_sql": "1234.5678",
1365
+ "expect": { "warehouse": "1234.5678" }
1366
+ },
1367
+ {
1368
+ "key": "clickhouse/Decimal(18, 4)/negative",
1369
+ "native_type": "Decimal(18, 4)",
1370
+ "class": "negative",
1371
+ "value_sql": "-1.25",
1372
+ "expect": { "warehouse": "-1.25" }
1373
+ },
1374
+ {
1375
+ "key": "clickhouse/Decimal(18, 4)/zero",
1376
+ "native_type": "Decimal(18, 4)",
1377
+ "class": "zero",
1378
+ "value_sql": "0",
1379
+ "expect": { "warehouse": "0" }
1380
+ },
1381
+ {
1382
+ "key": "clickhouse/Nullable(Decimal(18, 4))/null",
1383
+ "native_type": "Nullable(Decimal(18, 4))",
1384
+ "class": "null",
1385
+ "value_sql": "NULL",
1386
+ "expect": { "warehouse": null }
1387
+ },
1388
+ {
1389
+ "key": "clickhouse/Decimal(38, 10)/precision_gt_18",
1390
+ "native_type": "Decimal(38, 10)",
1391
+ "class": "precision_gt_18",
1392
+ "value_sql": "toDecimal128('1234567890123456789.0123456789', 10)",
1393
+ "expect": { "warehouse": "1.2345678901234568e+18" }
1394
+ },
1395
+ {
1396
+ "key": "clickhouse/Decimal(38, 0)/precision_gt_18",
1397
+ "native_type": "Decimal(38, 0)",
1398
+ "class": "precision_gt_18",
1399
+ "value_sql": "toDecimal128('12345678901234567890123456789012345678', 0)",
1400
+ "expect": { "warehouse": "12345678901234567890123456789012345678" }
1401
+ },
1402
+ {
1403
+ "key": "clickhouse/Decimal32(4)/plain",
1404
+ "native_type": "Decimal32(4)",
1405
+ "class": "plain",
1406
+ "value_sql": "1.5",
1407
+ "expect": { "warehouse": "1.5" }
1408
+ },
1409
+ {
1410
+ "key": "clickhouse/Date/plain",
1411
+ "native_type": "Date",
1412
+ "class": "plain",
1413
+ "value_sql": "'2024-03-10'",
1414
+ "expect": { "warehouse": "2024-03-10" }
1415
+ },
1416
+ {
1417
+ "key": "clickhouse/Date/date_before_1970",
1418
+ "native_type": "Date",
1419
+ "class": "date_before_1970",
1420
+ "value_sql": "'1969-12-31'",
1421
+ "expect": { "warehouse": "1970-01-01" }
1422
+ },
1423
+ {
1424
+ "key": "clickhouse/Date/date_after_2100",
1425
+ "native_type": "Date",
1426
+ "class": "date_after_2100",
1427
+ "value_sql": "'2149-06-06'",
1428
+ "expect": { "warehouse": "2149-06-06" }
1429
+ },
1430
+ {
1431
+ "key": "clickhouse/Nullable(Date)/null",
1432
+ "native_type": "Nullable(Date)",
1433
+ "class": "null",
1434
+ "value_sql": "NULL",
1435
+ "expect": { "warehouse": null }
1436
+ },
1437
+ {
1438
+ "key": "clickhouse/Date32/plain",
1439
+ "native_type": "Date32",
1440
+ "class": "plain",
1441
+ "value_sql": "'2024-03-10'",
1442
+ "expect": { "warehouse": "2024-03-10" }
1443
+ },
1444
+ {
1445
+ "key": "clickhouse/Date32/date_before_1970",
1446
+ "native_type": "Date32",
1447
+ "class": "date_before_1970",
1448
+ "value_sql": "'1900-01-01'",
1449
+ "expect": { "warehouse": "1900-01-01" }
1450
+ },
1451
+ {
1452
+ "key": "clickhouse/Date32/date_after_2100",
1453
+ "native_type": "Date32",
1454
+ "class": "date_after_2100",
1455
+ "value_sql": "'2299-12-31'",
1456
+ "expect": { "warehouse": "2299-12-31" }
1457
+ },
1458
+ {
1459
+ "key": "clickhouse/Nullable(Date32)/null",
1460
+ "native_type": "Nullable(Date32)",
1461
+ "class": "null",
1462
+ "value_sql": "NULL",
1463
+ "expect": { "warehouse": null }
1464
+ },
1465
+ {
1466
+ "key": "clickhouse/DateTime/plain",
1467
+ "native_type": "DateTime",
1468
+ "class": "plain",
1469
+ "value_sql": "'2024-03-10 12:34:56'",
1470
+ "expect": { "warehouse": "2024-03-10 12:34:56" }
1471
+ },
1472
+ {
1473
+ "key": "clickhouse/DateTime/date_before_1970",
1474
+ "native_type": "DateTime",
1475
+ "class": "date_before_1970",
1476
+ "value_sql": "'1969-12-31 23:59:59'",
1477
+ "expect": { "warehouse": "1970-01-01 00:00:00" }
1478
+ },
1479
+ {
1480
+ "key": "clickhouse/DateTime/date_after_2100",
1481
+ "native_type": "DateTime",
1482
+ "class": "date_after_2100",
1483
+ "value_sql": "'2105-12-31 23:59:59'",
1484
+ "expect": { "warehouse": "2105-12-31 23:59:59" }
1485
+ },
1486
+ {
1487
+ "key": "clickhouse/Nullable(DateTime)/null",
1488
+ "native_type": "Nullable(DateTime)",
1489
+ "class": "null",
1490
+ "value_sql": "NULL",
1491
+ "expect": { "warehouse": null }
1492
+ },
1493
+ {
1494
+ "key": "clickhouse/DateTime('Asia/Kolkata')/tz_bearing",
1495
+ "native_type": "DateTime('Asia/Kolkata')",
1496
+ "class": "tz_bearing",
1497
+ "value_sql": "'2024-03-10 12:34:56'",
1498
+ "expect": { "warehouse": "2024-03-10 12:34:56" }
1499
+ },
1500
+ {
1501
+ "key": "clickhouse/DateTime64(3)/plain",
1502
+ "native_type": "DateTime64(3)",
1503
+ "class": "plain",
1504
+ "value_sql": "'2024-03-10 12:34:56.789'",
1505
+ "expect": { "warehouse": "2024-03-10 12:34:56.789000" }
1506
+ },
1507
+ {
1508
+ "key": "clickhouse/DateTime64(3)/date_before_1970",
1509
+ "native_type": "DateTime64(3)",
1510
+ "class": "date_before_1970",
1511
+ "value_sql": "'1969-07-20 20:17:40.500'",
1512
+ "expect": { "warehouse": "1969-07-20 20:17:40.500000" }
1513
+ },
1514
+ {
1515
+ "key": "clickhouse/DateTime64(3)/date_after_2100",
1516
+ "native_type": "DateTime64(3)",
1517
+ "class": "date_after_2100",
1518
+ "value_sql": "'2150-01-01 00:00:00.000'",
1519
+ "expect": { "warehouse": "2150-01-01 00:00:00" }
1520
+ },
1521
+ {
1522
+ "key": "clickhouse/Nullable(DateTime64(3))/null",
1523
+ "native_type": "Nullable(DateTime64(3))",
1524
+ "class": "null",
1525
+ "value_sql": "NULL",
1526
+ "expect": { "warehouse": null }
1527
+ },
1528
+ {
1529
+ "key": "clickhouse/DateTime64(6, 'America/New_York')/tz_bearing",
1530
+ "native_type": "DateTime64(6, 'America/New_York')",
1531
+ "class": "tz_bearing",
1532
+ "value_sql": "'2024-03-10 12:34:56.123456'",
1533
+ "expect": { "warehouse": "2024-03-10 12:34:56.123456" }
1534
+ },
1535
+ {
1536
+ "key": "clickhouse/String/plain",
1537
+ "native_type": "String",
1538
+ "class": "plain",
1539
+ "value_sql": "'plain text'",
1540
+ "expect": { "warehouse": "plain text" }
1541
+ },
1542
+ {
1543
+ "key": "clickhouse/String/empty",
1544
+ "native_type": "String",
1545
+ "class": "empty",
1546
+ "value_sql": "''",
1547
+ "expect": { "warehouse": "" }
1548
+ },
1549
+ {
1550
+ "key": "clickhouse/String/whitespace",
1551
+ "native_type": "String",
1552
+ "class": "whitespace",
1553
+ "value_sql": "' \\t\\n '",
1554
+ "expect": { "warehouse": " \n " }
1555
+ },
1556
+ {
1557
+ "key": "clickhouse/String/non_bmp",
1558
+ "native_type": "String",
1559
+ "class": "non_bmp",
1560
+ "value_sql": "'𝔘nicode'",
1561
+ "expect": { "warehouse": "𝔘nicode" }
1562
+ },
1563
+ {
1564
+ "key": "clickhouse/String/len_gt_1k",
1565
+ "native_type": "String",
1566
+ "class": "len_gt_1k",
1567
+ "value_sql": "repeat('0123456789', 101)",
1568
+ "expect": { "warehouse": "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" }
1569
+ },
1570
+ {
1571
+ "key": "clickhouse/Nullable(String)/null",
1572
+ "native_type": "Nullable(String)",
1573
+ "class": "null",
1574
+ "value_sql": "NULL",
1575
+ "expect": { "warehouse": null }
1576
+ },
1577
+ {
1578
+ "key": "clickhouse/FixedString(4)/plain",
1579
+ "native_type": "FixedString(4)",
1580
+ "class": "plain",
1581
+ "value_sql": "'ab'",
1582
+ "expect": { "warehouse": "ab\0\0" }
1583
+ },
1584
+ {
1585
+ "key": "clickhouse/FixedString(4)/empty",
1586
+ "native_type": "FixedString(4)",
1587
+ "class": "empty",
1588
+ "value_sql": "''",
1589
+ "expect": { "warehouse": "\0\0\0\0" }
1590
+ },
1591
+ {
1592
+ "key": "clickhouse/Nullable(FixedString(4))/null",
1593
+ "native_type": "Nullable(FixedString(4))",
1594
+ "class": "null",
1595
+ "value_sql": "NULL",
1596
+ "expect": { "warehouse": null }
1597
+ },
1598
+ {
1599
+ "key": "clickhouse/LowCardinality(String)/plain",
1600
+ "native_type": "LowCardinality(String)",
1601
+ "class": "plain",
1602
+ "value_sql": "'low cardinality'",
1603
+ "expect": { "warehouse": "low cardinality" }
1604
+ },
1605
+ {
1606
+ "key": "clickhouse/LowCardinality(Nullable(String))/null",
1607
+ "native_type": "LowCardinality(Nullable(String))",
1608
+ "class": "null",
1609
+ "value_sql": "NULL",
1610
+ "expect": { "warehouse": null }
1611
+ },
1612
+ {
1613
+ "key": "clickhouse/Enum8('a' = 1, 'b' = 2)/plain",
1614
+ "native_type": "Enum8('a' = 1, 'b' = 2)",
1615
+ "class": "plain",
1616
+ "value_sql": "'b'",
1617
+ "expect": { "warehouse": "b" }
1618
+ },
1619
+ {
1620
+ "key": "clickhouse/Nullable(Enum8('a' = 1, 'b' = 2))/null",
1621
+ "native_type": "Nullable(Enum8('a' = 1, 'b' = 2))",
1622
+ "class": "null",
1623
+ "value_sql": "NULL",
1624
+ "expect": { "warehouse": null }
1625
+ },
1626
+ {
1627
+ "key": "clickhouse/UUID/plain",
1628
+ "native_type": "UUID",
1629
+ "class": "plain",
1630
+ "value_sql": "'00000000-0000-4000-8000-000000000001'",
1631
+ "expect": { "warehouse": "00000000-0000-4000-8000-000000000001" }
1632
+ },
1633
+ {
1634
+ "key": "clickhouse/Nullable(UUID)/null",
1635
+ "native_type": "Nullable(UUID)",
1636
+ "class": "null",
1637
+ "value_sql": "NULL",
1638
+ "expect": { "warehouse": null }
1639
+ },
1640
+ {
1641
+ "key": "clickhouse/IPv4/plain",
1642
+ "native_type": "IPv4",
1643
+ "class": "plain",
1644
+ "value_sql": "'10.0.0.1'",
1645
+ "expect": { "warehouse": "10.0.0.1" }
1646
+ },
1647
+ {
1648
+ "key": "clickhouse/Nullable(IPv4)/null",
1649
+ "native_type": "Nullable(IPv4)",
1650
+ "class": "null",
1651
+ "value_sql": "NULL",
1652
+ "expect": { "warehouse": null }
1653
+ },
1654
+ {
1655
+ "key": "clickhouse/IPv6/plain",
1656
+ "native_type": "IPv6",
1657
+ "class": "plain",
1658
+ "value_sql": "'2001:db8::1'",
1659
+ "expect": { "warehouse": "2001:db8::1" }
1660
+ },
1661
+ {
1662
+ "key": "clickhouse/Nullable(IPv6)/null",
1663
+ "native_type": "Nullable(IPv6)",
1664
+ "class": "null",
1665
+ "value_sql": "NULL",
1666
+ "expect": { "warehouse": null }
1667
+ },
1668
+ {
1669
+ "key": "clickhouse/JSON/nested_json",
1670
+ "native_type": "JSON",
1671
+ "class": "nested_json",
1672
+ "value_sql": "'{\"a\":{\"b\":\"x\",\"n\":1.5}}'",
1673
+ "expect": { "warehouse": { "a": {
1674
+ "b": "x",
1675
+ "n": 1.5
1676
+ } } }
1677
+ },
1678
+ {
1679
+ "key": "clickhouse/JSON/empty",
1680
+ "native_type": "JSON",
1681
+ "class": "empty",
1682
+ "value_sql": "'{}'",
1683
+ "expect": { "warehouse": {} }
1684
+ },
1685
+ {
1686
+ "key": "clickhouse/Array(Int32)/array",
1687
+ "native_type": "Array(Int32)",
1688
+ "class": "array",
1689
+ "value_sql": "[1, -2, 3]",
1690
+ "expect": { "warehouse": [
1691
+ 1,
1692
+ -2,
1693
+ 3
1694
+ ] }
1695
+ },
1696
+ {
1697
+ "key": "clickhouse/Array(Int32)/empty",
1698
+ "native_type": "Array(Int32)",
1699
+ "class": "empty",
1700
+ "value_sql": "[]",
1701
+ "expect": { "warehouse": [] }
1702
+ },
1703
+ {
1704
+ "key": "clickhouse/Array(Nullable(String))/array",
1705
+ "native_type": "Array(Nullable(String))",
1706
+ "class": "array",
1707
+ "value_sql": "['a', NULL]",
1708
+ "expect": { "warehouse": ["a", null] }
1709
+ },
1710
+ {
1711
+ "key": "clickhouse/Tuple(Int32, String)/array",
1712
+ "native_type": "Tuple(Int32, String)",
1713
+ "class": "array",
1714
+ "value_sql": "(1, 'a')",
1715
+ "expect": { "warehouse": [1, "a"] }
1716
+ },
1717
+ {
1718
+ "key": "clickhouse/Map(String, Int32)/nested_json",
1719
+ "native_type": "Map(String, Int32)",
1720
+ "class": "nested_json",
1721
+ "value_sql": "map('a', 1, 'b', 2)",
1722
+ "expect": { "warehouse": {
1723
+ "a": 1,
1724
+ "b": 2
1725
+ } }
1726
+ },
1727
+ {
1728
+ "key": "clickhouse/Map(String, Int32)/empty",
1729
+ "native_type": "Map(String, Int32)",
1730
+ "class": "empty",
1731
+ "value_sql": "map()",
1732
+ "expect": { "warehouse": {} }
1733
+ },
1734
+ {
1735
+ "key": "clickhouse/SimpleAggregateFunction(sum, UInt64)/plain",
1736
+ "native_type": "SimpleAggregateFunction(sum, UInt64)",
1737
+ "class": "plain",
1738
+ "value_sql": "3",
1739
+ "expect": { "warehouse": 3 }
1740
+ },
1741
+ {
1742
+ "key": "clickhouse/AggregateFunction(sum, UInt64)/plain",
1743
+ "native_type": "AggregateFunction(sum, UInt64)",
1744
+ "class": "plain",
1745
+ "value_sql": "arrayReduce('sumState', [toUInt64(3)])",
1746
+ "expect": { "warehouse": "\0\0\0\0\0\0\0" }
1747
+ }
1748
+ ] },
1749
+ "postgres": { "cases": [
1750
+ {
1751
+ "key": "postgres/bool/plain",
1752
+ "native_type": "bool",
1753
+ "class": "plain",
1754
+ "value_sql": "true",
1755
+ "expect": {
1756
+ "warehouse": true,
1757
+ "oltp": true
1758
+ }
1759
+ },
1760
+ {
1761
+ "key": "postgres/bool/null",
1762
+ "native_type": "bool",
1763
+ "class": "null",
1764
+ "value_sql": "NULL",
1765
+ "expect": {
1766
+ "warehouse": null,
1767
+ "oltp": null
1768
+ }
1769
+ },
1770
+ {
1771
+ "key": "postgres/int2/plain",
1772
+ "native_type": "int2",
1773
+ "class": "plain",
1774
+ "value_sql": "42",
1775
+ "expect": {
1776
+ "warehouse": 42,
1777
+ "oltp": 42
1778
+ }
1779
+ },
1780
+ {
1781
+ "key": "postgres/int2/negative",
1782
+ "native_type": "int2",
1783
+ "class": "negative",
1784
+ "value_sql": "-32768",
1785
+ "expect": {
1786
+ "warehouse": -32768,
1787
+ "oltp": -32768
1788
+ }
1789
+ },
1790
+ {
1791
+ "key": "postgres/int2/zero",
1792
+ "native_type": "int2",
1793
+ "class": "zero",
1794
+ "value_sql": "0",
1795
+ "expect": {
1796
+ "warehouse": 0,
1797
+ "oltp": 0
1798
+ }
1799
+ },
1800
+ {
1801
+ "key": "postgres/int2/null",
1802
+ "native_type": "int2",
1803
+ "class": "null",
1804
+ "value_sql": "NULL",
1805
+ "expect": {
1806
+ "warehouse": null,
1807
+ "oltp": null
1808
+ }
1809
+ },
1810
+ {
1811
+ "key": "postgres/int4/plain",
1812
+ "native_type": "int4",
1813
+ "class": "plain",
1814
+ "value_sql": "42",
1815
+ "expect": {
1816
+ "warehouse": 42,
1817
+ "oltp": 42
1818
+ }
1819
+ },
1820
+ {
1821
+ "key": "postgres/int4/negative",
1822
+ "native_type": "int4",
1823
+ "class": "negative",
1824
+ "value_sql": "-2147483648",
1825
+ "expect": {
1826
+ "warehouse": -2147483648,
1827
+ "oltp": -2147483648
1828
+ }
1829
+ },
1830
+ {
1831
+ "key": "postgres/int4/zero",
1832
+ "native_type": "int4",
1833
+ "class": "zero",
1834
+ "value_sql": "0",
1835
+ "expect": {
1836
+ "warehouse": 0,
1837
+ "oltp": 0
1838
+ }
1839
+ },
1840
+ {
1841
+ "key": "postgres/int4/null",
1842
+ "native_type": "int4",
1843
+ "class": "null",
1844
+ "value_sql": "NULL",
1845
+ "expect": {
1846
+ "warehouse": null,
1847
+ "oltp": null
1848
+ }
1849
+ },
1850
+ {
1851
+ "key": "postgres/int8/plain",
1852
+ "native_type": "int8",
1853
+ "class": "plain",
1854
+ "value_sql": "42",
1855
+ "expect": {
1856
+ "warehouse": 42,
1857
+ "oltp": 42
1858
+ }
1859
+ },
1860
+ {
1861
+ "key": "postgres/int8/negative",
1862
+ "native_type": "int8",
1863
+ "class": "negative",
1864
+ "value_sql": "-9007199254740991",
1865
+ "expect": {
1866
+ "warehouse": -9007199254740991,
1867
+ "oltp": -9007199254740991
1868
+ }
1869
+ },
1870
+ {
1871
+ "key": "postgres/int8/zero",
1872
+ "native_type": "int8",
1873
+ "class": "zero",
1874
+ "value_sql": "0",
1875
+ "expect": {
1876
+ "warehouse": 0,
1877
+ "oltp": 0
1878
+ }
1879
+ },
1880
+ {
1881
+ "key": "postgres/int8/precision_gt_18",
1882
+ "native_type": "int8",
1883
+ "class": "precision_gt_18",
1884
+ "value_sql": "9223372036854775807",
1885
+ "expect": {
1886
+ "warehouse": 0x8000000000000000,
1887
+ "oltp": 0x8000000000000000
1888
+ }
1889
+ },
1890
+ {
1891
+ "key": "postgres/int8/null",
1892
+ "native_type": "int8",
1893
+ "class": "null",
1894
+ "value_sql": "NULL",
1895
+ "expect": {
1896
+ "warehouse": null,
1897
+ "oltp": null
1898
+ }
1899
+ },
1900
+ {
1901
+ "key": "postgres/float4/plain",
1902
+ "native_type": "float4",
1903
+ "class": "plain",
1904
+ "value_sql": "0.1",
1905
+ "expect": {
1906
+ "warehouse": .10000000149011612,
1907
+ "oltp": .10000000149011612
1908
+ }
1909
+ },
1910
+ {
1911
+ "key": "postgres/float4/negative",
1912
+ "native_type": "float4",
1913
+ "class": "negative",
1914
+ "value_sql": "-1.5",
1915
+ "expect": {
1916
+ "warehouse": -1.5,
1917
+ "oltp": -1.5
1918
+ }
1919
+ },
1920
+ {
1921
+ "key": "postgres/float4/zero",
1922
+ "native_type": "float4",
1923
+ "class": "zero",
1924
+ "value_sql": "0",
1925
+ "expect": {
1926
+ "warehouse": 0,
1927
+ "oltp": 0
1928
+ }
1929
+ },
1930
+ {
1931
+ "key": "postgres/float4/nan_inf",
1932
+ "native_type": "float4",
1933
+ "class": "nan_inf",
1934
+ "value_sql": "'NaN'",
1935
+ "expect": {
1936
+ "warehouse": null,
1937
+ "oltp": null
1938
+ }
1939
+ },
1940
+ {
1941
+ "key": "postgres/float4/null",
1942
+ "native_type": "float4",
1943
+ "class": "null",
1944
+ "value_sql": "NULL",
1945
+ "expect": {
1946
+ "warehouse": null,
1947
+ "oltp": null
1948
+ }
1949
+ },
1950
+ {
1951
+ "key": "postgres/float8/plain",
1952
+ "native_type": "float8",
1953
+ "class": "plain",
1954
+ "value_sql": "0.1",
1955
+ "expect": {
1956
+ "warehouse": .1,
1957
+ "oltp": .1
1958
+ }
1959
+ },
1960
+ {
1961
+ "key": "postgres/float8/negative",
1962
+ "native_type": "float8",
1963
+ "class": "negative",
1964
+ "value_sql": "-1.5",
1965
+ "expect": {
1966
+ "warehouse": -1.5,
1967
+ "oltp": -1.5
1968
+ }
1969
+ },
1970
+ {
1971
+ "key": "postgres/float8/zero",
1972
+ "native_type": "float8",
1973
+ "class": "zero",
1974
+ "value_sql": "0",
1975
+ "expect": {
1976
+ "warehouse": 0,
1977
+ "oltp": 0
1978
+ }
1979
+ },
1980
+ {
1981
+ "key": "postgres/float8/nan_inf",
1982
+ "native_type": "float8",
1983
+ "class": "nan_inf",
1984
+ "value_sql": "'Infinity'",
1985
+ "expect": {
1986
+ "warehouse": null,
1987
+ "oltp": null
1988
+ }
1989
+ },
1990
+ {
1991
+ "key": "postgres/float8/null",
1992
+ "native_type": "float8",
1993
+ "class": "null",
1994
+ "value_sql": "NULL",
1995
+ "expect": {
1996
+ "warehouse": null,
1997
+ "oltp": null
1998
+ }
1999
+ },
2000
+ {
2001
+ "key": "postgres/numeric/plain",
2002
+ "native_type": "numeric",
2003
+ "class": "plain",
2004
+ "value_sql": "1234.5678",
2005
+ "expect": {
2006
+ "warehouse": "1234.5678",
2007
+ "oltp": { "$error": "Postgres type `numeric`, which cannot be returned directly" }
2008
+ }
2009
+ },
2010
+ {
2011
+ "key": "postgres/numeric/negative",
2012
+ "native_type": "numeric",
2013
+ "class": "negative",
2014
+ "value_sql": "-1.25",
2015
+ "expect": {
2016
+ "warehouse": "-1.25",
2017
+ "oltp": { "$error": "Postgres type `numeric`, which cannot be returned directly" }
2018
+ }
2019
+ },
2020
+ {
2021
+ "key": "postgres/numeric/zero",
2022
+ "native_type": "numeric",
2023
+ "class": "zero",
2024
+ "value_sql": "0",
2025
+ "expect": {
2026
+ "warehouse": "0.0",
2027
+ "oltp": { "$error": "Postgres type `numeric`, which cannot be returned directly" }
2028
+ }
2029
+ },
2030
+ {
2031
+ "key": "postgres/numeric/nan_inf",
2032
+ "native_type": "numeric",
2033
+ "class": "nan_inf",
2034
+ "value_sql": "'NaN'",
2035
+ "expect": {
2036
+ "warehouse": "NaN",
2037
+ "oltp": { "$error": "Postgres type `numeric`, which cannot be returned directly" }
2038
+ }
2039
+ },
2040
+ {
2041
+ "key": "postgres/numeric/precision_gt_18",
2042
+ "native_type": "numeric",
2043
+ "class": "precision_gt_18",
2044
+ "value_sql": "1234567890123456789.0123456789",
2045
+ "expect": {
2046
+ "warehouse": "1234567890123456768.0",
2047
+ "oltp": { "$error": "Postgres type `numeric`, which cannot be returned directly" }
2048
+ }
2049
+ },
2050
+ {
2051
+ "key": "postgres/numeric/null",
2052
+ "native_type": "numeric",
2053
+ "class": "null",
2054
+ "value_sql": "NULL",
2055
+ "expect": {
2056
+ "warehouse": null,
2057
+ "oltp": { "$error": "Postgres type `numeric`, which cannot be returned directly" }
2058
+ }
2059
+ },
2060
+ {
2061
+ "key": "postgres/text/plain",
2062
+ "native_type": "text",
2063
+ "class": "plain",
2064
+ "value_sql": "'plain text'",
2065
+ "expect": {
2066
+ "warehouse": "plain text",
2067
+ "oltp": "plain text"
2068
+ }
2069
+ },
2070
+ {
2071
+ "key": "postgres/text/empty",
2072
+ "native_type": "text",
2073
+ "class": "empty",
2074
+ "value_sql": "''",
2075
+ "expect": {
2076
+ "warehouse": "",
2077
+ "oltp": ""
2078
+ }
2079
+ },
2080
+ {
2081
+ "key": "postgres/text/whitespace",
2082
+ "native_type": "text",
2083
+ "class": "whitespace",
2084
+ "value_sql": "E' \\t\\n '",
2085
+ "expect": {
2086
+ "warehouse": " \n ",
2087
+ "oltp": " \n "
2088
+ }
2089
+ },
2090
+ {
2091
+ "key": "postgres/text/non_bmp",
2092
+ "native_type": "text",
2093
+ "class": "non_bmp",
2094
+ "value_sql": "'𝔘nicode'",
2095
+ "expect": {
2096
+ "warehouse": "𝔘nicode",
2097
+ "oltp": "𝔘nicode"
2098
+ }
2099
+ },
2100
+ {
2101
+ "key": "postgres/text/len_gt_1k",
2102
+ "native_type": "text",
2103
+ "class": "len_gt_1k",
2104
+ "value_sql": "repeat('0123456789', 101)",
2105
+ "expect": {
2106
+ "warehouse": "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789",
2107
+ "oltp": "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
2108
+ }
2109
+ },
2110
+ {
2111
+ "key": "postgres/text/null",
2112
+ "native_type": "text",
2113
+ "class": "null",
2114
+ "value_sql": "NULL",
2115
+ "expect": {
2116
+ "warehouse": null,
2117
+ "oltp": null
2118
+ }
2119
+ },
2120
+ {
2121
+ "key": "postgres/varchar(2000)/plain",
2122
+ "native_type": "varchar(2000)",
2123
+ "class": "plain",
2124
+ "value_sql": "'plain varchar'",
2125
+ "expect": {
2126
+ "warehouse": "plain varchar",
2127
+ "oltp": "plain varchar"
2128
+ }
2129
+ },
2130
+ {
2131
+ "key": "postgres/varchar(2000)/empty",
2132
+ "native_type": "varchar(2000)",
2133
+ "class": "empty",
2134
+ "value_sql": "''",
2135
+ "expect": {
2136
+ "warehouse": "",
2137
+ "oltp": ""
2138
+ }
2139
+ },
2140
+ {
2141
+ "key": "postgres/varchar(2000)/whitespace",
2142
+ "native_type": "varchar(2000)",
2143
+ "class": "whitespace",
2144
+ "value_sql": "E' \\t\\n '",
2145
+ "expect": {
2146
+ "warehouse": " \n ",
2147
+ "oltp": " \n "
2148
+ }
2149
+ },
2150
+ {
2151
+ "key": "postgres/varchar(2000)/non_bmp",
2152
+ "native_type": "varchar(2000)",
2153
+ "class": "non_bmp",
2154
+ "value_sql": "'𝔘nicode'",
2155
+ "expect": {
2156
+ "warehouse": "𝔘nicode",
2157
+ "oltp": "𝔘nicode"
2158
+ }
2159
+ },
2160
+ {
2161
+ "key": "postgres/varchar(2000)/len_gt_1k",
2162
+ "native_type": "varchar(2000)",
2163
+ "class": "len_gt_1k",
2164
+ "value_sql": "repeat('0123456789', 101)",
2165
+ "expect": {
2166
+ "warehouse": "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789",
2167
+ "oltp": "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
2168
+ }
2169
+ },
2170
+ {
2171
+ "key": "postgres/varchar(2000)/null",
2172
+ "native_type": "varchar(2000)",
2173
+ "class": "null",
2174
+ "value_sql": "NULL",
2175
+ "expect": {
2176
+ "warehouse": null,
2177
+ "oltp": null
2178
+ }
2179
+ },
2180
+ {
2181
+ "key": "postgres/bpchar(8)/plain",
2182
+ "native_type": "bpchar(8)",
2183
+ "class": "plain",
2184
+ "value_sql": "'ab'",
2185
+ "expect": {
2186
+ "warehouse": "ab ",
2187
+ "oltp": "ab "
2188
+ }
2189
+ },
2190
+ {
2191
+ "key": "postgres/bpchar(8)/empty",
2192
+ "native_type": "bpchar(8)",
2193
+ "class": "empty",
2194
+ "value_sql": "''",
2195
+ "expect": {
2196
+ "warehouse": " ",
2197
+ "oltp": " "
2198
+ }
2199
+ },
2200
+ {
2201
+ "key": "postgres/bpchar(8)/whitespace",
2202
+ "native_type": "bpchar(8)",
2203
+ "class": "whitespace",
2204
+ "value_sql": "E' \\t\\n '",
2205
+ "expect": {
2206
+ "warehouse": " \n ",
2207
+ "oltp": " \n "
2208
+ }
2209
+ },
2210
+ {
2211
+ "key": "postgres/bpchar(8)/non_bmp",
2212
+ "native_type": "bpchar(8)",
2213
+ "class": "non_bmp",
2214
+ "value_sql": "'𝔘'",
2215
+ "expect": {
2216
+ "warehouse": "𝔘 ",
2217
+ "oltp": "𝔘 "
2218
+ }
2219
+ },
2220
+ {
2221
+ "key": "postgres/bpchar(8)/null",
2222
+ "native_type": "bpchar(8)",
2223
+ "class": "null",
2224
+ "value_sql": "NULL",
2225
+ "expect": {
2226
+ "warehouse": null,
2227
+ "oltp": null
2228
+ }
2229
+ },
2230
+ {
2231
+ "key": "postgres/\"char\"/plain",
2232
+ "native_type": "\"char\"",
2233
+ "class": "plain",
2234
+ "value_sql": "'a'",
2235
+ "expect": {
2236
+ "warehouse": "a",
2237
+ "oltp": { "$error": "Postgres type `char`, which cannot be returned directly" }
2238
+ }
2239
+ },
2240
+ {
2241
+ "key": "postgres/\"char\"/null",
2242
+ "native_type": "\"char\"",
2243
+ "class": "null",
2244
+ "value_sql": "NULL",
2245
+ "expect": {
2246
+ "warehouse": null,
2247
+ "oltp": { "$error": "Postgres type `char`, which cannot be returned directly" }
2248
+ }
2249
+ },
2250
+ {
2251
+ "key": "postgres/name/plain",
2252
+ "native_type": "name",
2253
+ "class": "plain",
2254
+ "value_sql": "'plain_name'",
2255
+ "expect": {
2256
+ "warehouse": "plain_name",
2257
+ "oltp": "plain_name"
2258
+ }
2259
+ },
2260
+ {
2261
+ "key": "postgres/name/empty",
2262
+ "native_type": "name",
2263
+ "class": "empty",
2264
+ "value_sql": "''",
2265
+ "expect": {
2266
+ "warehouse": "",
2267
+ "oltp": ""
2268
+ }
2269
+ },
2270
+ {
2271
+ "key": "postgres/name/len_gt_1k",
2272
+ "native_type": "name",
2273
+ "class": "len_gt_1k",
2274
+ "value_sql": "repeat('0123456789', 101)",
2275
+ "expect": {
2276
+ "warehouse": "012345678901234567890123456789012345678901234567890123456789012",
2277
+ "oltp": "012345678901234567890123456789012345678901234567890123456789012"
2278
+ }
2279
+ },
2280
+ {
2281
+ "key": "postgres/name/null",
2282
+ "native_type": "name",
2283
+ "class": "null",
2284
+ "value_sql": "NULL",
2285
+ "expect": {
2286
+ "warehouse": null,
2287
+ "oltp": null
2288
+ }
2289
+ },
2290
+ {
2291
+ "key": "postgres/bytea/plain",
2292
+ "native_type": "bytea",
2293
+ "class": "plain",
2294
+ "value_sql": "decode('0001ff', 'hex')",
2295
+ "expect": {
2296
+ "warehouse": "<3 bytes>",
2297
+ "oltp": { "$error": "Postgres type `bytea`, which cannot be returned directly" }
2298
+ }
2299
+ },
2300
+ {
2301
+ "key": "postgres/bytea/empty",
2302
+ "native_type": "bytea",
2303
+ "class": "empty",
2304
+ "value_sql": "decode('', 'hex')",
2305
+ "expect": {
2306
+ "warehouse": "<0 bytes>",
2307
+ "oltp": { "$error": "Postgres type `bytea`, which cannot be returned directly" }
2308
+ }
2309
+ },
2310
+ {
2311
+ "key": "postgres/bytea/null",
2312
+ "native_type": "bytea",
2313
+ "class": "null",
2314
+ "value_sql": "NULL",
2315
+ "expect": {
2316
+ "warehouse": null,
2317
+ "oltp": { "$error": "Postgres type `bytea`, which cannot be returned directly" }
2318
+ }
2319
+ },
2320
+ {
2321
+ "key": "postgres/date/plain",
2322
+ "native_type": "date",
2323
+ "class": "plain",
2324
+ "value_sql": "DATE '2024-03-10'",
2325
+ "expect": {
2326
+ "warehouse": "2024-03-10",
2327
+ "oltp": "2024-03-10"
2328
+ }
2329
+ },
2330
+ {
2331
+ "key": "postgres/date/date_before_1970",
2332
+ "native_type": "date",
2333
+ "class": "date_before_1970",
2334
+ "value_sql": "DATE '1969-12-31'",
2335
+ "expect": {
2336
+ "warehouse": "1969-12-31",
2337
+ "oltp": "1969-12-31"
2338
+ }
2339
+ },
2340
+ {
2341
+ "key": "postgres/date/date_after_2100",
2342
+ "native_type": "date",
2343
+ "class": "date_after_2100",
2344
+ "value_sql": "DATE '2150-06-01'",
2345
+ "expect": {
2346
+ "warehouse": "2150-06-01",
2347
+ "oltp": "2150-06-01"
2348
+ }
2349
+ },
2350
+ {
2351
+ "key": "postgres/date/null",
2352
+ "native_type": "date",
2353
+ "class": "null",
2354
+ "value_sql": "NULL",
2355
+ "expect": {
2356
+ "warehouse": null,
2357
+ "oltp": null
2358
+ }
2359
+ },
2360
+ {
2361
+ "key": "postgres/timestamp/plain",
2362
+ "native_type": "timestamp",
2363
+ "class": "plain",
2364
+ "value_sql": "TIMESTAMP '2024-03-10 12:34:56.789'",
2365
+ "expect": {
2366
+ "warehouse": "2024-03-10 12:34:56.789000",
2367
+ "oltp": "2024-03-10T12:34:56.789000"
2368
+ }
2369
+ },
2370
+ {
2371
+ "key": "postgres/timestamp/date_before_1970",
2372
+ "native_type": "timestamp",
2373
+ "class": "date_before_1970",
2374
+ "value_sql": "TIMESTAMP '1969-07-20 20:17:40.5'",
2375
+ "expect": {
2376
+ "warehouse": "1969-07-20 20:17:40.500000",
2377
+ "oltp": "1969-07-20T20:17:40.500000"
2378
+ }
2379
+ },
2380
+ {
2381
+ "key": "postgres/timestamp/date_after_2100",
2382
+ "native_type": "timestamp",
2383
+ "class": "date_after_2100",
2384
+ "value_sql": "TIMESTAMP '2150-01-01 00:00:00'",
2385
+ "expect": {
2386
+ "warehouse": "2150-01-01 00:00:00",
2387
+ "oltp": "2150-01-01T00:00:00.000000"
2388
+ }
2389
+ },
2390
+ {
2391
+ "key": "postgres/timestamp/null",
2392
+ "native_type": "timestamp",
2393
+ "class": "null",
2394
+ "value_sql": "NULL",
2395
+ "expect": {
2396
+ "warehouse": null,
2397
+ "oltp": null
2398
+ }
2399
+ },
2400
+ {
2401
+ "key": "postgres/timestamptz/plain",
2402
+ "native_type": "timestamptz",
2403
+ "class": "plain",
2404
+ "value_sql": "TIMESTAMPTZ '2024-03-10 12:34:56.789+00'",
2405
+ "expect": {
2406
+ "warehouse": "2024-03-10 12:34:56.789000",
2407
+ "oltp": "2024-03-10T12:34:56.789000Z"
2408
+ }
2409
+ },
2410
+ {
2411
+ "key": "postgres/timestamptz/tz_bearing",
2412
+ "native_type": "timestamptz",
2413
+ "class": "tz_bearing",
2414
+ "value_sql": "TIMESTAMPTZ '2024-03-10 12:34:56+05:30'",
2415
+ "expect": {
2416
+ "warehouse": "2024-03-10 07:04:56",
2417
+ "oltp": "2024-03-10T07:04:56.000000Z"
2418
+ }
2419
+ },
2420
+ {
2421
+ "key": "postgres/timestamptz/date_before_1970",
2422
+ "native_type": "timestamptz",
2423
+ "class": "date_before_1970",
2424
+ "value_sql": "TIMESTAMPTZ '1969-07-20 20:17:40.5+00'",
2425
+ "expect": {
2426
+ "warehouse": "1969-07-20 20:17:40.500000",
2427
+ "oltp": "1969-07-20T20:17:40.500000Z"
2428
+ }
2429
+ },
2430
+ {
2431
+ "key": "postgres/timestamptz/date_after_2100",
2432
+ "native_type": "timestamptz",
2433
+ "class": "date_after_2100",
2434
+ "value_sql": "TIMESTAMPTZ '2150-01-01 00:00:00+00'",
2435
+ "expect": {
2436
+ "warehouse": "2150-01-01 00:00:00",
2437
+ "oltp": "2150-01-01T00:00:00.000000Z"
2438
+ }
2439
+ },
2440
+ {
2441
+ "key": "postgres/timestamptz/null",
2442
+ "native_type": "timestamptz",
2443
+ "class": "null",
2444
+ "value_sql": "NULL",
2445
+ "expect": {
2446
+ "warehouse": null,
2447
+ "oltp": null
2448
+ }
2449
+ },
2450
+ {
2451
+ "key": "postgres/time/plain",
2452
+ "native_type": "time",
2453
+ "class": "plain",
2454
+ "value_sql": "TIME '12:34:56.789'",
2455
+ "expect": {
2456
+ "warehouse": "12:34:56.789",
2457
+ "oltp": "12:34:56.789000"
2458
+ }
2459
+ },
2460
+ {
2461
+ "key": "postgres/time/null",
2462
+ "native_type": "time",
2463
+ "class": "null",
2464
+ "value_sql": "NULL",
2465
+ "expect": {
2466
+ "warehouse": null,
2467
+ "oltp": null
2468
+ }
2469
+ },
2470
+ {
2471
+ "key": "postgres/json/nested_json",
2472
+ "native_type": "json",
2473
+ "class": "nested_json",
2474
+ "value_sql": "'{\"a\":{\"b\":[1,2]},\"s\":\"x\"}'",
2475
+ "expect": {
2476
+ "warehouse": {
2477
+ "a": { "b": [1, 2] },
2478
+ "s": "x"
2479
+ },
2480
+ "oltp": {
2481
+ "a": { "b": [1, 2] },
2482
+ "s": "x"
2483
+ }
2484
+ }
2485
+ },
2486
+ {
2487
+ "key": "postgres/json/null",
2488
+ "native_type": "json",
2489
+ "class": "null",
2490
+ "value_sql": "NULL",
2491
+ "expect": {
2492
+ "warehouse": null,
2493
+ "oltp": null
2494
+ }
2495
+ },
2496
+ {
2497
+ "key": "postgres/jsonb/nested_json",
2498
+ "native_type": "jsonb",
2499
+ "class": "nested_json",
2500
+ "value_sql": "'{\"a\":{\"b\":[1,2]},\"s\":\"x\"}'",
2501
+ "expect": {
2502
+ "warehouse": {
2503
+ "a": { "b": [1, 2] },
2504
+ "s": "x"
2505
+ },
2506
+ "oltp": {
2507
+ "a": { "b": [1, 2] },
2508
+ "s": "x"
2509
+ }
2510
+ }
2511
+ },
2512
+ {
2513
+ "key": "postgres/jsonb/array",
2514
+ "native_type": "jsonb",
2515
+ "class": "array",
2516
+ "value_sql": "'[1,\"two\",null]'",
2517
+ "expect": {
2518
+ "warehouse": [
2519
+ 1,
2520
+ "two",
2521
+ null
2522
+ ],
2523
+ "oltp": [
2524
+ 1,
2525
+ "two",
2526
+ null
2527
+ ]
2528
+ }
2529
+ },
2530
+ {
2531
+ "key": "postgres/jsonb/null",
2532
+ "native_type": "jsonb",
2533
+ "class": "null",
2534
+ "value_sql": "NULL",
2535
+ "expect": {
2536
+ "warehouse": null,
2537
+ "oltp": null
2538
+ }
2539
+ },
2540
+ {
2541
+ "key": "postgres/uuid/plain",
2542
+ "native_type": "uuid",
2543
+ "class": "plain",
2544
+ "value_sql": "'00000000-0000-4000-8000-000000000001'",
2545
+ "expect": {
2546
+ "warehouse": "00000000-0000-4000-8000-000000000001",
2547
+ "oltp": "00000000-0000-4000-8000-000000000001"
2548
+ }
2549
+ },
2550
+ {
2551
+ "key": "postgres/uuid/null",
2552
+ "native_type": "uuid",
2553
+ "class": "null",
2554
+ "value_sql": "NULL",
2555
+ "expect": {
2556
+ "warehouse": null,
2557
+ "oltp": null
2558
+ }
2559
+ },
2560
+ {
2561
+ "key": "postgres/int4[]/array",
2562
+ "native_type": "int4[]",
2563
+ "class": "array",
2564
+ "value_sql": "ARRAY[1, -2, 3]",
2565
+ "expect": {
2566
+ "warehouse": "{1,-2,3}",
2567
+ "oltp": { "$error": "Postgres type `_int4`, which cannot be returned directly" }
2568
+ }
2569
+ },
2570
+ {
2571
+ "key": "postgres/int4[]/empty",
2572
+ "native_type": "int4[]",
2573
+ "class": "empty",
2574
+ "value_sql": "'{}'",
2575
+ "expect": {
2576
+ "warehouse": "{}",
2577
+ "oltp": { "$error": "Postgres type `_int4`, which cannot be returned directly" }
2578
+ }
2579
+ }
2580
+ ] },
2581
+ "duckdb": { "cases": [
2582
+ {
2583
+ "key": "duckdb/BOOLEAN/plain",
2584
+ "native_type": "BOOLEAN",
2585
+ "class": "plain",
2586
+ "value_sql": "true",
2587
+ "expect": { "warehouse": true }
2588
+ },
2589
+ {
2590
+ "key": "duckdb/BOOLEAN/null",
2591
+ "native_type": "BOOLEAN",
2592
+ "class": "null",
2593
+ "value_sql": "NULL",
2594
+ "expect": { "warehouse": null }
2595
+ },
2596
+ {
2597
+ "key": "duckdb/BOOL/plain",
2598
+ "native_type": "BOOL",
2599
+ "class": "plain",
2600
+ "value_sql": "false",
2601
+ "expect": { "warehouse": false }
2602
+ },
2603
+ {
2604
+ "key": "duckdb/TINYINT/plain",
2605
+ "native_type": "TINYINT",
2606
+ "class": "plain",
2607
+ "value_sql": "42",
2608
+ "expect": { "warehouse": 42 }
2609
+ },
2610
+ {
2611
+ "key": "duckdb/TINYINT/negative",
2612
+ "native_type": "TINYINT",
2613
+ "class": "negative",
2614
+ "value_sql": "-128",
2615
+ "expect": { "warehouse": -128 }
2616
+ },
2617
+ {
2618
+ "key": "duckdb/TINYINT/zero",
2619
+ "native_type": "TINYINT",
2620
+ "class": "zero",
2621
+ "value_sql": "0",
2622
+ "expect": { "warehouse": 0 }
2623
+ },
2624
+ {
2625
+ "key": "duckdb/TINYINT/null",
2626
+ "native_type": "TINYINT",
2627
+ "class": "null",
2628
+ "value_sql": "NULL",
2629
+ "expect": { "warehouse": null }
2630
+ },
2631
+ {
2632
+ "key": "duckdb/INT1/plain",
2633
+ "native_type": "INT1",
2634
+ "class": "plain",
2635
+ "value_sql": "42",
2636
+ "expect": { "warehouse": 42 }
2637
+ },
2638
+ {
2639
+ "key": "duckdb/SMALLINT/plain",
2640
+ "native_type": "SMALLINT",
2641
+ "class": "plain",
2642
+ "value_sql": "42",
2643
+ "expect": { "warehouse": 42 }
2644
+ },
2645
+ {
2646
+ "key": "duckdb/SMALLINT/negative",
2647
+ "native_type": "SMALLINT",
2648
+ "class": "negative",
2649
+ "value_sql": "-32768",
2650
+ "expect": { "warehouse": -32768 }
2651
+ },
2652
+ {
2653
+ "key": "duckdb/SMALLINT/zero",
2654
+ "native_type": "SMALLINT",
2655
+ "class": "zero",
2656
+ "value_sql": "0",
2657
+ "expect": { "warehouse": 0 }
2658
+ },
2659
+ {
2660
+ "key": "duckdb/SMALLINT/null",
2661
+ "native_type": "SMALLINT",
2662
+ "class": "null",
2663
+ "value_sql": "NULL",
2664
+ "expect": { "warehouse": null }
2665
+ },
2666
+ {
2667
+ "key": "duckdb/INT2/plain",
2668
+ "native_type": "INT2",
2669
+ "class": "plain",
2670
+ "value_sql": "42",
2671
+ "expect": { "warehouse": 42 }
2672
+ },
2673
+ {
2674
+ "key": "duckdb/INTEGER/plain",
2675
+ "native_type": "INTEGER",
2676
+ "class": "plain",
2677
+ "value_sql": "42",
2678
+ "expect": { "warehouse": 42 }
2679
+ },
2680
+ {
2681
+ "key": "duckdb/INTEGER/negative",
2682
+ "native_type": "INTEGER",
2683
+ "class": "negative",
2684
+ "value_sql": "-2147483648",
2685
+ "expect": { "warehouse": -2147483648 }
2686
+ },
2687
+ {
2688
+ "key": "duckdb/INTEGER/zero",
2689
+ "native_type": "INTEGER",
2690
+ "class": "zero",
2691
+ "value_sql": "0",
2692
+ "expect": { "warehouse": 0 }
2693
+ },
2694
+ {
2695
+ "key": "duckdb/INTEGER/null",
2696
+ "native_type": "INTEGER",
2697
+ "class": "null",
2698
+ "value_sql": "NULL",
2699
+ "expect": { "warehouse": null }
2700
+ },
2701
+ {
2702
+ "key": "duckdb/INT/plain",
2703
+ "native_type": "INT",
2704
+ "class": "plain",
2705
+ "value_sql": "42",
2706
+ "expect": { "warehouse": 42 }
2707
+ },
2708
+ {
2709
+ "key": "duckdb/INT4/plain",
2710
+ "native_type": "INT4",
2711
+ "class": "plain",
2712
+ "value_sql": "42",
2713
+ "expect": { "warehouse": 42 }
2714
+ },
2715
+ {
2716
+ "key": "duckdb/BIGINT/plain",
2717
+ "native_type": "BIGINT",
2718
+ "class": "plain",
2719
+ "value_sql": "42",
2720
+ "expect": { "warehouse": 42 }
2721
+ },
2722
+ {
2723
+ "key": "duckdb/BIGINT/negative",
2724
+ "native_type": "BIGINT",
2725
+ "class": "negative",
2726
+ "value_sql": "-9007199254740991",
2727
+ "expect": { "warehouse": -9007199254740991 }
2728
+ },
2729
+ {
2730
+ "key": "duckdb/BIGINT/zero",
2731
+ "native_type": "BIGINT",
2732
+ "class": "zero",
2733
+ "value_sql": "0",
2734
+ "expect": { "warehouse": 0 }
2735
+ },
2736
+ {
2737
+ "key": "duckdb/BIGINT/precision_gt_18",
2738
+ "native_type": "BIGINT",
2739
+ "class": "precision_gt_18",
2740
+ "value_sql": "9223372036854775807",
2741
+ "expect": { "warehouse": 0x8000000000000000 }
2742
+ },
2743
+ {
2744
+ "key": "duckdb/BIGINT/null",
2745
+ "native_type": "BIGINT",
2746
+ "class": "null",
2747
+ "value_sql": "NULL",
2748
+ "expect": { "warehouse": null }
2749
+ },
2750
+ {
2751
+ "key": "duckdb/INT8/plain",
2752
+ "native_type": "INT8",
2753
+ "class": "plain",
2754
+ "value_sql": "42",
2755
+ "expect": { "warehouse": 42 }
2756
+ },
2757
+ {
2758
+ "key": "duckdb/UTINYINT/plain",
2759
+ "native_type": "UTINYINT",
2760
+ "class": "plain",
2761
+ "value_sql": "42",
2762
+ "expect": { "warehouse": 42 }
2763
+ },
2764
+ {
2765
+ "key": "duckdb/UTINYINT/zero",
2766
+ "native_type": "UTINYINT",
2767
+ "class": "zero",
2768
+ "value_sql": "0",
2769
+ "expect": { "warehouse": 0 }
2770
+ },
2771
+ {
2772
+ "key": "duckdb/UTINYINT/null",
2773
+ "native_type": "UTINYINT",
2774
+ "class": "null",
2775
+ "value_sql": "NULL",
2776
+ "expect": { "warehouse": null }
2777
+ },
2778
+ {
2779
+ "key": "duckdb/USMALLINT/plain",
2780
+ "native_type": "USMALLINT",
2781
+ "class": "plain",
2782
+ "value_sql": "42",
2783
+ "expect": { "warehouse": 42 }
2784
+ },
2785
+ {
2786
+ "key": "duckdb/USMALLINT/zero",
2787
+ "native_type": "USMALLINT",
2788
+ "class": "zero",
2789
+ "value_sql": "0",
2790
+ "expect": { "warehouse": 0 }
2791
+ },
2792
+ {
2793
+ "key": "duckdb/USMALLINT/null",
2794
+ "native_type": "USMALLINT",
2795
+ "class": "null",
2796
+ "value_sql": "NULL",
2797
+ "expect": { "warehouse": null }
2798
+ },
2799
+ {
2800
+ "key": "duckdb/UINTEGER/plain",
2801
+ "native_type": "UINTEGER",
2802
+ "class": "plain",
2803
+ "value_sql": "42",
2804
+ "expect": { "warehouse": 42 }
2805
+ },
2806
+ {
2807
+ "key": "duckdb/UINTEGER/zero",
2808
+ "native_type": "UINTEGER",
2809
+ "class": "zero",
2810
+ "value_sql": "0",
2811
+ "expect": { "warehouse": 0 }
2812
+ },
2813
+ {
2814
+ "key": "duckdb/UINTEGER/null",
2815
+ "native_type": "UINTEGER",
2816
+ "class": "null",
2817
+ "value_sql": "NULL",
2818
+ "expect": { "warehouse": null }
2819
+ },
2820
+ {
2821
+ "key": "duckdb/UBIGINT/plain",
2822
+ "native_type": "UBIGINT",
2823
+ "class": "plain",
2824
+ "value_sql": "42",
2825
+ "expect": { "warehouse": 42 }
2826
+ },
2827
+ {
2828
+ "key": "duckdb/UBIGINT/zero",
2829
+ "native_type": "UBIGINT",
2830
+ "class": "zero",
2831
+ "value_sql": "0",
2832
+ "expect": { "warehouse": 0 }
2833
+ },
2834
+ {
2835
+ "key": "duckdb/UBIGINT/precision_gt_18",
2836
+ "native_type": "UBIGINT",
2837
+ "class": "precision_gt_18",
2838
+ "value_sql": "'18446744073709551615'::UBIGINT",
2839
+ "expect": { "warehouse": "18446744073709551615" }
2840
+ },
2841
+ {
2842
+ "key": "duckdb/UBIGINT/null",
2843
+ "native_type": "UBIGINT",
2844
+ "class": "null",
2845
+ "value_sql": "NULL",
2846
+ "expect": { "warehouse": null }
2847
+ },
2848
+ {
2849
+ "key": "duckdb/HUGEINT/plain",
2850
+ "native_type": "HUGEINT",
2851
+ "class": "plain",
2852
+ "value_sql": "42",
2853
+ "expect": { "warehouse": "42" }
2854
+ },
2855
+ {
2856
+ "key": "duckdb/HUGEINT/negative",
2857
+ "native_type": "HUGEINT",
2858
+ "class": "negative",
2859
+ "value_sql": "-42",
2860
+ "expect": { "warehouse": "-42" }
2861
+ },
2862
+ {
2863
+ "key": "duckdb/HUGEINT/zero",
2864
+ "native_type": "HUGEINT",
2865
+ "class": "zero",
2866
+ "value_sql": "0",
2867
+ "expect": { "warehouse": "0" }
2868
+ },
2869
+ {
2870
+ "key": "duckdb/HUGEINT/precision_gt_18",
2871
+ "native_type": "HUGEINT",
2872
+ "class": "precision_gt_18",
2873
+ "value_sql": "'12345678901234567890123456789012345678'::HUGEINT",
2874
+ "expect": { "warehouse": "12345678901234567890123456789012345678" }
2875
+ },
2876
+ {
2877
+ "key": "duckdb/HUGEINT/null",
2878
+ "native_type": "HUGEINT",
2879
+ "class": "null",
2880
+ "value_sql": "NULL",
2881
+ "expect": { "warehouse": null }
2882
+ },
2883
+ {
2884
+ "key": "duckdb/UHUGEINT/plain",
2885
+ "native_type": "UHUGEINT",
2886
+ "class": "plain",
2887
+ "value_sql": "42",
2888
+ "expect": { "warehouse": "42" }
2889
+ },
2890
+ {
2891
+ "key": "duckdb/UHUGEINT/zero",
2892
+ "native_type": "UHUGEINT",
2893
+ "class": "zero",
2894
+ "value_sql": "0",
2895
+ "expect": { "warehouse": "0" }
2896
+ },
2897
+ {
2898
+ "key": "duckdb/UHUGEINT/precision_gt_18",
2899
+ "native_type": "UHUGEINT",
2900
+ "class": "precision_gt_18",
2901
+ "value_sql": "'12345678901234567890123456789012345678'::UHUGEINT",
2902
+ "expect": { "warehouse": "12345678901234567890123456789012345678" }
2903
+ },
2904
+ {
2905
+ "key": "duckdb/UHUGEINT/null",
2906
+ "native_type": "UHUGEINT",
2907
+ "class": "null",
2908
+ "value_sql": "NULL",
2909
+ "expect": { "warehouse": null }
2910
+ },
2911
+ {
2912
+ "key": "duckdb/FLOAT/plain",
2913
+ "native_type": "FLOAT",
2914
+ "class": "plain",
2915
+ "value_sql": "0.1",
2916
+ "expect": { "warehouse": .10000000149011612 }
2917
+ },
2918
+ {
2919
+ "key": "duckdb/FLOAT/negative",
2920
+ "native_type": "FLOAT",
2921
+ "class": "negative",
2922
+ "value_sql": "-1.5",
2923
+ "expect": { "warehouse": -1.5 }
2924
+ },
2925
+ {
2926
+ "key": "duckdb/FLOAT/zero",
2927
+ "native_type": "FLOAT",
2928
+ "class": "zero",
2929
+ "value_sql": "0",
2930
+ "expect": { "warehouse": 0 }
2931
+ },
2932
+ {
2933
+ "key": "duckdb/FLOAT/nan_inf",
2934
+ "native_type": "FLOAT",
2935
+ "class": "nan_inf",
2936
+ "value_sql": "'nan'::FLOAT",
2937
+ "expect": { "warehouse": null }
2938
+ },
2939
+ {
2940
+ "key": "duckdb/FLOAT/null",
2941
+ "native_type": "FLOAT",
2942
+ "class": "null",
2943
+ "value_sql": "NULL",
2944
+ "expect": { "warehouse": null }
2945
+ },
2946
+ {
2947
+ "key": "duckdb/REAL/plain",
2948
+ "native_type": "REAL",
2949
+ "class": "plain",
2950
+ "value_sql": "0.1",
2951
+ "expect": { "warehouse": .10000000149011612 }
2952
+ },
2953
+ {
2954
+ "key": "duckdb/FLOAT4/plain",
2955
+ "native_type": "FLOAT4",
2956
+ "class": "plain",
2957
+ "value_sql": "0.1",
2958
+ "expect": { "warehouse": .10000000149011612 }
2959
+ },
2960
+ {
2961
+ "key": "duckdb/DOUBLE/plain",
2962
+ "native_type": "DOUBLE",
2963
+ "class": "plain",
2964
+ "value_sql": "0.1",
2965
+ "expect": { "warehouse": .1 }
2966
+ },
2967
+ {
2968
+ "key": "duckdb/DOUBLE/negative",
2969
+ "native_type": "DOUBLE",
2970
+ "class": "negative",
2971
+ "value_sql": "-1.5",
2972
+ "expect": { "warehouse": -1.5 }
2973
+ },
2974
+ {
2975
+ "key": "duckdb/DOUBLE/zero",
2976
+ "native_type": "DOUBLE",
2977
+ "class": "zero",
2978
+ "value_sql": "0",
2979
+ "expect": { "warehouse": 0 }
2980
+ },
2981
+ {
2982
+ "key": "duckdb/DOUBLE/nan_inf",
2983
+ "native_type": "DOUBLE",
2984
+ "class": "nan_inf",
2985
+ "value_sql": "'inf'::DOUBLE",
2986
+ "expect": { "warehouse": null }
2987
+ },
2988
+ {
2989
+ "key": "duckdb/DOUBLE/null",
2990
+ "native_type": "DOUBLE",
2991
+ "class": "null",
2992
+ "value_sql": "NULL",
2993
+ "expect": { "warehouse": null }
2994
+ },
2995
+ {
2996
+ "key": "duckdb/FLOAT8/plain",
2997
+ "native_type": "FLOAT8",
2998
+ "class": "plain",
2999
+ "value_sql": "0.1",
3000
+ "expect": { "warehouse": .1 }
3001
+ },
3002
+ {
3003
+ "key": "duckdb/DECIMAL(18,4)/plain",
3004
+ "native_type": "DECIMAL(18,4)",
3005
+ "class": "plain",
3006
+ "value_sql": "1234.5678",
3007
+ "expect": { "warehouse": "1234.5678" }
3008
+ },
3009
+ {
3010
+ "key": "duckdb/DECIMAL(18,4)/negative",
3011
+ "native_type": "DECIMAL(18,4)",
3012
+ "class": "negative",
3013
+ "value_sql": "-1.25",
3014
+ "expect": { "warehouse": "-1.2500" }
3015
+ },
3016
+ {
3017
+ "key": "duckdb/DECIMAL(18,4)/zero",
3018
+ "native_type": "DECIMAL(18,4)",
3019
+ "class": "zero",
3020
+ "value_sql": "0",
3021
+ "expect": { "warehouse": "0.0000" }
3022
+ },
3023
+ {
3024
+ "key": "duckdb/DECIMAL(18,4)/null",
3025
+ "native_type": "DECIMAL(18,4)",
3026
+ "class": "null",
3027
+ "value_sql": "NULL",
3028
+ "expect": { "warehouse": null }
3029
+ },
3030
+ {
3031
+ "key": "duckdb/DECIMAL(38,10)/precision_gt_18",
3032
+ "native_type": "DECIMAL(38,10)",
3033
+ "class": "precision_gt_18",
3034
+ "value_sql": "'1234567890123456789.0123456789'::DECIMAL(38,10)",
3035
+ "expect": { "warehouse": "1234567890123456789.0123456789" }
3036
+ },
3037
+ {
3038
+ "key": "duckdb/VARCHAR/plain",
3039
+ "native_type": "VARCHAR",
3040
+ "class": "plain",
3041
+ "value_sql": "'plain text'",
3042
+ "expect": { "warehouse": "plain text" }
3043
+ },
3044
+ {
3045
+ "key": "duckdb/VARCHAR/empty",
3046
+ "native_type": "VARCHAR",
3047
+ "class": "empty",
3048
+ "value_sql": "''",
3049
+ "expect": { "warehouse": "" }
3050
+ },
3051
+ {
3052
+ "key": "duckdb/VARCHAR/whitespace",
3053
+ "native_type": "VARCHAR",
3054
+ "class": "whitespace",
3055
+ "value_sql": "chr(32) || chr(9) || chr(10) || chr(32)",
3056
+ "expect": { "warehouse": " \n " }
3057
+ },
3058
+ {
3059
+ "key": "duckdb/VARCHAR/non_bmp",
3060
+ "native_type": "VARCHAR",
3061
+ "class": "non_bmp",
3062
+ "value_sql": "'𝔘nicode'",
3063
+ "expect": { "warehouse": "𝔘nicode" }
3064
+ },
3065
+ {
3066
+ "key": "duckdb/VARCHAR/len_gt_1k",
3067
+ "native_type": "VARCHAR",
3068
+ "class": "len_gt_1k",
3069
+ "value_sql": "repeat('0123456789', 101)",
3070
+ "expect": { "warehouse": "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" }
3071
+ },
3072
+ {
3073
+ "key": "duckdb/VARCHAR/null",
3074
+ "native_type": "VARCHAR",
3075
+ "class": "null",
3076
+ "value_sql": "NULL",
3077
+ "expect": { "warehouse": null }
3078
+ },
3079
+ {
3080
+ "key": "duckdb/CHAR/plain",
3081
+ "native_type": "CHAR",
3082
+ "class": "plain",
3083
+ "value_sql": "'plain text'",
3084
+ "expect": { "warehouse": "plain text" }
3085
+ },
3086
+ {
3087
+ "key": "duckdb/BPCHAR/plain",
3088
+ "native_type": "BPCHAR",
3089
+ "class": "plain",
3090
+ "value_sql": "'plain text'",
3091
+ "expect": { "warehouse": "plain text" }
3092
+ },
3093
+ {
3094
+ "key": "duckdb/TEXT/plain",
3095
+ "native_type": "TEXT",
3096
+ "class": "plain",
3097
+ "value_sql": "'plain text'",
3098
+ "expect": { "warehouse": "plain text" }
3099
+ },
3100
+ {
3101
+ "key": "duckdb/STRING/plain",
3102
+ "native_type": "STRING",
3103
+ "class": "plain",
3104
+ "value_sql": "'plain text'",
3105
+ "expect": { "warehouse": "plain text" }
3106
+ },
3107
+ {
3108
+ "key": "duckdb/UUID/plain",
3109
+ "native_type": "UUID",
3110
+ "class": "plain",
3111
+ "value_sql": "'00000000-0000-4000-8000-000000000001'",
3112
+ "expect": { "warehouse": "00000000-0000-4000-8000-000000000001" }
3113
+ },
3114
+ {
3115
+ "key": "duckdb/UUID/null",
3116
+ "native_type": "UUID",
3117
+ "class": "null",
3118
+ "value_sql": "NULL",
3119
+ "expect": { "warehouse": null }
3120
+ },
3121
+ {
3122
+ "key": "duckdb/BLOB/plain",
3123
+ "native_type": "BLOB",
3124
+ "class": "plain",
3125
+ "value_sql": "'\\x00\\x01\\xFF'::BLOB",
3126
+ "expect": { "warehouse": "<3 bytes>" }
3127
+ },
3128
+ {
3129
+ "key": "duckdb/BLOB/empty",
3130
+ "native_type": "BLOB",
3131
+ "class": "empty",
3132
+ "value_sql": "''::BLOB",
3133
+ "expect": { "warehouse": "<0 bytes>" }
3134
+ },
3135
+ {
3136
+ "key": "duckdb/BLOB/null",
3137
+ "native_type": "BLOB",
3138
+ "class": "null",
3139
+ "value_sql": "NULL",
3140
+ "expect": { "warehouse": null }
3141
+ },
3142
+ {
3143
+ "key": "duckdb/BYTEA/plain",
3144
+ "native_type": "BYTEA",
3145
+ "class": "plain",
3146
+ "value_sql": "'\\x00\\x01\\xFF'::BLOB",
3147
+ "expect": { "warehouse": "<3 bytes>" }
3148
+ },
3149
+ {
3150
+ "key": "duckdb/BINARY/plain",
3151
+ "native_type": "BINARY",
3152
+ "class": "plain",
3153
+ "value_sql": "'\\x00\\x01\\xFF'::BLOB",
3154
+ "expect": { "warehouse": "<3 bytes>" }
3155
+ },
3156
+ {
3157
+ "key": "duckdb/VARBINARY/plain",
3158
+ "native_type": "VARBINARY",
3159
+ "class": "plain",
3160
+ "value_sql": "'\\x00\\x01\\xFF'::BLOB",
3161
+ "expect": { "warehouse": "<3 bytes>" }
3162
+ },
3163
+ {
3164
+ "key": "duckdb/DATE/plain",
3165
+ "native_type": "DATE",
3166
+ "class": "plain",
3167
+ "value_sql": "DATE '2024-03-10'",
3168
+ "expect": { "warehouse": "2024-03-10" }
3169
+ },
3170
+ {
3171
+ "key": "duckdb/DATE/date_before_1970",
3172
+ "native_type": "DATE",
3173
+ "class": "date_before_1970",
3174
+ "value_sql": "DATE '1969-12-31'",
3175
+ "expect": { "warehouse": "1969-12-31" }
3176
+ },
3177
+ {
3178
+ "key": "duckdb/DATE/date_after_2100",
3179
+ "native_type": "DATE",
3180
+ "class": "date_after_2100",
3181
+ "value_sql": "DATE '2150-06-01'",
3182
+ "expect": { "warehouse": "2150-06-01" }
3183
+ },
3184
+ {
3185
+ "key": "duckdb/DATE/null",
3186
+ "native_type": "DATE",
3187
+ "class": "null",
3188
+ "value_sql": "NULL",
3189
+ "expect": { "warehouse": null }
3190
+ },
3191
+ {
3192
+ "key": "duckdb/TIMESTAMP/plain",
3193
+ "native_type": "TIMESTAMP",
3194
+ "class": "plain",
3195
+ "value_sql": "TIMESTAMP '2024-03-10 12:34:56.789'",
3196
+ "expect": { "warehouse": "2024-03-10 12:34:56.789000" }
3197
+ },
3198
+ {
3199
+ "key": "duckdb/TIMESTAMP/date_before_1970",
3200
+ "native_type": "TIMESTAMP",
3201
+ "class": "date_before_1970",
3202
+ "value_sql": "TIMESTAMP '1969-07-20 20:17:40.5'",
3203
+ "expect": { "warehouse": "1969-07-20 20:17:40.500000" }
3204
+ },
3205
+ {
3206
+ "key": "duckdb/TIMESTAMP/date_after_2100",
3207
+ "native_type": "TIMESTAMP",
3208
+ "class": "date_after_2100",
3209
+ "value_sql": "TIMESTAMP '2150-01-01 00:00:00'",
3210
+ "expect": { "warehouse": "2150-01-01 00:00:00" }
3211
+ },
3212
+ {
3213
+ "key": "duckdb/TIMESTAMP/null",
3214
+ "native_type": "TIMESTAMP",
3215
+ "class": "null",
3216
+ "value_sql": "NULL",
3217
+ "expect": { "warehouse": null }
3218
+ },
3219
+ {
3220
+ "key": "duckdb/DATETIME/plain",
3221
+ "native_type": "DATETIME",
3222
+ "class": "plain",
3223
+ "value_sql": "TIMESTAMP '2024-03-10 12:34:56.789'",
3224
+ "expect": { "warehouse": "2024-03-10 12:34:56.789000" }
3225
+ },
3226
+ {
3227
+ "key": "duckdb/TIMESTAMP_US/plain",
3228
+ "native_type": "TIMESTAMP_US",
3229
+ "class": "plain",
3230
+ "value_sql": "TIMESTAMP '2024-03-10 12:34:56.789'",
3231
+ "expect": { "warehouse": "2024-03-10 12:34:56.789000" }
3232
+ },
3233
+ {
3234
+ "key": "duckdb/TIMESTAMP_S/plain",
3235
+ "native_type": "TIMESTAMP_S",
3236
+ "class": "plain",
3237
+ "value_sql": "'2024-03-10 12:34:56'::TIMESTAMP_S",
3238
+ "expect": { "warehouse": "2024-03-10 12:34:56" }
3239
+ },
3240
+ {
3241
+ "key": "duckdb/TIMESTAMP_S/date_before_1970",
3242
+ "native_type": "TIMESTAMP_S",
3243
+ "class": "date_before_1970",
3244
+ "value_sql": "'1969-07-20 20:17:40'::TIMESTAMP_S",
3245
+ "expect": { "warehouse": "1969-07-20 20:17:40" }
3246
+ },
3247
+ {
3248
+ "key": "duckdb/TIMESTAMP_S/date_after_2100",
3249
+ "native_type": "TIMESTAMP_S",
3250
+ "class": "date_after_2100",
3251
+ "value_sql": "'2150-01-01 00:00:00'::TIMESTAMP_S",
3252
+ "expect": { "warehouse": "2150-01-01 00:00:00" }
3253
+ },
3254
+ {
3255
+ "key": "duckdb/TIMESTAMP_S/null",
3256
+ "native_type": "TIMESTAMP_S",
3257
+ "class": "null",
3258
+ "value_sql": "NULL",
3259
+ "expect": { "warehouse": null }
3260
+ },
3261
+ {
3262
+ "key": "duckdb/TIMESTAMP_MS/plain",
3263
+ "native_type": "TIMESTAMP_MS",
3264
+ "class": "plain",
3265
+ "value_sql": "'2024-03-10 12:34:56.789'::TIMESTAMP_MS",
3266
+ "expect": { "warehouse": "2024-03-10 12:34:56.789000" }
3267
+ },
3268
+ {
3269
+ "key": "duckdb/TIMESTAMP_MS/date_before_1970",
3270
+ "native_type": "TIMESTAMP_MS",
3271
+ "class": "date_before_1970",
3272
+ "value_sql": "'1969-07-20 20:17:40.5'::TIMESTAMP_MS",
3273
+ "expect": { "warehouse": "1969-07-20 20:17:40.500000" }
3274
+ },
3275
+ {
3276
+ "key": "duckdb/TIMESTAMP_MS/date_after_2100",
3277
+ "native_type": "TIMESTAMP_MS",
3278
+ "class": "date_after_2100",
3279
+ "value_sql": "'2150-01-01 00:00:00'::TIMESTAMP_MS",
3280
+ "expect": { "warehouse": "2150-01-01 00:00:00" }
3281
+ },
3282
+ {
3283
+ "key": "duckdb/TIMESTAMP_MS/null",
3284
+ "native_type": "TIMESTAMP_MS",
3285
+ "class": "null",
3286
+ "value_sql": "NULL",
3287
+ "expect": { "warehouse": null }
3288
+ },
3289
+ {
3290
+ "key": "duckdb/TIMESTAMP_NS/plain",
3291
+ "native_type": "TIMESTAMP_NS",
3292
+ "class": "plain",
3293
+ "value_sql": "'2024-03-10 12:34:56.789123456'::TIMESTAMP_NS",
3294
+ "expect": { "warehouse": "2024-03-10 12:34:56.789123" }
3295
+ },
3296
+ {
3297
+ "key": "duckdb/TIMESTAMP_NS/date_before_1970",
3298
+ "native_type": "TIMESTAMP_NS",
3299
+ "class": "date_before_1970",
3300
+ "value_sql": "'1969-07-20 20:17:40.500000001'::TIMESTAMP_NS",
3301
+ "expect": { "warehouse": "1969-07-20 20:17:40.500000" }
3302
+ },
3303
+ {
3304
+ "key": "duckdb/TIMESTAMP_NS/date_after_2100",
3305
+ "native_type": "TIMESTAMP_NS",
3306
+ "class": "date_after_2100",
3307
+ "value_sql": "'2150-01-01 00:00:00'::TIMESTAMP_NS",
3308
+ "expect": { "warehouse": "2150-01-01 00:00:00" }
3309
+ },
3310
+ {
3311
+ "key": "duckdb/TIMESTAMP_NS/null",
3312
+ "native_type": "TIMESTAMP_NS",
3313
+ "class": "null",
3314
+ "value_sql": "NULL",
3315
+ "expect": { "warehouse": null }
3316
+ },
3317
+ {
3318
+ "key": "duckdb/TIMESTAMP WITH TIME ZONE/plain",
3319
+ "native_type": "TIMESTAMP WITH TIME ZONE",
3320
+ "class": "plain",
3321
+ "value_sql": "TIMESTAMPTZ '2024-03-10 12:34:56.789+00'",
3322
+ "expect": { "warehouse": "2024-03-10 12:34:56.789000" }
3323
+ },
3324
+ {
3325
+ "key": "duckdb/TIMESTAMP WITH TIME ZONE/tz_bearing",
3326
+ "native_type": "TIMESTAMP WITH TIME ZONE",
3327
+ "class": "tz_bearing",
3328
+ "value_sql": "TIMESTAMPTZ '2024-03-10 12:34:56+05:30'",
3329
+ "expect": { "warehouse": "2024-03-10 07:04:56" }
3330
+ },
3331
+ {
3332
+ "key": "duckdb/TIMESTAMP WITH TIME ZONE/date_before_1970",
3333
+ "native_type": "TIMESTAMP WITH TIME ZONE",
3334
+ "class": "date_before_1970",
3335
+ "value_sql": "TIMESTAMPTZ '1969-07-20 20:17:40.5+00'",
3336
+ "expect": { "warehouse": "1969-07-20 20:17:40.500000" }
3337
+ },
3338
+ {
3339
+ "key": "duckdb/TIMESTAMP WITH TIME ZONE/date_after_2100",
3340
+ "native_type": "TIMESTAMP WITH TIME ZONE",
3341
+ "class": "date_after_2100",
3342
+ "value_sql": "TIMESTAMPTZ '2150-01-01 00:00:00+00'",
3343
+ "expect": { "warehouse": "2150-01-01 00:00:00" }
3344
+ },
3345
+ {
3346
+ "key": "duckdb/TIMESTAMP WITH TIME ZONE/null",
3347
+ "native_type": "TIMESTAMP WITH TIME ZONE",
3348
+ "class": "null",
3349
+ "value_sql": "NULL",
3350
+ "expect": { "warehouse": null }
3351
+ },
3352
+ {
3353
+ "key": "duckdb/TIMESTAMPTZ/plain",
3354
+ "native_type": "TIMESTAMPTZ",
3355
+ "class": "plain",
3356
+ "value_sql": "TIMESTAMPTZ '2024-03-10 12:34:56.789+00'",
3357
+ "expect": { "warehouse": "2024-03-10 12:34:56.789000" }
3358
+ },
3359
+ {
3360
+ "key": "duckdb/JSON/nested_json",
3361
+ "native_type": "JSON",
3362
+ "class": "nested_json",
3363
+ "value_sql": "'{\"a\":{\"b\":[1,2]},\"s\":\"x\"}'",
3364
+ "expect": { "warehouse": "{\"a\":{\"b\":[1,2]},\"s\":\"x\"}" }
3365
+ },
3366
+ {
3367
+ "key": "duckdb/JSON/array",
3368
+ "native_type": "JSON",
3369
+ "class": "array",
3370
+ "value_sql": "'[1,\"two\",null]'",
3371
+ "expect": { "warehouse": "[1,\"two\",null]" }
3372
+ },
3373
+ {
3374
+ "key": "duckdb/JSON/null",
3375
+ "native_type": "JSON",
3376
+ "class": "null",
3377
+ "value_sql": "NULL",
3378
+ "expect": { "warehouse": null }
3379
+ },
3380
+ {
3381
+ "key": "duckdb/INTEGER[]/array",
3382
+ "native_type": "INTEGER[]",
3383
+ "class": "array",
3384
+ "value_sql": "[1, -2, 3]",
3385
+ "expect": { "warehouse": "List([Int(1), Int(-2), Int(3)])" }
3386
+ },
3387
+ {
3388
+ "key": "duckdb/INTEGER[]/empty",
3389
+ "native_type": "INTEGER[]",
3390
+ "class": "empty",
3391
+ "value_sql": "[]",
3392
+ "expect": { "warehouse": "List([])" }
3393
+ },
3394
+ {
3395
+ "key": "duckdb/INTEGER[]/null",
3396
+ "native_type": "INTEGER[]",
3397
+ "class": "null",
3398
+ "value_sql": "NULL",
3399
+ "expect": { "warehouse": null }
3400
+ }
3401
+ ] }
3402
+ }
3403
+ };
3404
+
3405
+ //#endregion
3406
+ //#region src/testing/shape-zoo-sha256.ts
3407
+ const ZOO_SHA256 = "04f75f9054a46e521d8787d65f5d214440d041860971c77e66edc7bfbaf8d16a";
3408
+
3409
+ //#endregion
3410
+ //#region src/testing/zoo.ts
3411
+ /** A value a read would REFUSE rather than return: `expect.oltp.$error`. */
3412
+ var ZooRefusal = class {
3413
+ constructor(column, nativeType, detail) {
3414
+ this.column = column;
3415
+ this.nativeType = nativeType;
3416
+ this.detail = detail;
3417
+ }
3418
+ /** The host's full sentence for it, from the contract. */
3419
+ message() {
3420
+ return render(REFUSALS.oltpUnsupportedColumn, {
3421
+ name: this.column,
3422
+ ty: this.nativeType
3423
+ });
3424
+ }
3425
+ };
3426
+ const ZOO = shape_zoo_default;
3427
+ /** The zoo table's name, from the fixture's digest — the canary's `zooTableName`. */
3428
+ function zooTableName(sha256Hex = ZOO_SHA256) {
3429
+ return `oxy_shape_zoo_${sha256Hex.slice(0, 8)}`;
3430
+ }
3431
+ /** `c001`, `c002`, … — the zoo column for case `index`. */
3432
+ function zooColumn(index) {
3433
+ return `c${String(index + 1).padStart(3, "0")}`;
3434
+ }
3435
+ const isError = (v) => typeof v === "object" && v !== null && "$error" in v;
3436
+ /** What a read of case `c` on `plane` returns — or refuses. */
3437
+ function expectation(c, plane, column) {
3438
+ const value = plane === "oltp" ? c.expect.oltp : c.expect.warehouse;
3439
+ return isError(value) ? new ZooRefusal(column, c.native_type, value.$error) : value;
3440
+ }
3441
+ /** Every case of `engine` for `nativeType`, as written in the zoo. */
3442
+ function casesFor(engine, nativeType) {
3443
+ return ZOO.engines[engine].cases.filter((c) => c.native_type === nativeType);
3444
+ }
3445
+ /** The native types the zoo pins for `engine`, for a declaration error to list. */
3446
+ function knownTypes(engine) {
3447
+ return [...new Set(ZOO.engines[engine].cases.map((c) => c.native_type))];
3448
+ }
3449
+ const I64_MAX = 9223372036854775807n;
3450
+ const I64_MIN = -9223372036854775808n;
3451
+ /**
3452
+ * Render one SQL-side value of a typed column through the zoo.
3453
+ *
3454
+ * - The value IS a case's `value_sql` for this type → that case's expectation
3455
+ * (`source: "zoo"`).
3456
+ * - `NULL` → `null`.
3457
+ * - Otherwise the `plain` case's SHAPE decides: a number-shaped type parses the
3458
+ * literal, except that an integer outside `i64` becomes its exact digits as a
3459
+ * string where the zoo pins that (`precision_gt_18` expecting a string) — the
3460
+ * host reads an overflowing column as `u64` rendered to text; a string-shaped
3461
+ * type unquotes; a boolean-shaped type reads `true`/`false`/`1`/`0`; a JSON
3462
+ * shape parses (`source: "typed"`).
3463
+ */
3464
+ function renderValue(engine, nativeType, valueSql, plane, column) {
3465
+ const cases = casesFor(engine, nativeType);
3466
+ const raw = valueSql.trim();
3467
+ const exact = cases.find((c) => c.value_sql.trim() === raw);
3468
+ if (exact) return {
3469
+ value: expectation(exact, plane, column),
3470
+ source: "zoo"
3471
+ };
3472
+ if (/^NULL$/i.test(raw)) return {
3473
+ value: null,
3474
+ source: "typed"
3475
+ };
3476
+ const shape = expectation(cases.find((c) => c.class === "plain") ?? cases[0], plane, column);
3477
+ if (shape instanceof ZooRefusal) return {
3478
+ value: shape,
3479
+ source: "zoo"
3480
+ };
3481
+ return {
3482
+ value: shaped(raw, shape, cases, plane, column),
3483
+ source: "typed"
3484
+ };
3485
+ }
3486
+ function shaped(raw, shape, cases, plane, column) {
3487
+ const unquoted = raw.startsWith("'") && raw.endsWith("'") ? raw.slice(1, -1).replace(/''/g, "'") : raw;
3488
+ switch (typeof shape) {
3489
+ case "number": {
3490
+ if (/^-?\d+$/.test(raw)) {
3491
+ const big = BigInt(raw);
3492
+ if (big > I64_MAX || big < I64_MIN) {
3493
+ const wide = cases.find((c) => c.class === "precision_gt_18");
3494
+ if (wide && typeof expectation(wide, plane, column) === "string") return raw;
3495
+ }
3496
+ }
3497
+ const n = Number(unquoted);
3498
+ return Number.isNaN(n) ? unquoted : n;
3499
+ }
3500
+ case "boolean": return /^(true|1)$/i.test(unquoted);
3501
+ case "string": return unquoted;
3502
+ case "object":
3503
+ if (shape === null) return null;
3504
+ try {
3505
+ return JSON.parse(unquoted);
3506
+ } catch {
3507
+ return unquoted;
3508
+ }
3509
+ default: return unquoted;
3510
+ }
3511
+ }
3512
+
3513
+ //#endregion
3514
+ //#region src/testing/stores.ts
3515
+ const RANK = {
3516
+ zoo: 0,
3517
+ typed: 1,
3518
+ author: 2
3519
+ };
3520
+ const weakest = (a, b) => a === null || RANK[b] > RANK[a] ? b : a;
3521
+ /**
3522
+ * One SQL-evaluating store: a warehouse database, the OLTP schema or the
3523
+ * Airhouse schema. `engine` picks which zoo cases render typed columns;
3524
+ * `plane` picks which expectation a case yields.
3525
+ */
3526
+ var TableStore = class {
3527
+ constructor(engine, plane, schema = null) {
3528
+ this.engine = engine;
3529
+ this.plane = plane;
3530
+ this.schema = schema;
3531
+ this.tables = /* @__PURE__ */ new Map();
3532
+ }
3533
+ /** The zoo table for this engine: column `cNNN` is case NNN's expectation. */
3534
+ zoo() {
3535
+ const cases = ZOO.engines[this.engine].cases;
3536
+ const columns = {};
3537
+ const values = {};
3538
+ cases.forEach((c, i) => {
3539
+ const column = zooColumn(i);
3540
+ columns[column] = c.native_type;
3541
+ values[column] = expectation(c, this.plane, column);
3542
+ });
3543
+ this.tables.set(zooTableName(), {
3544
+ name: zooTableName(),
3545
+ columns,
3546
+ rows: [{
3547
+ values,
3548
+ source: "zoo"
3549
+ }]
3550
+ });
3551
+ return this;
3552
+ }
3553
+ /**
3554
+ * Declare a typed table: `{ id: "UInt64", amount: "Decimal(18, 4)" }`. A
3555
+ * type the zoo has no case for is an error here, not a guess at read time.
3556
+ */
3557
+ table(name, columns) {
3558
+ const key = this.key(name);
3559
+ for (const [column, type] of Object.entries(columns)) if (!ZOO.engines[this.engine].cases.some((c) => c.native_type === type)) throw contextError(`the zoo has no ${this.engine} case for type "${type}" (column "${column}" of "${name}"); it pins: ${knownTypes(this.engine).join(", ")}`);
3560
+ if (!this.tables.has(key)) this.tables.set(key, {
3561
+ name: key,
3562
+ columns,
3563
+ rows: []
3564
+ });
3565
+ return new TypedTable(this, key);
3566
+ }
3567
+ /** Seed rows as JS values, unrendered — every read of them is `source: "author"`. */
3568
+ raw(name, rows) {
3569
+ const key = this.key(name);
3570
+ const table = this.tables.get(key) ?? {
3571
+ name: key,
3572
+ columns: null,
3573
+ rows: []
3574
+ };
3575
+ for (const row of rows) table.rows.push({
3576
+ values: { ...row },
3577
+ source: "author"
3578
+ });
3579
+ this.tables.set(key, table);
3580
+ return this;
3581
+ }
3582
+ /** Every row of `name` as a function would read it; a `$error` cell is its refusal text. */
3583
+ rows(name) {
3584
+ return this.lookup(name)?.rows.map((r) => materialise(r.values)) ?? [];
3585
+ }
3586
+ /** The names of every table declared, seeded or created. */
3587
+ tableNames() {
3588
+ return [...this.tables.keys()];
3589
+ }
3590
+ /** Whether `name` exists. */
3591
+ has(name) {
3592
+ return this.lookup(name) !== void 0;
3593
+ }
3594
+ /** Evaluate `sql` as a read: rows, or a throw. */
3595
+ query(sql, params = []) {
3596
+ const statement = parse(sql);
3597
+ if (statement.kind !== "select") throw contextError(`expected a SELECT, got ${statement.kind.toUpperCase()}: ${sql.slice(0, 80)}`);
3598
+ return this.select(statement, params);
3599
+ }
3600
+ /** Evaluate `sql` as a statement: rows affected, or a throw. */
3601
+ exec(sql, params = []) {
3602
+ const statement = parse(sql);
3603
+ switch (statement.kind) {
3604
+ case "create": return this.create(statement);
3605
+ case "insert": return this.insert(statement, params);
3606
+ case "delete": return this.remove(statement, params);
3607
+ case "update": return this.update(statement, params);
3608
+ case "select": return this.select(statement, params).rows.length;
3609
+ }
3610
+ }
3611
+ /** Append JS rows to `name` (`ctx.warehouse.insert`, `ctx.airhouse.append`): unrendered. */
3612
+ append(name, rows) {
3613
+ this.raw(name, rows);
3614
+ return rows.length;
3615
+ }
3616
+ /** Snapshot every table, for `ctx.tx` rollback. */
3617
+ snapshot() {
3618
+ const copy = new Map([...this.tables].map(([k, t]) => [k, {
3619
+ ...t,
3620
+ rows: t.rows.map((r) => ({
3621
+ ...r,
3622
+ values: { ...r.values }
3623
+ }))
3624
+ }]));
3625
+ return () => {
3626
+ this.tables.clear();
3627
+ for (const [k, t] of copy) this.tables.set(k, t);
3628
+ };
3629
+ }
3630
+ key(name) {
3631
+ return this.schema && name.startsWith(`${this.schema}.`) ? name.slice(this.schema.length + 1) : name;
3632
+ }
3633
+ lookup(name) {
3634
+ return this.tables.get(this.key(name)) ?? this.tables.get(name);
3635
+ }
3636
+ require(name, statement) {
3637
+ const table = this.lookup(name);
3638
+ if (!table) throw contextError(`${statement.kind.toUpperCase()} names a table the test context does not have: "${name}". Declare it with t.state.<store>.table(name, columns), seed it with .raw(name, rows), or let the function CREATE it first. Known: ${this.tableNames().join(", ") || "none"}`);
3639
+ return table;
3640
+ }
3641
+ create(statement) {
3642
+ const key = this.key(statement.table);
3643
+ if (this.tables.has(key)) {
3644
+ if (statement.ifNotExists) return 0;
3645
+ throw contextError(`CREATE TABLE "${statement.table}": the table already exists`);
3646
+ }
3647
+ const columns = {};
3648
+ for (const c of statement.columns) columns[c.name] = c.type;
3649
+ this.tables.set(key, {
3650
+ name: key,
3651
+ columns,
3652
+ rows: []
3653
+ });
3654
+ return 0;
3655
+ }
3656
+ insert(statement, params) {
3657
+ const table = this.require(statement.table, statement);
3658
+ const names = statement.columns ?? (table.columns ? Object.keys(table.columns) : null);
3659
+ for (const tuple of statement.tuples) {
3660
+ if (!names || names.length !== tuple.length) throw contextError(`INSERT INTO "${statement.table}" gives ${tuple.length} value(s) for ${names?.length ?? "an unknown number of"} column(s)`);
3661
+ const values = {};
3662
+ let source = null;
3663
+ names.forEach((column, i) => {
3664
+ const type = table.columns?.[column];
3665
+ if (type && !/^\$\d+$/.test(tuple[i].trim())) {
3666
+ const rendered = renderValue(this.engine, type, tuple[i], this.plane, column);
3667
+ values[column] = rendered.value;
3668
+ source = weakest(source, rendered.source);
3669
+ } else {
3670
+ values[column] = literal(tuple[i], params);
3671
+ source = weakest(source, "author");
3672
+ }
3673
+ });
3674
+ table.rows.push({
3675
+ values,
3676
+ source: source ?? "author"
3677
+ });
3678
+ }
3679
+ return statement.tuples.length;
3680
+ }
3681
+ matching(table, statement, params) {
3682
+ return table.rows.filter((row) => statement.where.every((p) => {
3683
+ const cell = row.values[p.column];
3684
+ return p.values.some((v) => looselyEqual(cell, literal(v, params)));
3685
+ }));
3686
+ }
3687
+ select(statement, params) {
3688
+ if (statement.table === null) {
3689
+ const row = {};
3690
+ for (const item of statement.items) if (item.kind === "literal") row[item.alias] = literal(item.raw, params);
3691
+ else throw contextError(`SELECT without FROM can only project literals: ${JSON.stringify(item)}`);
3692
+ return {
3693
+ rows: [row],
3694
+ source: "author"
3695
+ };
3696
+ }
3697
+ const table = this.require(statement.table, statement);
3698
+ let matched = this.matching(table, statement, params);
3699
+ if (statement.items.some((i) => i.kind === "count")) return {
3700
+ rows: [{ [statement.items.find((i) => i.kind === "count")?.alias ?? "count(*)"]: matched.length }],
3701
+ source: matched[0]?.source ?? null
3702
+ };
3703
+ if (statement.orderBy) {
3704
+ const { column, desc } = statement.orderBy;
3705
+ matched = [...matched].sort((a, b) => compare(a.values[column], b.values[column]) * (desc ? -1 : 1));
3706
+ }
3707
+ if (statement.limit !== null) matched = matched.slice(0, statement.limit);
3708
+ let source = null;
3709
+ return {
3710
+ rows: matched.map((stored) => {
3711
+ source = weakest(source, stored.source);
3712
+ const out = {};
3713
+ for (const item of statement.items) if (item.kind === "all") Object.assign(out, materialise(stored.values));
3714
+ else if (item.kind === "column") out[item.alias] = materialise({ v: stored.values[item.column] }).v;
3715
+ else if (item.kind === "literal") out[item.alias] = literal(item.raw, params);
3716
+ return out;
3717
+ }),
3718
+ source
3719
+ };
3720
+ }
3721
+ remove(statement, params) {
3722
+ const table = this.require(statement.table, statement);
3723
+ const gone = new Set(this.matching(table, statement, params));
3724
+ table.rows = table.rows.filter((r) => !gone.has(r));
3725
+ return gone.size;
3726
+ }
3727
+ update(statement, params) {
3728
+ const table = this.require(statement.table, statement);
3729
+ const hit = this.matching(table, statement, params);
3730
+ for (const row of hit) for (const { column, raw } of statement.set) {
3731
+ row.values[column] = literal(raw, params);
3732
+ row.source = "author";
3733
+ }
3734
+ return hit.length;
3735
+ }
3736
+ };
3737
+ /** A declared typed table: insert SQL-side values, rendered through the zoo. */
3738
+ var TypedTable = class {
3739
+ constructor(store, name) {
3740
+ this.store = store;
3741
+ this.name = name;
3742
+ }
3743
+ /** Insert rows of SQL-side values (`{ id: "42", at: "'2024-03-10 12:34:56'" }`). */
3744
+ insert(rows) {
3745
+ for (const row of rows) {
3746
+ const columns = Object.keys(row);
3747
+ const values = columns.map((c) => row[c]);
3748
+ this.store.exec(`INSERT INTO ${this.name} (${columns.join(", ")}) VALUES (${values.join(", ")})`);
3749
+ }
3750
+ return this;
3751
+ }
3752
+ };
3753
+ /** A stored row as a read returns it; a refusal cell throws the host's sentence. */
3754
+ function materialise(values) {
3755
+ const out = {};
3756
+ for (const [k, v] of Object.entries(values)) {
3757
+ if (v instanceof ZooRefusal) throw refusalOf(v);
3758
+ out[k] = v;
3759
+ }
3760
+ return out;
3761
+ }
3762
+ /** Marker so the context can wrap a zoo refusal as the OLTP surface's `HostError`. */
3763
+ var ZooRefusalError = class extends Error {
3764
+ constructor(refusal) {
3765
+ super(refusal.message());
3766
+ this.refusal = refusal;
3767
+ this.name = "ZooRefusalError";
3768
+ }
3769
+ };
3770
+ const refusalOf = (r) => new ZooRefusalError(r);
3771
+ function looselyEqual(a, b) {
3772
+ if (a === b) return true;
3773
+ if (a === null || b === null || a === void 0 || b === void 0) return false;
3774
+ return String(a) === String(b);
3775
+ }
3776
+ function compare(a, b) {
3777
+ if (typeof a === "number" && typeof b === "number") return a - b;
3778
+ return String(a).localeCompare(String(b));
3779
+ }
3780
+ /** The `ctx.fetch` side: answers by URL, and what was received. */
3781
+ var FetchStore = class {
3782
+ constructor() {
3783
+ this.received = [];
3784
+ this.answers = [];
3785
+ }
3786
+ /** Answer every URL equal to `match` (or matching the RegExp) with `answer`. */
3787
+ on(match, answer) {
3788
+ this.answers.push({
3789
+ match,
3790
+ answer
3791
+ });
3792
+ return this;
3793
+ }
3794
+ answerFor(url) {
3795
+ return this.answers.find(({ match }) => typeof match === "string" ? match === url : match.test(url))?.answer;
3796
+ }
3797
+ };
3798
+
3799
+ //#endregion
3800
+ //#region src/testing/context.ts
3801
+ const encoder = new TextEncoder();
3802
+ const decoder = new TextDecoder();
3803
+ const nodeBtoa = globalThis.btoa;
3804
+ const nodeAtob = globalThis.atob;
3805
+ const nodeCryptoModule = nodeCryptoImport;
3806
+ const DEFAULT_USER = {
3807
+ id: "user-1",
3808
+ email: "author@example.test",
3809
+ orgId: "org-1",
3810
+ name: "Author",
3811
+ appRole: "member",
3812
+ orgRole: "member",
3813
+ teams: [],
3814
+ kind: "user",
3815
+ reach: {
3816
+ everywhere: true,
3817
+ via: "org-member",
3818
+ locations: []
3819
+ }
3820
+ };
3821
+ function createTestContext(manifest, options) {
3822
+ const gates = readGates(manifest, options.function);
3823
+ const manifestSlug = typeof manifest.slug === "string" ? manifest.slug : "";
3824
+ const databases = options.databases ?? {};
3825
+ const calls = [];
3826
+ const overrides = /* @__PURE__ */ new Map();
3827
+ const warehouses = /* @__PURE__ */ new Map();
3828
+ let semanticAnswer = null;
3829
+ const state = {
3830
+ warehouse(database) {
3831
+ const db = databases[database];
3832
+ if (!db) throw contextError(`no database "${database}" in options.databases`);
3833
+ let store = warehouses.get(database);
3834
+ if (!store) {
3835
+ store = new TableStore(db.dialect, "warehouse");
3836
+ warehouses.set(database, store);
3837
+ }
3838
+ return store;
3839
+ },
3840
+ oltp: new TableStore("postgres", "oltp", gates.writerSchema),
3841
+ airhouse: new TableStore("duckdb", "warehouse", gates.writerSchema),
3842
+ storage: /* @__PURE__ */ new Map(),
3843
+ secrets: /* @__PURE__ */ new Map(),
3844
+ emails: [],
3845
+ fetch: new FetchStore(),
3846
+ org: {
3847
+ people: [],
3848
+ places: [],
3849
+ assignments: []
3850
+ },
3851
+ semantic: { on: (answer) => {
3852
+ semanticAnswer = answer;
3853
+ } },
3854
+ airway: { runs: [] }
3855
+ };
3856
+ /** Run one host op: the override or `impl`, recorded either way. */
3857
+ async function op(name, args, impl) {
3858
+ const call = {
3859
+ op: name,
3860
+ args,
3861
+ outcome: "ok"
3862
+ };
3863
+ calls.push(call);
3864
+ try {
3865
+ const result = await (overrides.get(name) ?? impl)(args);
3866
+ if (result && typeof result === "object" && "__source" in result) {
3867
+ const { __source } = result;
3868
+ if (__source) call.source = __source;
3869
+ const rest = Array.isArray(result) ? [...result] : Object.fromEntries(Object.entries(result).filter(([k]) => k !== "__source"));
3870
+ call.result = rest;
3871
+ return rest;
3872
+ }
3873
+ call.result = result;
3874
+ return result;
3875
+ } catch (err) {
3876
+ const thrown = err instanceof ZooRefusalError ? hostError(name.startsWith("tx.") ? SURFACES.tx : SURFACES.oltp, err.message) : err;
3877
+ call.outcome = isHostError(thrown) ? "refused" : "threw";
3878
+ call.message = thrown instanceof Error ? thrown.message : String(thrown);
3879
+ throw thrown;
3880
+ }
3881
+ }
3882
+ /** `check_write_destination` then `destination_write_policy` (`host.rs`, `destinations.rs`). */
3883
+ function checkWriteDestination(surface, database, transaction) {
3884
+ if (!gates.destinations.includes(database)) throw refuse(surface, REFUSALS.destinationNotDeclared, { database });
3885
+ const db = databases[database];
3886
+ if (!db) throw refuse(surface, REFUSALS.databaseNotConfigured, { database });
3887
+ switch (db.kind) {
3888
+ case "airhouse":
3889
+ case "airhouse_managed": return db;
3890
+ case "postgres_managed": throw refuse(surface, REFUSALS.managedOltpWrite, { database });
3891
+ default: {
3892
+ if (gates.customerWarehouseWrites[database]) return db;
3893
+ const words = [REFUSALS.customerWarehouseWrite.refusal];
3894
+ if (transaction) words.push(REFUSALS.customerWarehouseTransaction.refusal);
3895
+ throw hostError(surface, words.join("").replace(/\{database\}/g, database));
3896
+ }
3897
+ }
3898
+ }
3899
+ /**
3900
+ * The host's `WriterCapability` has three states, not two: enabled, disabled,
3901
+ * and enabled-but-the-slug-cannot-back-a-schema. Gating on the boolean alone
3902
+ * let an app whose slug derives no schema pass here and fail closed in
3903
+ * production — the exact shape this module exists to catch.
3904
+ */
3905
+ function requireWriterSchema(surface, store) {
3906
+ if (gates.writerSchema === null) throw refuse(surface, REFUSALS.slugCannotBackASchema, {
3907
+ slug: manifestSlug,
3908
+ store,
3909
+ max: 56
3910
+ });
3911
+ }
3912
+ function requireOltp(surface) {
3913
+ if (!gates.oltp) throw refuse(surface, REFUSALS.oltp);
3914
+ requireWriterSchema(surface, "OLTP");
3915
+ return state.oltp;
3916
+ }
3917
+ function requireAirhouse() {
3918
+ if (!gates.airhouse) throw refuse(SURFACES.airhouse, REFUSALS.airhouse);
3919
+ requireWriterSchema(SURFACES.airhouse, "Airhouse");
3920
+ return state.airhouse;
3921
+ }
3922
+ function requireStorage(opName) {
3923
+ const needsWrite = [
3924
+ "getUploadUrl",
3925
+ "put",
3926
+ "delete",
3927
+ "copy"
3928
+ ].includes(opName);
3929
+ const needsRead = [
3930
+ "getDownloadUrl",
3931
+ "get",
3932
+ "head",
3933
+ "list",
3934
+ "copy"
3935
+ ].includes(opName);
3936
+ if (needsWrite && !gates.storageWrite) throw refuse(SURFACES.storage, REFUSALS.storageWrite);
3937
+ if (needsRead && !gates.storageRead) throw refuse(SURFACES.storage, REFUSALS.storageRead);
3938
+ }
3939
+ function defaultDatabase() {
3940
+ const name = options.defaultDatabase ?? Object.keys(databases)[0];
3941
+ if (!name) throw refuse(SURFACES.query, REFUSALS.noDefaultDatabase);
3942
+ return name;
3943
+ }
3944
+ /** `oltp_statement`: `params` absent or an array, else refused. */
3945
+ function oltpParams(surface, params) {
3946
+ if (params === void 0 || params === null) return [];
3947
+ if (Array.isArray(params)) return params;
3948
+ throw refuse(surface, REFUSALS.oltpParamsNotArray);
3949
+ }
3950
+ const read = (store, sql, params = []) => {
3951
+ const { rows, source } = store.query(sql, params);
3952
+ return {
3953
+ rows,
3954
+ truncated: false,
3955
+ __source: source
3956
+ };
3957
+ };
3958
+ let open = 0;
3959
+ let nextTxId = 0;
3960
+ async function runTx(signature, label, beginOp, beginPayload, fn) {
3961
+ if (typeof fn !== "function") throw new TypeError(REFUSALS.transactionFnNotFunction.refusal.replace("{signature}", signature));
3962
+ let store = null;
3963
+ let incremented = false;
3964
+ const { id } = await op(beginOp, beginPayload, () => {
3965
+ if (beginOp === "tx.begin") {
3966
+ const database = String(beginPayload.database);
3967
+ const db = checkWriteDestination(SURFACES.tx, database, true);
3968
+ if (!DIALECTS[db.dialect].opensTransactions) {
3969
+ const cause = REFUSALS.transactionUnsupported.refusal.replace("{backend}", DIALECTS[db.dialect].name);
3970
+ throw refuse(SURFACES.tx, REFUSALS.transactionOpen, {
3971
+ database,
3972
+ e: cause
3973
+ });
3974
+ }
3975
+ store = state.warehouse(database);
3976
+ } else store = requireOltp(SURFACES.tx);
3977
+ if (open >= 4) throw refuse(SURFACES.tx, REFUSALS.transactionsOpen, { MAX_OPEN: 4 });
3978
+ open++;
3979
+ incremented = true;
3980
+ return { id: ++nextTxId };
3981
+ });
3982
+ const table = store ?? (beginOp === "tx.begin_oltp" ? state.oltp : databases[String(beginPayload.database)] ? state.warehouse(String(beginPayload.database)) : new TableStore("postgres", "warehouse"));
3983
+ const restore = table.snapshot();
3984
+ let closed = false;
3985
+ const live = (what) => {
3986
+ if (closed) throw hostError(label, REFUSALS.transactionFinished.refusal.replace("{label}", label).replace("{what}", what));
3987
+ };
3988
+ const handle = {
3989
+ query: async (sql, params) => {
3990
+ live("query");
3991
+ return (await op("tx.query", {
3992
+ id,
3993
+ sql: String(sql),
3994
+ params: params ?? []
3995
+ }, (a) => read(table, String(a.sql), oltpParams(SURFACES.tx, a.params)))).rows;
3996
+ },
3997
+ exec: async (sql, params) => {
3998
+ live("exec");
3999
+ return (await op("tx.exec", {
4000
+ id,
4001
+ sql: String(sql),
4002
+ params: params ?? []
4003
+ }, (a) => ({ rowCount: table.exec(String(a.sql), oltpParams(SURFACES.tx, a.params)) }))).rowCount;
4004
+ }
4005
+ };
4006
+ let result;
4007
+ try {
4008
+ result = await fn(handle);
4009
+ } catch (err) {
4010
+ closed = true;
4011
+ if (incremented) open--;
4012
+ try {
4013
+ await op("tx.rollback", { id }, () => {
4014
+ restore();
4015
+ return {};
4016
+ });
4017
+ } catch {}
4018
+ throw err;
4019
+ }
4020
+ closed = true;
4021
+ if (incremented) open--;
4022
+ await op("tx.commit", { id }, () => ({}));
4023
+ return result;
4024
+ }
4025
+ const ctx = {
4026
+ user: {
4027
+ ...DEFAULT_USER,
4028
+ ...options.user
4029
+ },
4030
+ env: { ...options.env ?? {} },
4031
+ log: () => {},
4032
+ crypto: nodeCrypto(),
4033
+ query: async (sql) => await op("query", { sql: String(sql) }, (a) => read(state.warehouse(defaultDatabase()), String(a.sql))),
4034
+ queryStream: async function* (sql, opts) {
4035
+ const batchSize = opts?.batchSize || 1e3;
4036
+ const rows = await op("query_stream", { sql: String(sql) }, (a) => {
4037
+ const { rows, __source } = read(state.warehouse(defaultDatabase()), String(a.sql));
4038
+ return Object.assign(rows, { __source });
4039
+ });
4040
+ for (let i = 0; i < rows.length; i += batchSize) yield rows.slice(i, i + batchSize);
4041
+ },
4042
+ fetch: (url, init) => op("fetch", {
4043
+ url,
4044
+ init: init ?? {}
4045
+ }, (a) => fetchOp(String(a.url), a.init ?? {})),
4046
+ warehouse: {
4047
+ insert: (database, table, rows) => op("warehouse.insert", {
4048
+ database,
4049
+ table,
4050
+ rows
4051
+ }, (a) => {
4052
+ checkWriteDestination(SURFACES.warehouse, String(a.database), false);
4053
+ state.warehouse(String(a.database)).append(String(a.table), a.rows);
4054
+ return { ok: true };
4055
+ }),
4056
+ exec: (database, sql) => op("warehouse.exec", {
4057
+ database,
4058
+ sql
4059
+ }, (a) => {
4060
+ checkWriteDestination(SURFACES.warehouse, String(a.database), false);
4061
+ state.warehouse(String(a.database)).exec(String(a.sql));
4062
+ return { ok: true };
4063
+ }),
4064
+ upsert: (database, table, rows, conflictColumns) => op("warehouse.upsert", {
4065
+ database,
4066
+ table,
4067
+ rows,
4068
+ conflictColumns
4069
+ }, (a) => {
4070
+ const database = String(a.database);
4071
+ const db = checkWriteDestination(SURFACES.warehouse, database, false);
4072
+ if (!DIALECTS[db.dialect].parsesOnConflict) throw refuse(SURFACES.warehouse, REFUSALS.upsertUnsupported, { dialect: DIALECTS[db.dialect].name });
4073
+ if (db.kind === "airhouse" || db.kind === "airhouse_managed") throw contextError(`@oxy-hq/sdk/testing: ctx.warehouse.upsert on "${database}" would be refused by the ENGINE, not the host. Airhouse is DuckLake, and a DuckLake table cannot carry the primary key or unique constraint that INSERT … ON CONFLICT needs, so the statement the host lets through fails at runtime. Use ctx.airhouse.append and keep one row per id on read. (These are the test context's words, not a host refusal — assert that the call was refused, not on this text, which may be reworded.)`);
4074
+ state.warehouse(database).append(String(a.table), a.rows);
4075
+ return { ok: true };
4076
+ }),
4077
+ query: (database, sql) => op("warehouse.query", {
4078
+ database,
4079
+ sql
4080
+ }, (a) => {
4081
+ const database = String(a.database);
4082
+ if (!databases[database]) throw refuse(SURFACES.warehouse, REFUSALS.databaseNotConfigured, { database });
4083
+ return read(state.warehouse(database), String(a.sql));
4084
+ })
4085
+ },
4086
+ tx: (database, fn) => runTx("ctx.tx(database, fn)", SURFACES.tx, "tx.begin", { database: String(database) }, fn),
4087
+ oltp: {
4088
+ tx: (fn) => runTx("ctx.oltp.tx(fn)", "ctx.oltp.tx", "tx.begin_oltp", {}, fn),
4089
+ query: async (sql, params) => {
4090
+ return (await op("oltp.query", {
4091
+ sql: String(sql),
4092
+ params: params ?? []
4093
+ }, (a) => read(requireOltp(SURFACES.oltp), String(a.sql), oltpParams(SURFACES.oltp, a.params)))).rows;
4094
+ },
4095
+ exec: async (sql, params) => {
4096
+ return (await op("oltp.exec", {
4097
+ sql: String(sql),
4098
+ params: params ?? []
4099
+ }, (a) => ({ rowCount: requireOltp(SURFACES.oltp).exec(String(a.sql), oltpParams(SURFACES.oltp, a.params)) }))).rowCount;
4100
+ }
4101
+ },
4102
+ airhouse: {
4103
+ schema: gates.airhouse ? gates.writerSchema : null,
4104
+ query: (sql) => op("airhouse.query", { sql: String(sql) }, (a) => read(requireAirhouse(), String(a.sql))),
4105
+ exec: async (sql) => {
4106
+ await op("airhouse.exec", { sql: String(sql) }, (a) => {
4107
+ requireAirhouse().exec(String(a.sql));
4108
+ return { ok: true };
4109
+ });
4110
+ },
4111
+ append: async (table, rows) => {
4112
+ return (await op("airhouse.append", {
4113
+ table: String(table),
4114
+ rows
4115
+ }, (a) => ({ rowCount: requireAirhouse().append(String(a.table), a.rows) }))).rowCount;
4116
+ }
4117
+ },
4118
+ secrets: { set: async (key, value) => {
4119
+ await op("secrets.set", {
4120
+ key: String(key),
4121
+ value: String(value)
4122
+ }, (a) => {
4123
+ if (!gates.secretsWrite) throw refuse(SURFACES.secretsSet, REFUSALS.secretsWrite);
4124
+ state.secrets.set(String(a.key), String(a.value));
4125
+ return null;
4126
+ });
4127
+ } },
4128
+ email: { send: (input) => op("email.send", { ...input }, (a) => {
4129
+ if (!gates.emailSend) throw refuse(SURFACES.emailSend, REFUSALS.emailSend);
4130
+ state.emails.push(a);
4131
+ return { messageId: `message-${state.emails.length}` };
4132
+ }) },
4133
+ org: {
4134
+ people: () => op("org.people", {}, () => {
4135
+ if (!gates.orgRead) throw refuse(SURFACES.orgPeople, REFUSALS.orgPeople);
4136
+ return {
4137
+ people: [...state.org.people],
4138
+ total: state.org.people.length
4139
+ };
4140
+ }),
4141
+ places: () => op("org.places", {}, () => {
4142
+ if (!gates.orgRead) throw refuse(SURFACES.orgPlaces, REFUSALS.orgMember, { member: "places" });
4143
+ return {
4144
+ total: state.org.places.length,
4145
+ places: [...state.org.places]
4146
+ };
4147
+ }),
4148
+ assignments: () => op("org.assignments", {}, () => {
4149
+ if (!gates.orgRead) throw refuse(SURFACES.orgAssignments, REFUSALS.orgMember, { member: "assignments" });
4150
+ return {
4151
+ total: state.org.assignments.length,
4152
+ assignments: [...state.org.assignments]
4153
+ };
4154
+ })
4155
+ },
4156
+ storage: storageApi(),
4157
+ semantic: { query: (spec) => op("semantic.query", { spec }, (a) => {
4158
+ if (!semanticAnswer) throw contextError("ctx.semantic.query has no answer registered: the zoo pins no semantic payload, so supply one with t.state.semantic.on((spec) => result)");
4159
+ return semanticAnswer(a.spec);
4160
+ }) },
4161
+ airway: { run: (pipelineRef, variables) => op("airway.run", {
4162
+ pipelineRef: String(pipelineRef),
4163
+ variables: variables ?? null
4164
+ }, (a) => {
4165
+ state.airway.runs.push({
4166
+ pipelineRef: String(a.pipelineRef),
4167
+ variables: a.variables
4168
+ });
4169
+ return { runId: `run-${state.airway.runs.length}` };
4170
+ }) }
4171
+ };
4172
+ function fetchOp(url, init) {
4173
+ let parsed;
4174
+ try {
4175
+ parsed = new URL(url);
4176
+ } catch (e) {
4177
+ throw refuse(SURFACES.fetch, REFUSALS.fetchInvalidUrl, { e: e instanceof Error ? e.message : String(e) });
4178
+ }
4179
+ if (!isSafeOutbound(parsed)) throw refuse(SURFACES.fetch, REFUSALS.fetchBlocked, { url });
4180
+ for (const [k, v] of Object.entries(headersOf(init.headers))) {
4181
+ if (!/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/.test(k)) throw refuse(SURFACES.fetch, REFUSALS.fetchInvalidHeaderName, { k });
4182
+ if (/[\r\n\0]/.test(v)) throw refuse(SURFACES.fetch, REFUSALS.fetchInvalidHeaderValue, { k });
4183
+ }
4184
+ state.fetch.received.push({
4185
+ url,
4186
+ init
4187
+ });
4188
+ const answer = state.fetch.answerFor(url);
4189
+ if (answer === void 0) throw contextError(`ctx.fetch has no answer for ${url}: register one with t.state.fetch.on(url, { status, body }) — nothing here reaches the network`);
4190
+ const reply = typeof answer === "function" ? answer(url, init) : answer;
4191
+ const fixture = reply.body ?? "";
4192
+ const fixtureIsBase64 = reply.encoding === "base64";
4193
+ const max = gates.fetchMaxBytes ?? 10485760;
4194
+ const len = fixtureIsBase64 ? base64ByteLength(fixture) : encoder.encode(fixture).length;
4195
+ if (len > max) throw refuse(SURFACES.fetch, REFUSALS.fetchTooLarge, {
4196
+ len,
4197
+ max_bytes: max
4198
+ });
4199
+ if (init.encoding !== void 0 && init.encoding !== "utf8" && init.encoding !== "base64") throw contextError(`ctx.fetch: unknown encoding '${String(init.encoding)}' (expected 'utf8' or 'base64')`);
4200
+ const wantBase64 = init.encoding === "base64";
4201
+ const body = wantBase64 ? fixtureIsBase64 ? fixture : utf8ToBase64(fixture) : fixtureIsBase64 ? base64ToUtf8(fixture) : fixture;
4202
+ return {
4203
+ status: reply.status ?? 200,
4204
+ body,
4205
+ encoding: wantBase64 ? "base64" : "utf8"
4206
+ };
4207
+ }
4208
+ function storageApi() {
4209
+ const now = () => (/* @__PURE__ */ new Date()).toISOString();
4210
+ const put = (key, body, contentType) => {
4211
+ const object = {
4212
+ key,
4213
+ body,
4214
+ contentType,
4215
+ size: base64ByteLength(body),
4216
+ lastModified: now()
4217
+ };
4218
+ state.storage.set(key, object);
4219
+ return object;
4220
+ };
4221
+ const storageOp = (name, args, impl) => op(`storage.${name}`, args, (a) => {
4222
+ requireStorage(name);
4223
+ return impl(a);
4224
+ });
4225
+ return {
4226
+ getUploadUrl: (opts) => storageOp("getUploadUrl", { ...opts }, (a) => {
4227
+ const key = `${String(a.pathname ?? `uploads/${String(a.filename ?? "upload")}`).replace(/(\.[^.]*)?$/, `-${randomSuffix()}$1`)}`;
4228
+ return {
4229
+ url: `https://storage.example.test/put/${key}`,
4230
+ key,
4231
+ expiresAt: now()
4232
+ };
4233
+ }),
4234
+ getDownloadUrl: (key, opts) => storageOp("getDownloadUrl", {
4235
+ key: String(key),
4236
+ ...opts
4237
+ }, (a) => ({
4238
+ url: `https://storage.example.test/get/${String(a.key)}`,
4239
+ expiresAt: now()
4240
+ })),
4241
+ put: (pathname, body, opts) => storageOp("put", {
4242
+ pathname: String(pathname),
4243
+ body: String(body),
4244
+ ...opts
4245
+ }, (a) => {
4246
+ const key = a.addRandomSuffix ? String(a.pathname).replace(/(\.[^.]*)?$/, `-${randomSuffix()}$1`) : String(a.pathname);
4247
+ if (state.storage.has(key) && !a.allowOverwrite) throw hostError(SURFACES.storage, `put: "${key}" already exists (pass allowOverwrite: true)`);
4248
+ const base64 = a.encoding === "base64" ? String(a.body) : utf8ToBase64(String(a.body));
4249
+ const stored = put(key, base64, a.contentType ?? null);
4250
+ return {
4251
+ key,
4252
+ size: stored.size,
4253
+ contentType: stored.contentType ?? "application/octet-stream"
4254
+ };
4255
+ }),
4256
+ get: (key, opts) => storageOp("get", {
4257
+ key: String(key),
4258
+ ...opts
4259
+ }, (a) => {
4260
+ const object = state.storage.get(String(a.key));
4261
+ if (!object) return null;
4262
+ const base64 = a.encoding === "base64";
4263
+ return {
4264
+ body: base64 ? object.body : base64ToUtf8(object.body),
4265
+ contentType: object.contentType,
4266
+ size: object.size,
4267
+ encoding: base64 ? "base64" : "utf8"
4268
+ };
4269
+ }),
4270
+ head: (key) => storageOp("head", { key: String(key) }, (a) => {
4271
+ const object = state.storage.get(String(a.key));
4272
+ return object ? {
4273
+ key: object.key,
4274
+ size: object.size,
4275
+ contentType: object.contentType,
4276
+ lastModified: object.lastModified
4277
+ } : null;
4278
+ }),
4279
+ list: (opts) => storageOp("list", { ...opts }, (a) => {
4280
+ const prefix = String(a.prefix ?? "");
4281
+ const limit = Number(a.limit ?? 1e3);
4282
+ const offset = a.cursor ? Number(a.cursor) : 0;
4283
+ const keys = [...state.storage.keys()].filter((k) => k.startsWith(prefix)).sort();
4284
+ const page = keys.slice(offset, offset + limit).map((k) => {
4285
+ const o = state.storage.get(k);
4286
+ return {
4287
+ key: o.key,
4288
+ size: o.size,
4289
+ contentType: o.contentType,
4290
+ lastModified: o.lastModified
4291
+ };
4292
+ });
4293
+ const hasMore = offset + limit < keys.length;
4294
+ return {
4295
+ objects: page,
4296
+ cursor: hasMore ? String(offset + limit) : null,
4297
+ hasMore
4298
+ };
4299
+ }),
4300
+ delete: (keyOrKeys) => storageOp("delete", Array.isArray(keyOrKeys) ? { keys: keyOrKeys.map(String) } : { key: String(keyOrKeys) }, (a) => {
4301
+ const keys = Array.isArray(a.keys) ? a.keys : [String(a.key)];
4302
+ for (const k of keys) state.storage.delete(k);
4303
+ return { deleted: keys.length };
4304
+ }),
4305
+ copy: (fromKey, toPathname, opts) => storageOp("copy", {
4306
+ fromKey: String(fromKey),
4307
+ toPathname: String(toPathname),
4308
+ ...opts
4309
+ }, (a) => {
4310
+ const from = state.storage.get(String(a.fromKey));
4311
+ if (!from) throw hostError(SURFACES.storage, `copy: "${String(a.fromKey)}" does not exist`);
4312
+ const key = String(a.toPathname);
4313
+ if (state.storage.has(key) && !a.allowOverwrite) throw hostError(SURFACES.storage, `copy: "${key}" already exists (pass allowOverwrite: true)`);
4314
+ const stored = put(key, from.body, from.contentType);
4315
+ return {
4316
+ key,
4317
+ size: stored.size,
4318
+ contentType: stored.contentType ?? "application/octet-stream"
4319
+ };
4320
+ })
4321
+ };
4322
+ }
4323
+ return {
4324
+ ctx,
4325
+ calls,
4326
+ ops: () => [...new Set(calls.map((c) => c.op))],
4327
+ callsTo: (name) => calls.filter((c) => c.op === name),
4328
+ override: (name, impl) => {
4329
+ overrides.set(name, impl);
4330
+ },
4331
+ run: runWithoutIsolateGlobals,
4332
+ state,
4333
+ gates
4334
+ };
4335
+ }
4336
+ function headersOf(headers) {
4337
+ if (!headers) return {};
4338
+ if (Array.isArray(headers)) return Object.fromEntries(headers);
4339
+ if (typeof Headers !== "undefined" && headers instanceof Headers) return Object.fromEntries(headers.entries());
4340
+ return headers;
4341
+ }
4342
+ function randomSuffix() {
4343
+ return Math.random().toString(36).slice(2, 8);
4344
+ }
4345
+ /**
4346
+ * Bytes a base64 string decodes to. `length * 3 / 4` overstates by the padding,
4347
+ * which made `size` wrong by up to two bytes and fired the `ctx.fetch` cap early.
4348
+ */
4349
+ function base64ByteLength(base64) {
4350
+ const s = base64.trim();
4351
+ if (s === "") return 0;
4352
+ const padding = s.endsWith("==") ? 2 : s.endsWith("=") ? 1 : 0;
4353
+ return Math.floor(s.length * 3 / 4) - padding;
4354
+ }
4355
+ function utf8ToBase64(text) {
4356
+ const bytes = encoder.encode(text);
4357
+ let binary = "";
4358
+ for (const b of bytes) binary += String.fromCharCode(b);
4359
+ return nodeBtoa(binary);
4360
+ }
4361
+ function base64ToUtf8(base64) {
4362
+ const binary = nodeAtob(base64);
4363
+ const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0));
4364
+ return decoder.decode(bytes);
4365
+ }
4366
+ /**
4367
+ * `ctx.crypto` over `node:crypto`: the same three synchronous members
4368
+ * `__buildCtx` binds, with the host's argument rules (`key` and `data`
4369
+ * required; `signature` and both sides of `timingSafeEqual` lenient). A digest
4370
+ * is ASCII, so the byte views need no `Buffer` — which `t.run` removes.
4371
+ */
4372
+ function nodeCrypto() {
4373
+ const lib = () => nodeCryptoModule;
4374
+ const ascii = (s) => Uint8Array.from(s, (c) => c.charCodeAt(0));
4375
+ const digest = (algorithm, key, data, encoding) => lib().createHmac(algorithm, key).update(data).digest(encoding);
4376
+ const same = (a, b) => a !== "" && b !== "" && a.length === b.length && lib().timingSafeEqual(ascii(a), ascii(b));
4377
+ return {
4378
+ hmac: ({ algorithm, key, data, encoding }) => {
4379
+ if (key == null) throw new TypeError("ctx.crypto.hmac: `key` is required — is the secret set?");
4380
+ if (data == null) throw new TypeError("ctx.crypto.hmac: `data` is required");
4381
+ return digest(algorithm ?? "sha256", String(key), String(data), encoding ?? "hex");
4382
+ },
4383
+ verifyHmac: ({ algorithm, key, data, signature, encoding }) => {
4384
+ if (key == null) throw new TypeError("ctx.crypto.verifyHmac: `key` is required — is the secret set?");
4385
+ if (data == null) throw new TypeError("ctx.crypto.verifyHmac: `data` is required");
4386
+ const expected = digest(algorithm ?? "sha256", String(key), String(data), encoding ?? "hex");
4387
+ return same(String(signature ?? ""), expected);
4388
+ },
4389
+ timingSafeEqual: (a, b) => same(a == null ? "" : String(a), b == null ? "" : String(b))
4390
+ };
4391
+ }
4392
+
4393
+ //#endregion
4394
+ export { ABSENT_GLOBALS, DIALECTS, FETCH_MAX_BYTES, FETCH_RULES, FetchStore, GATES, HOST_ERROR_NAME, HOST_OPS, MAX_OPEN_TRANSACTIONS, REFUSALS, SURFACES, TableStore, TypedTable, ZOO, ZOO_SHA256, ZooRefusal, casesFor, contextError, createTestContext, expectation, hostError, isHostError, isSafeOutbound, isolateAtob, isolateBtoa, knownTypes, readGates, refuse, render, renderValue, runWithoutIsolateGlobals, writerSchema, zooColumn, zooTableName };
4395
+ //# sourceMappingURL=testing.mjs.map