@fabricorg/databricks-testkit 0.7.1 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/parity.cjs CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  var vitest = require('vitest');
4
4
  var promises = require('fs/promises');
5
- var databricks = require('@fabric-harness/databricks');
6
5
 
7
6
  // src/parity.ts
8
7
 
@@ -181,6 +180,125 @@ If the change is intentional, re-run with DBX_TEST_UPDATE_GOLDEN=1 and commit th
181
180
  function normalize(json) {
182
181
  return JSON.stringify(JSON.parse(json));
183
182
  }
183
+
184
+ // src/workspace-client.ts
185
+ var WorkspaceRestClient = class {
186
+ host;
187
+ token;
188
+ fetchImpl;
189
+ maxRetries;
190
+ retryBaseDelayMs;
191
+ signal;
192
+ constructor(options) {
193
+ this.host = workspaceOrigin(options.host);
194
+ this.token = options.token;
195
+ this.fetchImpl = options.fetchImpl ?? fetch;
196
+ this.maxRetries = options.maxRetries ?? 3;
197
+ this.retryBaseDelayMs = options.retryBaseDelayMs ?? 500;
198
+ this.signal = options.signal;
199
+ }
200
+ get(path, query) {
201
+ return this.request("GET", path, void 0, query);
202
+ }
203
+ post(path, body, query, options) {
204
+ return this.request("POST", path, body, query, options);
205
+ }
206
+ async request(method, path, body, query = {}, options = {}) {
207
+ const url = new URL(`${this.host}${path.startsWith("/") ? path : `/${path}`}`);
208
+ for (const [key, value] of Object.entries(query)) {
209
+ if (value !== void 0) url.searchParams.set(key, String(value));
210
+ }
211
+ const bodyHasIdempotencyToken = typeof body === "object" && body !== null && typeof body.idempotency_token === "string";
212
+ const canRetry = options.retry === "always" || options.retry !== "never" && (options.retry === "safe" || method === "GET" || Boolean(options.idempotencyKey) || bodyHasIdempotencyToken);
213
+ const maxRetries = canRetry ? options.maxRetries ?? this.maxRetries : 0;
214
+ for (let attempt = 0; ; attempt += 1) {
215
+ const token = typeof this.token === "function" ? await this.token() : this.token;
216
+ let response;
217
+ try {
218
+ response = await this.fetchImpl(url, {
219
+ method,
220
+ headers: {
221
+ authorization: `Bearer ${token}`,
222
+ ...body !== void 0 ? { "content-type": "application/json" } : {},
223
+ ...options.idempotencyKey ? { "idempotency-key": options.idempotencyKey } : {}
224
+ },
225
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {},
226
+ ...this.signal ? { signal: this.signal } : {}
227
+ });
228
+ } catch (error) {
229
+ if (this.signal?.aborted || attempt >= maxRetries) throw error;
230
+ await delay(this.retryBaseDelayMs * 2 ** attempt, this.signal);
231
+ continue;
232
+ }
233
+ if (response.ok) {
234
+ if (response.status === 204) return void 0;
235
+ return await response.json();
236
+ }
237
+ if (isRetryableStatus(response.status) && attempt < maxRetries) {
238
+ await delay(retryDelayMs(response, attempt, this.retryBaseDelayMs), this.signal);
239
+ continue;
240
+ }
241
+ const message = (await response.text()).split(token).join("[REDACTED]");
242
+ throw new Error(
243
+ `databricks: ${response.status} ${response.statusText}: ${message.slice(0, 2e3)}`
244
+ );
245
+ }
246
+ }
247
+ };
248
+ async function waitForDatabricksStatement(client, statementId, options = {}) {
249
+ const deadline = Date.now() + (options.timeoutMs ?? 3e5);
250
+ const interval = options.pollIntervalMs ?? 2e3;
251
+ const path = `/api/2.0/sql/statements/${encodeURIComponent(statementId)}`;
252
+ let current = await client.get(path);
253
+ while (!isTerminalStatement(current) && Date.now() < deadline) {
254
+ await delay(interval, options.signal);
255
+ current = await client.get(path);
256
+ }
257
+ return current;
258
+ }
259
+ function workspaceOrigin(host) {
260
+ const value = host.trim();
261
+ if (!value) throw new Error("databricks: workspace host cannot be empty");
262
+ const url = new URL(value.includes("://") ? value : `https://${value}`);
263
+ if (url.username || url.password) {
264
+ throw new Error("databricks: workspace host must not contain credentials");
265
+ }
266
+ return url.origin;
267
+ }
268
+ function isRetryableStatus(status) {
269
+ return status === 429 || status === 499 || status >= 500 && status <= 599;
270
+ }
271
+ function retryDelayMs(response, attempt, base) {
272
+ const retryAfterHeader = response.headers.get("retry-after");
273
+ const retryAfter = retryAfterHeader === null ? Number.NaN : Number(retryAfterHeader);
274
+ return Number.isFinite(retryAfter) && retryAfter >= 0 ? retryAfter * 1e3 : base * 2 ** attempt;
275
+ }
276
+ function isTerminalStatement(statement) {
277
+ const status = statement.status;
278
+ return ["SUCCEEDED", "FAILED", "CANCELED", "CLOSED"].includes(status?.state ?? "");
279
+ }
280
+ function delay(ms, signal) {
281
+ if (!signal) return new Promise((resolve) => setTimeout(resolve, ms));
282
+ if (signal.aborted) {
283
+ return Promise.reject(
284
+ signal.reason ?? new DOMException("The operation was aborted", "AbortError")
285
+ );
286
+ }
287
+ return new Promise((resolve, reject) => {
288
+ const timer = setTimeout(done, ms);
289
+ signal.addEventListener("abort", aborted, { once: true });
290
+ function done() {
291
+ signal?.removeEventListener("abort", aborted);
292
+ resolve();
293
+ }
294
+ function aborted() {
295
+ clearTimeout(timer);
296
+ reject(signal?.reason ?? new DOMException("The operation was aborted", "AbortError"));
297
+ }
298
+ });
299
+ }
300
+
301
+ // src/workspace-context.ts
184
302
  async function createWorkspaceContext(options = {}) {
185
303
  const env = options.env ?? process.env;
186
304
  const warehouseId = resolveWarehouseId(env);
@@ -207,11 +325,10 @@ async function createWorkspaceContext(options = {}) {
207
325
  const state = submitted.status?.state;
208
326
  let terminal = submitted;
209
327
  if (state !== "SUCCEEDED" && state !== "FAILED" && state !== "CANCELED" && state !== "CLOSED") {
210
- terminal = await databricks.waitForDatabricksStatement(
211
- client,
212
- submitted.statement_id ?? "",
213
- { pollIntervalMs: options.pollIntervalMs, timeoutMs: options.timeoutMs }
214
- );
328
+ terminal = await waitForDatabricksStatement(client, submitted.statement_id ?? "", {
329
+ pollIntervalMs: options.pollIntervalMs,
330
+ timeoutMs: options.timeoutMs
331
+ });
215
332
  }
216
333
  if (terminal.status?.state !== "SUCCEEDED") {
217
334
  throw new Error(
@@ -328,7 +445,7 @@ function resolveWarehouseId(env) {
328
445
  function createClientFromEnv(env, fetchImpl) {
329
446
  const host = env.DATABRICKS_HOST;
330
447
  if (!host) throw new Error("Live profile requires DATABRICKS_HOST");
331
- return new databricks.DatabricksRestClient({
448
+ return new WorkspaceRestClient({
332
449
  host,
333
450
  token: resolveTokenProvider(host, env, fetchImpl),
334
451
  ...fetchImpl ? { fetchImpl } : {}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/fixtures.ts","../src/duckdb-context.ts","../src/golden.ts","../src/workspace-context.ts","../src/parity.ts"],"names":["columns","rows","waitForDatabricksStatement","DatabricksRestClient","token","readFile","describe","it","expect"],"mappings":";;;;;;;;;AAwBO,SAAS,oBAAoB,MAAA,EAAiC;AACnE,EAAA,MAAM,UAA2B,EAAC;AAClC,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,OAAA,GAAU,EAAA;AACd,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,KAAA,MAAW,MAAM,MAAA,EAAQ;AACvB,IAAA,IAAI,OAAO,GAAA,EAAK,KAAA,EAAA;AAChB,IAAA,IAAI,OAAO,GAAA,EAAK,KAAA,EAAA;AAChB,IAAA,IAAI,EAAA,KAAO,GAAA,IAAO,KAAA,KAAU,CAAA,EAAG;AAC7B,MAAA,KAAA,CAAM,KAAK,OAAO,CAAA;AAClB,MAAA,OAAA,GAAU,EAAA;AAAA,IACZ,CAAA,MAAO;AACL,MAAA,OAAA,IAAW,EAAA;AAAA,IACb;AAAA,EACF;AACA,EAAA,IAAI,OAAA,CAAQ,IAAA,EAAK,EAAG,KAAA,CAAM,KAAK,OAAO,CAAA;AACtC,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,OAAA,GAAU,KAAK,IAAA,EAAK;AAC1B,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,uCAAuC,CAAA;AACnE,IAAA,IAAI,CAAC,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,CAAA,6BAAA,EAAgC,OAAO,CAAA,CAAA,CAAG,CAAA;AACtE,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,IAAA,EAAM,MAAM,CAAC,CAAA,IAAK,MAAM,CAAC,CAAA,IAAK,KAAA,CAAM,CAAC,CAAA,IAAK,EAAA;AAAA,MAC1C,IAAA,EAAA,CAAO,KAAA,CAAM,CAAC,CAAA,IAAK,IAAI,IAAA;AAAK,KAC7B,CAAA;AAAA,EACH;AACA,EAAA,IAAI,QAAQ,MAAA,KAAW,CAAA,EAAG,MAAM,IAAI,MAAM,oCAAoC,CAAA;AAC9E,EAAA,OAAO,OAAA;AACT;AAGA,eAAsB,kBAAA,CACpB,SACA,OAAA,EACsB;AACtB,EAAA,MAAM,MAAwD,CAAC,GAAI,OAAA,CAAQ,IAAA,IAAQ,EAAG,CAAA;AACtF,EAAA,IAAI,QAAQ,UAAA,EAAY;AACtB,IAAA,MAAM,EAAA,GAAK,MAAM,OAAO,aAAkB,CAAA;AAC1C,IAAA,MAAM,OAAO,MAAM,EAAA,CAAG,QAAA,CAAS,OAAA,CAAQ,YAAY,MAAM,CAAA;AACzD,IAAA,KAAA,MAAW,IAAA,IAAQ,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,EAAG;AACnC,MAAA,IAAI,IAAA,CAAK,IAAA,EAAK,CAAE,MAAA,KAAW,CAAA,EAAG;AAC9B,MAAA,GAAA,CAAI,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,IAAI,CAA4B,CAAA;AAAA,IACtD;AAAA,EACF;AACA,EAAA,OAAO,GAAA,CAAI,GAAA,CAAI,CAAC,GAAA,KAAQ;AACtB,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACtB,MAAA,IAAI,GAAA,CAAI,MAAA,KAAW,OAAA,CAAQ,MAAA,EAAQ;AACjC,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,gBAAA,EAAmB,QAAQ,KAAK,CAAA,KAAA,EAAQ,IAAI,MAAM,CAAA,kBAAA,EAAqB,QAAQ,MAAM,CAAA;AAAA,SACvF;AAAA,MACF;AACA,MAAA,OAAO,CAAC,GAAG,GAAG,CAAA;AAAA,IAChB;AACA,IAAA,MAAM,MAAA,GAAS,GAAA;AACf,IAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,IAAA,IAAQ,MAAA,GAAS,MAAA,CAAO,CAAA,CAAE,IAAI,CAAA,GAAI,IAAK,CAAA;AAAA,EACtE,CAAC,CAAA;AACH;;;ACrDA,eAAsB,mBAAA,CACpB,OAAA,GAAgC,EAAC,EACN;AAC3B,EAAA,MAAM,OAAA,GAAU,QAAQ,iBAAA,IAAqB,wBAAA;AAC7C,EAAA,MAAM,IAAA,GAAO,MAAM,OAAA,CAAQ,OAAA,CAAQ,QAAQ,UAAU,CAAA;AACrD,EAAA,MAAM,SAAS,OAAA,CAAQ,MAAA;AACvB,EAAA,IAAI,QAAQ,MAAM,IAAA,CAAK,GAAA,CAAI,CAAA,4BAAA,EAA+B,MAAM,CAAA,CAAE,CAAA;AAClE,EAAA,MAAM,IAAA,GAAO,CAAC,KAAA,KAAmB,MAAA,GAAS,GAAG,MAAM,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,GAAK,KAAA;AAEjE,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,OAAA;AAAA,IACT,IAAA;AAAA,IACA,MAAM,IAAA,CAAK,GAAA,EAAK,MAAA,EAAQ;AACtB,MAAA,MAAM,IAAA,CAAK,IAAI,GAAA,EAAK,MAAA,GAAS,CAAC,GAAG,MAAM,IAAI,MAAS,CAAA;AAAA,IACtD,CAAA;AAAA,IACA,MAAM,KAAA,CAAM,GAAA,EAAK,MAAA,EAAQ;AACvB,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,aAAA,CAAc,GAAA,EAAK,SAAS,CAAC,GAAG,MAAM,CAAA,GAAI,MAAS,CAAA;AAC7E,MAAA,OAAO,MAAA,CAAO,aAAA,EAAc,CAAE,GAAA,CAAI,YAAY,CAAA;AAAA,IAChD,CAAA;AAAA,IACA,MAAM,YAAY,OAAA,EAAuB;AACvC,MAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,QAAA,MAAMA,QAAAA,GAAU,mBAAA,CAAoB,OAAA,CAAQ,MAAM,CAAA;AAClD,QAAA,MAAM,MAAMA,QAAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,IAAI,CAAA,CAAE,IAAI,CAAA,EAAA,EAAK,YAAA,CAAa,EAAE,IAAI,CAAC,CAAA,CAAE,CAAA,CAAE,KAAK,IAAI,CAAA;AAC/E,QAAA,MAAM,IAAA,CAAK,IAAI,CAAA,2BAAA,EAA8B,IAAA,CAAK,QAAQ,KAAK,CAAC,CAAA,EAAA,EAAK,GAAG,CAAA,CAAA,CAAG,CAAA;AAC3E,QAAA,MAAMC,KAAAA,GAAO,MAAM,kBAAA,CAAmB,OAAA,EAASD,QAAO,CAAA;AACtD,QAAA,KAAA,MAAW,OAAOC,KAAAA,EAAM;AACtB,UAAA,MAAM,KAAA,GAAQD,QAAAA,CACX,GAAA,CAAI,CAAC,CAAA,KAAO,WAAA,CAAY,CAAA,CAAE,IAAI,CAAA,GAAI,sBAAA,GAAyB,GAAI,CAAA,CAC/D,KAAK,IAAI,CAAA;AACZ,UAAA,MAAM,IAAA,CAAK,GAAA,CAAI,CAAA,YAAA,EAAe,IAAA,CAAK,OAAA,CAAQ,KAAK,CAAC,CAAA,SAAA,EAAY,KAAK,CAAA,CAAA,CAAA,EAAK,GAAG,CAAA;AAAA,QAC5E;AACA,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,SAAA,GAAY,MAAM,IAAA,CAAK,aAAA,CAAc,YAAY,IAAA,CAAK,OAAA,CAAQ,KAAK,CAAC,CAAA,CAAE,CAAA;AAC5E,MAAA,MAAM,UAAU,SAAA,CACb,aAAA,GACA,GAAA,CAAI,CAAC,OAAO,EAAE,IAAA,EAAM,MAAA,CAAO,CAAA,CAAE,WAAW,CAAA,EAAG,IAAA,EAAM,OAAO,CAAA,CAAE,WAAW,GAAE,CAAE,CAAA;AAC5E,MAAA,MAAM,IAAA,GAAO,MAAM,kBAAA,CAAmB,OAAA,EAAS,OAAO,CAAA;AACtD,MAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,QAAA,MAAM,KAAA,GAAQ,OAAA,CACX,GAAA,CAAI,CAAC,CAAA,KAAO,WAAA,CAAY,CAAA,CAAE,IAAI,CAAA,GAAI,sBAAA,GAAyB,GAAI,CAAA,CAC/D,KAAK,IAAI,CAAA;AACZ,QAAA,MAAM,IAAA,CAAK,GAAA,CAAI,CAAA,YAAA,EAAe,IAAA,CAAK,OAAA,CAAQ,KAAK,CAAC,CAAA,SAAA,EAAY,KAAK,CAAA,CAAA,CAAA,EAAK,GAAG,CAAA;AAAA,MAC5E;AAAA,IACF,CAAA;AAAA,IACA,MAAM,KAAA,GAAQ;AACZ,MAAA,IAAA,CAAK,SAAA,EAAU;AAAA,IACjB;AAAA,GACF;AACF;AAGA,SAAS,aAAa,IAAA,EAAsB;AAC1C,EAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,cAAA,EAAgB,SAAS,CAAA;AAC/C;AAEA,SAAS,YAAY,IAAA,EAAuB;AAC1C,EAAA,OAAO,YAAA,CAAa,KAAK,IAAI,CAAA;AAC/B;AAOO,SAAS,aAAa,GAAA,EAAuD;AAClF,EAAA,MAAM,MAA+B,EAAC;AACtC,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG;AAC9C,IAAA,GAAA,CAAI,GAAG,CAAA,GAAI,cAAA,CAAe,KAAK,CAAA;AAAA,EACjC;AACA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,eAAe,KAAA,EAAyB;AAC/C,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,IAAI,KAAA,GAAQ,MAAA,CAAO,MAAA,CAAO,gBAAgB,CAAA,IAAK,QAAQ,MAAA,CAAO,CAAC,MAAA,CAAO,gBAAgB,CAAA,EAAG;AACvF,MAAA,OAAO,MAAM,QAAA,EAAS;AAAA,IACxB;AACA,IAAA,OAAO,OAAO,KAAK,CAAA;AAAA,EACrB;AACA,EAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,OAAO,KAAA,KAAU,QAAA,EAAU;AAC/C,IAAA,MAAM,CAAA,GAAI,KAAA;AACV,IAAA,IAAI,OAAO,CAAA,CAAE,MAAA,KAAW,QAAA,EAAU;AAEhC,MAAA,MAAM,MAAA,GAAS,MAAA,CAAO,CAAA,CAAE,MAAA,GAAS,KAAK,CAAA;AACtC,MAAA,OAAO,IAAI,IAAA,CAAK,MAAM,CAAA,CACnB,WAAA,EAAY,CACZ,OAAA,CAAQ,GAAA,EAAK,GAAG,CAAA,CAChB,OAAA,CAAQ,SAAA,EAAW,EAAE,CAAA;AAAA,IAC1B;AACA,IAAA,IAAI,OAAO,CAAA,CAAE,KAAA,KAAU,YAAY,OAAO,CAAA,CAAE,UAAU,QAAA,EAAU;AAE9D,MAAA,OAAO,MAAA,CAAO,CAAA,CAAE,KAAK,CAAA,GAAI,MAAM,CAAA,CAAE,KAAA;AAAA,IACnC;AACA,IAAA,OAAO,OAAO,KAAK,CAAA;AAAA,EACrB;AACA,EAAA,OAAO,KAAA;AACT;AAEA,eAAe,yBAAyB,IAAA,EAA6C;AACnF,EAAA,MAAM,UAAA,GAAa,kBAAA;AACnB,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAO,MAAM,OAAO,UAAA,CAAA;AAAA,EACtB,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AACA,EAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,cAAA,CAAe,OAAO,IAAI,CAAA;AACrD,EAAA,OAAQ,MAAM,SAAS,OAAA,EAAQ;AACjC;;;ACrIA,eAAsB,gBACpB,UAAA,EACA,MAAA,EACA,KAAA,EACA,GAAA,GAA0C,QAAQ,GAAA,EACnC;AACf,EAAA,MAAM,EAAA,GAAK,MAAM,OAAO,aAAkB,CAAA;AAC1C,EAAA,MAAM,aAAa,CAAA,EAAG,IAAA,CAAK,UAAU,MAAA,EAAQ,IAAA,EAAM,CAAC,CAAC;AAAA,CAAA;AACrD,EAAA,IAAI,GAAA,CAAI,2BAA2B,GAAA,EAAK;AACtC,IAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,MAAM,OAAO,MAAW,CAAA;AAC5C,IAAA,MAAM,EAAA,CAAG,MAAM,OAAA,CAAQ,UAAU,GAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AACvD,IAAA,MAAM,EAAA,CAAG,SAAA,CAAU,UAAA,EAAY,UAAA,EAAY,MAAM,CAAA;AACjD,IAAA;AAAA,EACF;AACA,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI;AACF,IAAA,QAAA,GAAW,MAAM,EAAA,CAAG,QAAA,CAAS,UAAA,EAAY,MAAM,CAAA;AAAA,EACjD,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,YAAA,EAAe,UAAU,CAAA,oBAAA,EAAuB,KAAK,CAAA,sEAAA;AAAA,KACvD;AAAA,EACF;AACA,EAAA,IAAI,SAAA,CAAU,QAAQ,CAAA,KAAM,SAAA,CAAU,UAAU,CAAA,EAAG;AACjD,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,EAAG,KAAK,CAAA,sBAAA,EAAyB,UAAU,CAAA;AAAA;AAAA,EAAiB,QAAQ;AAAA;AAAA,EAAc,UAAU;AAAA,uFAAA;AAAA,KAC9F;AAAA,EACF;AACF;AAEA,SAAS,UAAU,IAAA,EAAsB;AACvC,EAAA,OAAO,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,KAAA,CAAM,IAAI,CAAC,CAAA;AACxC;ACUA,eAAsB,sBAAA,CACpB,OAAA,GAAmC,EAAC,EACT;AAC3B,EAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,GAAA,IAAO,OAAA,CAAQ,GAAA;AACnC,EAAA,MAAM,WAAA,GAAc,mBAAmB,GAAG,CAAA;AAC1C,EAAA,MAAM,UAAU,GAAA,CAAI,gBAAA;AACpB,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,MAAA,IAAU,GAAA,CAAI,eAAA;AACrC,EAAA,MAAM,SAAS,OAAA,CAAQ,MAAA,IAAU,mBAAA,CAAoB,GAAA,EAAK,QAAQ,SAAS,CAAA;AAC3E,EAAA,MAAM,aAAA,uBAAoB,GAAA,EAAY;AAEtC,EAAA,MAAM,OAAO,CAAC,KAAA,KACZ,CAAC,OAAA,EAAS,QAAQ,KAAK,CAAA,CAAE,MAAA,CAAO,CAAC,SAAyB,OAAA,CAAQ,IAAI,CAAC,CAAA,CAAE,KAAK,GAAG,CAAA;AAEnF,EAAA,eAAe,GAAA,CAAI,KAAa,MAAA,EAAyD;AACvF,IAAA,MAAM,EAAE,WAAW,UAAA,EAAW,GAAI,kBAAkB,GAAA,EAAK,MAAA,IAAU,EAAE,CAAA;AACrE,IAAA,MAAM,SAAA,GAAY,MAAM,MAAA,CAAO,IAAA,CAAwB,yBAAA,EAA2B;AAAA,MAChF,SAAA;AAAA,MACA,YAAA,EAAc,WAAA;AAAA,MACd,GAAI,OAAA,GAAU,EAAE,OAAA,KAAY,EAAC;AAAA,MAC7B,GAAI,MAAA,GAAS,EAAE,MAAA,KAAW,EAAC;AAAA,MAC3B,GAAI,UAAA,CAAW,MAAA,GAAS,IAAI,EAAE,UAAA,KAAe,EAAC;AAAA,MAC9C,YAAA,EAAc,KAAA;AAAA,MACd,eAAA,EAAiB;AAAA,KAClB,CAAA;AACD,IAAA,OAAA,CAAQ,WAAA,GAAc;AAAA,MACpB,GAAA;AAAA,MACA,GAAI,UAAU,YAAA,GAAe,EAAE,aAAa,SAAA,CAAU,YAAA,KAAiB;AAAC,KACzE,CAAA;AACD,IAAA,MAAM,KAAA,GAAQ,UAAU,MAAA,EAAQ,KAAA;AAChC,IAAA,IAAI,QAAA,GAAW,SAAA;AACf,IAAA,IAAI,UAAU,WAAA,IAAe,KAAA,KAAU,YAAY,KAAA,KAAU,UAAA,IAAc,UAAU,QAAA,EAAU;AAC7F,MAAA,QAAA,GAAY,MAAME,qCAAA;AAAA,QAChB,MAAA;AAAA,QACA,UAAU,YAAA,IAAgB,EAAA;AAAA,QAC1B,EAAE,cAAA,EAAgB,OAAA,CAAQ,cAAA,EAAgB,SAAA,EAAW,QAAQ,SAAA;AAAU,OACzE;AAAA,IACF;AACA,IAAA,IAAI,QAAA,CAAS,MAAA,EAAQ,KAAA,KAAU,WAAA,EAAa;AAC1C,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,qBAAA,EAAwB,QAAA,CAAS,MAAA,EAAQ,KAAA,IAAS,SAAS,CAAA,EAAA,EACzD,QAAA,CAAS,MAAA,EAAQ,KAAA,EAAO,OAAA,IAAW,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,GAAG,CACrD,CAAA;AAAA,OACF;AAAA,IACF;AACA,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,MAAA;AAAA,IACT,IAAA;AAAA,IACA,MAAM,IAAA,CAAK,GAAA,EAAK,MAAA,EAAQ;AACtB,MAAA,MAAM,GAAA,CAAI,KAAK,MAAM,CAAA;AAAA,IACvB,CAAA;AAAA,IACA,MAAM,KAAA,CAAM,GAAA,EAAK,MAAA,EAAQ;AACvB,MAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,GAAA,EAAK,MAAM,CAAA;AACtC,MAAA,OAAO,mBAAmB,QAAQ,CAAA;AAAA,IACpC,CAAA;AAAA,IACA,MAAM,YAAY,OAAA,EAAuB;AACvC,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,MAAM,IAAI,KAAA;AAAA,UACR;AAAA,SACF;AAAA,MACF;AACA,MAAA,IAAI,CAAC,QAAQ,MAAA,EAAQ;AACnB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,8CAAA,EAAiD,QAAQ,KAAK,CAAA,iCAAA;AAAA,SAChE;AAAA,MACF;AACA,MAAA,MAAM,OAAA,GAAU,mBAAA,CAAoB,OAAA,CAAQ,MAAM,CAAA;AAClD,MAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAM,CAAA,EAAA,EAAK,CAAA,CAAE,IAAI,CAAA,GAAA,EAAM,CAAA,CAAE,IAAI,CAAA,CAAE,CAAA,CAAE,KAAK,IAAI,CAAA;AACnE,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,KAAK,CAAA;AACjC,MAAA,MAAM,GAAA,CAAI,CAAA,wBAAA,EAA2B,MAAM,CAAA,EAAA,EAAK,GAAG,CAAA,aAAA,CAAe,CAAA;AAClE,MAAA,aAAA,CAAc,IAAI,MAAM,CAAA;AACxB,MAAA,MAAM,IAAA,GAAO,MAAM,kBAAA,CAAmB,OAAA,EAAS,OAAO,CAAA;AACtD,MAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,QAAA,MAAM,YAAA,GAAe,OAAA,CAClB,GAAA,CAAI,CAAC,MAAO,YAAA,CAAa,IAAA,CAAK,CAAA,CAAE,IAAI,CAAA,GAAI,sBAAA,GAAyB,GAAI,CAAA,CACrE,KAAK,IAAI,CAAA;AACZ,QAAA,MAAM,GAAA,CAAI,eAAe,IAAA,CAAK,OAAA,CAAQ,KAAK,CAAC,CAAA,SAAA,EAAY,YAAY,CAAA,CAAA,CAAA,EAAK,GAAG,CAAA;AAAA,MAC9E;AAAA,IACF,CAAA;AAAA,IACA,MAAM,KAAA,GAAQ;AACZ,MAAA,IAAI,OAAA,CAAQ,eAAA,KAAoB,KAAA,IAAS,GAAA,CAAI,2BAA2B,GAAA,EAAK;AAC3E,QAAA,KAAA,MAAW,SAAS,CAAC,GAAG,aAAa,CAAA,CAAE,SAAQ,EAAG;AAChD,UAAA,MAAM,GAAA,CAAI,CAAA,qBAAA,EAAwB,KAAK,CAAA,CAAE,CAAA;AAAA,QAC3C;AAAA,MACF;AACA,MAAA,aAAA,CAAc,KAAA,EAAM;AAAA,IACtB;AAAA,GACF;AACF;AAGO,SAAS,iBAAA,CACd,KACA,MAAA,EAC6E;AAC7E,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,KAAA,GAAuB,IAAA;AAC3B,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,QAAQ,CAAA,EAAA,EAAK;AACnC,IAAA,MAAM,EAAA,GAAK,IAAI,CAAC,CAAA;AAChB,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,GAAA,IAAO,EAAA;AACP,MAAA,IAAI,EAAA,KAAO,OAAO,KAAA,GAAQ,IAAA;AAC1B,MAAA;AAAA,IACF;AACA,IAAA,IAAI,EAAA,KAAO,GAAA,IAAO,EAAA,KAAO,GAAA,IAAO,OAAO,GAAA,EAAK;AAC1C,MAAA,KAAA,GAAQ,EAAA;AACR,MAAA,GAAA,IAAO,EAAA;AACP,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAO,GAAA,EAAK;AACd,MAAA,KAAA,IAAS,CAAA;AACT,MAAA,GAAA,IAAO,KAAK,KAAK,CAAA,CAAA;AACjB,MAAA;AAAA,IACF;AACA,IAAA,GAAA,IAAO,EAAA;AAAA,EACT;AACA,EAAA,IAAI,KAAA,KAAU,OAAO,MAAA,EAAQ;AAC3B,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,QAAA,EAAW,KAAK,CAAA,kBAAA,EAAqB,MAAA,CAAO,MAAM,CAAA,qBAAA,CAAuB,CAAA;AAAA,EAC3F;AACA,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,GAAA;AAAA,IACX,UAAA,EAAY,MAAA,CAAO,GAAA,CAAI,CAAC,OAAO,CAAA,MAAO;AAAA,MACpC,IAAA,EAAM,CAAA,CAAA,EAAI,CAAA,GAAI,CAAC,CAAA,CAAA;AAAA,MACf,OAAO,KAAA,KAAU,IAAA,IAAQ,UAAU,MAAA,GAAY,IAAA,GAAO,OAAO,KAAK;AAAA,KACpE,CAAE;AAAA,GACJ;AACF;AAGO,SAAS,mBAAmB,QAAA,EAAwD;AACzF,EAAA,MAAM,OAAA,GAAU,CAAC,GAAI,QAAA,CAAS,UAAU,MAAA,EAAQ,OAAA,IAAW,EAAG,CAAA,CAAE,IAAA;AAAA,IAC9D,CAAC,CAAA,EAAG,CAAA,KAAA,CAAO,EAAE,QAAA,IAAY,CAAA,KAAM,EAAE,QAAA,IAAY,CAAA;AAAA,GAC/C;AACA,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,MAAA,EAAQ,UAAA,IAAc,EAAC;AAC7C,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAC,KAAA,KAAU;AACzB,IAAA,MAAM,MAA+B,EAAC;AACtC,IAAA,OAAA,CAAQ,OAAA,CAAQ,CAAC,MAAA,EAAQ,CAAA,KAAM;AAC7B,MAAA,GAAA,CAAI,MAAA,CAAO,IAAI,CAAA,GAAI,YAAA,CAAa,KAAA,CAAM,CAAC,CAAA,IAAK,IAAA,EAAM,MAAA,CAAO,SAAA,IAAa,QAAQ,CAAA;AAAA,IAChF,CAAC,CAAA;AACD,IAAA,OAAO,GAAA;AAAA,EACT,CAAC,CAAA;AACH;AAEA,IAAM,aAAA,GAAgB,8CAAA;AAEtB,SAAS,YAAA,CAAa,OAAsB,QAAA,EAA2B;AACrE,EAAA,IAAI,KAAA,KAAU,MAAM,OAAO,IAAA;AAC3B,EAAA,IAAI,cAAc,IAAA,CAAK,QAAQ,CAAA,EAAG,OAAO,OAAO,KAAK,CAAA;AACrD,EAAA,IAAI,WAAA,CAAY,IAAA,CAAK,QAAQ,CAAA,SAAU,KAAA,KAAU,MAAA;AACjD,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,mBAAmB,GAAA,EAAiD;AAC3E,EAAA,IAAI,GAAA,CAAI,uBAAA,EAAyB,OAAO,GAAA,CAAI,uBAAA;AAC5C,EAAA,MAAM,WAAW,GAAA,CAAI,oBAAA;AACrB,EAAA,MAAM,KAAA,GAAQ,QAAA,EAAU,KAAA,CAAM,wBAAwB,CAAA;AACtD,EAAA,IAAI,KAAA,GAAQ,CAAC,CAAA,EAAG,OAAO,MAAM,CAAC,CAAA;AAC9B,EAAA,MAAM,IAAI,KAAA;AAAA,IACR;AAAA,GACF;AACF;AAOO,SAAS,mBAAA,CACd,KACA,SAAA,EACsB;AACtB,EAAA,MAAM,OAAO,GAAA,CAAI,eAAA;AACjB,EAAA,IAAI,CAAC,IAAA,EAAM,MAAM,IAAI,MAAM,uCAAuC,CAAA;AAClE,EAAA,OAAO,IAAIC,+BAAA,CAAqB;AAAA,IAC9B,IAAA;AAAA,IACA,KAAA,EAAO,oBAAA,CAAqB,IAAA,EAAM,GAAA,EAAK,SAAS,CAAA;AAAA,IAChD,GAAI,SAAA,GAAY,EAAE,SAAA,KAAc;AAAC,GAClC,CAAA;AACH;AAEO,SAAS,oBAAA,CACd,IAAA,EACA,GAAA,EACA,SAAA,GAA0B,KAAA,EACQ;AAClC,EAAA,IAAI,GAAA,CAAI,iBAAA,EAAmB,OAAO,GAAA,CAAI,iBAAA;AACtC,EAAA,MAAM,WAAW,GAAA,CAAI,oBAAA;AACrB,EAAA,IAAI,QAAA,KAAa,UAAA,IAAc,QAAA,KAAa,WAAA,EAAa;AACvD,IAAA,IAAI,MAAA,GAAsD,IAAA;AAC1D,IAAA,OAAO,YAAY;AACjB,MAAA,IAAI,UAAU,IAAA,CAAK,GAAA,KAAQ,MAAA,CAAO,SAAA,SAAkB,MAAA,CAAO,KAAA;AAC3D,MAAA,MAAM,YAAA,GAAe,MAAM,4BAAA,CAA6B,QAAA,EAAU,GAAG,CAAA;AACrE,MAAA,MAAM,MAAA,GAAS,IAAI,eAAA,CAAgB;AAAA,QACjC,UAAA,EAAY,iDAAA;AAAA,QACZ,aAAA,EAAe,YAAA;AAAA,QACf,kBAAA,EAAoB,sCAAA;AAAA,QACpB,KAAA,EAAO,IAAI,gBAAA,IAAoB;AAAA,OAChC,CAAA;AACD,MAAA,IAAI,IAAI,oBAAA,EAAsB,MAAA,CAAO,GAAA,CAAI,WAAA,EAAa,IAAI,oBAAoB,CAAA;AAC9E,MAAA,MAAM,QAAA,GAAW,MAAM,SAAA,CAAU,CAAA,EAAG,KAAK,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA,cAAA,CAAA,EAAkB;AAAA,QAC3E,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS,EAAE,cAAA,EAAgB,mCAAA,EAAoC;AAAA,QAC/D,IAAA,EAAM,OAAO,QAAA;AAAS,OACvB,CAAA;AACD,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,uCAAA,EAA0C,QAAA,CAAS,MAAM,CAAA,CAAE,CAAA;AAAA,MAC7E;AACA,MAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,MAAA,IAAI,OAAO,IAAA,CAAK,YAAA,KAAiB,QAAA,IAAY,CAAC,KAAK,YAAA,EAAc;AAC/D,QAAA,MAAM,IAAI,MAAM,yDAAyD,CAAA;AAAA,MAC3E;AACA,MAAA,MAAM,YAAY,OAAO,IAAA,CAAK,UAAA,KAAe,QAAA,GAAW,KAAK,UAAA,GAAa,IAAA;AAC1E,MAAA,MAAA,GAAS;AAAA,QACP,OAAO,IAAA,CAAK,YAAA;AAAA,QACZ,SAAA,EAAW,KAAK,GAAA,EAAI,GAAI,KAAK,GAAA,CAAI,CAAA,EAAG,SAAA,GAAY,GAAG,CAAA,GAAI;AAAA,OACzD;AACA,MAAA,OAAO,IAAA,CAAK,YAAA;AAAA,IACd,CAAA;AAAA,EACF;AACA,EAAA,MAAM,WAAW,GAAA,CAAI,oBAAA;AACrB,EAAA,MAAM,eAAe,GAAA,CAAI,wBAAA;AACzB,EAAA,IAAI,YAAY,YAAA,EAAc;AAC5B,IAAA,IAAI,MAAA,GAAsD,IAAA;AAC1D,IAAA,OAAO,YAAY;AACjB,MAAA,IAAI,UAAU,IAAA,CAAK,GAAA,KAAQ,MAAA,CAAO,SAAA,SAAkB,MAAA,CAAO,KAAA;AAC3D,MAAA,MAAM,QAAA,GAAW,MAAM,SAAA,CAAU,CAAA,EAAG,KAAK,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA,cAAA,CAAA,EAAkB;AAAA,QAC3E,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS;AAAA,UACP,cAAA,EAAgB,mCAAA;AAAA,UAChB,aAAA,EAAe,CAAA,MAAA,EAAS,MAAA,CAAO,IAAA,CAAK,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,YAAY,CAAA,CAAE,CAAA,CAAE,QAAA,CAAS,QAAQ,CAAC,CAAA;AAAA,SACvF;AAAA,QACA,IAAA,EAAM,IAAI,eAAA,CAAgB;AAAA,UACxB,UAAA,EAAY,oBAAA;AAAA,UACZ,KAAA,EAAO,IAAI,gBAAA,IAAoB;AAAA,SAChC,EAAE,QAAA;AAAS,OACb,CAAA;AACD,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iCAAA,EAAoC,QAAA,CAAS,MAAM,CAAA,CAAE,CAAA;AAAA,MACvE;AACA,MAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,MAAA,MAAA,GAAS;AAAA,QACP,OAAO,IAAA,CAAK,YAAA;AAAA,QACZ,WAAW,IAAA,CAAK,GAAA,OAAU,IAAA,CAAK,UAAA,IAAc,QAAQ,GAAA,IAAO;AAAA,OAC9D;AACA,MAAA,OAAO,IAAA,CAAK,YAAA;AAAA,IACd,CAAA;AAAA,EACF;AACA,EAAA,IAAI,GAAA,CAAI,gBAAA,EAAkB,OAAO,GAAA,CAAI,gBAAA;AACrC,EAAA,MAAM,IAAI,KAAA;AAAA,IACR;AAAA,GACF;AACF;AAEA,eAAe,4BAAA,CACb,UACA,GAAA,EACiB;AACjB,EAAA,IAAI,aAAa,UAAA,EAAY;AAC3B,IAAA,MAAM,QAAA,GAAW,IAAI,yBAAA,IAA6B,uBAAA;AAClD,IAAA,MAAMC,MAAAA,GAAQ,GAAA,CAAI,QAAQ,CAAA,EAAG,IAAA,EAAK;AAClC,IAAA,IAAI,CAACA,MAAAA,EAAO,MAAM,IAAI,KAAA,CAAM,CAAA,0CAAA,EAA6C,QAAQ,CAAA,SAAA,CAAW,CAAA;AAC5F,IAAA,OAAOA,MAAAA;AAAA,EACT;AACA,EAAA,MAAM,OAAO,GAAA,CAAI,8BAAA;AACjB,EAAA,IAAI,CAAC,IAAA,EAAM,MAAM,IAAI,MAAM,0DAA0D,CAAA;AACrF,EAAA,MAAM,SAAS,MAAMC,iBAAA,CAAS,IAAA,EAAM,MAAM,GAAG,IAAA,EAAK;AAClD,EAAA,IAAI,CAAC,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,CAAA,0BAAA,EAA6B,IAAI,CAAA,SAAA,CAAW,CAAA;AACxE,EAAA,OAAO,KAAA;AACT;;;AC9RO,SAAS,kBAAkB,IAAA,EAA6B;AAC7D,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,IAAO,OAAA,CAAQ,GAAA;AAChC,EAAA,MAAM,WAAA,GAAc,IAAI,aAAA,KAAkB,GAAA;AAC1C,EAAA,MAAM,aAAA,GAAgB,MAAA,CAAO,GAAA,CAAI,mBAAA,IAAuB,IAAO,CAAA;AAE/D,EAAAC,eAAA,CAAS,CAAA,QAAA,EAAW,IAAA,CAAK,IAAI,CAAA,CAAA,EAAI,MAAM;AACrC,IAAAC,SAAA,CAAG,qCAAqC,YAAY;AAClD,MAAA,MAAM,MAAM,MAAM,mBAAA,CAAoB,EAAE,MAAA,EAAQ,IAAA,CAAK,QAAQ,CAAA;AAC7D,MAAA,IAAI;AACF,QAAA,MAAM,YAAA,CAAa,KAAK,IAAI,CAAA;AAAA,MAC9B,CAAA,SAAE;AACA,QAAA,MAAM,IAAI,KAAA,EAAM;AAAA,MAClB;AAAA,IACF,CAAC,CAAA;AAED,IAAAA,SAAA,CAAG,MAAA,CAAO,CAAC,WAAW,CAAA;AAAA,MACpB,uCAAA;AAAA,MACA,YAAY;AACV,QAAA,MAAM,GAAA,GAAM,MAAM,sBAAA,CAAuB,EAAE,KAAK,MAAA,EAAQ,IAAA,CAAK,QAAQ,CAAA;AACrE,QAAA,IAAI;AACF,UAAA,MAAM,YAAA,CAAa,KAAK,IAAI,CAAA;AAAA,QAC9B,CAAA,SAAE;AACA,UAAA,MAAM,IAAI,KAAA,EAAM;AAAA,QAClB;AAAA,MACF,CAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF,CAAC,CAAA;AACH;AAEA,eAAe,YAAA,CAAa,KAAuB,IAAA,EAAsC;AACvF,EAAA,KAAA,MAAW,OAAA,IAAW,KAAK,QAAA,EAAU;AACnC,IAAA,MAAM,GAAA,CAAI,YAAY,OAAO,CAAA;AAAA,EAC/B;AACA,EAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAM,IAAA,CAAK,GAAA,EAAK,KAAK,MAAM,CAAA;AAClD,EAAAC,aAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,eAAA,CAAgB,CAAC,CAAA;AACrC,EAAA,MAAM,eAAA,CAAgB,IAAA,CAAK,MAAA,EAAQ,IAAA,EAAM,CAAA,aAAA,EAAgB,KAAK,IAAI,CAAA,EAAA,EAAK,GAAA,CAAI,OAAO,CAAA,CAAA,CAAG,CAAA;AACvF","file":"parity.cjs","sourcesContent":["/**\n * Declarative, engine-agnostic table seeds. The same fixture applies to a\n * local DuckDB table or a scratch Unity Catalog schema — column DDL uses the\n * portable subset (VARCHAR/STRING, BIGINT, DOUBLE, TIMESTAMP, BOOLEAN).\n */\nexport interface TableFixture {\n table: string;\n /**\n * Column DDL, e.g. `subject_id STRING, value DOUBLE, \"at\" TIMESTAMP`.\n * Optional when the table already exists in the target context.\n */\n schema?: string;\n /** Row tuples in column order, or row objects keyed by column name. */\n rows?: readonly (readonly unknown[] | Record<string, unknown>)[];\n /** Path to an NDJSON file of row objects (one JSON object per line). */\n ndjsonFile?: string;\n}\n\nexport interface FixtureColumn {\n name: string;\n type: string;\n}\n\n/** Parse `name TYPE, name TYPE(args), \"quoted\" TYPE` column DDL into columns. */\nexport function parseFixtureColumns(schema: string): FixtureColumn[] {\n const columns: FixtureColumn[] = [];\n let depth = 0;\n let current = '';\n const parts: string[] = [];\n for (const ch of schema) {\n if (ch === '(') depth++;\n if (ch === ')') depth--;\n if (ch === ',' && depth === 0) {\n parts.push(current);\n current = '';\n } else {\n current += ch;\n }\n }\n if (current.trim()) parts.push(current);\n for (const part of parts) {\n const trimmed = part.trim();\n const match = trimmed.match(/^(\"([^\"]+)\"|`([^`]+)`|(\\w+))\\s+(.+)$/s);\n if (!match) throw new Error(`Unparseable fixture column: '${trimmed}'`);\n columns.push({\n name: match[2] ?? match[3] ?? match[4] ?? '',\n type: (match[5] ?? '').trim(),\n });\n }\n if (columns.length === 0) throw new Error('Fixture schema declared no columns');\n return columns;\n}\n\n/** Resolve fixture rows (inline tuples/objects or NDJSON file) into tuples in `columns` order. */\nexport async function resolveFixtureRows(\n fixture: TableFixture,\n columns: readonly FixtureColumn[],\n): Promise<unknown[][]> {\n const raw: (readonly unknown[] | Record<string, unknown>)[] = [...(fixture.rows ?? [])];\n if (fixture.ndjsonFile) {\n const fs = await import('node:fs/promises');\n const text = await fs.readFile(fixture.ndjsonFile, 'utf8');\n for (const line of text.split('\\n')) {\n if (line.trim().length === 0) continue;\n raw.push(JSON.parse(line) as Record<string, unknown>);\n }\n }\n return raw.map((row) => {\n if (Array.isArray(row)) {\n if (row.length !== columns.length) {\n throw new Error(\n `Fixture row for ${fixture.table} has ${row.length} values, expected ${columns.length}`,\n );\n }\n return [...row];\n }\n const record = row as Record<string, unknown>;\n return columns.map((c) => (c.name in record ? record[c.name] : null));\n });\n}\n","import type { ExecutionContext } from './context.js';\nimport { type TableFixture, parseFixtureColumns, resolveFixtureRows } from './fixtures.js';\n\nexport interface DuckDbContextOptions {\n /** Database file path; ':memory:' (default) for a throwaway in-process db. */\n path?: string;\n /** Optional schema to create + qualify tables with. */\n schema?: string;\n /** Injectable for tests of this module itself. */\n connectionFactory?: (path: string) => Promise<DuckDbConnectionLike>;\n}\n\n/** Structural slice of the lazily-imported @duckdb/node-api connection. */\nexport interface DuckDbConnectionLike {\n run(sql: string, values?: unknown[]): Promise<unknown>;\n runAndReadAll(\n sql: string,\n values?: unknown[],\n ): Promise<{ getRowObjects(): Record<string, unknown>[] }>;\n closeSync(): void;\n}\n\n/**\n * Hermetic local execution context on DuckDB — the `local` profile of the\n * testing pyramid. No workspace, no credentials, sub-second.\n */\nexport async function createDuckDbContext(\n options: DuckDbContextOptions = {},\n): Promise<ExecutionContext> {\n const factory = options.connectionFactory ?? defaultConnectionFactory;\n const conn = await factory(options.path ?? ':memory:');\n const schema = options.schema;\n if (schema) await conn.run(`CREATE SCHEMA IF NOT EXISTS ${schema}`);\n const qual = (table: string) => (schema ? `${schema}.${table}` : table);\n\n return {\n profile: 'local',\n qual,\n async exec(sql, params) {\n await conn.run(sql, params ? [...params] : undefined);\n },\n async query(sql, params) {\n const reader = await conn.runAndReadAll(sql, params ? [...params] : undefined);\n return reader.getRowObjects().map(normalizeRow);\n },\n async loadFixture(fixture: TableFixture) {\n if (fixture.schema) {\n const columns = parseFixtureColumns(fixture.schema);\n const ddl = columns.map((c) => `\"${c.name}\" ${portableType(c.type)}`).join(', ');\n await conn.run(`CREATE TABLE IF NOT EXISTS ${qual(fixture.table)} (${ddl})`);\n const rows = await resolveFixtureRows(fixture, columns);\n for (const row of rows) {\n const casts = columns\n .map((c) => (isTimestamp(c.type) ? 'CAST(? AS TIMESTAMP)' : '?'))\n .join(', ');\n await conn.run(`INSERT INTO ${qual(fixture.table)} VALUES (${casts})`, row);\n }\n return;\n }\n // Table pre-exists: infer column order from the catalog.\n const described = await conn.runAndReadAll(`DESCRIBE ${qual(fixture.table)}`);\n const columns = described\n .getRowObjects()\n .map((r) => ({ name: String(r.column_name), type: String(r.column_type) }));\n const rows = await resolveFixtureRows(fixture, columns);\n for (const row of rows) {\n const casts = columns\n .map((c) => (isTimestamp(c.type) ? 'CAST(? AS TIMESTAMP)' : '?'))\n .join(', ');\n await conn.run(`INSERT INTO ${qual(fixture.table)} VALUES (${casts})`, row);\n }\n },\n async close() {\n conn.closeSync();\n },\n };\n}\n\n/** Databricks types → DuckDB types for the portable fixture subset. */\nfunction portableType(type: string): string {\n return type.replace(/\\bSTRING\\b/gi, 'VARCHAR');\n}\n\nfunction isTimestamp(type: string): boolean {\n return /TIMESTAMP/i.test(type);\n}\n\n/**\n * Normalize DuckDB values to plain JSON-ish values so assertions and golden\n * files are engine-portable: bigint→number, TIMESTAMP→`YYYY-MM-DD HH:MM:SS`\n * (UTC, microseconds trimmed), DECIMAL→number.\n */\nexport function normalizeRow(row: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(row)) {\n out[key] = normalizeValue(value);\n }\n return out;\n}\n\nfunction normalizeValue(value: unknown): unknown {\n if (typeof value === 'bigint') {\n if (value > BigInt(Number.MAX_SAFE_INTEGER) || value < BigInt(-Number.MAX_SAFE_INTEGER)) {\n return value.toString();\n }\n return Number(value);\n }\n if (value !== null && typeof value === 'object') {\n const v = value as { micros?: bigint; width?: number; scale?: number; value?: bigint };\n if (typeof v.micros === 'bigint') {\n // DuckDBTimestampValue — micros since epoch, UTC.\n const millis = Number(v.micros / 1000n);\n return new Date(millis)\n .toISOString()\n .replace('T', ' ')\n .replace(/\\.\\d+Z$/, '');\n }\n if (typeof v.scale === 'number' && typeof v.value === 'bigint') {\n // DuckDBDecimalValue.\n return Number(v.value) / 10 ** v.scale;\n }\n return String(value);\n }\n return value;\n}\n\nasync function defaultConnectionFactory(path: string): Promise<DuckDbConnectionLike> {\n const moduleName = '@duckdb/node-api';\n let mod: { DuckDBInstance: { create(path: string): Promise<{ connect(): Promise<unknown> }> } };\n try {\n mod = (await import(moduleName)) as typeof mod;\n } catch {\n throw new Error(\n 'createDuckDbContext requires the optional peer @duckdb/node-api — run: pnpm add -D @duckdb/node-api',\n );\n }\n const instance = await mod.DuckDBInstance.create(path);\n return (await instance.connect()) as DuckDbConnectionLike;\n}\n","/**\n * Golden-result files: committed JSON snapshots of query results that every\n * engine and every refactor must reproduce exactly — the frozen-vector\n * pattern from @fabricorg/experiments-testkit generalized to warehouse rows.\n */\nexport async function compareToGolden(\n goldenPath: string,\n actual: readonly Record<string, unknown>[],\n label: string,\n env: Record<string, string | undefined> = process.env,\n): Promise<void> {\n const fs = await import('node:fs/promises');\n const serialized = `${JSON.stringify(actual, null, 2)}\\n`;\n if (env.DBX_TEST_UPDATE_GOLDEN === '1') {\n const { dirname } = await import('node:path');\n await fs.mkdir(dirname(goldenPath), { recursive: true });\n await fs.writeFile(goldenPath, serialized, 'utf8');\n return;\n }\n let expected: string;\n try {\n expected = await fs.readFile(goldenPath, 'utf8');\n } catch {\n throw new Error(\n `Golden file ${goldenPath} does not exist for ${label}. Run once with DBX_TEST_UPDATE_GOLDEN=1 to create it, then commit it.`,\n );\n }\n if (normalize(expected) !== normalize(serialized)) {\n throw new Error(\n `${label} diverges from golden ${goldenPath}.\\nExpected:\\n${expected}\\nActual:\\n${serialized}\\nIf the change is intentional, re-run with DBX_TEST_UPDATE_GOLDEN=1 and commit the diff.`,\n );\n }\n}\n\nfunction normalize(json: string): string {\n return JSON.stringify(JSON.parse(json));\n}\n","import { readFile } from 'node:fs/promises';\nimport { DatabricksRestClient, waitForDatabricksStatement } from '@fabric-harness/databricks';\nimport type { ExecutionContext } from './context.js';\nimport { type TableFixture, parseFixtureColumns, resolveFixtureRows } from './fixtures.js';\n\n/** Structural slice of DatabricksRestClient the workspace context uses (injectable in tests). */\nexport interface WorkspaceClientLike {\n get<T>(path: string, query?: Record<string, string | number | boolean | undefined>): Promise<T>;\n post<T>(\n path: string,\n body?: unknown,\n query?: Record<string, string | number | boolean | undefined>,\n options?: unknown,\n ): Promise<T>;\n}\n\nexport interface WorkspaceContextOptions {\n env?: Record<string, string | undefined>;\n /** Schema within the catalog used by qual(); defaults to DBX_TEST_SCHEMA. */\n schema?: string;\n /** Injectable client for hermetic tests; defaults to a DatabricksRestClient from env auth. */\n client?: WorkspaceClientLike;\n /** Injectable fetch for the OAuth M2M exchange. */\n fetchImpl?: typeof fetch;\n pollIntervalMs?: number;\n timeoutMs?: number;\n /** Drop tables seeded by this context on close. Defaults to true. */\n cleanupFixtures?: boolean;\n /** Observe submitted statements for redacted failure evidence. */\n onStatement?: (statement: { sql: string; statementId?: string }) => void;\n}\n\ninterface StatementResponse {\n statement_id?: string;\n status?: { state?: string; error?: { message?: string } };\n manifest?: { schema?: { columns?: { name: string; type_name?: string; position?: number }[] } };\n result?: { data_array?: (string | null)[][] };\n}\n\n/**\n * Live execution context on a Databricks SQL warehouse via the SQL Statement\n * Execution API (/api/2.0/sql/statements). The Statement Execution API takes\n * NAMED parameter markers, so positional `?` params are rewritten to\n * `:p1..:pn` — the ExecutionContext surface stays identical to the local\n * profile.\n */\nexport async function createWorkspaceContext(\n options: WorkspaceContextOptions = {},\n): Promise<ExecutionContext> {\n const env = options.env ?? process.env;\n const warehouseId = resolveWarehouseId(env);\n const catalog = env.DBX_TEST_CATALOG;\n const schema = options.schema ?? env.DBX_TEST_SCHEMA;\n const client = options.client ?? createClientFromEnv(env, options.fetchImpl);\n const fixtureTables = new Set<string>();\n\n const qual = (table: string) =>\n [catalog, schema, table].filter((part): part is string => Boolean(part)).join('.');\n\n async function run(sql: string, params?: readonly unknown[]): Promise<StatementResponse> {\n const { statement, parameters } = toNamedParameters(sql, params ?? []);\n const submitted = await client.post<StatementResponse>('/api/2.0/sql/statements', {\n statement,\n warehouse_id: warehouseId,\n ...(catalog ? { catalog } : {}),\n ...(schema ? { schema } : {}),\n ...(parameters.length > 0 ? { parameters } : {}),\n wait_timeout: '30s',\n on_wait_timeout: 'CONTINUE',\n });\n options.onStatement?.({\n sql,\n ...(submitted.statement_id ? { statementId: submitted.statement_id } : {}),\n });\n const state = submitted.status?.state;\n let terminal = submitted;\n if (state !== 'SUCCEEDED' && state !== 'FAILED' && state !== 'CANCELED' && state !== 'CLOSED') {\n terminal = (await waitForDatabricksStatement(\n client as DatabricksRestClient,\n submitted.statement_id ?? '',\n { pollIntervalMs: options.pollIntervalMs, timeoutMs: options.timeoutMs },\n )) as StatementResponse;\n }\n if (terminal.status?.state !== 'SUCCEEDED') {\n throw new Error(\n `Databricks statement ${terminal.status?.state ?? 'UNKNOWN'}: ${\n terminal.status?.error?.message ?? sql.slice(0, 200)\n }`,\n );\n }\n return terminal;\n }\n\n return {\n profile: 'live',\n qual,\n async exec(sql, params) {\n await run(sql, params);\n },\n async query(sql, params) {\n const response = await run(sql, params);\n return parseStatementRows(response);\n },\n async loadFixture(fixture: TableFixture) {\n if (!schema) {\n throw new Error(\n 'Live fixtures require DBX_TEST_SCHEMA (or a schema option) so tests cannot replace unscoped tables',\n );\n }\n if (!fixture.schema) {\n throw new Error(\n `Live fixtures require explicit column DDL for ${fixture.table} (schema inference is local-only)`,\n );\n }\n const columns = parseFixtureColumns(fixture.schema);\n const ddl = columns.map((c) => `\\`${c.name}\\` ${c.type}`).join(', ');\n const target = qual(fixture.table);\n await run(`CREATE OR REPLACE TABLE ${target} (${ddl}) USING DELTA`);\n fixtureTables.add(target);\n const rows = await resolveFixtureRows(fixture, columns);\n for (const row of rows) {\n const placeholders = columns\n .map((c) => (/TIMESTAMP/i.test(c.type) ? 'CAST(? AS TIMESTAMP)' : '?'))\n .join(', ');\n await run(`INSERT INTO ${qual(fixture.table)} VALUES (${placeholders})`, row);\n }\n },\n async close() {\n if (options.cleanupFixtures !== false && env.DBX_TEST_KEEP_FIXTURES !== '1') {\n for (const table of [...fixtureTables].reverse()) {\n await run(`DROP TABLE IF EXISTS ${table}`);\n }\n }\n fixtureTables.clear();\n },\n };\n}\n\n/** Rewrite positional `?` markers to the named `:pN` markers the Statement Execution API requires. */\nexport function toNamedParameters(\n sql: string,\n params: readonly unknown[],\n): { statement: string; parameters: { name: string; value: string | null }[] } {\n let out = '';\n let index = 0;\n let quote: string | null = null;\n for (let i = 0; i < sql.length; i++) {\n const ch = sql[i] as string;\n if (quote) {\n out += ch;\n if (ch === quote) quote = null;\n continue;\n }\n if (ch === \"'\" || ch === '\"' || ch === '`') {\n quote = ch;\n out += ch;\n continue;\n }\n if (ch === '?') {\n index += 1;\n out += `:p${index}`;\n continue;\n }\n out += ch;\n }\n if (index !== params.length) {\n throw new Error(`SQL has ${index} placeholders but ${params.length} params were provided`);\n }\n return {\n statement: out,\n parameters: params.map((value, i) => ({\n name: `p${i + 1}`,\n value: value === null || value === undefined ? null : String(value),\n })),\n };\n}\n\n/** Map a terminal statement response to normalized row objects. */\nexport function parseStatementRows(response: StatementResponse): Record<string, unknown>[] {\n const columns = [...(response.manifest?.schema?.columns ?? [])].sort(\n (a, b) => (a.position ?? 0) - (b.position ?? 0),\n );\n const data = response.result?.data_array ?? [];\n return data.map((tuple) => {\n const row: Record<string, unknown> = {};\n columns.forEach((column, i) => {\n row[column.name] = convertValue(tuple[i] ?? null, column.type_name ?? 'STRING');\n });\n return row;\n });\n}\n\nconst NUMERIC_TYPES = /^(INT|LONG|SHORT|BYTE|FLOAT|DOUBLE|DECIMAL)/i;\n\nfunction convertValue(value: string | null, typeName: string): unknown {\n if (value === null) return null;\n if (NUMERIC_TYPES.test(typeName)) return Number(value);\n if (/^BOOLEAN/i.test(typeName)) return value === 'true';\n return value;\n}\n\nfunction resolveWarehouseId(env: Record<string, string | undefined>): string {\n if (env.DATABRICKS_WAREHOUSE_ID) return env.DATABRICKS_WAREHOUSE_ID;\n const httpPath = env.DATABRICKS_HTTP_PATH;\n const match = httpPath?.match(/\\/warehouses\\/([\\w-]+)/);\n if (match?.[1]) return match[1];\n throw new Error(\n 'Live profile requires DATABRICKS_WAREHOUSE_ID or DATABRICKS_HTTP_PATH (/sql/1.0/warehouses/<id>)',\n );\n}\n\n/**\n * Auth precedence (ADR-0006): DATABRICKS_BEARER (pre-minted, CI) →\n * explicit env/file OIDC federation → DATABRICKS_CLIENT_ID/SECRET (OAuth\n * M2M) → DATABRICKS_TOKEN (legacy PAT).\n */\nexport function createClientFromEnv(\n env: Record<string, string | undefined>,\n fetchImpl?: typeof fetch,\n): DatabricksRestClient {\n const host = env.DATABRICKS_HOST;\n if (!host) throw new Error('Live profile requires DATABRICKS_HOST');\n return new DatabricksRestClient({\n host,\n token: resolveTokenProvider(host, env, fetchImpl),\n ...(fetchImpl ? { fetchImpl } : {}),\n });\n}\n\nexport function resolveTokenProvider(\n host: string,\n env: Record<string, string | undefined>,\n fetchImpl: typeof fetch = fetch,\n): string | (() => Promise<string>) {\n if (env.DATABRICKS_BEARER) return env.DATABRICKS_BEARER;\n const authType = env.DATABRICKS_AUTH_TYPE;\n if (authType === 'env-oidc' || authType === 'file-oidc') {\n let cached: { token: string; expiresAt: number } | null = null;\n return async () => {\n if (cached && Date.now() < cached.expiresAt) return cached.token;\n const subjectToken = await resolveFederatedSubjectToken(authType, env);\n const params = new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',\n subject_token: subjectToken,\n subject_token_type: 'urn:ietf:params:oauth:token-type:jwt',\n scope: env.DATABRICKS_SCOPE ?? 'all-apis',\n });\n if (env.DATABRICKS_CLIENT_ID) params.set('client_id', env.DATABRICKS_CLIENT_ID);\n const response = await fetchImpl(`${host.replace(/\\/$/, '')}/oidc/v1/token`, {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: params.toString(),\n });\n if (!response.ok) {\n throw new Error(`OAuth federated token exchange failed: ${response.status}`);\n }\n const body = (await response.json()) as { access_token?: unknown; expires_in?: unknown };\n if (typeof body.access_token !== 'string' || !body.access_token) {\n throw new Error('OAuth federated token exchange returned no access_token');\n }\n const expiresIn = typeof body.expires_in === 'number' ? body.expires_in : 3600;\n cached = {\n token: body.access_token,\n expiresAt: Date.now() + Math.max(1, expiresIn - 300) * 1000,\n };\n return body.access_token;\n };\n }\n const clientId = env.DATABRICKS_CLIENT_ID;\n const clientSecret = env.DATABRICKS_CLIENT_SECRET;\n if (clientId && clientSecret) {\n let cached: { token: string; expiresAt: number } | null = null;\n return async () => {\n if (cached && Date.now() < cached.expiresAt) return cached.token;\n const response = await fetchImpl(`${host.replace(/\\/$/, '')}/oidc/v1/token`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/x-www-form-urlencoded',\n authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`,\n },\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n scope: env.DATABRICKS_SCOPE ?? 'all-apis',\n }).toString(),\n });\n if (!response.ok) {\n throw new Error(`OAuth M2M token exchange failed: ${response.status}`);\n }\n const body = (await response.json()) as { access_token: string; expires_in?: number };\n cached = {\n token: body.access_token,\n expiresAt: Date.now() + ((body.expires_in ?? 3600) - 300) * 1000,\n };\n return body.access_token;\n };\n }\n if (env.DATABRICKS_TOKEN) return env.DATABRICKS_TOKEN;\n throw new Error(\n 'Live profile requires DATABRICKS_BEARER, env/file OIDC federation, DATABRICKS_CLIENT_ID/SECRET, or DATABRICKS_TOKEN',\n );\n}\n\nasync function resolveFederatedSubjectToken(\n authType: 'env-oidc' | 'file-oidc',\n env: Record<string, string | undefined>,\n): Promise<string> {\n if (authType === 'env-oidc') {\n const tokenEnv = env.DATABRICKS_OIDC_TOKEN_ENV ?? 'DATABRICKS_OIDC_TOKEN';\n const token = env[tokenEnv]?.trim();\n if (!token) throw new Error(`Federated OIDC token environment variable ${tokenEnv} is empty`);\n return token;\n }\n const path = env.DATABRICKS_OIDC_TOKEN_FILEPATH;\n if (!path) throw new Error('DATABRICKS_OIDC_TOKEN_FILEPATH is required for file-oidc');\n const token = (await readFile(path, 'utf8')).trim();\n if (!token) throw new Error(`Federated OIDC token file ${path} is empty`);\n return token;\n}\n","/**\n * Cross-engine parity suites (vitest subpath — import from\n * '@fabricorg/databricks-testkit/parity').\n *\n * The same statement runs on DuckDB against committed fixtures and is\n * asserted against a golden file; when live credentials are present\n * (DBX_TEST_LIVE=1 + DBX_TEST_PROFILE may stay local), the statement ALSO\n * runs on a real Databricks SQL warehouse and both engines must reproduce\n * the same golden rows. This is how \"DuckDB in CI, Photon in prod\" stays\n * honest.\n */\nimport { describe, expect, it } from 'vitest';\nimport type { ExecutionContext } from './context.js';\nimport { createDuckDbContext } from './duckdb-context.js';\nimport type { TableFixture } from './fixtures.js';\nimport { compareToGolden } from './golden.js';\nimport { createWorkspaceContext } from './workspace-context.js';\n\nexport interface ParitySuiteSpec {\n name: string;\n /** Statement to execute (positional `?` params in both engines). */\n sql: string;\n params?: readonly unknown[];\n fixtures: readonly TableFixture[];\n /** Path to the committed golden JSON (created with DBX_TEST_UPDATE_GOLDEN=1). */\n golden: string;\n /** Scenario-scoped schema; defaults to no schema locally. */\n schema?: string;\n env?: Record<string, string | undefined>;\n}\n\nexport function defineParitySuite(spec: ParitySuiteSpec): void {\n const env = spec.env ?? process.env;\n const liveEnabled = env.DBX_TEST_LIVE === '1';\n const liveTimeoutMs = Number(env.DBX_TEST_TIMEOUT_MS ?? 120_000);\n\n describe(`parity: ${spec.name}`, () => {\n it('DuckDB reproduces the golden rows', async () => {\n const ctx = await createDuckDbContext({ schema: spec.schema });\n try {\n await expectGolden(ctx, spec);\n } finally {\n await ctx.close();\n }\n });\n\n it.skipIf(!liveEnabled)(\n 'Databricks reproduces the golden rows',\n async () => {\n const ctx = await createWorkspaceContext({ env, schema: spec.schema });\n try {\n await expectGolden(ctx, spec);\n } finally {\n await ctx.close();\n }\n },\n liveTimeoutMs,\n );\n });\n}\n\nasync function expectGolden(ctx: ExecutionContext, spec: ParitySuiteSpec): Promise<void> {\n for (const fixture of spec.fixtures) {\n await ctx.loadFixture(fixture);\n }\n const rows = await ctx.query(spec.sql, spec.params);\n expect(rows.length).toBeGreaterThan(0);\n await compareToGolden(spec.golden, rows, `parity suite ${spec.name} (${ctx.profile})`);\n}\n"]}
1
+ {"version":3,"sources":["../src/fixtures.ts","../src/duckdb-context.ts","../src/golden.ts","../src/workspace-client.ts","../src/workspace-context.ts","../src/parity.ts"],"names":["columns","rows","token","readFile","describe","it","expect"],"mappings":"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","file":"parity.cjs","sourcesContent":["/**\n * Declarative, engine-agnostic table seeds. The same fixture applies to a\n * local DuckDB table or a scratch Unity Catalog schema — column DDL uses the\n * portable subset (VARCHAR/STRING, BIGINT, DOUBLE, TIMESTAMP, BOOLEAN).\n */\nexport interface TableFixture {\n table: string;\n /**\n * Column DDL, e.g. `subject_id STRING, value DOUBLE, \"at\" TIMESTAMP`.\n * Optional when the table already exists in the target context.\n */\n schema?: string;\n /** Row tuples in column order, or row objects keyed by column name. */\n rows?: readonly (readonly unknown[] | Record<string, unknown>)[];\n /** Path to an NDJSON file of row objects (one JSON object per line). */\n ndjsonFile?: string;\n}\n\nexport interface FixtureColumn {\n name: string;\n type: string;\n}\n\n/** Parse `name TYPE, name TYPE(args), \"quoted\" TYPE` column DDL into columns. */\nexport function parseFixtureColumns(schema: string): FixtureColumn[] {\n const columns: FixtureColumn[] = [];\n let depth = 0;\n let current = '';\n const parts: string[] = [];\n for (const ch of schema) {\n if (ch === '(') depth++;\n if (ch === ')') depth--;\n if (ch === ',' && depth === 0) {\n parts.push(current);\n current = '';\n } else {\n current += ch;\n }\n }\n if (current.trim()) parts.push(current);\n for (const part of parts) {\n const trimmed = part.trim();\n const match = trimmed.match(/^(\"([^\"]+)\"|`([^`]+)`|(\\w+))\\s+(.+)$/s);\n if (!match) throw new Error(`Unparseable fixture column: '${trimmed}'`);\n columns.push({\n name: match[2] ?? match[3] ?? match[4] ?? '',\n type: (match[5] ?? '').trim(),\n });\n }\n if (columns.length === 0) throw new Error('Fixture schema declared no columns');\n return columns;\n}\n\n/** Resolve fixture rows (inline tuples/objects or NDJSON file) into tuples in `columns` order. */\nexport async function resolveFixtureRows(\n fixture: TableFixture,\n columns: readonly FixtureColumn[],\n): Promise<unknown[][]> {\n const raw: (readonly unknown[] | Record<string, unknown>)[] = [...(fixture.rows ?? [])];\n if (fixture.ndjsonFile) {\n const fs = await import('node:fs/promises');\n const text = await fs.readFile(fixture.ndjsonFile, 'utf8');\n for (const line of text.split('\\n')) {\n if (line.trim().length === 0) continue;\n raw.push(JSON.parse(line) as Record<string, unknown>);\n }\n }\n return raw.map((row) => {\n if (Array.isArray(row)) {\n if (row.length !== columns.length) {\n throw new Error(\n `Fixture row for ${fixture.table} has ${row.length} values, expected ${columns.length}`,\n );\n }\n return [...row];\n }\n const record = row as Record<string, unknown>;\n return columns.map((c) => (c.name in record ? record[c.name] : null));\n });\n}\n","import type { ExecutionContext } from './context.js';\nimport { type TableFixture, parseFixtureColumns, resolveFixtureRows } from './fixtures.js';\n\nexport interface DuckDbContextOptions {\n /** Database file path; ':memory:' (default) for a throwaway in-process db. */\n path?: string;\n /** Optional schema to create + qualify tables with. */\n schema?: string;\n /** Injectable for tests of this module itself. */\n connectionFactory?: (path: string) => Promise<DuckDbConnectionLike>;\n}\n\n/** Structural slice of the lazily-imported @duckdb/node-api connection. */\nexport interface DuckDbConnectionLike {\n run(sql: string, values?: unknown[]): Promise<unknown>;\n runAndReadAll(\n sql: string,\n values?: unknown[],\n ): Promise<{ getRowObjects(): Record<string, unknown>[] }>;\n closeSync(): void;\n}\n\n/**\n * Hermetic local execution context on DuckDB — the `local` profile of the\n * testing pyramid. No workspace, no credentials, sub-second.\n */\nexport async function createDuckDbContext(\n options: DuckDbContextOptions = {},\n): Promise<ExecutionContext> {\n const factory = options.connectionFactory ?? defaultConnectionFactory;\n const conn = await factory(options.path ?? ':memory:');\n const schema = options.schema;\n if (schema) await conn.run(`CREATE SCHEMA IF NOT EXISTS ${schema}`);\n const qual = (table: string) => (schema ? `${schema}.${table}` : table);\n\n return {\n profile: 'local',\n qual,\n async exec(sql, params) {\n await conn.run(sql, params ? [...params] : undefined);\n },\n async query(sql, params) {\n const reader = await conn.runAndReadAll(sql, params ? [...params] : undefined);\n return reader.getRowObjects().map(normalizeRow);\n },\n async loadFixture(fixture: TableFixture) {\n if (fixture.schema) {\n const columns = parseFixtureColumns(fixture.schema);\n const ddl = columns.map((c) => `\"${c.name}\" ${portableType(c.type)}`).join(', ');\n await conn.run(`CREATE TABLE IF NOT EXISTS ${qual(fixture.table)} (${ddl})`);\n const rows = await resolveFixtureRows(fixture, columns);\n for (const row of rows) {\n const casts = columns\n .map((c) => (isTimestamp(c.type) ? 'CAST(? AS TIMESTAMP)' : '?'))\n .join(', ');\n await conn.run(`INSERT INTO ${qual(fixture.table)} VALUES (${casts})`, row);\n }\n return;\n }\n // Table pre-exists: infer column order from the catalog.\n const described = await conn.runAndReadAll(`DESCRIBE ${qual(fixture.table)}`);\n const columns = described\n .getRowObjects()\n .map((r) => ({ name: String(r.column_name), type: String(r.column_type) }));\n const rows = await resolveFixtureRows(fixture, columns);\n for (const row of rows) {\n const casts = columns\n .map((c) => (isTimestamp(c.type) ? 'CAST(? AS TIMESTAMP)' : '?'))\n .join(', ');\n await conn.run(`INSERT INTO ${qual(fixture.table)} VALUES (${casts})`, row);\n }\n },\n async close() {\n conn.closeSync();\n },\n };\n}\n\n/** Databricks types → DuckDB types for the portable fixture subset. */\nfunction portableType(type: string): string {\n return type.replace(/\\bSTRING\\b/gi, 'VARCHAR');\n}\n\nfunction isTimestamp(type: string): boolean {\n return /TIMESTAMP/i.test(type);\n}\n\n/**\n * Normalize DuckDB values to plain JSON-ish values so assertions and golden\n * files are engine-portable: bigint→number, TIMESTAMP→`YYYY-MM-DD HH:MM:SS`\n * (UTC, microseconds trimmed), DECIMAL→number.\n */\nexport function normalizeRow(row: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(row)) {\n out[key] = normalizeValue(value);\n }\n return out;\n}\n\nfunction normalizeValue(value: unknown): unknown {\n if (typeof value === 'bigint') {\n if (value > BigInt(Number.MAX_SAFE_INTEGER) || value < BigInt(-Number.MAX_SAFE_INTEGER)) {\n return value.toString();\n }\n return Number(value);\n }\n if (value !== null && typeof value === 'object') {\n const v = value as { micros?: bigint; width?: number; scale?: number; value?: bigint };\n if (typeof v.micros === 'bigint') {\n // DuckDBTimestampValue — micros since epoch, UTC.\n const millis = Number(v.micros / 1000n);\n return new Date(millis)\n .toISOString()\n .replace('T', ' ')\n .replace(/\\.\\d+Z$/, '');\n }\n if (typeof v.scale === 'number' && typeof v.value === 'bigint') {\n // DuckDBDecimalValue.\n return Number(v.value) / 10 ** v.scale;\n }\n return String(value);\n }\n return value;\n}\n\nasync function defaultConnectionFactory(path: string): Promise<DuckDbConnectionLike> {\n const moduleName = '@duckdb/node-api';\n let mod: { DuckDBInstance: { create(path: string): Promise<{ connect(): Promise<unknown> }> } };\n try {\n mod = (await import(moduleName)) as typeof mod;\n } catch {\n throw new Error(\n 'createDuckDbContext requires the optional peer @duckdb/node-api — run: pnpm add -D @duckdb/node-api',\n );\n }\n const instance = await mod.DuckDBInstance.create(path);\n return (await instance.connect()) as DuckDbConnectionLike;\n}\n","/**\n * Golden-result files: committed JSON snapshots of query results that every\n * engine and every refactor must reproduce exactly — the frozen-vector\n * pattern from @fabricorg/experiments-testkit generalized to warehouse rows.\n */\nexport async function compareToGolden(\n goldenPath: string,\n actual: readonly Record<string, unknown>[],\n label: string,\n env: Record<string, string | undefined> = process.env,\n): Promise<void> {\n const fs = await import('node:fs/promises');\n const serialized = `${JSON.stringify(actual, null, 2)}\\n`;\n if (env.DBX_TEST_UPDATE_GOLDEN === '1') {\n const { dirname } = await import('node:path');\n await fs.mkdir(dirname(goldenPath), { recursive: true });\n await fs.writeFile(goldenPath, serialized, 'utf8');\n return;\n }\n let expected: string;\n try {\n expected = await fs.readFile(goldenPath, 'utf8');\n } catch {\n throw new Error(\n `Golden file ${goldenPath} does not exist for ${label}. Run once with DBX_TEST_UPDATE_GOLDEN=1 to create it, then commit it.`,\n );\n }\n if (normalize(expected) !== normalize(serialized)) {\n throw new Error(\n `${label} diverges from golden ${goldenPath}.\\nExpected:\\n${expected}\\nActual:\\n${serialized}\\nIf the change is intentional, re-run with DBX_TEST_UPDATE_GOLDEN=1 and commit the diff.`,\n );\n }\n}\n\nfunction normalize(json: string): string {\n return JSON.stringify(JSON.parse(json));\n}\n","/** Minimal request boundary used by the live Databricks certification suite. */\nexport interface WorkspaceClientLike {\n get<T>(path: string, query?: Record<string, string | number | boolean | undefined>): Promise<T>;\n post<T>(\n path: string,\n body?: unknown,\n query?: Record<string, string | number | boolean | undefined>,\n options?: WorkspaceRequestOptions,\n ): Promise<T>;\n}\n\nexport interface WorkspaceClientOptions {\n host: string;\n token: string | (() => string | Promise<string>);\n fetchImpl?: typeof fetch;\n maxRetries?: number;\n retryBaseDelayMs?: number;\n signal?: AbortSignal;\n}\n\nexport interface WorkspaceRequestOptions {\n retry?: 'safe' | 'always' | 'never';\n idempotencyKey?: string;\n maxRetries?: number;\n}\n\nexport interface WorkspaceWaitOptions {\n pollIntervalMs?: number;\n timeoutMs?: number;\n signal?: AbortSignal;\n}\n\n/**\n * Testkit-owned REST boundary for workspace certification endpoints.\n *\n * Harness 4 removed its generic public REST client in favor of generated,\n * capability-specific Databricks SDK clients. The testkit intentionally keeps\n * this narrow injectable transport because it certifies APIs across several\n * services and because its mock client implements the same two-method shape.\n */\nexport class WorkspaceRestClient implements WorkspaceClientLike {\n private readonly host: string;\n private readonly token: WorkspaceClientOptions['token'];\n private readonly fetchImpl: typeof fetch;\n private readonly maxRetries: number;\n private readonly retryBaseDelayMs: number;\n private readonly signal: AbortSignal | undefined;\n\n constructor(options: WorkspaceClientOptions) {\n this.host = workspaceOrigin(options.host);\n this.token = options.token;\n this.fetchImpl = options.fetchImpl ?? fetch;\n this.maxRetries = options.maxRetries ?? 3;\n this.retryBaseDelayMs = options.retryBaseDelayMs ?? 500;\n this.signal = options.signal;\n }\n\n get<T>(path: string, query?: Record<string, string | number | boolean | undefined>): Promise<T> {\n return this.request<T>('GET', path, undefined, query);\n }\n\n post<T>(\n path: string,\n body?: unknown,\n query?: Record<string, string | number | boolean | undefined>,\n options?: WorkspaceRequestOptions,\n ): Promise<T> {\n return this.request<T>('POST', path, body, query, options);\n }\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n query: Record<string, string | number | boolean | undefined> = {},\n options: WorkspaceRequestOptions = {},\n ): Promise<T> {\n const url = new URL(`${this.host}${path.startsWith('/') ? path : `/${path}`}`);\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined) url.searchParams.set(key, String(value));\n }\n const bodyHasIdempotencyToken =\n typeof body === 'object' &&\n body !== null &&\n typeof (body as Record<string, unknown>).idempotency_token === 'string';\n const canRetry =\n options.retry === 'always' ||\n (options.retry !== 'never' &&\n (options.retry === 'safe' ||\n method === 'GET' ||\n Boolean(options.idempotencyKey) ||\n bodyHasIdempotencyToken));\n const maxRetries = canRetry ? (options.maxRetries ?? this.maxRetries) : 0;\n\n for (let attempt = 0; ; attempt += 1) {\n const token = typeof this.token === 'function' ? await this.token() : this.token;\n let response: Response;\n try {\n response = await this.fetchImpl(url, {\n method,\n headers: {\n authorization: `Bearer ${token}`,\n ...(body !== undefined ? { 'content-type': 'application/json' } : {}),\n ...(options.idempotencyKey ? { 'idempotency-key': options.idempotencyKey } : {}),\n },\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n ...(this.signal ? { signal: this.signal } : {}),\n });\n } catch (error) {\n if (this.signal?.aborted || attempt >= maxRetries) throw error;\n await delay(this.retryBaseDelayMs * 2 ** attempt, this.signal);\n continue;\n }\n\n if (response.ok) {\n if (response.status === 204) return undefined as T;\n return (await response.json()) as T;\n }\n if (isRetryableStatus(response.status) && attempt < maxRetries) {\n await delay(retryDelayMs(response, attempt, this.retryBaseDelayMs), this.signal);\n continue;\n }\n\n const message = (await response.text()).split(token).join('[REDACTED]');\n throw new Error(\n `databricks: ${response.status} ${response.statusText}: ${message.slice(0, 2000)}`,\n );\n }\n }\n}\n\nexport async function waitForDatabricksRun(\n client: WorkspaceClientLike,\n runId: number,\n options: WorkspaceWaitOptions = {},\n): Promise<Record<string, unknown>> {\n const deadline = Date.now() + (options.timeoutMs ?? 600_000);\n const interval = options.pollIntervalMs ?? 5_000;\n let current = await client.get<Record<string, unknown>>('/api/2.2/jobs/runs/get', {\n run_id: runId,\n });\n while (!isTerminalRun(current) && Date.now() < deadline) {\n await delay(interval, options.signal);\n current = await client.get<Record<string, unknown>>('/api/2.2/jobs/runs/get', {\n run_id: runId,\n });\n }\n return current;\n}\n\nexport async function waitForDatabricksStatement(\n client: WorkspaceClientLike,\n statementId: string,\n options: WorkspaceWaitOptions = {},\n): Promise<Record<string, unknown>> {\n const deadline = Date.now() + (options.timeoutMs ?? 300_000);\n const interval = options.pollIntervalMs ?? 2_000;\n const path = `/api/2.0/sql/statements/${encodeURIComponent(statementId)}`;\n let current = await client.get<Record<string, unknown>>(path);\n while (!isTerminalStatement(current) && Date.now() < deadline) {\n await delay(interval, options.signal);\n current = await client.get<Record<string, unknown>>(path);\n }\n return current;\n}\n\nfunction workspaceOrigin(host: string): string {\n const value = host.trim();\n if (!value) throw new Error('databricks: workspace host cannot be empty');\n const url = new URL(value.includes('://') ? value : `https://${value}`);\n if (url.username || url.password) {\n throw new Error('databricks: workspace host must not contain credentials');\n }\n return url.origin;\n}\n\nfunction isRetryableStatus(status: number): boolean {\n return status === 429 || status === 499 || (status >= 500 && status <= 599);\n}\n\nfunction retryDelayMs(response: Response, attempt: number, base: number): number {\n const retryAfterHeader = response.headers.get('retry-after');\n const retryAfter = retryAfterHeader === null ? Number.NaN : Number(retryAfterHeader);\n return Number.isFinite(retryAfter) && retryAfter >= 0 ? retryAfter * 1000 : base * 2 ** attempt;\n}\n\nfunction isTerminalRun(run: Record<string, unknown>): boolean {\n const state = run.state as { life_cycle_state?: string } | undefined;\n return ['TERMINATED', 'SKIPPED', 'INTERNAL_ERROR'].includes(state?.life_cycle_state ?? '');\n}\n\nfunction isTerminalStatement(statement: Record<string, unknown>): boolean {\n const status = statement.status as { state?: string } | undefined;\n return ['SUCCEEDED', 'FAILED', 'CANCELED', 'CLOSED'].includes(status?.state ?? '');\n}\n\nfunction delay(ms: number, signal?: AbortSignal): Promise<void> {\n if (!signal) return new Promise((resolve) => setTimeout(resolve, ms));\n if (signal.aborted) {\n return Promise.reject(\n signal.reason ?? new DOMException('The operation was aborted', 'AbortError'),\n );\n }\n return new Promise((resolve, reject) => {\n const timer = setTimeout(done, ms);\n signal.addEventListener('abort', aborted, { once: true });\n function done() {\n signal?.removeEventListener('abort', aborted);\n resolve();\n }\n function aborted() {\n clearTimeout(timer);\n reject(signal?.reason ?? new DOMException('The operation was aborted', 'AbortError'));\n }\n });\n}\n","import { readFile } from 'node:fs/promises';\nimport type { ExecutionContext } from './context.js';\nimport { type TableFixture, parseFixtureColumns, resolveFixtureRows } from './fixtures.js';\nimport {\n type WorkspaceClientLike,\n WorkspaceRestClient,\n waitForDatabricksStatement,\n} from './workspace-client.js';\nexport type { WorkspaceClientLike } from './workspace-client.js';\n\nexport interface WorkspaceContextOptions {\n env?: Record<string, string | undefined>;\n /** Schema within the catalog used by qual(); defaults to DBX_TEST_SCHEMA. */\n schema?: string;\n /** Injectable client for hermetic tests; defaults to the testkit workspace client. */\n client?: WorkspaceClientLike;\n /** Injectable fetch for the OAuth M2M exchange. */\n fetchImpl?: typeof fetch;\n pollIntervalMs?: number;\n timeoutMs?: number;\n /** Drop tables seeded by this context on close. Defaults to true. */\n cleanupFixtures?: boolean;\n /** Observe submitted statements for redacted failure evidence. */\n onStatement?: (statement: { sql: string; statementId?: string }) => void;\n}\n\ninterface StatementResponse {\n statement_id?: string;\n status?: { state?: string; error?: { message?: string } };\n manifest?: { schema?: { columns?: { name: string; type_name?: string; position?: number }[] } };\n result?: { data_array?: (string | null)[][] };\n}\n\n/**\n * Live execution context on a Databricks SQL warehouse via the SQL Statement\n * Execution API (/api/2.0/sql/statements). The Statement Execution API takes\n * NAMED parameter markers, so positional `?` params are rewritten to\n * `:p1..:pn` — the ExecutionContext surface stays identical to the local\n * profile.\n */\nexport async function createWorkspaceContext(\n options: WorkspaceContextOptions = {},\n): Promise<ExecutionContext> {\n const env = options.env ?? process.env;\n const warehouseId = resolveWarehouseId(env);\n const catalog = env.DBX_TEST_CATALOG;\n const schema = options.schema ?? env.DBX_TEST_SCHEMA;\n const client = options.client ?? createClientFromEnv(env, options.fetchImpl);\n const fixtureTables = new Set<string>();\n\n const qual = (table: string) =>\n [catalog, schema, table].filter((part): part is string => Boolean(part)).join('.');\n\n async function run(sql: string, params?: readonly unknown[]): Promise<StatementResponse> {\n const { statement, parameters } = toNamedParameters(sql, params ?? []);\n const submitted = await client.post<StatementResponse>('/api/2.0/sql/statements', {\n statement,\n warehouse_id: warehouseId,\n ...(catalog ? { catalog } : {}),\n ...(schema ? { schema } : {}),\n ...(parameters.length > 0 ? { parameters } : {}),\n wait_timeout: '30s',\n on_wait_timeout: 'CONTINUE',\n });\n options.onStatement?.({\n sql,\n ...(submitted.statement_id ? { statementId: submitted.statement_id } : {}),\n });\n const state = submitted.status?.state;\n let terminal = submitted;\n if (state !== 'SUCCEEDED' && state !== 'FAILED' && state !== 'CANCELED' && state !== 'CLOSED') {\n terminal = (await waitForDatabricksStatement(client, submitted.statement_id ?? '', {\n pollIntervalMs: options.pollIntervalMs,\n timeoutMs: options.timeoutMs,\n })) as StatementResponse;\n }\n if (terminal.status?.state !== 'SUCCEEDED') {\n throw new Error(\n `Databricks statement ${terminal.status?.state ?? 'UNKNOWN'}: ${\n terminal.status?.error?.message ?? sql.slice(0, 200)\n }`,\n );\n }\n return terminal;\n }\n\n return {\n profile: 'live',\n qual,\n async exec(sql, params) {\n await run(sql, params);\n },\n async query(sql, params) {\n const response = await run(sql, params);\n return parseStatementRows(response);\n },\n async loadFixture(fixture: TableFixture) {\n if (!schema) {\n throw new Error(\n 'Live fixtures require DBX_TEST_SCHEMA (or a schema option) so tests cannot replace unscoped tables',\n );\n }\n if (!fixture.schema) {\n throw new Error(\n `Live fixtures require explicit column DDL for ${fixture.table} (schema inference is local-only)`,\n );\n }\n const columns = parseFixtureColumns(fixture.schema);\n const ddl = columns.map((c) => `\\`${c.name}\\` ${c.type}`).join(', ');\n const target = qual(fixture.table);\n await run(`CREATE OR REPLACE TABLE ${target} (${ddl}) USING DELTA`);\n fixtureTables.add(target);\n const rows = await resolveFixtureRows(fixture, columns);\n for (const row of rows) {\n const placeholders = columns\n .map((c) => (/TIMESTAMP/i.test(c.type) ? 'CAST(? AS TIMESTAMP)' : '?'))\n .join(', ');\n await run(`INSERT INTO ${qual(fixture.table)} VALUES (${placeholders})`, row);\n }\n },\n async close() {\n if (options.cleanupFixtures !== false && env.DBX_TEST_KEEP_FIXTURES !== '1') {\n for (const table of [...fixtureTables].reverse()) {\n await run(`DROP TABLE IF EXISTS ${table}`);\n }\n }\n fixtureTables.clear();\n },\n };\n}\n\n/** Rewrite positional `?` markers to the named `:pN` markers the Statement Execution API requires. */\nexport function toNamedParameters(\n sql: string,\n params: readonly unknown[],\n): { statement: string; parameters: { name: string; value: string | null }[] } {\n let out = '';\n let index = 0;\n let quote: string | null = null;\n for (let i = 0; i < sql.length; i++) {\n const ch = sql[i] as string;\n if (quote) {\n out += ch;\n if (ch === quote) quote = null;\n continue;\n }\n if (ch === \"'\" || ch === '\"' || ch === '`') {\n quote = ch;\n out += ch;\n continue;\n }\n if (ch === '?') {\n index += 1;\n out += `:p${index}`;\n continue;\n }\n out += ch;\n }\n if (index !== params.length) {\n throw new Error(`SQL has ${index} placeholders but ${params.length} params were provided`);\n }\n return {\n statement: out,\n parameters: params.map((value, i) => ({\n name: `p${i + 1}`,\n value: value === null || value === undefined ? null : String(value),\n })),\n };\n}\n\n/** Map a terminal statement response to normalized row objects. */\nexport function parseStatementRows(response: StatementResponse): Record<string, unknown>[] {\n const columns = [...(response.manifest?.schema?.columns ?? [])].sort(\n (a, b) => (a.position ?? 0) - (b.position ?? 0),\n );\n const data = response.result?.data_array ?? [];\n return data.map((tuple) => {\n const row: Record<string, unknown> = {};\n columns.forEach((column, i) => {\n row[column.name] = convertValue(tuple[i] ?? null, column.type_name ?? 'STRING');\n });\n return row;\n });\n}\n\nconst NUMERIC_TYPES = /^(INT|LONG|SHORT|BYTE|FLOAT|DOUBLE|DECIMAL)/i;\n\nfunction convertValue(value: string | null, typeName: string): unknown {\n if (value === null) return null;\n if (NUMERIC_TYPES.test(typeName)) return Number(value);\n if (/^BOOLEAN/i.test(typeName)) return value === 'true';\n return value;\n}\n\nfunction resolveWarehouseId(env: Record<string, string | undefined>): string {\n if (env.DATABRICKS_WAREHOUSE_ID) return env.DATABRICKS_WAREHOUSE_ID;\n const httpPath = env.DATABRICKS_HTTP_PATH;\n const match = httpPath?.match(/\\/warehouses\\/([\\w-]+)/);\n if (match?.[1]) return match[1];\n throw new Error(\n 'Live profile requires DATABRICKS_WAREHOUSE_ID or DATABRICKS_HTTP_PATH (/sql/1.0/warehouses/<id>)',\n );\n}\n\n/**\n * Auth precedence (ADR-0006): DATABRICKS_BEARER (pre-minted, CI) →\n * explicit env/file OIDC federation → DATABRICKS_CLIENT_ID/SECRET (OAuth\n * M2M) → DATABRICKS_TOKEN (legacy PAT).\n */\nexport function createClientFromEnv(\n env: Record<string, string | undefined>,\n fetchImpl?: typeof fetch,\n): WorkspaceClientLike {\n const host = env.DATABRICKS_HOST;\n if (!host) throw new Error('Live profile requires DATABRICKS_HOST');\n return new WorkspaceRestClient({\n host,\n token: resolveTokenProvider(host, env, fetchImpl),\n ...(fetchImpl ? { fetchImpl } : {}),\n });\n}\n\nexport function resolveTokenProvider(\n host: string,\n env: Record<string, string | undefined>,\n fetchImpl: typeof fetch = fetch,\n): string | (() => Promise<string>) {\n if (env.DATABRICKS_BEARER) return env.DATABRICKS_BEARER;\n const authType = env.DATABRICKS_AUTH_TYPE;\n if (authType === 'env-oidc' || authType === 'file-oidc') {\n let cached: { token: string; expiresAt: number } | null = null;\n return async () => {\n if (cached && Date.now() < cached.expiresAt) return cached.token;\n const subjectToken = await resolveFederatedSubjectToken(authType, env);\n const params = new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',\n subject_token: subjectToken,\n subject_token_type: 'urn:ietf:params:oauth:token-type:jwt',\n scope: env.DATABRICKS_SCOPE ?? 'all-apis',\n });\n if (env.DATABRICKS_CLIENT_ID) params.set('client_id', env.DATABRICKS_CLIENT_ID);\n const response = await fetchImpl(`${host.replace(/\\/$/, '')}/oidc/v1/token`, {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: params.toString(),\n });\n if (!response.ok) {\n throw new Error(`OAuth federated token exchange failed: ${response.status}`);\n }\n const body = (await response.json()) as { access_token?: unknown; expires_in?: unknown };\n if (typeof body.access_token !== 'string' || !body.access_token) {\n throw new Error('OAuth federated token exchange returned no access_token');\n }\n const expiresIn = typeof body.expires_in === 'number' ? body.expires_in : 3600;\n cached = {\n token: body.access_token,\n expiresAt: Date.now() + Math.max(1, expiresIn - 300) * 1000,\n };\n return body.access_token;\n };\n }\n const clientId = env.DATABRICKS_CLIENT_ID;\n const clientSecret = env.DATABRICKS_CLIENT_SECRET;\n if (clientId && clientSecret) {\n let cached: { token: string; expiresAt: number } | null = null;\n return async () => {\n if (cached && Date.now() < cached.expiresAt) return cached.token;\n const response = await fetchImpl(`${host.replace(/\\/$/, '')}/oidc/v1/token`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/x-www-form-urlencoded',\n authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`,\n },\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n scope: env.DATABRICKS_SCOPE ?? 'all-apis',\n }).toString(),\n });\n if (!response.ok) {\n throw new Error(`OAuth M2M token exchange failed: ${response.status}`);\n }\n const body = (await response.json()) as { access_token: string; expires_in?: number };\n cached = {\n token: body.access_token,\n expiresAt: Date.now() + ((body.expires_in ?? 3600) - 300) * 1000,\n };\n return body.access_token;\n };\n }\n if (env.DATABRICKS_TOKEN) return env.DATABRICKS_TOKEN;\n throw new Error(\n 'Live profile requires DATABRICKS_BEARER, env/file OIDC federation, DATABRICKS_CLIENT_ID/SECRET, or DATABRICKS_TOKEN',\n );\n}\n\nasync function resolveFederatedSubjectToken(\n authType: 'env-oidc' | 'file-oidc',\n env: Record<string, string | undefined>,\n): Promise<string> {\n if (authType === 'env-oidc') {\n const tokenEnv = env.DATABRICKS_OIDC_TOKEN_ENV ?? 'DATABRICKS_OIDC_TOKEN';\n const token = env[tokenEnv]?.trim();\n if (!token) throw new Error(`Federated OIDC token environment variable ${tokenEnv} is empty`);\n return token;\n }\n const path = env.DATABRICKS_OIDC_TOKEN_FILEPATH;\n if (!path) throw new Error('DATABRICKS_OIDC_TOKEN_FILEPATH is required for file-oidc');\n const token = (await readFile(path, 'utf8')).trim();\n if (!token) throw new Error(`Federated OIDC token file ${path} is empty`);\n return token;\n}\n","/**\n * Cross-engine parity suites (vitest subpath — import from\n * '@fabricorg/databricks-testkit/parity').\n *\n * The same statement runs on DuckDB against committed fixtures and is\n * asserted against a golden file; when live credentials are present\n * (DBX_TEST_LIVE=1 + DBX_TEST_PROFILE may stay local), the statement ALSO\n * runs on a real Databricks SQL warehouse and both engines must reproduce\n * the same golden rows. This is how \"DuckDB in CI, Photon in prod\" stays\n * honest.\n */\nimport { describe, expect, it } from 'vitest';\nimport type { ExecutionContext } from './context.js';\nimport { createDuckDbContext } from './duckdb-context.js';\nimport type { TableFixture } from './fixtures.js';\nimport { compareToGolden } from './golden.js';\nimport { createWorkspaceContext } from './workspace-context.js';\n\nexport interface ParitySuiteSpec {\n name: string;\n /** Statement to execute (positional `?` params in both engines). */\n sql: string;\n params?: readonly unknown[];\n fixtures: readonly TableFixture[];\n /** Path to the committed golden JSON (created with DBX_TEST_UPDATE_GOLDEN=1). */\n golden: string;\n /** Scenario-scoped schema; defaults to no schema locally. */\n schema?: string;\n env?: Record<string, string | undefined>;\n}\n\nexport function defineParitySuite(spec: ParitySuiteSpec): void {\n const env = spec.env ?? process.env;\n const liveEnabled = env.DBX_TEST_LIVE === '1';\n const liveTimeoutMs = Number(env.DBX_TEST_TIMEOUT_MS ?? 120_000);\n\n describe(`parity: ${spec.name}`, () => {\n it('DuckDB reproduces the golden rows', async () => {\n const ctx = await createDuckDbContext({ schema: spec.schema });\n try {\n await expectGolden(ctx, spec);\n } finally {\n await ctx.close();\n }\n });\n\n it.skipIf(!liveEnabled)(\n 'Databricks reproduces the golden rows',\n async () => {\n const ctx = await createWorkspaceContext({ env, schema: spec.schema });\n try {\n await expectGolden(ctx, spec);\n } finally {\n await ctx.close();\n }\n },\n liveTimeoutMs,\n );\n });\n}\n\nasync function expectGolden(ctx: ExecutionContext, spec: ParitySuiteSpec): Promise<void> {\n for (const fixture of spec.fixtures) {\n await ctx.loadFixture(fixture);\n }\n const rows = await ctx.query(spec.sql, spec.params);\n expect(rows.length).toBeGreaterThan(0);\n await compareToGolden(spec.golden, rows, `parity suite ${spec.name} (${ctx.profile})`);\n}\n"]}
package/dist/parity.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { compareToGolden } from './chunk-MLBZCHRM.js';
2
2
  import { createDuckDbContext } from './chunk-7JVDOSBO.js';
3
- import { createWorkspaceContext } from './chunk-SCVVMUAF.js';
3
+ import { createWorkspaceContext } from './chunk-MV752EAZ.js';
4
4
  import './chunk-F3KU6VZS.js';
5
5
  import { describe, it, expect } from 'vitest';
6
6
 
@@ -1,4 +1,4 @@
1
- export { createClientFromEnv, createWorkspaceContext, parseStatementRows, resolveTokenProvider, toNamedParameters } from './chunk-SCVVMUAF.js';
1
+ export { createClientFromEnv, createWorkspaceContext, parseStatementRows, resolveTokenProvider, toNamedParameters } from './chunk-MV752EAZ.js';
2
2
  import './chunk-F3KU6VZS.js';
3
- //# sourceMappingURL=workspace-context-VLBKMX3V.js.map
4
- //# sourceMappingURL=workspace-context-VLBKMX3V.js.map
3
+ //# sourceMappingURL=workspace-context-PCQAQSCO.js.map
4
+ //# sourceMappingURL=workspace-context-PCQAQSCO.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"workspace-context-VLBKMX3V.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"workspace-context-PCQAQSCO.js"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fabricorg/databricks-testkit",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "Testing toolkit for Databricks artifacts — DuckDB/local + live workspace execution contexts, fixtures, golden results, and cross-engine parity suites.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -29,7 +29,6 @@
29
29
  "clean": "rm -rf dist"
30
30
  },
31
31
  "dependencies": {
32
- "@fabric-harness/databricks": "^1.6.0",
33
32
  "@fabricorg/experiments-db-pool": "^0.1.2"
34
33
  },
35
34
  "peerDependencies": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/workspace-context.ts"],"names":["token"],"mappings":"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","file":"chunk-SCVVMUAF.js","sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { DatabricksRestClient, waitForDatabricksStatement } from '@fabric-harness/databricks';\nimport type { ExecutionContext } from './context.js';\nimport { type TableFixture, parseFixtureColumns, resolveFixtureRows } from './fixtures.js';\n\n/** Structural slice of DatabricksRestClient the workspace context uses (injectable in tests). */\nexport interface WorkspaceClientLike {\n get<T>(path: string, query?: Record<string, string | number | boolean | undefined>): Promise<T>;\n post<T>(\n path: string,\n body?: unknown,\n query?: Record<string, string | number | boolean | undefined>,\n options?: unknown,\n ): Promise<T>;\n}\n\nexport interface WorkspaceContextOptions {\n env?: Record<string, string | undefined>;\n /** Schema within the catalog used by qual(); defaults to DBX_TEST_SCHEMA. */\n schema?: string;\n /** Injectable client for hermetic tests; defaults to a DatabricksRestClient from env auth. */\n client?: WorkspaceClientLike;\n /** Injectable fetch for the OAuth M2M exchange. */\n fetchImpl?: typeof fetch;\n pollIntervalMs?: number;\n timeoutMs?: number;\n /** Drop tables seeded by this context on close. Defaults to true. */\n cleanupFixtures?: boolean;\n /** Observe submitted statements for redacted failure evidence. */\n onStatement?: (statement: { sql: string; statementId?: string }) => void;\n}\n\ninterface StatementResponse {\n statement_id?: string;\n status?: { state?: string; error?: { message?: string } };\n manifest?: { schema?: { columns?: { name: string; type_name?: string; position?: number }[] } };\n result?: { data_array?: (string | null)[][] };\n}\n\n/**\n * Live execution context on a Databricks SQL warehouse via the SQL Statement\n * Execution API (/api/2.0/sql/statements). The Statement Execution API takes\n * NAMED parameter markers, so positional `?` params are rewritten to\n * `:p1..:pn` — the ExecutionContext surface stays identical to the local\n * profile.\n */\nexport async function createWorkspaceContext(\n options: WorkspaceContextOptions = {},\n): Promise<ExecutionContext> {\n const env = options.env ?? process.env;\n const warehouseId = resolveWarehouseId(env);\n const catalog = env.DBX_TEST_CATALOG;\n const schema = options.schema ?? env.DBX_TEST_SCHEMA;\n const client = options.client ?? createClientFromEnv(env, options.fetchImpl);\n const fixtureTables = new Set<string>();\n\n const qual = (table: string) =>\n [catalog, schema, table].filter((part): part is string => Boolean(part)).join('.');\n\n async function run(sql: string, params?: readonly unknown[]): Promise<StatementResponse> {\n const { statement, parameters } = toNamedParameters(sql, params ?? []);\n const submitted = await client.post<StatementResponse>('/api/2.0/sql/statements', {\n statement,\n warehouse_id: warehouseId,\n ...(catalog ? { catalog } : {}),\n ...(schema ? { schema } : {}),\n ...(parameters.length > 0 ? { parameters } : {}),\n wait_timeout: '30s',\n on_wait_timeout: 'CONTINUE',\n });\n options.onStatement?.({\n sql,\n ...(submitted.statement_id ? { statementId: submitted.statement_id } : {}),\n });\n const state = submitted.status?.state;\n let terminal = submitted;\n if (state !== 'SUCCEEDED' && state !== 'FAILED' && state !== 'CANCELED' && state !== 'CLOSED') {\n terminal = (await waitForDatabricksStatement(\n client as DatabricksRestClient,\n submitted.statement_id ?? '',\n { pollIntervalMs: options.pollIntervalMs, timeoutMs: options.timeoutMs },\n )) as StatementResponse;\n }\n if (terminal.status?.state !== 'SUCCEEDED') {\n throw new Error(\n `Databricks statement ${terminal.status?.state ?? 'UNKNOWN'}: ${\n terminal.status?.error?.message ?? sql.slice(0, 200)\n }`,\n );\n }\n return terminal;\n }\n\n return {\n profile: 'live',\n qual,\n async exec(sql, params) {\n await run(sql, params);\n },\n async query(sql, params) {\n const response = await run(sql, params);\n return parseStatementRows(response);\n },\n async loadFixture(fixture: TableFixture) {\n if (!schema) {\n throw new Error(\n 'Live fixtures require DBX_TEST_SCHEMA (or a schema option) so tests cannot replace unscoped tables',\n );\n }\n if (!fixture.schema) {\n throw new Error(\n `Live fixtures require explicit column DDL for ${fixture.table} (schema inference is local-only)`,\n );\n }\n const columns = parseFixtureColumns(fixture.schema);\n const ddl = columns.map((c) => `\\`${c.name}\\` ${c.type}`).join(', ');\n const target = qual(fixture.table);\n await run(`CREATE OR REPLACE TABLE ${target} (${ddl}) USING DELTA`);\n fixtureTables.add(target);\n const rows = await resolveFixtureRows(fixture, columns);\n for (const row of rows) {\n const placeholders = columns\n .map((c) => (/TIMESTAMP/i.test(c.type) ? 'CAST(? AS TIMESTAMP)' : '?'))\n .join(', ');\n await run(`INSERT INTO ${qual(fixture.table)} VALUES (${placeholders})`, row);\n }\n },\n async close() {\n if (options.cleanupFixtures !== false && env.DBX_TEST_KEEP_FIXTURES !== '1') {\n for (const table of [...fixtureTables].reverse()) {\n await run(`DROP TABLE IF EXISTS ${table}`);\n }\n }\n fixtureTables.clear();\n },\n };\n}\n\n/** Rewrite positional `?` markers to the named `:pN` markers the Statement Execution API requires. */\nexport function toNamedParameters(\n sql: string,\n params: readonly unknown[],\n): { statement: string; parameters: { name: string; value: string | null }[] } {\n let out = '';\n let index = 0;\n let quote: string | null = null;\n for (let i = 0; i < sql.length; i++) {\n const ch = sql[i] as string;\n if (quote) {\n out += ch;\n if (ch === quote) quote = null;\n continue;\n }\n if (ch === \"'\" || ch === '\"' || ch === '`') {\n quote = ch;\n out += ch;\n continue;\n }\n if (ch === '?') {\n index += 1;\n out += `:p${index}`;\n continue;\n }\n out += ch;\n }\n if (index !== params.length) {\n throw new Error(`SQL has ${index} placeholders but ${params.length} params were provided`);\n }\n return {\n statement: out,\n parameters: params.map((value, i) => ({\n name: `p${i + 1}`,\n value: value === null || value === undefined ? null : String(value),\n })),\n };\n}\n\n/** Map a terminal statement response to normalized row objects. */\nexport function parseStatementRows(response: StatementResponse): Record<string, unknown>[] {\n const columns = [...(response.manifest?.schema?.columns ?? [])].sort(\n (a, b) => (a.position ?? 0) - (b.position ?? 0),\n );\n const data = response.result?.data_array ?? [];\n return data.map((tuple) => {\n const row: Record<string, unknown> = {};\n columns.forEach((column, i) => {\n row[column.name] = convertValue(tuple[i] ?? null, column.type_name ?? 'STRING');\n });\n return row;\n });\n}\n\nconst NUMERIC_TYPES = /^(INT|LONG|SHORT|BYTE|FLOAT|DOUBLE|DECIMAL)/i;\n\nfunction convertValue(value: string | null, typeName: string): unknown {\n if (value === null) return null;\n if (NUMERIC_TYPES.test(typeName)) return Number(value);\n if (/^BOOLEAN/i.test(typeName)) return value === 'true';\n return value;\n}\n\nfunction resolveWarehouseId(env: Record<string, string | undefined>): string {\n if (env.DATABRICKS_WAREHOUSE_ID) return env.DATABRICKS_WAREHOUSE_ID;\n const httpPath = env.DATABRICKS_HTTP_PATH;\n const match = httpPath?.match(/\\/warehouses\\/([\\w-]+)/);\n if (match?.[1]) return match[1];\n throw new Error(\n 'Live profile requires DATABRICKS_WAREHOUSE_ID or DATABRICKS_HTTP_PATH (/sql/1.0/warehouses/<id>)',\n );\n}\n\n/**\n * Auth precedence (ADR-0006): DATABRICKS_BEARER (pre-minted, CI) →\n * explicit env/file OIDC federation → DATABRICKS_CLIENT_ID/SECRET (OAuth\n * M2M) → DATABRICKS_TOKEN (legacy PAT).\n */\nexport function createClientFromEnv(\n env: Record<string, string | undefined>,\n fetchImpl?: typeof fetch,\n): DatabricksRestClient {\n const host = env.DATABRICKS_HOST;\n if (!host) throw new Error('Live profile requires DATABRICKS_HOST');\n return new DatabricksRestClient({\n host,\n token: resolveTokenProvider(host, env, fetchImpl),\n ...(fetchImpl ? { fetchImpl } : {}),\n });\n}\n\nexport function resolveTokenProvider(\n host: string,\n env: Record<string, string | undefined>,\n fetchImpl: typeof fetch = fetch,\n): string | (() => Promise<string>) {\n if (env.DATABRICKS_BEARER) return env.DATABRICKS_BEARER;\n const authType = env.DATABRICKS_AUTH_TYPE;\n if (authType === 'env-oidc' || authType === 'file-oidc') {\n let cached: { token: string; expiresAt: number } | null = null;\n return async () => {\n if (cached && Date.now() < cached.expiresAt) return cached.token;\n const subjectToken = await resolveFederatedSubjectToken(authType, env);\n const params = new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',\n subject_token: subjectToken,\n subject_token_type: 'urn:ietf:params:oauth:token-type:jwt',\n scope: env.DATABRICKS_SCOPE ?? 'all-apis',\n });\n if (env.DATABRICKS_CLIENT_ID) params.set('client_id', env.DATABRICKS_CLIENT_ID);\n const response = await fetchImpl(`${host.replace(/\\/$/, '')}/oidc/v1/token`, {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: params.toString(),\n });\n if (!response.ok) {\n throw new Error(`OAuth federated token exchange failed: ${response.status}`);\n }\n const body = (await response.json()) as { access_token?: unknown; expires_in?: unknown };\n if (typeof body.access_token !== 'string' || !body.access_token) {\n throw new Error('OAuth federated token exchange returned no access_token');\n }\n const expiresIn = typeof body.expires_in === 'number' ? body.expires_in : 3600;\n cached = {\n token: body.access_token,\n expiresAt: Date.now() + Math.max(1, expiresIn - 300) * 1000,\n };\n return body.access_token;\n };\n }\n const clientId = env.DATABRICKS_CLIENT_ID;\n const clientSecret = env.DATABRICKS_CLIENT_SECRET;\n if (clientId && clientSecret) {\n let cached: { token: string; expiresAt: number } | null = null;\n return async () => {\n if (cached && Date.now() < cached.expiresAt) return cached.token;\n const response = await fetchImpl(`${host.replace(/\\/$/, '')}/oidc/v1/token`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/x-www-form-urlencoded',\n authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`,\n },\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n scope: env.DATABRICKS_SCOPE ?? 'all-apis',\n }).toString(),\n });\n if (!response.ok) {\n throw new Error(`OAuth M2M token exchange failed: ${response.status}`);\n }\n const body = (await response.json()) as { access_token: string; expires_in?: number };\n cached = {\n token: body.access_token,\n expiresAt: Date.now() + ((body.expires_in ?? 3600) - 300) * 1000,\n };\n return body.access_token;\n };\n }\n if (env.DATABRICKS_TOKEN) return env.DATABRICKS_TOKEN;\n throw new Error(\n 'Live profile requires DATABRICKS_BEARER, env/file OIDC federation, DATABRICKS_CLIENT_ID/SECRET, or DATABRICKS_TOKEN',\n );\n}\n\nasync function resolveFederatedSubjectToken(\n authType: 'env-oidc' | 'file-oidc',\n env: Record<string, string | undefined>,\n): Promise<string> {\n if (authType === 'env-oidc') {\n const tokenEnv = env.DATABRICKS_OIDC_TOKEN_ENV ?? 'DATABRICKS_OIDC_TOKEN';\n const token = env[tokenEnv]?.trim();\n if (!token) throw new Error(`Federated OIDC token environment variable ${tokenEnv} is empty`);\n return token;\n }\n const path = env.DATABRICKS_OIDC_TOKEN_FILEPATH;\n if (!path) throw new Error('DATABRICKS_OIDC_TOKEN_FILEPATH is required for file-oidc');\n const token = (await readFile(path, 'utf8')).trim();\n if (!token) throw new Error(`Federated OIDC token file ${path} is empty`);\n return token;\n}\n"]}