@xylex-group/athena 2.1.2 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +287 -116
- package/dist/browser.cjs +1628 -156
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +14 -14
- package/dist/browser.d.ts +14 -14
- package/dist/browser.js +1625 -156
- package/dist/browser.js.map +1 -1
- package/dist/cli/index.cjs +1532 -145
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +3 -3
- package/dist/cli/index.d.ts +3 -3
- package/dist/cli/index.js +1533 -146
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +1658 -167
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +1656 -168
- package/dist/index.js.map +1 -1
- package/dist/{model-form-2hqmoOUX.d.ts → model-form-BpDXlbxb.d.ts} +97 -2
- package/dist/{model-form-Cy-zaO0u.d.cts → model-form-hoE2jHIi.d.cts} +97 -2
- package/dist/{pipeline-BOPszLsL.d.ts → pipeline-BNIw8pDQ.d.ts} +1 -1
- package/dist/{pipeline-E3FDbs4W.d.cts → pipeline-DNIpEsN8.d.cts} +1 -1
- package/dist/{client-dpAp-NZK.d.cts → react-email-BvyCZnfW.d.cts} +349 -174
- package/dist/{client-BX0NQqOn.d.ts → react-email-qPA1wjFV.d.ts} +349 -174
- package/dist/react.cjs +30 -9
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +4 -4
- package/dist/react.d.ts +4 -4
- package/dist/react.js +30 -9
- package/dist/react.js.map +1 -1
- package/dist/{types-BaBzjwXr.d.cts → types-A5e97acl.d.cts} +2 -1
- package/dist/{types-BaBzjwXr.d.ts → types-A5e97acl.d.ts} +2 -1
- package/dist/{types-CeBPrnGj.d.ts → types-BnD22-vb.d.ts} +1 -1
- package/dist/{types-CpqL-pZx.d.cts → types-bDlr4u7p.d.cts} +1 -1
- package/dist/utils.cjs +153 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.cts +23 -0
- package/dist/utils.d.ts +23 -0
- package/dist/utils.js +146 -0
- package/dist/utils.js.map +1 -0
- package/package.json +75 -17
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'fs';
|
|
2
2
|
import { resolve, dirname, posix } from 'path';
|
|
3
3
|
import { pathToFileURL } from 'url';
|
|
4
|
-
import { mkdir, writeFile } from 'fs/promises';
|
|
4
|
+
import { mkdir, writeFile, stat } from 'fs/promises';
|
|
5
5
|
|
|
6
6
|
// src/gateway/errors.ts
|
|
7
7
|
var AthenaGatewayError = class _AthenaGatewayError extends Error {
|
|
@@ -91,23 +91,39 @@ function normalizeHeaderValue(value) {
|
|
|
91
91
|
function isRecord(value) {
|
|
92
92
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
93
93
|
}
|
|
94
|
+
function nonEmptyString(value) {
|
|
95
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
96
|
+
}
|
|
97
|
+
function resolveStructuredErrorPayload(payload) {
|
|
98
|
+
if (!isRecord(payload)) return null;
|
|
99
|
+
return isRecord(payload.error) ? payload.error : payload;
|
|
100
|
+
}
|
|
94
101
|
function resolveRequestId(headers) {
|
|
95
102
|
return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
|
|
96
103
|
}
|
|
97
104
|
function resolveErrorMessage(payload, fallback) {
|
|
98
|
-
|
|
99
|
-
|
|
105
|
+
const structuredPayload = resolveStructuredErrorPayload(payload);
|
|
106
|
+
if (structuredPayload) {
|
|
107
|
+
const messageCandidates = [structuredPayload.message, structuredPayload.error, structuredPayload.details];
|
|
100
108
|
for (const candidate of messageCandidates) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
109
|
+
const resolved = nonEmptyString(candidate);
|
|
110
|
+
if (resolved) return resolved;
|
|
104
111
|
}
|
|
105
112
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
113
|
+
const rawMessage = nonEmptyString(payload);
|
|
114
|
+
if (rawMessage) return rawMessage;
|
|
109
115
|
return fallback;
|
|
110
116
|
}
|
|
117
|
+
function resolveErrorHint(payload) {
|
|
118
|
+
const structuredPayload = resolveStructuredErrorPayload(payload);
|
|
119
|
+
return structuredPayload ? nonEmptyString(structuredPayload.hint) : void 0;
|
|
120
|
+
}
|
|
121
|
+
function resolveStatusText(response, payload) {
|
|
122
|
+
const rawStatusText = nonEmptyString(response.statusText);
|
|
123
|
+
if (rawStatusText) return rawStatusText;
|
|
124
|
+
const payloadRecord = isRecord(payload) ? payload : null;
|
|
125
|
+
return payloadRecord ? nonEmptyString(payloadRecord.statusText) ?? null : null;
|
|
126
|
+
}
|
|
111
127
|
function detailsFromError(error) {
|
|
112
128
|
return error.toDetails();
|
|
113
129
|
}
|
|
@@ -278,6 +294,7 @@ async function callAthena(config, endpoint, method, payload, options) {
|
|
|
278
294
|
return {
|
|
279
295
|
ok: false,
|
|
280
296
|
status: response.status,
|
|
297
|
+
statusText: resolveStatusText(response, parsedBody.parsed),
|
|
281
298
|
data: null,
|
|
282
299
|
error: invalidJsonError.message,
|
|
283
300
|
errorDetails: detailsFromError(invalidJsonError),
|
|
@@ -296,11 +313,13 @@ async function callAthena(config, endpoint, method, payload, options) {
|
|
|
296
313
|
status: response.status,
|
|
297
314
|
endpoint,
|
|
298
315
|
method,
|
|
299
|
-
requestId
|
|
316
|
+
requestId,
|
|
317
|
+
hint: resolveErrorHint(parsed)
|
|
300
318
|
});
|
|
301
319
|
return {
|
|
302
320
|
ok: false,
|
|
303
321
|
status: response.status,
|
|
322
|
+
statusText: resolveStatusText(response, parsed),
|
|
304
323
|
data: null,
|
|
305
324
|
error: httpError.message,
|
|
306
325
|
errorDetails: detailsFromError(httpError),
|
|
@@ -312,6 +331,7 @@ async function callAthena(config, endpoint, method, payload, options) {
|
|
|
312
331
|
return {
|
|
313
332
|
ok: true,
|
|
314
333
|
status: response.status,
|
|
334
|
+
statusText: resolveStatusText(response, parsed),
|
|
315
335
|
data: payloadData ?? null,
|
|
316
336
|
count: payloadCount,
|
|
317
337
|
error: void 0,
|
|
@@ -331,6 +351,7 @@ async function callAthena(config, endpoint, method, payload, options) {
|
|
|
331
351
|
return {
|
|
332
352
|
ok: false,
|
|
333
353
|
status: 0,
|
|
354
|
+
statusText: null,
|
|
334
355
|
data: null,
|
|
335
356
|
error: networkError.message,
|
|
336
357
|
errorDetails: detailsFromError(networkError),
|
|
@@ -372,10 +393,29 @@ function createAthenaGatewayClient(config = {}) {
|
|
|
372
393
|
// src/sql-identifiers.ts
|
|
373
394
|
var SIMPLE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
374
395
|
var COMPOSITE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/;
|
|
375
|
-
var
|
|
396
|
+
var SQL_ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
|
|
397
|
+
var RESPONSE_ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([A-Za-z_][A-Za-z0-9_.]*)$/i;
|
|
376
398
|
function quoteIdentifierSegment(identifier2) {
|
|
377
399
|
return `"${identifier2.replace(/"/g, '""')}"`;
|
|
378
400
|
}
|
|
401
|
+
function parseAliasedIdentifierToken(token) {
|
|
402
|
+
const responseAliasMatch = RESPONSE_ALIAS_PATTERN.exec(token);
|
|
403
|
+
if (responseAliasMatch) {
|
|
404
|
+
const [, aliasIdentifier2, baseIdentifier2] = responseAliasMatch;
|
|
405
|
+
if (COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier2) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier2)) {
|
|
406
|
+
return { baseIdentifier: baseIdentifier2, aliasIdentifier: aliasIdentifier2 };
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
const sqlAliasMatch = SQL_ALIAS_PATTERN.exec(token);
|
|
410
|
+
if (!sqlAliasMatch) {
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
413
|
+
const [, baseIdentifier, aliasIdentifier] = sqlAliasMatch;
|
|
414
|
+
if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
return { baseIdentifier, aliasIdentifier };
|
|
418
|
+
}
|
|
379
419
|
function quoteQualifiedIdentifier(identifier2) {
|
|
380
420
|
return identifier2.split(".").map((segment) => quoteIdentifierSegment(segment)).join(".");
|
|
381
421
|
}
|
|
@@ -384,23 +424,27 @@ function quoteSelectToken(token) {
|
|
|
384
424
|
if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) {
|
|
385
425
|
return quoteQualifiedIdentifier(token);
|
|
386
426
|
}
|
|
387
|
-
const
|
|
388
|
-
if (!
|
|
389
|
-
return token;
|
|
390
|
-
}
|
|
391
|
-
const [, baseIdentifier, aliasIdentifier] = aliasMatch;
|
|
392
|
-
if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
|
|
427
|
+
const aliasedIdentifier = parseAliasedIdentifierToken(token);
|
|
428
|
+
if (!aliasedIdentifier) {
|
|
393
429
|
return token;
|
|
394
430
|
}
|
|
431
|
+
const { baseIdentifier, aliasIdentifier } = aliasedIdentifier;
|
|
395
432
|
return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
|
|
396
433
|
}
|
|
434
|
+
function quoteSelectColumnToken(token) {
|
|
435
|
+
const trimmed = token.trim();
|
|
436
|
+
if (!trimmed || trimmed === "*") return trimmed || "*";
|
|
437
|
+
const responseAliasMatch = RESPONSE_ALIAS_PATTERN.exec(trimmed);
|
|
438
|
+
if (responseAliasMatch) {
|
|
439
|
+
const [, aliasIdentifier, baseIdentifier] = responseAliasMatch;
|
|
440
|
+
return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
|
|
441
|
+
}
|
|
442
|
+
return quoteQualifiedIdentifier(trimmed);
|
|
443
|
+
}
|
|
397
444
|
function canAutoQuoteToken(token) {
|
|
398
445
|
if (token === "*") return true;
|
|
399
446
|
if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) return true;
|
|
400
|
-
|
|
401
|
-
if (!aliasMatch) return false;
|
|
402
|
-
const [, baseIdentifier, aliasIdentifier] = aliasMatch;
|
|
403
|
-
return COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier);
|
|
447
|
+
return parseAliasedIdentifierToken(token) != null;
|
|
404
448
|
}
|
|
405
449
|
function splitTopLevelCommaSeparated(input) {
|
|
406
450
|
const parts = [];
|
|
@@ -500,6 +544,231 @@ function identifier(...segments) {
|
|
|
500
544
|
return new SqlIdentifierPath(expandedSegments);
|
|
501
545
|
}
|
|
502
546
|
|
|
547
|
+
// src/auth/react-email.ts
|
|
548
|
+
var reactEmailRenderModulePromise;
|
|
549
|
+
function isRecord2(value) {
|
|
550
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
551
|
+
}
|
|
552
|
+
function isFunction(value) {
|
|
553
|
+
return typeof value === "function";
|
|
554
|
+
}
|
|
555
|
+
function toStringOrUndefined(value) {
|
|
556
|
+
if (typeof value !== "string") return void 0;
|
|
557
|
+
return value;
|
|
558
|
+
}
|
|
559
|
+
function nowIsoString() {
|
|
560
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
561
|
+
}
|
|
562
|
+
function emitReactEmailEvent(observe, phase, input = {}) {
|
|
563
|
+
if (!observe) return;
|
|
564
|
+
try {
|
|
565
|
+
observe({
|
|
566
|
+
phase,
|
|
567
|
+
timestamp: nowIsoString(),
|
|
568
|
+
...input
|
|
569
|
+
});
|
|
570
|
+
} catch {
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
function mergeRenderDefaults(input, defaults) {
|
|
574
|
+
return {
|
|
575
|
+
...input,
|
|
576
|
+
pretty: input.pretty ?? defaults?.pretty,
|
|
577
|
+
includePlainText: input.includePlainText ?? defaults?.includePlainText
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
function mergeRuntimeOptions(options) {
|
|
581
|
+
if (!options) return void 0;
|
|
582
|
+
return {
|
|
583
|
+
defaults: options.defaults,
|
|
584
|
+
observe: options.observe,
|
|
585
|
+
route: "route" in options ? options.route : void 0
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
async function resolveReactEmailRenderModule() {
|
|
589
|
+
if (!reactEmailRenderModulePromise) {
|
|
590
|
+
reactEmailRenderModulePromise = (async () => {
|
|
591
|
+
try {
|
|
592
|
+
const loaded = await import('@react-email/render');
|
|
593
|
+
if (!isFunction(loaded.render)) {
|
|
594
|
+
throw new Error("missing render(...) export");
|
|
595
|
+
}
|
|
596
|
+
return {
|
|
597
|
+
render: loaded.render,
|
|
598
|
+
toPlainText: isFunction(loaded.toPlainText) ? loaded.toPlainText : void 0,
|
|
599
|
+
pretty: isFunction(loaded.pretty) ? loaded.pretty : void 0
|
|
600
|
+
};
|
|
601
|
+
} catch (error) {
|
|
602
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
603
|
+
throw new Error(
|
|
604
|
+
`React Email rendering requires @react-email/render. Install it in your project (for example: pnpm add @react-email/render). Loader error: ${message}`
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
})();
|
|
608
|
+
}
|
|
609
|
+
if (!reactEmailRenderModulePromise) {
|
|
610
|
+
throw new Error("React Email renderer module failed to initialize");
|
|
611
|
+
}
|
|
612
|
+
return reactEmailRenderModulePromise;
|
|
613
|
+
}
|
|
614
|
+
async function resolveReactEmailElement(input) {
|
|
615
|
+
if (input.element != null) {
|
|
616
|
+
return input.element;
|
|
617
|
+
}
|
|
618
|
+
if (!input.component) {
|
|
619
|
+
throw new Error("react email payload requires either `element` or `component`");
|
|
620
|
+
}
|
|
621
|
+
try {
|
|
622
|
+
const reactModule = await import('react');
|
|
623
|
+
if (typeof reactModule.createElement !== "function") {
|
|
624
|
+
throw new Error("react createElement(...) export is unavailable");
|
|
625
|
+
}
|
|
626
|
+
return reactModule.createElement(
|
|
627
|
+
input.component,
|
|
628
|
+
input.props ?? {}
|
|
629
|
+
);
|
|
630
|
+
} catch (error) {
|
|
631
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
632
|
+
throw new Error(
|
|
633
|
+
`React Email component rendering requires react runtime support. Install react in your project. Loader error: ${message}`
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
function createAuthReactEmailInput(component, props, overrides = {}) {
|
|
638
|
+
return {
|
|
639
|
+
...overrides,
|
|
640
|
+
component,
|
|
641
|
+
props
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
function defineAuthEmailTemplate(definition) {
|
|
645
|
+
const react = (props, overrides) => createAuthReactEmailInput(definition.component, props, {
|
|
646
|
+
...definition.defaults,
|
|
647
|
+
...overrides
|
|
648
|
+
});
|
|
649
|
+
return {
|
|
650
|
+
component: definition.component,
|
|
651
|
+
react,
|
|
652
|
+
toTemplateCreate: (input) => {
|
|
653
|
+
const templateKey = input.templateKey ?? definition.templateKey;
|
|
654
|
+
const subjectTemplate = input.subjectTemplate ?? definition.subjectTemplate;
|
|
655
|
+
if (!templateKey) {
|
|
656
|
+
throw new Error("defineAuthEmailTemplate.toTemplateCreate requires templateKey");
|
|
657
|
+
}
|
|
658
|
+
if (!subjectTemplate) {
|
|
659
|
+
throw new Error("defineAuthEmailTemplate.toTemplateCreate requires subjectTemplate");
|
|
660
|
+
}
|
|
661
|
+
const { props, react: reactOverrides, ...rest } = input;
|
|
662
|
+
return {
|
|
663
|
+
...rest,
|
|
664
|
+
templateKey,
|
|
665
|
+
subjectTemplate,
|
|
666
|
+
react: react(props, reactOverrides)
|
|
667
|
+
};
|
|
668
|
+
},
|
|
669
|
+
toTemplateUpdate: (input) => {
|
|
670
|
+
const { props, react: reactOverrides, ...rest } = input;
|
|
671
|
+
return {
|
|
672
|
+
...rest,
|
|
673
|
+
react: react(props, reactOverrides)
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
async function renderAthenaReactEmail(input, options) {
|
|
679
|
+
if (!isRecord2(input)) {
|
|
680
|
+
throw new Error("react email payload must be an object");
|
|
681
|
+
}
|
|
682
|
+
const runtimeOptions = mergeRuntimeOptions(options);
|
|
683
|
+
const start = Date.now();
|
|
684
|
+
emitReactEmailEvent(runtimeOptions?.observe, "render:start", {
|
|
685
|
+
route: runtimeOptions?.route,
|
|
686
|
+
message: "Rendering react email payload"
|
|
687
|
+
});
|
|
688
|
+
try {
|
|
689
|
+
const normalizedInput = mergeRenderDefaults(input, runtimeOptions?.defaults);
|
|
690
|
+
const element = await resolveReactEmailElement(normalizedInput);
|
|
691
|
+
const renderModule = await resolveReactEmailRenderModule();
|
|
692
|
+
const htmlValue = await renderModule.render(element);
|
|
693
|
+
const renderedHtml = typeof htmlValue === "string" ? htmlValue : String(htmlValue ?? "");
|
|
694
|
+
if (!renderedHtml.trim()) {
|
|
695
|
+
throw new Error("react email renderer returned an empty HTML string");
|
|
696
|
+
}
|
|
697
|
+
let html = renderedHtml;
|
|
698
|
+
if (normalizedInput.pretty && renderModule.pretty) {
|
|
699
|
+
const prettyValue = await renderModule.pretty(renderedHtml);
|
|
700
|
+
if (typeof prettyValue === "string" && prettyValue.trim().length > 0) {
|
|
701
|
+
html = prettyValue;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
const explicitText = toStringOrUndefined(normalizedInput.text);
|
|
705
|
+
if (explicitText !== void 0) {
|
|
706
|
+
emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
|
|
707
|
+
route: runtimeOptions?.route,
|
|
708
|
+
durationMs: Date.now() - start,
|
|
709
|
+
message: "Rendered react email with explicit text"
|
|
710
|
+
});
|
|
711
|
+
return {
|
|
712
|
+
html,
|
|
713
|
+
text: explicitText
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
if (normalizedInput.includePlainText === false || !renderModule.toPlainText) {
|
|
717
|
+
emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
|
|
718
|
+
route: runtimeOptions?.route,
|
|
719
|
+
durationMs: Date.now() - start,
|
|
720
|
+
message: "Rendered react email without plain-text derivation"
|
|
721
|
+
});
|
|
722
|
+
return { html };
|
|
723
|
+
}
|
|
724
|
+
const plainTextValue = await renderModule.toPlainText(html);
|
|
725
|
+
const plainText = toStringOrUndefined(plainTextValue);
|
|
726
|
+
emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
|
|
727
|
+
route: runtimeOptions?.route,
|
|
728
|
+
durationMs: Date.now() - start,
|
|
729
|
+
message: plainText ? "Rendered react email with derived plain text" : "Rendered react email HTML only"
|
|
730
|
+
});
|
|
731
|
+
if (plainText === void 0) {
|
|
732
|
+
return { html };
|
|
733
|
+
}
|
|
734
|
+
return {
|
|
735
|
+
html,
|
|
736
|
+
text: plainText
|
|
737
|
+
};
|
|
738
|
+
} catch (error) {
|
|
739
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
740
|
+
emitReactEmailEvent(runtimeOptions?.observe, "render:error", {
|
|
741
|
+
route: runtimeOptions?.route,
|
|
742
|
+
durationMs: Date.now() - start,
|
|
743
|
+
error: message,
|
|
744
|
+
message: "Failed to render react email payload"
|
|
745
|
+
});
|
|
746
|
+
throw error;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
async function resolveReactEmailPayloadFields(input, fields, options) {
|
|
750
|
+
const { react, ...payloadWithoutReact } = input;
|
|
751
|
+
if (!react) {
|
|
752
|
+
return payloadWithoutReact;
|
|
753
|
+
}
|
|
754
|
+
const rendered = await renderAthenaReactEmail(react, options);
|
|
755
|
+
const payload = {
|
|
756
|
+
...payloadWithoutReact
|
|
757
|
+
};
|
|
758
|
+
payload[fields.htmlField] = rendered.html;
|
|
759
|
+
const currentTextValue = payload[fields.textField];
|
|
760
|
+
if (rendered.text !== void 0 && (currentTextValue === void 0 || currentTextValue === null || currentTextValue === "")) {
|
|
761
|
+
payload[fields.textField] = rendered.text;
|
|
762
|
+
}
|
|
763
|
+
if (fields.variablesField && (payload[fields.variablesField] === void 0 || payload[fields.variablesField] === null) && isRecord2(react.props)) {
|
|
764
|
+
const derivedVariables = Object.keys(react.props);
|
|
765
|
+
if (derivedVariables.length > 0) {
|
|
766
|
+
payload[fields.variablesField] = derivedVariables;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
return payload;
|
|
770
|
+
}
|
|
771
|
+
|
|
503
772
|
// src/auth/client.ts
|
|
504
773
|
var DEFAULT_AUTH_BASE_URL = "http://localhost:3001/api/auth";
|
|
505
774
|
var FALLBACK_SDK_VERSION2 = "1.0.0";
|
|
@@ -509,7 +778,7 @@ var SDK_HEADER_VALUE2 = `${SDK_NAME2} ${SDK_VERSION2}`;
|
|
|
509
778
|
function normalizeBaseUrl(baseUrl) {
|
|
510
779
|
return (baseUrl ?? DEFAULT_AUTH_BASE_URL).replace(/\/$/, "");
|
|
511
780
|
}
|
|
512
|
-
function
|
|
781
|
+
function isRecord3(value) {
|
|
513
782
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
514
783
|
}
|
|
515
784
|
function normalizeHeaderValue2(value) {
|
|
@@ -534,7 +803,7 @@ function resolveRequestId2(headers) {
|
|
|
534
803
|
return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
|
|
535
804
|
}
|
|
536
805
|
function resolveErrorMessage2(payload, fallback) {
|
|
537
|
-
if (
|
|
806
|
+
if (isRecord3(payload)) {
|
|
538
807
|
const messageCandidates = [payload.error, payload.message, payload.details];
|
|
539
808
|
for (const candidate of messageCandidates) {
|
|
540
809
|
if (typeof candidate === "string" && candidate.trim().length > 0) {
|
|
@@ -860,6 +1129,19 @@ function createAuthClient(config = {}) {
|
|
|
860
1129
|
options
|
|
861
1130
|
);
|
|
862
1131
|
};
|
|
1132
|
+
const withReactEmailRoute = (route) => ({
|
|
1133
|
+
...resolvedConfig.reactEmail,
|
|
1134
|
+
route
|
|
1135
|
+
});
|
|
1136
|
+
const resolveAdminEmailPayload = (route, input) => resolveReactEmailPayloadFields(input, {
|
|
1137
|
+
htmlField: "htmlBody",
|
|
1138
|
+
textField: "textBody"
|
|
1139
|
+
}, withReactEmailRoute(route));
|
|
1140
|
+
const resolveAdminEmailTemplatePayload = (route, input) => resolveReactEmailPayloadFields(input, {
|
|
1141
|
+
htmlField: "htmlTemplate",
|
|
1142
|
+
textField: "textTemplate",
|
|
1143
|
+
variablesField: "variables"
|
|
1144
|
+
}, withReactEmailRoute(route));
|
|
863
1145
|
const listUserEmailsWithFallback = async (input, options) => {
|
|
864
1146
|
const primary = await getWithQuery(
|
|
865
1147
|
"/email/list",
|
|
@@ -887,7 +1169,7 @@ function createAuthClient(config = {}) {
|
|
|
887
1169
|
data: null
|
|
888
1170
|
};
|
|
889
1171
|
}
|
|
890
|
-
const fallbackStatus =
|
|
1172
|
+
const fallbackStatus = isRecord3(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
|
|
891
1173
|
return {
|
|
892
1174
|
...fallback,
|
|
893
1175
|
data: {
|
|
@@ -1323,8 +1605,16 @@ function createAuthClient(config = {}) {
|
|
|
1323
1605
|
email: {
|
|
1324
1606
|
list: (input, options) => getWithQuery("/admin/email/list", input, options),
|
|
1325
1607
|
get: (input, options) => getWithQuery("/admin/email/get", input, options),
|
|
1326
|
-
create: (input, options) => postGeneric(
|
|
1327
|
-
|
|
1608
|
+
create: async (input, options) => postGeneric(
|
|
1609
|
+
"/admin/email/create",
|
|
1610
|
+
await resolveAdminEmailPayload("/admin/email/create", input),
|
|
1611
|
+
options
|
|
1612
|
+
),
|
|
1613
|
+
update: async (input, options) => postGeneric(
|
|
1614
|
+
"/admin/email/update",
|
|
1615
|
+
await resolveAdminEmailPayload("/admin/email/update", input),
|
|
1616
|
+
options
|
|
1617
|
+
),
|
|
1328
1618
|
delete: (input, options) => postGeneric("/admin/email/delete", input, options),
|
|
1329
1619
|
failure: {
|
|
1330
1620
|
list: (input, options) => getWithQuery("/admin/email-failure/list", input, options),
|
|
@@ -1336,17 +1626,33 @@ function createAuthClient(config = {}) {
|
|
|
1336
1626
|
template: {
|
|
1337
1627
|
list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
|
|
1338
1628
|
get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
|
|
1339
|
-
create: (input, options) => postGeneric(
|
|
1340
|
-
|
|
1629
|
+
create: async (input, options) => postGeneric(
|
|
1630
|
+
"/admin/email-template/create",
|
|
1631
|
+
await resolveAdminEmailTemplatePayload("/admin/email-template/create", input),
|
|
1632
|
+
options
|
|
1633
|
+
),
|
|
1634
|
+
update: async (input, options) => postGeneric(
|
|
1635
|
+
"/admin/email-template/update",
|
|
1636
|
+
await resolveAdminEmailTemplatePayload("/admin/email-template/update", input),
|
|
1637
|
+
options
|
|
1638
|
+
),
|
|
1341
1639
|
delete: (input, options) => postGeneric("/admin/email-template/delete", input, options)
|
|
1342
1640
|
}
|
|
1343
1641
|
},
|
|
1344
1642
|
emailTemplate: {
|
|
1345
1643
|
get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
|
|
1346
|
-
create: (input, options) => postGeneric(
|
|
1644
|
+
create: async (input, options) => postGeneric(
|
|
1645
|
+
"/admin/email-template/create",
|
|
1646
|
+
await resolveAdminEmailTemplatePayload("/admin/email-template/create", input),
|
|
1647
|
+
options
|
|
1648
|
+
),
|
|
1347
1649
|
delete: (input, options) => postGeneric("/admin/email-template/delete", input, options),
|
|
1348
1650
|
list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
|
|
1349
|
-
update: (input, options) => postGeneric(
|
|
1651
|
+
update: async (input, options) => postGeneric(
|
|
1652
|
+
"/admin/email-template/update",
|
|
1653
|
+
await resolveAdminEmailTemplatePayload("/admin/email-template/update", input),
|
|
1654
|
+
options
|
|
1655
|
+
)
|
|
1350
1656
|
}
|
|
1351
1657
|
},
|
|
1352
1658
|
apiKey: {
|
|
@@ -1538,6 +1844,19 @@ function createAuthClient(config = {}) {
|
|
|
1538
1844
|
};
|
|
1539
1845
|
}
|
|
1540
1846
|
|
|
1847
|
+
// src/utils/parse-boolean-flag.ts
|
|
1848
|
+
function parseBooleanFlag(rawValue, fallback) {
|
|
1849
|
+
if (!rawValue) return fallback;
|
|
1850
|
+
const normalized = rawValue.trim().toLowerCase();
|
|
1851
|
+
if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
|
|
1852
|
+
return true;
|
|
1853
|
+
}
|
|
1854
|
+
if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
|
|
1855
|
+
return false;
|
|
1856
|
+
}
|
|
1857
|
+
return fallback;
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1541
1860
|
// src/auxiliaries.ts
|
|
1542
1861
|
var AthenaErrorKind = {
|
|
1543
1862
|
UniqueViolation: "unique_violation",
|
|
@@ -1567,16 +1886,8 @@ var AthenaErrorCategory = {
|
|
|
1567
1886
|
Database: "database",
|
|
1568
1887
|
Unknown: "unknown"
|
|
1569
1888
|
};
|
|
1570
|
-
function
|
|
1571
|
-
|
|
1572
|
-
const normalized = rawValue.trim().toLowerCase();
|
|
1573
|
-
if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
|
|
1574
|
-
return true;
|
|
1575
|
-
}
|
|
1576
|
-
if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
|
|
1577
|
-
return false;
|
|
1578
|
-
}
|
|
1579
|
-
return fallback;
|
|
1889
|
+
function parseBooleanFlag2(rawValue, fallback) {
|
|
1890
|
+
return parseBooleanFlag(rawValue, fallback);
|
|
1580
1891
|
}
|
|
1581
1892
|
var AthenaError = class extends Error {
|
|
1582
1893
|
code;
|
|
@@ -1600,9 +1911,38 @@ var AthenaError = class extends Error {
|
|
|
1600
1911
|
this.raw = input.raw;
|
|
1601
1912
|
}
|
|
1602
1913
|
};
|
|
1603
|
-
function
|
|
1914
|
+
function isRecord4(value) {
|
|
1604
1915
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1605
1916
|
}
|
|
1917
|
+
function firstNonEmptyString(...values) {
|
|
1918
|
+
for (const value of values) {
|
|
1919
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
1920
|
+
return value.trim();
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
return void 0;
|
|
1924
|
+
}
|
|
1925
|
+
function messageFromUnknownError(error) {
|
|
1926
|
+
if (typeof error === "string" && error.trim().length > 0) {
|
|
1927
|
+
return error.trim();
|
|
1928
|
+
}
|
|
1929
|
+
if (error instanceof Error && error.message.trim().length > 0) {
|
|
1930
|
+
return error.message.trim();
|
|
1931
|
+
}
|
|
1932
|
+
if (!isRecord4(error)) {
|
|
1933
|
+
return void 0;
|
|
1934
|
+
}
|
|
1935
|
+
return firstNonEmptyString(error.message, error.error, error.details);
|
|
1936
|
+
}
|
|
1937
|
+
function gatewayCodeFromUnknownError(error) {
|
|
1938
|
+
if (!isRecord4(error) || typeof error.gatewayCode !== "string") {
|
|
1939
|
+
return void 0;
|
|
1940
|
+
}
|
|
1941
|
+
return error.gatewayCode;
|
|
1942
|
+
}
|
|
1943
|
+
function isAthenaResultErrorLike(value) {
|
|
1944
|
+
return isRecord4(value) && typeof value.message === "string" && (value.athenaCode === void 0 || isAthenaErrorCode(value.athenaCode)) && (value.kind === void 0 || isAthenaErrorKind(value.kind)) && (value.category === void 0 || isAthenaErrorCategory(value.category)) && (value.retryable === void 0 || typeof value.retryable === "boolean") && (value.status === void 0 || typeof value.status === "number");
|
|
1945
|
+
}
|
|
1606
1946
|
function isAthenaErrorKind(value) {
|
|
1607
1947
|
return value === "unique_violation" || value === "not_found" || value === "validation" || value === "auth" || value === "rate_limit" || value === "transient" || value === "unknown";
|
|
1608
1948
|
}
|
|
@@ -1613,7 +1953,7 @@ function isAthenaErrorCategory(value) {
|
|
|
1613
1953
|
return value === "transport" || value === "client" || value === "server" || value === "database" || value === "unknown";
|
|
1614
1954
|
}
|
|
1615
1955
|
function isNormalizedAthenaError(value) {
|
|
1616
|
-
return
|
|
1956
|
+
return isRecord4(value) && isAthenaErrorKind(value.kind) && isAthenaErrorCode(value.code) && isAthenaErrorCategory(value.category) && typeof value.retryable === "boolean" && typeof value.message === "string" && "raw" in value;
|
|
1617
1957
|
}
|
|
1618
1958
|
function withContextOverrides(normalized, context) {
|
|
1619
1959
|
if (!context?.table && !context?.operation) {
|
|
@@ -1626,7 +1966,7 @@ function withContextOverrides(normalized, context) {
|
|
|
1626
1966
|
};
|
|
1627
1967
|
}
|
|
1628
1968
|
function resolveAttachedNormalizedError(resultOrError) {
|
|
1629
|
-
if (!
|
|
1969
|
+
if (!isRecord4(resultOrError)) return void 0;
|
|
1630
1970
|
if (!("__athenaNormalizedError" in resultOrError)) return void 0;
|
|
1631
1971
|
const candidate = resultOrError.__athenaNormalizedError;
|
|
1632
1972
|
return isNormalizedAthenaError(candidate) ? candidate : void 0;
|
|
@@ -1645,7 +1985,7 @@ function contextHint(context) {
|
|
|
1645
1985
|
return `Identity: ${identity}`;
|
|
1646
1986
|
}
|
|
1647
1987
|
function isAthenaResultLike(value) {
|
|
1648
|
-
return
|
|
1988
|
+
return isRecord4(value) && "status" in value && "error" in value && "data" in value && typeof value.status === "number";
|
|
1649
1989
|
}
|
|
1650
1990
|
function operationFromDetails(details) {
|
|
1651
1991
|
if (!details?.endpoint) return void 0;
|
|
@@ -1742,15 +2082,16 @@ function toAthenaGatewayError(source, fallbackMessage, context) {
|
|
|
1742
2082
|
return source;
|
|
1743
2083
|
}
|
|
1744
2084
|
if (isAthenaResultLike(source) && source.errorDetails) {
|
|
2085
|
+
const message2 = messageFromUnknownError(source.error) ?? source.errorDetails.message ?? fallbackMessage;
|
|
1745
2086
|
return new AthenaGatewayError({
|
|
1746
2087
|
code: source.errorDetails.code,
|
|
1747
|
-
message:
|
|
2088
|
+
message: message2,
|
|
1748
2089
|
status: source.status,
|
|
1749
2090
|
endpoint: source.errorDetails.endpoint,
|
|
1750
2091
|
method: source.errorDetails.method,
|
|
1751
2092
|
requestId: source.errorDetails.requestId,
|
|
1752
|
-
hint: source.errorDetails.hint,
|
|
1753
|
-
cause: source.errorDetails.cause
|
|
2093
|
+
hint: (isRecord4(source.error) ? firstNonEmptyString(source.error.hint) : void 0) ?? source.errorDetails.hint,
|
|
2094
|
+
cause: (isRecord4(source.error) ? firstNonEmptyString(source.error.cause) : void 0) ?? source.errorDetails.cause
|
|
1754
2095
|
});
|
|
1755
2096
|
}
|
|
1756
2097
|
const normalized = normalizeAthenaError(source, context);
|
|
@@ -1772,13 +2113,50 @@ function normalizeAthenaError(resultOrError, context) {
|
|
|
1772
2113
|
return withContextOverrides(attached, context);
|
|
1773
2114
|
}
|
|
1774
2115
|
if (isAthenaResultLike(resultOrError)) {
|
|
2116
|
+
if (isAthenaResultErrorLike(resultOrError.error)) {
|
|
2117
|
+
return {
|
|
2118
|
+
kind: resultOrError.error.kind ?? classifyKind(resultOrError.status, gatewayCodeFromUnknownError(resultOrError.error), resultOrError.error.message),
|
|
2119
|
+
code: resultOrError.error.athenaCode ?? toAthenaErrorCode(
|
|
2120
|
+
resultOrError.error.kind ?? classifyKind(
|
|
2121
|
+
resultOrError.status,
|
|
2122
|
+
gatewayCodeFromUnknownError(resultOrError.error),
|
|
2123
|
+
resultOrError.error.message
|
|
2124
|
+
),
|
|
2125
|
+
resultOrError.error.status ?? resultOrError.status,
|
|
2126
|
+
gatewayCodeFromUnknownError(resultOrError.error)
|
|
2127
|
+
),
|
|
2128
|
+
category: resultOrError.error.category ?? toAthenaErrorCategory(
|
|
2129
|
+
resultOrError.error.kind ?? classifyKind(
|
|
2130
|
+
resultOrError.status,
|
|
2131
|
+
gatewayCodeFromUnknownError(resultOrError.error),
|
|
2132
|
+
resultOrError.error.message
|
|
2133
|
+
),
|
|
2134
|
+
resultOrError.error.status ?? resultOrError.status
|
|
2135
|
+
),
|
|
2136
|
+
retryable: resultOrError.error.retryable ?? isRetryable(
|
|
2137
|
+
resultOrError.error.kind ?? classifyKind(
|
|
2138
|
+
resultOrError.status,
|
|
2139
|
+
gatewayCodeFromUnknownError(resultOrError.error),
|
|
2140
|
+
resultOrError.error.message
|
|
2141
|
+
),
|
|
2142
|
+
resultOrError.error.status ?? resultOrError.status
|
|
2143
|
+
),
|
|
2144
|
+
status: resultOrError.error.status ?? resultOrError.status,
|
|
2145
|
+
constraint: resultOrError.error.constraint,
|
|
2146
|
+
table: context?.table ?? resultOrError.error.table,
|
|
2147
|
+
operation: context?.operation ?? resultOrError.error.operation,
|
|
2148
|
+
message: resultOrError.error.message,
|
|
2149
|
+
raw: resultOrError.error.raw ?? resultOrError.raw
|
|
2150
|
+
};
|
|
2151
|
+
}
|
|
1775
2152
|
const details = resultOrError.errorDetails;
|
|
1776
|
-
const message2 = resultOrError.error ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
|
|
2153
|
+
const message2 = messageFromUnknownError(resultOrError.error) ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
|
|
1777
2154
|
const operation = context?.operation ?? operationFromDetails(details);
|
|
1778
2155
|
const table = context?.table ?? extractTable(message2);
|
|
1779
2156
|
const constraint = extractConstraint(message2);
|
|
1780
|
-
const
|
|
1781
|
-
const
|
|
2157
|
+
const gatewayCode = details?.code ?? gatewayCodeFromUnknownError(resultOrError.error);
|
|
2158
|
+
const kind2 = classifyKind(resultOrError.status, gatewayCode, message2);
|
|
2159
|
+
const code = toAthenaErrorCode(kind2, resultOrError.status, gatewayCode);
|
|
1782
2160
|
const category = toAthenaErrorCategory(kind2, resultOrError.status);
|
|
1783
2161
|
return {
|
|
1784
2162
|
kind: kind2,
|
|
@@ -1815,7 +2193,7 @@ function normalizeAthenaError(resultOrError, context) {
|
|
|
1815
2193
|
};
|
|
1816
2194
|
}
|
|
1817
2195
|
if (resultOrError instanceof Error) {
|
|
1818
|
-
const maybeStatus =
|
|
2196
|
+
const maybeStatus = isRecord4(resultOrError) && typeof resultOrError.status === "number" ? resultOrError.status : void 0;
|
|
1819
2197
|
const kind2 = classifyKind(maybeStatus, void 0, resultOrError.message);
|
|
1820
2198
|
return {
|
|
1821
2199
|
kind: kind2,
|
|
@@ -2032,45 +2410,527 @@ function createDbModule(input) {
|
|
|
2032
2410
|
return db;
|
|
2033
2411
|
}
|
|
2034
2412
|
|
|
2413
|
+
// src/query-ast.ts
|
|
2414
|
+
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
2415
|
+
var FILTER_OPERATORS = /* @__PURE__ */ new Set([
|
|
2416
|
+
"eq",
|
|
2417
|
+
"neq",
|
|
2418
|
+
"gt",
|
|
2419
|
+
"gte",
|
|
2420
|
+
"lt",
|
|
2421
|
+
"lte",
|
|
2422
|
+
"like",
|
|
2423
|
+
"ilike",
|
|
2424
|
+
"is",
|
|
2425
|
+
"in",
|
|
2426
|
+
"contains",
|
|
2427
|
+
"containedBy"
|
|
2428
|
+
]);
|
|
2429
|
+
var BOOLEAN_SAFE_OPERATORS = /* @__PURE__ */ new Set([
|
|
2430
|
+
"eq",
|
|
2431
|
+
"neq",
|
|
2432
|
+
"gt",
|
|
2433
|
+
"gte",
|
|
2434
|
+
"lt",
|
|
2435
|
+
"lte",
|
|
2436
|
+
"like",
|
|
2437
|
+
"ilike",
|
|
2438
|
+
"is"
|
|
2439
|
+
]);
|
|
2440
|
+
function isRecord5(value) {
|
|
2441
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2442
|
+
}
|
|
2443
|
+
function isUuidString(value) {
|
|
2444
|
+
return UUID_PATTERN.test(value.trim());
|
|
2445
|
+
}
|
|
2446
|
+
function isUuidIdentifierColumn(column) {
|
|
2447
|
+
return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
|
|
2448
|
+
}
|
|
2449
|
+
function shouldUseUuidTextComparison(column, value) {
|
|
2450
|
+
return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
|
|
2451
|
+
}
|
|
2452
|
+
function isRelationSelectNode(value) {
|
|
2453
|
+
return isRecord5(value) && isRecord5(value.select);
|
|
2454
|
+
}
|
|
2455
|
+
function normalizeIdentifier(value, label) {
|
|
2456
|
+
const normalized = value.trim();
|
|
2457
|
+
if (!normalized) {
|
|
2458
|
+
throw new Error(`${label} must be a non-empty string`);
|
|
2459
|
+
}
|
|
2460
|
+
return normalized;
|
|
2461
|
+
}
|
|
2462
|
+
function stringifyFilterValue(value) {
|
|
2463
|
+
if (Array.isArray(value)) {
|
|
2464
|
+
return value.join(",");
|
|
2465
|
+
}
|
|
2466
|
+
return String(value);
|
|
2467
|
+
}
|
|
2468
|
+
function buildGatewayCondition(operator, column, value) {
|
|
2469
|
+
const condition = { operator };
|
|
2470
|
+
if (column) {
|
|
2471
|
+
condition.column = column;
|
|
2472
|
+
if (operator === "eq") {
|
|
2473
|
+
condition.eq_column = column;
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
if (value !== void 0) {
|
|
2477
|
+
condition.value = value;
|
|
2478
|
+
if (operator === "eq") {
|
|
2479
|
+
condition.eq_value = value;
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
if (operator === "eq" && column && value !== void 0 && shouldUseUuidTextComparison(column, value)) {
|
|
2483
|
+
condition.column_cast = "text";
|
|
2484
|
+
condition.eq_column_cast = "text";
|
|
2485
|
+
}
|
|
2486
|
+
return condition;
|
|
2487
|
+
}
|
|
2488
|
+
function compileRelationToken(key, node) {
|
|
2489
|
+
const nested = compileSelectShape(node.select);
|
|
2490
|
+
const propertyKey = normalizeIdentifier(key, "select relation key");
|
|
2491
|
+
const relationToken = normalizeIdentifier(node.via ?? propertyKey, "select relation token");
|
|
2492
|
+
const alias = node.as?.trim() || (relationToken !== propertyKey ? propertyKey : "");
|
|
2493
|
+
const prefix = alias ? `${alias}:` : "";
|
|
2494
|
+
return `${prefix}${relationToken}(${nested})`;
|
|
2495
|
+
}
|
|
2496
|
+
function compileSelectShape(select) {
|
|
2497
|
+
if (!isRecord5(select)) {
|
|
2498
|
+
throw new Error("findMany select must be an object");
|
|
2499
|
+
}
|
|
2500
|
+
const tokens = [];
|
|
2501
|
+
for (const [rawKey, rawValue] of Object.entries(select)) {
|
|
2502
|
+
if (rawValue === void 0) {
|
|
2503
|
+
continue;
|
|
2504
|
+
}
|
|
2505
|
+
if (rawValue === true) {
|
|
2506
|
+
tokens.push(normalizeIdentifier(rawKey, "select column"));
|
|
2507
|
+
continue;
|
|
2508
|
+
}
|
|
2509
|
+
if (isRelationSelectNode(rawValue)) {
|
|
2510
|
+
tokens.push(compileRelationToken(rawKey, rawValue));
|
|
2511
|
+
continue;
|
|
2512
|
+
}
|
|
2513
|
+
throw new Error(`Unsupported select node for "${rawKey}"`);
|
|
2514
|
+
}
|
|
2515
|
+
if (tokens.length === 0) {
|
|
2516
|
+
throw new Error("findMany select requires at least one field");
|
|
2517
|
+
}
|
|
2518
|
+
return tokens.join(",");
|
|
2519
|
+
}
|
|
2520
|
+
function compileColumnWhere(column, input) {
|
|
2521
|
+
const normalizedColumn = normalizeIdentifier(column, "where column");
|
|
2522
|
+
if (!isRecord5(input)) {
|
|
2523
|
+
return [buildGatewayCondition("eq", normalizedColumn, input)];
|
|
2524
|
+
}
|
|
2525
|
+
const conditions = [];
|
|
2526
|
+
for (const [rawOperator, rawValue] of Object.entries(input)) {
|
|
2527
|
+
if (rawValue === void 0) {
|
|
2528
|
+
continue;
|
|
2529
|
+
}
|
|
2530
|
+
if (!FILTER_OPERATORS.has(rawOperator)) {
|
|
2531
|
+
throw new Error(`Unsupported where operator "${rawOperator}" on "${normalizedColumn}"`);
|
|
2532
|
+
}
|
|
2533
|
+
if ((rawOperator === "in" || rawOperator === "contains" || rawOperator === "containedBy") && !Array.isArray(rawValue)) {
|
|
2534
|
+
throw new Error(`where.${normalizedColumn}.${rawOperator} requires an array value`);
|
|
2535
|
+
}
|
|
2536
|
+
conditions.push(
|
|
2537
|
+
buildGatewayCondition(
|
|
2538
|
+
rawOperator,
|
|
2539
|
+
normalizedColumn,
|
|
2540
|
+
rawValue
|
|
2541
|
+
)
|
|
2542
|
+
);
|
|
2543
|
+
}
|
|
2544
|
+
if (conditions.length === 0) {
|
|
2545
|
+
throw new Error(`where.${normalizedColumn} requires at least one operator`);
|
|
2546
|
+
}
|
|
2547
|
+
return conditions;
|
|
2548
|
+
}
|
|
2549
|
+
function compileBooleanExpressionTerms(clause, label) {
|
|
2550
|
+
if (!isRecord5(clause)) {
|
|
2551
|
+
throw new Error(`findMany where.${label} clauses must be objects`);
|
|
2552
|
+
}
|
|
2553
|
+
const entries = Object.entries(clause).filter(([, value]) => value !== void 0);
|
|
2554
|
+
if (entries.length !== 1) {
|
|
2555
|
+
throw new Error(`findMany where.${label} clauses must target exactly one column`);
|
|
2556
|
+
}
|
|
2557
|
+
const [rawColumn, rawValue] = entries[0];
|
|
2558
|
+
const column = normalizeIdentifier(rawColumn, `where.${label} column`);
|
|
2559
|
+
if (!isRecord5(rawValue)) {
|
|
2560
|
+
return [`${column}.eq.${stringifyFilterValue(rawValue)}`];
|
|
2561
|
+
}
|
|
2562
|
+
const operatorEntries = Object.entries(rawValue).filter(([, value]) => value !== void 0);
|
|
2563
|
+
if (operatorEntries.length === 0) {
|
|
2564
|
+
throw new Error(`findMany where.${label}.${column} requires at least one operator`);
|
|
2565
|
+
}
|
|
2566
|
+
if (label === "not" && operatorEntries.length > 1) {
|
|
2567
|
+
throw new Error("findMany where.not only supports a single lossless operator expression");
|
|
2568
|
+
}
|
|
2569
|
+
return operatorEntries.map(([rawOperator, rawOperand]) => {
|
|
2570
|
+
if (!BOOLEAN_SAFE_OPERATORS.has(rawOperator)) {
|
|
2571
|
+
throw new Error(`findMany where.${label} only supports lossless scalar operators`);
|
|
2572
|
+
}
|
|
2573
|
+
if (Array.isArray(rawOperand)) {
|
|
2574
|
+
throw new Error(`findMany where.${label} does not support array-valued operators`);
|
|
2575
|
+
}
|
|
2576
|
+
return `${column}.${rawOperator}.${stringifyFilterValue(rawOperand)}`;
|
|
2577
|
+
});
|
|
2578
|
+
}
|
|
2579
|
+
function compileWhere(where) {
|
|
2580
|
+
if (where === void 0) {
|
|
2581
|
+
return void 0;
|
|
2582
|
+
}
|
|
2583
|
+
if (!isRecord5(where)) {
|
|
2584
|
+
throw new Error("findMany where must be an object");
|
|
2585
|
+
}
|
|
2586
|
+
const conditions = [];
|
|
2587
|
+
for (const [rawKey, rawValue] of Object.entries(where)) {
|
|
2588
|
+
if (rawValue === void 0) {
|
|
2589
|
+
continue;
|
|
2590
|
+
}
|
|
2591
|
+
if (rawKey === "or") {
|
|
2592
|
+
if (!Array.isArray(rawValue) || rawValue.length === 0) {
|
|
2593
|
+
throw new Error("findMany where.or must be a non-empty array");
|
|
2594
|
+
}
|
|
2595
|
+
const expressions = rawValue.flatMap(
|
|
2596
|
+
(value) => compileBooleanExpressionTerms(value, "or")
|
|
2597
|
+
);
|
|
2598
|
+
conditions.push(buildGatewayCondition("or", void 0, expressions.join(",")));
|
|
2599
|
+
continue;
|
|
2600
|
+
}
|
|
2601
|
+
if (rawKey === "not") {
|
|
2602
|
+
const expressions = compileBooleanExpressionTerms(rawValue, "not");
|
|
2603
|
+
if (expressions.length !== 1) {
|
|
2604
|
+
throw new Error("findMany where.not must compile to exactly one lossless expression");
|
|
2605
|
+
}
|
|
2606
|
+
conditions.push(buildGatewayCondition("not", void 0, expressions[0]));
|
|
2607
|
+
continue;
|
|
2608
|
+
}
|
|
2609
|
+
conditions.push(...compileColumnWhere(rawKey, rawValue));
|
|
2610
|
+
}
|
|
2611
|
+
return conditions.length > 0 ? conditions : void 0;
|
|
2612
|
+
}
|
|
2613
|
+
function resolveOrderDirection(input) {
|
|
2614
|
+
if (typeof input === "boolean") {
|
|
2615
|
+
return input === false ? "descending" : "ascending";
|
|
2616
|
+
}
|
|
2617
|
+
if (typeof input === "string") {
|
|
2618
|
+
const normalized = input.trim().toLowerCase();
|
|
2619
|
+
if (normalized === "asc" || normalized === "ascending") {
|
|
2620
|
+
return "ascending";
|
|
2621
|
+
}
|
|
2622
|
+
if (normalized === "desc" || normalized === "descending") {
|
|
2623
|
+
return "descending";
|
|
2624
|
+
}
|
|
2625
|
+
throw new Error(`Unsupported orderBy direction "${input}"`);
|
|
2626
|
+
}
|
|
2627
|
+
return input.ascending === false ? "descending" : "ascending";
|
|
2628
|
+
}
|
|
2629
|
+
function compileOrderBy(orderBy) {
|
|
2630
|
+
if (orderBy === void 0) {
|
|
2631
|
+
return void 0;
|
|
2632
|
+
}
|
|
2633
|
+
if (!isRecord5(orderBy)) {
|
|
2634
|
+
throw new Error("findMany orderBy must be an object");
|
|
2635
|
+
}
|
|
2636
|
+
if ("column" in orderBy) {
|
|
2637
|
+
return {
|
|
2638
|
+
field: normalizeIdentifier(String(orderBy.column), "orderBy column"),
|
|
2639
|
+
direction: orderBy.ascending === false ? "descending" : "ascending"
|
|
2640
|
+
};
|
|
2641
|
+
}
|
|
2642
|
+
const entries = Object.entries(orderBy).filter(([, value]) => value !== void 0);
|
|
2643
|
+
if (entries.length === 0) {
|
|
2644
|
+
return void 0;
|
|
2645
|
+
}
|
|
2646
|
+
if (entries.length > 1) {
|
|
2647
|
+
throw new Error("findMany orderBy only supports a single column in v1");
|
|
2648
|
+
}
|
|
2649
|
+
const [column, input] = entries[0];
|
|
2650
|
+
return {
|
|
2651
|
+
field: normalizeIdentifier(column, "orderBy column"),
|
|
2652
|
+
direction: resolveOrderDirection(input)
|
|
2653
|
+
};
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2035
2656
|
// src/client.ts
|
|
2036
2657
|
var DEFAULT_COLUMNS = "*";
|
|
2037
|
-
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
2038
2658
|
var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
|
|
2039
2659
|
var ATHENA_NORMALIZED_ERROR_KEY = "__athenaNormalizedError";
|
|
2660
|
+
var QUERY_TRACE_STACK_SKIP_PATTERNS = [
|
|
2661
|
+
"src\\client.ts",
|
|
2662
|
+
"src/client.ts",
|
|
2663
|
+
"dist\\client.",
|
|
2664
|
+
"dist/client.",
|
|
2665
|
+
"node_modules\\@xylex-group\\athena",
|
|
2666
|
+
"node_modules/@xylex-group/athena",
|
|
2667
|
+
"node:internal",
|
|
2668
|
+
"internal/process"
|
|
2669
|
+
];
|
|
2670
|
+
function canUseFindManyAstTransport(state) {
|
|
2671
|
+
return state.conditions.length === 0 && state.offset === void 0 && state.currentPage === void 0 && state.pageSize === void 0 && state.totalPages === void 0;
|
|
2672
|
+
}
|
|
2673
|
+
function toFindManyAstOrder(order) {
|
|
2674
|
+
if (!order) {
|
|
2675
|
+
return void 0;
|
|
2676
|
+
}
|
|
2677
|
+
return {
|
|
2678
|
+
column: order.field,
|
|
2679
|
+
ascending: order.direction !== "descending"
|
|
2680
|
+
};
|
|
2681
|
+
}
|
|
2040
2682
|
function formatResult(response) {
|
|
2041
2683
|
const result = {
|
|
2042
2684
|
data: response.data ?? null,
|
|
2043
|
-
error:
|
|
2685
|
+
error: null,
|
|
2044
2686
|
errorDetails: response.errorDetails ?? null,
|
|
2045
2687
|
status: response.status,
|
|
2688
|
+
statusText: response.statusText ?? null,
|
|
2046
2689
|
raw: response.raw
|
|
2047
2690
|
};
|
|
2048
|
-
if (response.count !== void 0) {
|
|
2049
|
-
result.count = response.count;
|
|
2050
|
-
}
|
|
2051
|
-
return result;
|
|
2052
|
-
}
|
|
2053
|
-
function attachNormalizedError(result, normalizedError) {
|
|
2054
|
-
Object.defineProperty(result, ATHENA_NORMALIZED_ERROR_KEY, {
|
|
2055
|
-
value: normalizedError,
|
|
2056
|
-
enumerable: false,
|
|
2057
|
-
configurable: true,
|
|
2058
|
-
writable: false
|
|
2059
|
-
});
|
|
2691
|
+
if (response.count !== void 0) {
|
|
2692
|
+
result.count = response.count;
|
|
2693
|
+
}
|
|
2694
|
+
return result;
|
|
2695
|
+
}
|
|
2696
|
+
function attachNormalizedError(result, normalizedError) {
|
|
2697
|
+
Object.defineProperty(result, ATHENA_NORMALIZED_ERROR_KEY, {
|
|
2698
|
+
value: normalizedError,
|
|
2699
|
+
enumerable: false,
|
|
2700
|
+
configurable: true,
|
|
2701
|
+
writable: false
|
|
2702
|
+
});
|
|
2703
|
+
}
|
|
2704
|
+
function createResultFormatter(experimental) {
|
|
2705
|
+
return (response, context) => {
|
|
2706
|
+
const result = formatResult(response);
|
|
2707
|
+
if (response.error == null && response.errorDetails == null) {
|
|
2708
|
+
return result;
|
|
2709
|
+
}
|
|
2710
|
+
const normalizedError = normalizeAthenaError(
|
|
2711
|
+
{
|
|
2712
|
+
...result,
|
|
2713
|
+
error: response.error ?? response.errorDetails?.message ?? null
|
|
2714
|
+
},
|
|
2715
|
+
context
|
|
2716
|
+
);
|
|
2717
|
+
result.error = createResultError(response, result, normalizedError);
|
|
2718
|
+
attachNormalizedError(result, normalizedError);
|
|
2719
|
+
return result;
|
|
2720
|
+
};
|
|
2721
|
+
}
|
|
2722
|
+
function isRecord6(value) {
|
|
2723
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2724
|
+
}
|
|
2725
|
+
function firstNonEmptyString2(...values) {
|
|
2726
|
+
for (const value of values) {
|
|
2727
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
2728
|
+
return value.trim();
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
return void 0;
|
|
2732
|
+
}
|
|
2733
|
+
function resolveStructuredErrorPayload2(raw) {
|
|
2734
|
+
if (!isRecord6(raw)) return null;
|
|
2735
|
+
return isRecord6(raw.error) ? raw.error : raw;
|
|
2736
|
+
}
|
|
2737
|
+
function resolveStructuredErrorDetails(payload, message) {
|
|
2738
|
+
if (!payload || !("details" in payload)) {
|
|
2739
|
+
return null;
|
|
2740
|
+
}
|
|
2741
|
+
const details = payload.details;
|
|
2742
|
+
if (details == null) {
|
|
2743
|
+
return null;
|
|
2744
|
+
}
|
|
2745
|
+
if (typeof details === "string" && details.trim() === message.trim()) {
|
|
2746
|
+
return null;
|
|
2747
|
+
}
|
|
2748
|
+
return details;
|
|
2749
|
+
}
|
|
2750
|
+
function createResultError(response, result, normalized) {
|
|
2751
|
+
const rawRecord = isRecord6(response.raw) ? response.raw : null;
|
|
2752
|
+
const payload = resolveStructuredErrorPayload2(response.raw);
|
|
2753
|
+
const message = firstNonEmptyString2(
|
|
2754
|
+
response.error,
|
|
2755
|
+
payload?.message,
|
|
2756
|
+
payload?.error,
|
|
2757
|
+
payload?.details,
|
|
2758
|
+
response.errorDetails?.message,
|
|
2759
|
+
normalized.message
|
|
2760
|
+
) ?? normalized.message;
|
|
2761
|
+
const statusText = firstNonEmptyString2(response.statusText, rawRecord?.statusText) ?? null;
|
|
2762
|
+
const hint = firstNonEmptyString2(payload?.hint, response.errorDetails?.hint) ?? null;
|
|
2763
|
+
const code = firstNonEmptyString2(payload?.code) ?? normalized.code;
|
|
2764
|
+
const details = resolveStructuredErrorDetails(payload, message) ?? response.errorDetails?.cause ?? null;
|
|
2765
|
+
return {
|
|
2766
|
+
message,
|
|
2767
|
+
code,
|
|
2768
|
+
athenaCode: normalized.code,
|
|
2769
|
+
gatewayCode: response.errorDetails?.code ?? null,
|
|
2770
|
+
kind: normalized.kind,
|
|
2771
|
+
category: normalized.category,
|
|
2772
|
+
retryable: normalized.retryable,
|
|
2773
|
+
details,
|
|
2774
|
+
hint,
|
|
2775
|
+
status: result.status,
|
|
2776
|
+
statusText,
|
|
2777
|
+
constraint: normalized.constraint,
|
|
2778
|
+
table: normalized.table,
|
|
2779
|
+
operation: normalized.operation,
|
|
2780
|
+
endpoint: response.errorDetails?.endpoint,
|
|
2781
|
+
method: response.errorDetails?.method,
|
|
2782
|
+
requestId: response.errorDetails?.requestId,
|
|
2783
|
+
cause: response.errorDetails?.cause,
|
|
2784
|
+
raw: result.raw
|
|
2785
|
+
};
|
|
2786
|
+
}
|
|
2787
|
+
function parseQueryTraceCallsiteFrame(frame) {
|
|
2788
|
+
const trimmed = frame.trim();
|
|
2789
|
+
if (!trimmed) {
|
|
2790
|
+
return null;
|
|
2791
|
+
}
|
|
2792
|
+
let body = trimmed.replace(/^at\s+/, "");
|
|
2793
|
+
if (body.startsWith("async ")) {
|
|
2794
|
+
body = body.slice(6);
|
|
2795
|
+
}
|
|
2796
|
+
let functionName;
|
|
2797
|
+
let location = body;
|
|
2798
|
+
const wrappedMatch = body.match(/^(.*?)\s+\((.*)\)$/);
|
|
2799
|
+
if (wrappedMatch) {
|
|
2800
|
+
functionName = wrappedMatch[1].trim() || void 0;
|
|
2801
|
+
location = wrappedMatch[2].trim();
|
|
2802
|
+
}
|
|
2803
|
+
const locationMatch = location.match(/^(.*):(\d+):(\d+)$/);
|
|
2804
|
+
if (!locationMatch) {
|
|
2805
|
+
return null;
|
|
2806
|
+
}
|
|
2807
|
+
const filePath = locationMatch[1].replace(/^file:\/\//, "");
|
|
2808
|
+
const line = Number(locationMatch[2]);
|
|
2809
|
+
const column = Number(locationMatch[3]);
|
|
2810
|
+
if (!Number.isFinite(line) || !Number.isFinite(column)) {
|
|
2811
|
+
return null;
|
|
2812
|
+
}
|
|
2813
|
+
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
2814
|
+
const fileName = normalizedPath.split("/").at(-1) ?? filePath;
|
|
2815
|
+
return {
|
|
2816
|
+
filePath,
|
|
2817
|
+
fileName,
|
|
2818
|
+
line,
|
|
2819
|
+
column,
|
|
2820
|
+
frame: trimmed,
|
|
2821
|
+
functionName
|
|
2822
|
+
};
|
|
2823
|
+
}
|
|
2824
|
+
function captureQueryTraceCallsite() {
|
|
2825
|
+
const stack = new Error().stack;
|
|
2826
|
+
if (!stack) return null;
|
|
2827
|
+
const frames = stack.split("\n").slice(2).map((frame) => frame.trim()).filter(Boolean);
|
|
2828
|
+
for (const frame of frames) {
|
|
2829
|
+
if (QUERY_TRACE_STACK_SKIP_PATTERNS.some((pattern) => frame.includes(pattern))) {
|
|
2830
|
+
continue;
|
|
2831
|
+
}
|
|
2832
|
+
const callsite = parseQueryTraceCallsiteFrame(frame);
|
|
2833
|
+
if (callsite) return callsite;
|
|
2834
|
+
}
|
|
2835
|
+
const fallback = frames.find((frame) => !frame.includes("captureQueryTraceCallsite"));
|
|
2836
|
+
return fallback ? parseQueryTraceCallsiteFrame(fallback) : null;
|
|
2837
|
+
}
|
|
2838
|
+
function defaultQueryTraceLogger(event) {
|
|
2839
|
+
const target = event.table ?? event.functionName ?? "gateway";
|
|
2840
|
+
const outcomeState = event.outcome?.error ? "error" : "ok";
|
|
2841
|
+
const banner = `[athena-js][trace] ${event.operation.toUpperCase()} ${event.endpoint} ${target} ${event.durationMs}ms ${outcomeState}`;
|
|
2842
|
+
console.info(banner, event);
|
|
2843
|
+
}
|
|
2844
|
+
function captureTraceCallsite(tracer) {
|
|
2845
|
+
return tracer?.captureCallsite() ?? null;
|
|
2846
|
+
}
|
|
2847
|
+
function createTraceCallsiteStore(tracer, initialCallsite) {
|
|
2848
|
+
let storedCallsite = initialCallsite ?? void 0;
|
|
2849
|
+
return {
|
|
2850
|
+
resolve(callsite) {
|
|
2851
|
+
if (callsite) {
|
|
2852
|
+
storedCallsite = callsite;
|
|
2853
|
+
return callsite;
|
|
2854
|
+
}
|
|
2855
|
+
if (storedCallsite !== void 0) {
|
|
2856
|
+
return storedCallsite;
|
|
2857
|
+
}
|
|
2858
|
+
const capturedCallsite = captureTraceCallsite(tracer);
|
|
2859
|
+
if (capturedCallsite) {
|
|
2860
|
+
storedCallsite = capturedCallsite;
|
|
2861
|
+
}
|
|
2862
|
+
return capturedCallsite;
|
|
2863
|
+
}
|
|
2864
|
+
};
|
|
2865
|
+
}
|
|
2866
|
+
function createQueryTracer(experimental) {
|
|
2867
|
+
const traceOption = experimental?.traceQueries;
|
|
2868
|
+
if (!traceOption) {
|
|
2869
|
+
return void 0;
|
|
2870
|
+
}
|
|
2871
|
+
const logger = typeof traceOption === "object" && traceOption.logger ? traceOption.logger : defaultQueryTraceLogger;
|
|
2872
|
+
const emit = (event) => {
|
|
2873
|
+
try {
|
|
2874
|
+
logger(event);
|
|
2875
|
+
} catch (error) {
|
|
2876
|
+
console.warn("[athena-js][trace] logger failed", error);
|
|
2877
|
+
}
|
|
2878
|
+
};
|
|
2879
|
+
return {
|
|
2880
|
+
captureCallsite: captureQueryTraceCallsite,
|
|
2881
|
+
publishSuccess(context, result, durationMs, callsite) {
|
|
2882
|
+
emit({
|
|
2883
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2884
|
+
durationMs,
|
|
2885
|
+
operation: context.operation,
|
|
2886
|
+
endpoint: context.endpoint,
|
|
2887
|
+
table: context.table,
|
|
2888
|
+
functionName: context.functionName,
|
|
2889
|
+
sql: context.sql,
|
|
2890
|
+
payload: context.payload,
|
|
2891
|
+
options: context.options,
|
|
2892
|
+
callsite,
|
|
2893
|
+
outcome: {
|
|
2894
|
+
status: result.status,
|
|
2895
|
+
error: result.error,
|
|
2896
|
+
errorDetails: result.errorDetails ?? null,
|
|
2897
|
+
count: result.count ?? null,
|
|
2898
|
+
data: result.data,
|
|
2899
|
+
raw: result.raw
|
|
2900
|
+
}
|
|
2901
|
+
});
|
|
2902
|
+
},
|
|
2903
|
+
publishFailure(context, error, durationMs, callsite) {
|
|
2904
|
+
emit({
|
|
2905
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2906
|
+
durationMs,
|
|
2907
|
+
operation: context.operation,
|
|
2908
|
+
endpoint: context.endpoint,
|
|
2909
|
+
table: context.table,
|
|
2910
|
+
functionName: context.functionName,
|
|
2911
|
+
sql: context.sql,
|
|
2912
|
+
payload: context.payload,
|
|
2913
|
+
options: context.options,
|
|
2914
|
+
callsite,
|
|
2915
|
+
thrownError: error
|
|
2916
|
+
});
|
|
2917
|
+
}
|
|
2918
|
+
};
|
|
2060
2919
|
}
|
|
2061
|
-
function
|
|
2062
|
-
if (!
|
|
2063
|
-
return
|
|
2920
|
+
async function executeWithQueryTrace(tracer, context, runner, callsiteOverride) {
|
|
2921
|
+
if (!tracer) {
|
|
2922
|
+
return runner();
|
|
2064
2923
|
}
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
const normalizedError = normalizeAthenaError(result, context);
|
|
2071
|
-
attachNormalizedError(result, normalizedError);
|
|
2924
|
+
const callsite = callsiteOverride ?? tracer.captureCallsite();
|
|
2925
|
+
const startedAt = Date.now();
|
|
2926
|
+
try {
|
|
2927
|
+
const result = await runner();
|
|
2928
|
+
tracer.publishSuccess(context, result, Date.now() - startedAt, callsite);
|
|
2072
2929
|
return result;
|
|
2073
|
-
}
|
|
2930
|
+
} catch (error) {
|
|
2931
|
+
tracer.publishFailure(context, error, Date.now() - startedAt, callsite);
|
|
2932
|
+
throw error;
|
|
2933
|
+
}
|
|
2074
2934
|
}
|
|
2075
2935
|
function toSingleResult(response) {
|
|
2076
2936
|
const payload = response.data;
|
|
@@ -2092,15 +2952,16 @@ function asAthenaJsonObject(value) {
|
|
|
2092
2952
|
function asAthenaJsonObjectArray(values) {
|
|
2093
2953
|
return values;
|
|
2094
2954
|
}
|
|
2095
|
-
function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
|
|
2955
|
+
function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS, tracer, initialCallsite) {
|
|
2096
2956
|
let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
|
|
2097
2957
|
let selectedOptions;
|
|
2098
2958
|
let promise = null;
|
|
2099
|
-
const
|
|
2959
|
+
const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
|
|
2960
|
+
const run = (columns, options, callsite) => {
|
|
2100
2961
|
const payloadColumns = columns ?? selectedColumns;
|
|
2101
2962
|
const payloadOptions = options ?? selectedOptions;
|
|
2102
2963
|
if (!promise) {
|
|
2103
|
-
promise = executor(payloadColumns, payloadOptions);
|
|
2964
|
+
promise = executor(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
|
|
2104
2965
|
}
|
|
2105
2966
|
return promise;
|
|
2106
2967
|
};
|
|
@@ -2108,7 +2969,7 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
|
|
|
2108
2969
|
select(columns = selectedColumns, options) {
|
|
2109
2970
|
selectedColumns = columns;
|
|
2110
2971
|
selectedOptions = options ?? selectedOptions;
|
|
2111
|
-
return run(columns, options);
|
|
2972
|
+
return run(columns, options, captureTraceCallsite(tracer));
|
|
2112
2973
|
},
|
|
2113
2974
|
returning(columns = selectedColumns, options) {
|
|
2114
2975
|
return mutationQuery.select(columns, options);
|
|
@@ -2116,7 +2977,7 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
|
|
|
2116
2977
|
single(columns = selectedColumns, options) {
|
|
2117
2978
|
selectedColumns = columns;
|
|
2118
2979
|
selectedOptions = options ?? selectedOptions;
|
|
2119
|
-
return run(columns, options).then(toSingleResult);
|
|
2980
|
+
return run(columns, options, captureTraceCallsite(tracer)).then(toSingleResult);
|
|
2120
2981
|
},
|
|
2121
2982
|
maybeSingle(columns = selectedColumns, options) {
|
|
2122
2983
|
return mutationQuery.single(columns, options);
|
|
@@ -2139,21 +3000,12 @@ function getResourceId(state) {
|
|
|
2139
3000
|
);
|
|
2140
3001
|
return candidate?.value?.toString();
|
|
2141
3002
|
}
|
|
2142
|
-
function
|
|
3003
|
+
function stringifyFilterValue2(value) {
|
|
2143
3004
|
if (Array.isArray(value)) {
|
|
2144
3005
|
return value.join(",");
|
|
2145
3006
|
}
|
|
2146
3007
|
return String(value);
|
|
2147
3008
|
}
|
|
2148
|
-
function isUuidString(value) {
|
|
2149
|
-
return UUID_PATTERN.test(value.trim());
|
|
2150
|
-
}
|
|
2151
|
-
function isUuidIdentifierColumn(column) {
|
|
2152
|
-
return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
|
|
2153
|
-
}
|
|
2154
|
-
function shouldUseUuidTextComparison(column, value) {
|
|
2155
|
-
return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
|
|
2156
|
-
}
|
|
2157
3009
|
function normalizeCast(cast) {
|
|
2158
3010
|
const normalized = cast.trim().toLowerCase();
|
|
2159
3011
|
if (!SAFE_CAST_PATTERN.test(normalized)) {
|
|
@@ -2176,25 +3028,92 @@ function withCast(expression, cast) {
|
|
|
2176
3028
|
}
|
|
2177
3029
|
function buildSelectColumnsClause(columns) {
|
|
2178
3030
|
if (Array.isArray(columns)) {
|
|
2179
|
-
return columns.map((column) =>
|
|
3031
|
+
return columns.map((column) => quoteSelectColumnToken(column)).join(", ");
|
|
2180
3032
|
}
|
|
2181
3033
|
return quoteSelectColumnsExpression(columns);
|
|
2182
3034
|
}
|
|
3035
|
+
function parseIdentifierSegment(input) {
|
|
3036
|
+
const trimmed = input.trim();
|
|
3037
|
+
if (!trimmed) return null;
|
|
3038
|
+
if (!trimmed.startsWith('"')) {
|
|
3039
|
+
return {
|
|
3040
|
+
normalizedValue: trimmed.toLowerCase()
|
|
3041
|
+
};
|
|
3042
|
+
}
|
|
3043
|
+
let value = "";
|
|
3044
|
+
let index = 1;
|
|
3045
|
+
let closed = false;
|
|
3046
|
+
while (index < trimmed.length) {
|
|
3047
|
+
const char = trimmed[index];
|
|
3048
|
+
const next = index + 1 < trimmed.length ? trimmed[index + 1] : "";
|
|
3049
|
+
if (char === '"' && next === '"') {
|
|
3050
|
+
value += '"';
|
|
3051
|
+
index += 2;
|
|
3052
|
+
continue;
|
|
3053
|
+
}
|
|
3054
|
+
if (char === '"') {
|
|
3055
|
+
closed = true;
|
|
3056
|
+
index += 1;
|
|
3057
|
+
break;
|
|
3058
|
+
}
|
|
3059
|
+
value += char;
|
|
3060
|
+
index += 1;
|
|
3061
|
+
}
|
|
3062
|
+
if (!closed || trimmed.slice(index).trim().length > 0 || !value.trim()) {
|
|
3063
|
+
return null;
|
|
3064
|
+
}
|
|
3065
|
+
return {
|
|
3066
|
+
normalizedValue: value
|
|
3067
|
+
};
|
|
3068
|
+
}
|
|
3069
|
+
function splitQualifiedTableName(tableName) {
|
|
3070
|
+
const trimmed = tableName.trim();
|
|
3071
|
+
let inQuotes = false;
|
|
3072
|
+
for (let index = 0; index < trimmed.length; index += 1) {
|
|
3073
|
+
const char = trimmed[index];
|
|
3074
|
+
const next = index + 1 < trimmed.length ? trimmed[index + 1] : "";
|
|
3075
|
+
if (char === '"') {
|
|
3076
|
+
if (inQuotes && next === '"') {
|
|
3077
|
+
index += 1;
|
|
3078
|
+
continue;
|
|
3079
|
+
}
|
|
3080
|
+
inQuotes = !inQuotes;
|
|
3081
|
+
continue;
|
|
3082
|
+
}
|
|
3083
|
+
if (char === "." && !inQuotes) {
|
|
3084
|
+
const schemaSegment = trimmed.slice(0, index).trim();
|
|
3085
|
+
const tableSegment = trimmed.slice(index + 1).trim();
|
|
3086
|
+
if (!schemaSegment || !tableSegment) {
|
|
3087
|
+
return null;
|
|
3088
|
+
}
|
|
3089
|
+
return { schemaSegment };
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
return null;
|
|
3093
|
+
}
|
|
2183
3094
|
function resolveTableNameForCall(tableName, schema) {
|
|
2184
3095
|
if (!schema) return tableName;
|
|
2185
3096
|
const normalizedSchema = schema.trim();
|
|
2186
3097
|
if (!normalizedSchema) {
|
|
2187
3098
|
throw new Error("schema option must be a non-empty string");
|
|
2188
3099
|
}
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
3100
|
+
const normalizedTableName = tableName.trim();
|
|
3101
|
+
const parsedSchema = parseIdentifierSegment(normalizedSchema);
|
|
3102
|
+
if (!parsedSchema) {
|
|
3103
|
+
throw new Error("schema option must be a non-empty string");
|
|
3104
|
+
}
|
|
3105
|
+
const qualified = splitQualifiedTableName(normalizedTableName);
|
|
3106
|
+
if (qualified) {
|
|
3107
|
+
const parsedTableSchema = parseIdentifierSegment(qualified.schemaSegment);
|
|
3108
|
+
const sameSchema = parsedTableSchema ? parsedTableSchema.normalizedValue === parsedSchema.normalizedValue : normalizedTableName.startsWith(`${normalizedSchema}.`);
|
|
3109
|
+
if (sameSchema) {
|
|
3110
|
+
return normalizedTableName;
|
|
2192
3111
|
}
|
|
2193
3112
|
throw new Error(
|
|
2194
|
-
`schema option "${normalizedSchema}" conflicts with schema-qualified table "${
|
|
3113
|
+
`schema option "${normalizedSchema}" conflicts with schema-qualified table "${normalizedTableName}"`
|
|
2195
3114
|
);
|
|
2196
3115
|
}
|
|
2197
|
-
return `${normalizedSchema}.${
|
|
3116
|
+
return `${normalizedSchema}.${normalizedTableName}`;
|
|
2198
3117
|
}
|
|
2199
3118
|
function conditionToSqlClause(condition) {
|
|
2200
3119
|
if (!condition.column) return null;
|
|
@@ -2272,6 +3191,237 @@ function buildTypedSelectQuery(input) {
|
|
|
2272
3191
|
}
|
|
2273
3192
|
return `${sqlParts.join(" ")};`;
|
|
2274
3193
|
}
|
|
3194
|
+
function sanitizeSqlComment(comment) {
|
|
3195
|
+
return comment.replace(/\*\//g, "* /");
|
|
3196
|
+
}
|
|
3197
|
+
function toSqlJsonLiteral(value) {
|
|
3198
|
+
if (value === void 0) return "DEFAULT";
|
|
3199
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
3200
|
+
return toSqlLiteral(value);
|
|
3201
|
+
}
|
|
3202
|
+
return `'${escapeSqlStringLiteral(JSON.stringify(value))}'::jsonb`;
|
|
3203
|
+
}
|
|
3204
|
+
function conditionToDebugSqlClause(condition) {
|
|
3205
|
+
const exact = conditionToSqlClause(condition);
|
|
3206
|
+
if (exact) return exact;
|
|
3207
|
+
const rawCondition = sanitizeSqlComment(JSON.stringify(condition));
|
|
3208
|
+
if (!condition.column) {
|
|
3209
|
+
return `TRUE /* unsupported condition: ${rawCondition} */`;
|
|
3210
|
+
}
|
|
3211
|
+
const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
|
|
3212
|
+
const value = condition.value;
|
|
3213
|
+
const rhs = withCast(toSqlJsonLiteral(value), condition.value_cast);
|
|
3214
|
+
switch (condition.operator) {
|
|
3215
|
+
case "contains":
|
|
3216
|
+
return `${column} @> ${rhs}`;
|
|
3217
|
+
case "containedBy":
|
|
3218
|
+
return `${column} <@ ${rhs}`;
|
|
3219
|
+
case "not":
|
|
3220
|
+
return `TRUE /* NOT expression passthrough: ${rawCondition} */`;
|
|
3221
|
+
case "or":
|
|
3222
|
+
return `TRUE /* OR expression passthrough: ${rawCondition} */`;
|
|
3223
|
+
default:
|
|
3224
|
+
return `TRUE /* unsupported condition: ${rawCondition} */`;
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
function resolvePagination(input) {
|
|
3228
|
+
let limit = input.limit;
|
|
3229
|
+
let offset = input.offset;
|
|
3230
|
+
if (limit === void 0 && input.pageSize !== void 0) {
|
|
3231
|
+
limit = input.pageSize;
|
|
3232
|
+
}
|
|
3233
|
+
if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
|
|
3234
|
+
offset = (input.currentPage - 1) * input.pageSize;
|
|
3235
|
+
}
|
|
3236
|
+
return { limit, offset };
|
|
3237
|
+
}
|
|
3238
|
+
function appendOrderLimitOffset(sqlParts, order, limit, offset) {
|
|
3239
|
+
if (order?.field) {
|
|
3240
|
+
const direction = order.direction === "descending" ? "DESC" : "ASC";
|
|
3241
|
+
sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(order.field)} ${direction}`);
|
|
3242
|
+
}
|
|
3243
|
+
if (limit !== void 0) {
|
|
3244
|
+
sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(limit))}`);
|
|
3245
|
+
}
|
|
3246
|
+
if (offset !== void 0) {
|
|
3247
|
+
sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
function buildDebugSelectQuery(input) {
|
|
3251
|
+
const sqlParts = [
|
|
3252
|
+
`SELECT ${buildSelectColumnsClause(input.columns)} FROM ${quoteQualifiedIdentifier(input.tableName)}`
|
|
3253
|
+
];
|
|
3254
|
+
if (input.conditions?.length) {
|
|
3255
|
+
const whereClauses = input.conditions.map(conditionToDebugSqlClause);
|
|
3256
|
+
sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
|
|
3257
|
+
}
|
|
3258
|
+
const pagination = resolvePagination(input);
|
|
3259
|
+
appendOrderLimitOffset(sqlParts, input.order, pagination.limit, pagination.offset);
|
|
3260
|
+
return `${sqlParts.join(" ")};`;
|
|
3261
|
+
}
|
|
3262
|
+
function resolveDebugTableIdentifier(tableName) {
|
|
3263
|
+
if (!tableName?.trim()) {
|
|
3264
|
+
return '"__unknown_table__"';
|
|
3265
|
+
}
|
|
3266
|
+
return quoteQualifiedIdentifier(tableName);
|
|
3267
|
+
}
|
|
3268
|
+
function buildInsertDebugSql(payload) {
|
|
3269
|
+
const rows = Array.isArray(payload.insert_body) ? payload.insert_body : [payload.insert_body];
|
|
3270
|
+
const columns = [];
|
|
3271
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3272
|
+
for (const row of rows) {
|
|
3273
|
+
for (const column of Object.keys(row)) {
|
|
3274
|
+
if (seen.has(column)) continue;
|
|
3275
|
+
seen.add(column);
|
|
3276
|
+
columns.push(column);
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
3279
|
+
const sqlParts = [`INSERT INTO ${quoteQualifiedIdentifier(payload.table_name)}`];
|
|
3280
|
+
if (!rows.length || !columns.length) {
|
|
3281
|
+
sqlParts.push("DEFAULT VALUES");
|
|
3282
|
+
if (rows.length > 1) {
|
|
3283
|
+
sqlParts.push(`/* trace: ${rows.length} rows collapsed to DEFAULT VALUES */`);
|
|
3284
|
+
}
|
|
3285
|
+
} else {
|
|
3286
|
+
const valuesClause = rows.map((row) => {
|
|
3287
|
+
const values = columns.map((column) => {
|
|
3288
|
+
const hasColumn = Object.prototype.hasOwnProperty.call(row, column);
|
|
3289
|
+
if (!hasColumn) {
|
|
3290
|
+
return payload.default_to_null ? "NULL" : "DEFAULT";
|
|
3291
|
+
}
|
|
3292
|
+
const rowValue = row[column];
|
|
3293
|
+
return toSqlJsonLiteral(rowValue);
|
|
3294
|
+
});
|
|
3295
|
+
return `(${values.join(", ")})`;
|
|
3296
|
+
}).join(", ");
|
|
3297
|
+
const columnClause = columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
|
|
3298
|
+
sqlParts.push(`(${columnClause})`);
|
|
3299
|
+
sqlParts.push(`VALUES ${valuesClause}`);
|
|
3300
|
+
}
|
|
3301
|
+
if (payload.on_conflict) {
|
|
3302
|
+
const conflictColumns = Array.isArray(payload.on_conflict) ? payload.on_conflict.map((column) => quoteQualifiedIdentifier(column)).join(", ") : payload.on_conflict;
|
|
3303
|
+
if (payload.update_body && Object.keys(payload.update_body).length > 0) {
|
|
3304
|
+
const assignments = Object.entries(payload.update_body).map(
|
|
3305
|
+
([column, value]) => `${quoteQualifiedIdentifier(column)} = ${toSqlJsonLiteral(value)}`
|
|
3306
|
+
);
|
|
3307
|
+
sqlParts.push(`ON CONFLICT (${conflictColumns}) DO UPDATE SET ${assignments.join(", ")}`);
|
|
3308
|
+
} else {
|
|
3309
|
+
sqlParts.push(`ON CONFLICT (${conflictColumns}) DO NOTHING`);
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
if (payload.columns) {
|
|
3313
|
+
sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
|
|
3314
|
+
}
|
|
3315
|
+
return `${sqlParts.join(" ")};`;
|
|
3316
|
+
}
|
|
3317
|
+
function buildUpdateDebugSql(payload) {
|
|
3318
|
+
const set = payload.set ?? payload.data ?? {};
|
|
3319
|
+
const assignments = Object.entries(set).map(
|
|
3320
|
+
([column, value]) => `${quoteQualifiedIdentifier(column)} = ${toSqlJsonLiteral(value)}`
|
|
3321
|
+
);
|
|
3322
|
+
const sqlParts = [
|
|
3323
|
+
`UPDATE ${resolveDebugTableIdentifier(payload.table_name)} SET ${assignments.length ? assignments.join(", ") : "/* empty set */"}`
|
|
3324
|
+
];
|
|
3325
|
+
if (payload.conditions?.length) {
|
|
3326
|
+
const whereClauses = payload.conditions.map(conditionToDebugSqlClause);
|
|
3327
|
+
sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
|
|
3328
|
+
}
|
|
3329
|
+
const pagination = resolvePagination({
|
|
3330
|
+
currentPage: payload.current_page,
|
|
3331
|
+
pageSize: payload.page_size
|
|
3332
|
+
});
|
|
3333
|
+
appendOrderLimitOffset(sqlParts, payload.sort_by, pagination.limit, pagination.offset);
|
|
3334
|
+
if (payload.columns) {
|
|
3335
|
+
sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
|
|
3336
|
+
}
|
|
3337
|
+
return `${sqlParts.join(" ")};`;
|
|
3338
|
+
}
|
|
3339
|
+
function buildDeleteDebugSql(payload) {
|
|
3340
|
+
const sqlParts = [`DELETE FROM ${quoteQualifiedIdentifier(payload.table_name)}`];
|
|
3341
|
+
const whereClauses = [];
|
|
3342
|
+
if (payload.resource_id) {
|
|
3343
|
+
whereClauses.push(`"resource_id" = ${toSqlLiteral(payload.resource_id)}`);
|
|
3344
|
+
}
|
|
3345
|
+
if (payload.conditions?.length) {
|
|
3346
|
+
whereClauses.push(...payload.conditions.map(conditionToDebugSqlClause));
|
|
3347
|
+
}
|
|
3348
|
+
if (whereClauses.length) {
|
|
3349
|
+
sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
|
|
3350
|
+
}
|
|
3351
|
+
const pagination = resolvePagination({
|
|
3352
|
+
currentPage: payload.current_page,
|
|
3353
|
+
pageSize: payload.page_size
|
|
3354
|
+
});
|
|
3355
|
+
appendOrderLimitOffset(sqlParts, payload.sort_by, pagination.limit, pagination.offset);
|
|
3356
|
+
if (payload.columns) {
|
|
3357
|
+
sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
|
|
3358
|
+
}
|
|
3359
|
+
return `${sqlParts.join(" ")};`;
|
|
3360
|
+
}
|
|
3361
|
+
function rpcFilterToSqlClause(filter) {
|
|
3362
|
+
const column = quoteQualifiedIdentifier(filter.column);
|
|
3363
|
+
const value = filter.value;
|
|
3364
|
+
switch (filter.operator) {
|
|
3365
|
+
case "eq":
|
|
3366
|
+
case "neq":
|
|
3367
|
+
case "gt":
|
|
3368
|
+
case "gte":
|
|
3369
|
+
case "lt":
|
|
3370
|
+
case "lte":
|
|
3371
|
+
case "like":
|
|
3372
|
+
case "ilike": {
|
|
3373
|
+
if (value === void 0 || Array.isArray(value)) {
|
|
3374
|
+
return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
|
|
3375
|
+
}
|
|
3376
|
+
const operatorMap = {
|
|
3377
|
+
eq: "=",
|
|
3378
|
+
neq: "!=",
|
|
3379
|
+
gt: ">",
|
|
3380
|
+
gte: ">=",
|
|
3381
|
+
lt: "<",
|
|
3382
|
+
lte: "<=",
|
|
3383
|
+
like: "LIKE",
|
|
3384
|
+
ilike: "ILIKE"
|
|
3385
|
+
};
|
|
3386
|
+
return `${column} ${operatorMap[filter.operator]} ${toSqlLiteral(value)}`;
|
|
3387
|
+
}
|
|
3388
|
+
case "is":
|
|
3389
|
+
if (value === null) return `${column} IS NULL`;
|
|
3390
|
+
if (value === true) return `${column} IS TRUE`;
|
|
3391
|
+
if (value === false) return `${column} IS FALSE`;
|
|
3392
|
+
return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
|
|
3393
|
+
case "in":
|
|
3394
|
+
if (!Array.isArray(value)) {
|
|
3395
|
+
return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
|
|
3396
|
+
}
|
|
3397
|
+
if (value.length === 0) return "FALSE";
|
|
3398
|
+
return `${column} IN (${value.map((item) => toSqlLiteral(item)).join(", ")})`;
|
|
3399
|
+
default:
|
|
3400
|
+
return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
function buildRpcDebugSql(payload) {
|
|
3404
|
+
const argsEntries = payload.args ? Object.entries(payload.args) : [];
|
|
3405
|
+
const argsClause = argsEntries.map(([key, value]) => `${quoteQualifiedIdentifier(key)} => ${toSqlJsonLiteral(value)}`).join(", ");
|
|
3406
|
+
const functionRef = payload.schema ? `${quoteQualifiedIdentifier(payload.schema)}.${quoteQualifiedIdentifier(payload.function)}` : quoteQualifiedIdentifier(payload.function);
|
|
3407
|
+
const sqlParts = [
|
|
3408
|
+
`SELECT ${payload.select ? quoteSelectColumnsExpression(payload.select) : "*"} FROM ${functionRef}(${argsClause})`
|
|
3409
|
+
];
|
|
3410
|
+
if (payload.filters?.length) {
|
|
3411
|
+
sqlParts.push(`WHERE ${payload.filters.map(rpcFilterToSqlClause).join(" AND ")}`);
|
|
3412
|
+
}
|
|
3413
|
+
if (payload.order?.column) {
|
|
3414
|
+
const direction = payload.order.ascending === false ? "DESC" : "ASC";
|
|
3415
|
+
sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(payload.order.column)} ${direction}`);
|
|
3416
|
+
}
|
|
3417
|
+
if (payload.limit !== void 0) {
|
|
3418
|
+
sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(payload.limit))}`);
|
|
3419
|
+
}
|
|
3420
|
+
if (payload.offset !== void 0) {
|
|
3421
|
+
sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(payload.offset))}`);
|
|
3422
|
+
}
|
|
3423
|
+
return `${sqlParts.join(" ")};`;
|
|
3424
|
+
}
|
|
2275
3425
|
function createFilterMethods(state, addCondition, self) {
|
|
2276
3426
|
return {
|
|
2277
3427
|
eq(column, value) {
|
|
@@ -2383,7 +3533,7 @@ function createFilterMethods(state, addCondition, self) {
|
|
|
2383
3533
|
not(columnOrExpression, operator, value) {
|
|
2384
3534
|
const expression = String(columnOrExpression);
|
|
2385
3535
|
if (operator != null && value !== void 0) {
|
|
2386
|
-
addCondition("not", void 0, `${expression}.${operator}.${
|
|
3536
|
+
addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue2(value)}`);
|
|
2387
3537
|
} else {
|
|
2388
3538
|
addCondition("not", void 0, expression);
|
|
2389
3539
|
}
|
|
@@ -2446,14 +3596,15 @@ function createRpcFilterMethods(filters, self) {
|
|
|
2446
3596
|
}
|
|
2447
3597
|
};
|
|
2448
3598
|
}
|
|
2449
|
-
function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult) {
|
|
3599
|
+
function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult, tracer, initialCallsite) {
|
|
2450
3600
|
const state = {
|
|
2451
3601
|
filters: []
|
|
2452
3602
|
};
|
|
2453
3603
|
let selectedColumns;
|
|
2454
3604
|
let selectedOptions;
|
|
2455
3605
|
let promise = null;
|
|
2456
|
-
const
|
|
3606
|
+
const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
|
|
3607
|
+
const executeRpc = async (columns, options, callsite) => {
|
|
2457
3608
|
const mergedOptions = mergeOptions(baseOptions, options);
|
|
2458
3609
|
const payload = {
|
|
2459
3610
|
function: functionName,
|
|
@@ -2467,14 +3618,30 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
|
|
|
2467
3618
|
offset: state.offset,
|
|
2468
3619
|
order: state.order
|
|
2469
3620
|
};
|
|
2470
|
-
const
|
|
2471
|
-
|
|
3621
|
+
const endpoint = mergedOptions?.get ? `/rpc/${functionName}` : "/gateway/rpc";
|
|
3622
|
+
const sql = buildRpcDebugSql(payload);
|
|
3623
|
+
return executeWithQueryTrace(
|
|
3624
|
+
tracer,
|
|
3625
|
+
{
|
|
3626
|
+
operation: "rpc",
|
|
3627
|
+
endpoint,
|
|
3628
|
+
functionName,
|
|
3629
|
+
sql,
|
|
3630
|
+
payload,
|
|
3631
|
+
options: mergedOptions
|
|
3632
|
+
},
|
|
3633
|
+
async () => {
|
|
3634
|
+
const response = await client.rpcGateway(payload, mergedOptions);
|
|
3635
|
+
return formatGatewayResult(response, { operation: "rpc" });
|
|
3636
|
+
},
|
|
3637
|
+
callsite
|
|
3638
|
+
);
|
|
2472
3639
|
};
|
|
2473
|
-
const run = (columns, options) => {
|
|
3640
|
+
const run = (columns, options, callsite) => {
|
|
2474
3641
|
const payloadColumns = columns ?? selectedColumns;
|
|
2475
3642
|
const payloadOptions = options ?? selectedOptions;
|
|
2476
3643
|
if (!promise) {
|
|
2477
|
-
promise = executeRpc(payloadColumns, payloadOptions);
|
|
3644
|
+
promise = executeRpc(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
|
|
2478
3645
|
}
|
|
2479
3646
|
return promise;
|
|
2480
3647
|
};
|
|
@@ -2484,10 +3651,10 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
|
|
|
2484
3651
|
select(columns = selectedColumns, options) {
|
|
2485
3652
|
selectedColumns = columns;
|
|
2486
3653
|
selectedOptions = options ?? selectedOptions;
|
|
2487
|
-
return run(columns, options);
|
|
3654
|
+
return run(columns, options, captureTraceCallsite(tracer));
|
|
2488
3655
|
},
|
|
2489
3656
|
async single(columns, options) {
|
|
2490
|
-
const result = await run(columns, options);
|
|
3657
|
+
const result = await run(columns, options, captureTraceCallsite(tracer));
|
|
2491
3658
|
return toSingleResult(result);
|
|
2492
3659
|
},
|
|
2493
3660
|
maybeSingle(columns, options) {
|
|
@@ -2522,7 +3689,7 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
|
|
|
2522
3689
|
});
|
|
2523
3690
|
return builder;
|
|
2524
3691
|
}
|
|
2525
|
-
function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
3692
|
+
function createTableBuilder(tableName, client, formatGatewayResult, tracer, experimental) {
|
|
2526
3693
|
const state = {
|
|
2527
3694
|
conditions: []
|
|
2528
3695
|
};
|
|
@@ -2554,15 +3721,24 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2554
3721
|
}
|
|
2555
3722
|
state.conditions.push(condition);
|
|
2556
3723
|
};
|
|
3724
|
+
const snapshotState = () => ({
|
|
3725
|
+
conditions: state.conditions.map((condition) => ({ ...condition })),
|
|
3726
|
+
limit: state.limit,
|
|
3727
|
+
offset: state.offset,
|
|
3728
|
+
order: state.order ? { ...state.order } : void 0,
|
|
3729
|
+
currentPage: state.currentPage,
|
|
3730
|
+
pageSize: state.pageSize,
|
|
3731
|
+
totalPages: state.totalPages
|
|
3732
|
+
});
|
|
2557
3733
|
const builder = {};
|
|
2558
3734
|
const filterMethods = createFilterMethods(
|
|
2559
3735
|
state,
|
|
2560
3736
|
addCondition,
|
|
2561
3737
|
builder
|
|
2562
3738
|
);
|
|
2563
|
-
const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
|
|
3739
|
+
const runSelect = async (columns = DEFAULT_COLUMNS, options, executionState = snapshotState(), callsite) => {
|
|
2564
3740
|
const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
|
|
2565
|
-
const conditions =
|
|
3741
|
+
const conditions = executionState.conditions.length ? executionState.conditions.map((condition) => ({ ...condition })) : void 0;
|
|
2566
3742
|
const hasTypedEqualityComparison = conditions?.some(
|
|
2567
3743
|
(condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
|
|
2568
3744
|
) ?? false;
|
|
@@ -2571,53 +3747,107 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2571
3747
|
tableName: resolvedTableName,
|
|
2572
3748
|
columns,
|
|
2573
3749
|
conditions,
|
|
2574
|
-
limit:
|
|
2575
|
-
offset:
|
|
2576
|
-
currentPage:
|
|
2577
|
-
pageSize:
|
|
2578
|
-
order:
|
|
3750
|
+
limit: executionState.limit,
|
|
3751
|
+
offset: executionState.offset,
|
|
3752
|
+
currentPage: executionState.currentPage,
|
|
3753
|
+
pageSize: executionState.pageSize,
|
|
3754
|
+
order: executionState.order
|
|
2579
3755
|
});
|
|
2580
3756
|
if (query) {
|
|
2581
|
-
const
|
|
2582
|
-
return
|
|
3757
|
+
const payload2 = { query };
|
|
3758
|
+
return executeWithQueryTrace(
|
|
3759
|
+
tracer,
|
|
3760
|
+
{
|
|
3761
|
+
operation: "select",
|
|
3762
|
+
endpoint: "/gateway/query",
|
|
3763
|
+
table: resolvedTableName,
|
|
3764
|
+
sql: query,
|
|
3765
|
+
payload: payload2,
|
|
3766
|
+
options
|
|
3767
|
+
},
|
|
3768
|
+
async () => {
|
|
3769
|
+
const queryResponse = await client.queryGateway(payload2, options);
|
|
3770
|
+
return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
|
|
3771
|
+
},
|
|
3772
|
+
callsite
|
|
3773
|
+
);
|
|
2583
3774
|
}
|
|
2584
3775
|
}
|
|
2585
3776
|
const payload = {
|
|
2586
3777
|
table_name: resolvedTableName,
|
|
2587
3778
|
columns,
|
|
2588
3779
|
conditions,
|
|
2589
|
-
limit:
|
|
2590
|
-
offset:
|
|
2591
|
-
current_page:
|
|
2592
|
-
page_size:
|
|
2593
|
-
total_pages:
|
|
2594
|
-
sort_by:
|
|
3780
|
+
limit: executionState.limit,
|
|
3781
|
+
offset: executionState.offset,
|
|
3782
|
+
current_page: executionState.currentPage,
|
|
3783
|
+
page_size: executionState.pageSize,
|
|
3784
|
+
total_pages: executionState.totalPages,
|
|
3785
|
+
sort_by: executionState.order,
|
|
2595
3786
|
strip_nulls: options?.stripNulls ?? true,
|
|
2596
3787
|
count: options?.count,
|
|
2597
3788
|
head: options?.head
|
|
2598
3789
|
};
|
|
2599
|
-
const
|
|
2600
|
-
|
|
3790
|
+
const sql = buildDebugSelectQuery({
|
|
3791
|
+
tableName: resolvedTableName,
|
|
3792
|
+
columns,
|
|
3793
|
+
conditions,
|
|
3794
|
+
limit: executionState.limit,
|
|
3795
|
+
offset: executionState.offset,
|
|
3796
|
+
currentPage: executionState.currentPage,
|
|
3797
|
+
pageSize: executionState.pageSize,
|
|
3798
|
+
order: executionState.order
|
|
3799
|
+
});
|
|
3800
|
+
return executeWithQueryTrace(
|
|
3801
|
+
tracer,
|
|
3802
|
+
{
|
|
3803
|
+
operation: "select",
|
|
3804
|
+
endpoint: "/gateway/fetch",
|
|
3805
|
+
table: resolvedTableName,
|
|
3806
|
+
sql,
|
|
3807
|
+
payload,
|
|
3808
|
+
options
|
|
3809
|
+
},
|
|
3810
|
+
async () => {
|
|
3811
|
+
const response = await client.fetchGateway(payload, options);
|
|
3812
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
|
|
3813
|
+
},
|
|
3814
|
+
callsite
|
|
3815
|
+
);
|
|
2601
3816
|
};
|
|
2602
|
-
const createSelectChain = (columns, options) => {
|
|
3817
|
+
const createSelectChain = (columns, options, initialCallsite) => {
|
|
2603
3818
|
const chain = {};
|
|
3819
|
+
const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
|
|
2604
3820
|
const filterMethods2 = createFilterMethods(state, addCondition, chain);
|
|
2605
3821
|
Object.assign(chain, filterMethods2, {
|
|
2606
3822
|
async single(cols, opts) {
|
|
2607
|
-
const r = await runSelect(
|
|
3823
|
+
const r = await runSelect(
|
|
3824
|
+
cols ?? columns,
|
|
3825
|
+
opts ?? options,
|
|
3826
|
+
snapshotState(),
|
|
3827
|
+
callsiteStore.resolve(captureTraceCallsite(tracer))
|
|
3828
|
+
);
|
|
2608
3829
|
return toSingleResult(r);
|
|
2609
3830
|
},
|
|
2610
3831
|
maybeSingle(cols, opts) {
|
|
2611
3832
|
return chain.single(cols, opts);
|
|
2612
3833
|
},
|
|
2613
3834
|
then(onfulfilled, onrejected) {
|
|
2614
|
-
return runSelect(
|
|
3835
|
+
return runSelect(
|
|
3836
|
+
columns,
|
|
3837
|
+
options,
|
|
3838
|
+
snapshotState(),
|
|
3839
|
+
callsiteStore.resolve()
|
|
3840
|
+
).then(onfulfilled, onrejected);
|
|
2615
3841
|
},
|
|
2616
3842
|
catch(onrejected) {
|
|
2617
|
-
return runSelect(columns, options).catch(
|
|
3843
|
+
return runSelect(columns, options, snapshotState(), callsiteStore.resolve()).catch(
|
|
3844
|
+
onrejected
|
|
3845
|
+
);
|
|
2618
3846
|
},
|
|
2619
3847
|
finally(onfinally) {
|
|
2620
|
-
return runSelect(columns, options).finally(
|
|
3848
|
+
return runSelect(columns, options, snapshotState(), callsiteStore.resolve()).finally(
|
|
3849
|
+
onfinally
|
|
3850
|
+
);
|
|
2621
3851
|
}
|
|
2622
3852
|
});
|
|
2623
3853
|
return chain;
|
|
@@ -2634,11 +3864,75 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2634
3864
|
return builder;
|
|
2635
3865
|
},
|
|
2636
3866
|
select(columns = DEFAULT_COLUMNS, options) {
|
|
2637
|
-
return createSelectChain(columns, options);
|
|
3867
|
+
return createSelectChain(columns, options, captureTraceCallsite(tracer));
|
|
3868
|
+
},
|
|
3869
|
+
async findMany(options) {
|
|
3870
|
+
const columns = compileSelectShape(options.select);
|
|
3871
|
+
const baseState = snapshotState();
|
|
3872
|
+
const executionState = snapshotState();
|
|
3873
|
+
const callsite = captureTraceCallsite(tracer);
|
|
3874
|
+
const compiledWhere = compileWhere(options.where);
|
|
3875
|
+
if (compiledWhere?.length) {
|
|
3876
|
+
executionState.conditions.push(...compiledWhere);
|
|
3877
|
+
}
|
|
3878
|
+
if (options.orderBy !== void 0) {
|
|
3879
|
+
executionState.order = compileOrderBy(options.orderBy);
|
|
3880
|
+
}
|
|
3881
|
+
if (options.limit !== void 0) {
|
|
3882
|
+
executionState.limit = options.limit;
|
|
3883
|
+
}
|
|
3884
|
+
if (experimental?.findManyAst && canUseFindManyAstTransport(baseState)) {
|
|
3885
|
+
const resolvedTableName = resolveTableNameForCall(tableName, void 0);
|
|
3886
|
+
const payload = {
|
|
3887
|
+
table_name: resolvedTableName,
|
|
3888
|
+
select: options.select
|
|
3889
|
+
};
|
|
3890
|
+
if (options.where !== void 0) {
|
|
3891
|
+
payload.where = options.where;
|
|
3892
|
+
}
|
|
3893
|
+
const astOrder = toFindManyAstOrder(executionState.order);
|
|
3894
|
+
if (astOrder !== void 0) {
|
|
3895
|
+
payload.orderBy = astOrder;
|
|
3896
|
+
}
|
|
3897
|
+
if (executionState.limit !== void 0) {
|
|
3898
|
+
payload.limit = executionState.limit;
|
|
3899
|
+
}
|
|
3900
|
+
const sql = buildDebugSelectQuery({
|
|
3901
|
+
tableName: resolvedTableName,
|
|
3902
|
+
columns,
|
|
3903
|
+
conditions: executionState.conditions,
|
|
3904
|
+
limit: executionState.limit,
|
|
3905
|
+
order: executionState.order
|
|
3906
|
+
});
|
|
3907
|
+
return executeWithQueryTrace(
|
|
3908
|
+
tracer,
|
|
3909
|
+
{
|
|
3910
|
+
operation: "select",
|
|
3911
|
+
endpoint: "/gateway/fetch",
|
|
3912
|
+
table: resolvedTableName,
|
|
3913
|
+
sql,
|
|
3914
|
+
payload
|
|
3915
|
+
},
|
|
3916
|
+
async () => {
|
|
3917
|
+
const response = await client.fetchGateway(
|
|
3918
|
+
payload
|
|
3919
|
+
);
|
|
3920
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
|
|
3921
|
+
},
|
|
3922
|
+
callsite
|
|
3923
|
+
);
|
|
3924
|
+
}
|
|
3925
|
+
return runSelect(
|
|
3926
|
+
columns,
|
|
3927
|
+
void 0,
|
|
3928
|
+
executionState,
|
|
3929
|
+
callsite
|
|
3930
|
+
);
|
|
2638
3931
|
},
|
|
2639
3932
|
insert(values, options) {
|
|
3933
|
+
const mutationCallsite = captureTraceCallsite(tracer);
|
|
2640
3934
|
if (Array.isArray(values)) {
|
|
2641
|
-
const executeInsertMany = async (columns, selectOptions) => {
|
|
3935
|
+
const executeInsertMany = async (columns, selectOptions, callsite) => {
|
|
2642
3936
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2643
3937
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
2644
3938
|
const payload = {
|
|
@@ -2651,12 +3945,27 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2651
3945
|
if (mergedOptions?.defaultToNull !== void 0) {
|
|
2652
3946
|
payload.default_to_null = mergedOptions.defaultToNull;
|
|
2653
3947
|
}
|
|
2654
|
-
const
|
|
2655
|
-
return
|
|
3948
|
+
const sql = buildInsertDebugSql(payload);
|
|
3949
|
+
return executeWithQueryTrace(
|
|
3950
|
+
tracer,
|
|
3951
|
+
{
|
|
3952
|
+
operation: "insert",
|
|
3953
|
+
endpoint: "/gateway/insert",
|
|
3954
|
+
table: resolvedTableName,
|
|
3955
|
+
sql,
|
|
3956
|
+
payload,
|
|
3957
|
+
options: mergedOptions
|
|
3958
|
+
},
|
|
3959
|
+
async () => {
|
|
3960
|
+
const response = await client.insertGateway(payload, mergedOptions);
|
|
3961
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
3962
|
+
},
|
|
3963
|
+
callsite
|
|
3964
|
+
);
|
|
2656
3965
|
};
|
|
2657
|
-
return createMutationQuery(executeInsertMany);
|
|
3966
|
+
return createMutationQuery(executeInsertMany, DEFAULT_COLUMNS, tracer, mutationCallsite);
|
|
2658
3967
|
}
|
|
2659
|
-
const executeInsertOne = async (columns, selectOptions) => {
|
|
3968
|
+
const executeInsertOne = async (columns, selectOptions, callsite) => {
|
|
2660
3969
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2661
3970
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
2662
3971
|
const payload = {
|
|
@@ -2669,14 +3978,30 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2669
3978
|
if (mergedOptions?.defaultToNull !== void 0) {
|
|
2670
3979
|
payload.default_to_null = mergedOptions.defaultToNull;
|
|
2671
3980
|
}
|
|
2672
|
-
const
|
|
2673
|
-
return
|
|
3981
|
+
const sql = buildInsertDebugSql(payload);
|
|
3982
|
+
return executeWithQueryTrace(
|
|
3983
|
+
tracer,
|
|
3984
|
+
{
|
|
3985
|
+
operation: "insert",
|
|
3986
|
+
endpoint: "/gateway/insert",
|
|
3987
|
+
table: resolvedTableName,
|
|
3988
|
+
sql,
|
|
3989
|
+
payload,
|
|
3990
|
+
options: mergedOptions
|
|
3991
|
+
},
|
|
3992
|
+
async () => {
|
|
3993
|
+
const response = await client.insertGateway(payload, mergedOptions);
|
|
3994
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
3995
|
+
},
|
|
3996
|
+
callsite
|
|
3997
|
+
);
|
|
2674
3998
|
};
|
|
2675
|
-
return createMutationQuery(executeInsertOne);
|
|
3999
|
+
return createMutationQuery(executeInsertOne, DEFAULT_COLUMNS, tracer, mutationCallsite);
|
|
2676
4000
|
},
|
|
2677
4001
|
upsert(values, options) {
|
|
4002
|
+
const mutationCallsite = captureTraceCallsite(tracer);
|
|
2678
4003
|
if (Array.isArray(values)) {
|
|
2679
|
-
const executeUpsertMany = async (columns, selectOptions) => {
|
|
4004
|
+
const executeUpsertMany = async (columns, selectOptions, callsite) => {
|
|
2680
4005
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2681
4006
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
2682
4007
|
const payload = {
|
|
@@ -2691,12 +4016,27 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2691
4016
|
if (mergedOptions?.defaultToNull !== void 0) {
|
|
2692
4017
|
payload.default_to_null = mergedOptions.defaultToNull;
|
|
2693
4018
|
}
|
|
2694
|
-
const
|
|
2695
|
-
return
|
|
4019
|
+
const sql = buildInsertDebugSql(payload);
|
|
4020
|
+
return executeWithQueryTrace(
|
|
4021
|
+
tracer,
|
|
4022
|
+
{
|
|
4023
|
+
operation: "upsert",
|
|
4024
|
+
endpoint: "/gateway/insert",
|
|
4025
|
+
table: resolvedTableName,
|
|
4026
|
+
sql,
|
|
4027
|
+
payload,
|
|
4028
|
+
options: mergedOptions
|
|
4029
|
+
},
|
|
4030
|
+
async () => {
|
|
4031
|
+
const response = await client.insertGateway(payload, mergedOptions);
|
|
4032
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
4033
|
+
},
|
|
4034
|
+
callsite
|
|
4035
|
+
);
|
|
2696
4036
|
};
|
|
2697
|
-
return createMutationQuery(executeUpsertMany);
|
|
4037
|
+
return createMutationQuery(executeUpsertMany, DEFAULT_COLUMNS, tracer, mutationCallsite);
|
|
2698
4038
|
}
|
|
2699
|
-
const executeUpsertOne = async (columns, selectOptions) => {
|
|
4039
|
+
const executeUpsertOne = async (columns, selectOptions, callsite) => {
|
|
2700
4040
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2701
4041
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
2702
4042
|
const payload = {
|
|
@@ -2711,13 +4051,29 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2711
4051
|
if (mergedOptions?.defaultToNull !== void 0) {
|
|
2712
4052
|
payload.default_to_null = mergedOptions.defaultToNull;
|
|
2713
4053
|
}
|
|
2714
|
-
const
|
|
2715
|
-
return
|
|
4054
|
+
const sql = buildInsertDebugSql(payload);
|
|
4055
|
+
return executeWithQueryTrace(
|
|
4056
|
+
tracer,
|
|
4057
|
+
{
|
|
4058
|
+
operation: "upsert",
|
|
4059
|
+
endpoint: "/gateway/insert",
|
|
4060
|
+
table: resolvedTableName,
|
|
4061
|
+
sql,
|
|
4062
|
+
payload,
|
|
4063
|
+
options: mergedOptions
|
|
4064
|
+
},
|
|
4065
|
+
async () => {
|
|
4066
|
+
const response = await client.insertGateway(payload, mergedOptions);
|
|
4067
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
4068
|
+
},
|
|
4069
|
+
callsite
|
|
4070
|
+
);
|
|
2716
4071
|
};
|
|
2717
|
-
return createMutationQuery(executeUpsertOne);
|
|
4072
|
+
return createMutationQuery(executeUpsertOne, DEFAULT_COLUMNS, tracer, mutationCallsite);
|
|
2718
4073
|
},
|
|
2719
4074
|
update(values, options) {
|
|
2720
|
-
const
|
|
4075
|
+
const mutationCallsite = captureTraceCallsite(tracer);
|
|
4076
|
+
const executeUpdate = async (columns, selectOptions, callsite) => {
|
|
2721
4077
|
const filters = state.conditions.length ? [...state.conditions] : void 0;
|
|
2722
4078
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2723
4079
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
@@ -2732,10 +4088,25 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2732
4088
|
if (state.pageSize !== void 0) payload.page_size = state.pageSize;
|
|
2733
4089
|
if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
|
|
2734
4090
|
if (columns) payload.columns = columns;
|
|
2735
|
-
const
|
|
2736
|
-
return
|
|
4091
|
+
const sql = buildUpdateDebugSql(payload);
|
|
4092
|
+
return executeWithQueryTrace(
|
|
4093
|
+
tracer,
|
|
4094
|
+
{
|
|
4095
|
+
operation: "update",
|
|
4096
|
+
endpoint: "/gateway/update",
|
|
4097
|
+
table: resolvedTableName,
|
|
4098
|
+
sql,
|
|
4099
|
+
payload,
|
|
4100
|
+
options: mergedOptions
|
|
4101
|
+
},
|
|
4102
|
+
async () => {
|
|
4103
|
+
const response = await client.updateGateway(payload, mergedOptions);
|
|
4104
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "update" });
|
|
4105
|
+
},
|
|
4106
|
+
callsite
|
|
4107
|
+
);
|
|
2737
4108
|
};
|
|
2738
|
-
const mutation = createMutationQuery(executeUpdate, null);
|
|
4109
|
+
const mutation = createMutationQuery(executeUpdate, null, tracer, mutationCallsite);
|
|
2739
4110
|
const updateChain = {};
|
|
2740
4111
|
const filterMethods2 = createFilterMethods(state, addCondition, updateChain);
|
|
2741
4112
|
Object.assign(updateChain, filterMethods2, mutation);
|
|
@@ -2747,7 +4118,8 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2747
4118
|
if (!resourceId && !filters?.length) {
|
|
2748
4119
|
throw new Error('delete requires a resource_id either via eq("resource_id", ...) or options.resourceId');
|
|
2749
4120
|
}
|
|
2750
|
-
const
|
|
4121
|
+
const mutationCallsite = captureTraceCallsite(tracer);
|
|
4122
|
+
const executeDelete = async (columns, selectOptions, callsite) => {
|
|
2751
4123
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2752
4124
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
2753
4125
|
const payload = {
|
|
@@ -2760,13 +4132,33 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2760
4132
|
if (state.pageSize !== void 0) payload.page_size = state.pageSize;
|
|
2761
4133
|
if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
|
|
2762
4134
|
if (columns) payload.columns = columns;
|
|
2763
|
-
const
|
|
2764
|
-
return
|
|
4135
|
+
const sql = buildDeleteDebugSql(payload);
|
|
4136
|
+
return executeWithQueryTrace(
|
|
4137
|
+
tracer,
|
|
4138
|
+
{
|
|
4139
|
+
operation: "delete",
|
|
4140
|
+
endpoint: "/gateway/delete",
|
|
4141
|
+
table: resolvedTableName,
|
|
4142
|
+
sql,
|
|
4143
|
+
payload,
|
|
4144
|
+
options: mergedOptions
|
|
4145
|
+
},
|
|
4146
|
+
async () => {
|
|
4147
|
+
const response = await client.deleteGateway(payload, mergedOptions);
|
|
4148
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "delete" });
|
|
4149
|
+
},
|
|
4150
|
+
callsite
|
|
4151
|
+
);
|
|
2765
4152
|
};
|
|
2766
|
-
return createMutationQuery(executeDelete, null);
|
|
4153
|
+
return createMutationQuery(executeDelete, null, tracer, mutationCallsite);
|
|
2767
4154
|
},
|
|
2768
4155
|
async single(columns, options) {
|
|
2769
|
-
const response = await
|
|
4156
|
+
const response = await runSelect(
|
|
4157
|
+
columns ?? DEFAULT_COLUMNS,
|
|
4158
|
+
options,
|
|
4159
|
+
snapshotState(),
|
|
4160
|
+
captureTraceCallsite(tracer)
|
|
4161
|
+
);
|
|
2770
4162
|
return toSingleResult(response);
|
|
2771
4163
|
},
|
|
2772
4164
|
async maybeSingle(columns, options) {
|
|
@@ -2775,14 +4167,29 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2775
4167
|
});
|
|
2776
4168
|
return builder;
|
|
2777
4169
|
}
|
|
2778
|
-
function createQueryBuilder(client, formatGatewayResult) {
|
|
4170
|
+
function createQueryBuilder(client, formatGatewayResult, tracer) {
|
|
2779
4171
|
return async function query(query, options) {
|
|
2780
4172
|
const normalizedQuery = query.trim();
|
|
2781
4173
|
if (!normalizedQuery) {
|
|
2782
4174
|
throw new Error("query requires a non-empty string");
|
|
2783
4175
|
}
|
|
2784
|
-
const
|
|
2785
|
-
|
|
4176
|
+
const payload = { query: normalizedQuery };
|
|
4177
|
+
const callsite = captureTraceCallsite(tracer);
|
|
4178
|
+
return executeWithQueryTrace(
|
|
4179
|
+
tracer,
|
|
4180
|
+
{
|
|
4181
|
+
operation: "query",
|
|
4182
|
+
endpoint: "/gateway/query",
|
|
4183
|
+
sql: normalizedQuery,
|
|
4184
|
+
payload,
|
|
4185
|
+
options
|
|
4186
|
+
},
|
|
4187
|
+
async () => {
|
|
4188
|
+
const response = await client.queryGateway(payload, options);
|
|
4189
|
+
return formatGatewayResult(response, { operation: "query" });
|
|
4190
|
+
},
|
|
4191
|
+
callsite
|
|
4192
|
+
);
|
|
2786
4193
|
};
|
|
2787
4194
|
}
|
|
2788
4195
|
function createClientFromConfig(config) {
|
|
@@ -2794,8 +4201,9 @@ function createClientFromConfig(config) {
|
|
|
2794
4201
|
headers: config.headers
|
|
2795
4202
|
});
|
|
2796
4203
|
const formatGatewayResult = createResultFormatter(config.experimental);
|
|
4204
|
+
const queryTracer = createQueryTracer(config.experimental);
|
|
2797
4205
|
const auth = createAuthClient(config.auth);
|
|
2798
|
-
const from = (table) => createTableBuilder(table, gateway, formatGatewayResult);
|
|
4206
|
+
const from = (table) => createTableBuilder(table, gateway, formatGatewayResult, queryTracer, config.experimental);
|
|
2799
4207
|
const rpc = (fn, args, options) => {
|
|
2800
4208
|
const normalizedFn = fn.trim();
|
|
2801
4209
|
if (!normalizedFn) {
|
|
@@ -2806,10 +4214,12 @@ function createClientFromConfig(config) {
|
|
|
2806
4214
|
args,
|
|
2807
4215
|
options,
|
|
2808
4216
|
gateway,
|
|
2809
|
-
formatGatewayResult
|
|
4217
|
+
formatGatewayResult,
|
|
4218
|
+
queryTracer,
|
|
4219
|
+
captureTraceCallsite(queryTracer)
|
|
2810
4220
|
);
|
|
2811
4221
|
};
|
|
2812
|
-
const query = createQueryBuilder(gateway, formatGatewayResult);
|
|
4222
|
+
const query = createQueryBuilder(gateway, formatGatewayResult, queryTracer);
|
|
2813
4223
|
const db = createDbModule({ from, rpc, query });
|
|
2814
4224
|
return {
|
|
2815
4225
|
from,
|
|
@@ -2824,12 +4234,40 @@ function toBackendConfig(b) {
|
|
|
2824
4234
|
if (!b) return DEFAULT_BACKEND;
|
|
2825
4235
|
return typeof b === "string" ? { type: b } : b;
|
|
2826
4236
|
}
|
|
4237
|
+
function mergeAuthClientConfig(current, next) {
|
|
4238
|
+
const merged = {
|
|
4239
|
+
...current ?? {},
|
|
4240
|
+
...next
|
|
4241
|
+
};
|
|
4242
|
+
if (current?.headers || next.headers) {
|
|
4243
|
+
merged.headers = {
|
|
4244
|
+
...current?.headers ?? {},
|
|
4245
|
+
...next.headers ?? {}
|
|
4246
|
+
};
|
|
4247
|
+
}
|
|
4248
|
+
return merged;
|
|
4249
|
+
}
|
|
4250
|
+
function mergeExperimentalOptions(current, next) {
|
|
4251
|
+
const merged = {
|
|
4252
|
+
...current ?? {},
|
|
4253
|
+
...next
|
|
4254
|
+
};
|
|
4255
|
+
if (current?.traceQueries && typeof current.traceQueries === "object" && next.traceQueries && typeof next.traceQueries === "object") {
|
|
4256
|
+
merged.traceQueries = {
|
|
4257
|
+
...current.traceQueries,
|
|
4258
|
+
...next.traceQueries
|
|
4259
|
+
};
|
|
4260
|
+
}
|
|
4261
|
+
return merged;
|
|
4262
|
+
}
|
|
2827
4263
|
var AthenaClientBuilderImpl = class {
|
|
2828
4264
|
baseUrl;
|
|
2829
4265
|
apiKey;
|
|
2830
4266
|
backendConfig = DEFAULT_BACKEND;
|
|
2831
4267
|
clientName;
|
|
2832
4268
|
defaultHeaders;
|
|
4269
|
+
authConfig;
|
|
4270
|
+
experimentalOptions;
|
|
2833
4271
|
isHealthTrackingEnabled = false;
|
|
2834
4272
|
url(url) {
|
|
2835
4273
|
this.baseUrl = url;
|
|
@@ -2851,6 +4289,35 @@ var AthenaClientBuilderImpl = class {
|
|
|
2851
4289
|
this.defaultHeaders = headers;
|
|
2852
4290
|
return this;
|
|
2853
4291
|
}
|
|
4292
|
+
auth(config) {
|
|
4293
|
+
this.authConfig = mergeAuthClientConfig(this.authConfig, config);
|
|
4294
|
+
return this;
|
|
4295
|
+
}
|
|
4296
|
+
experimental(options) {
|
|
4297
|
+
this.experimentalOptions = mergeExperimentalOptions(this.experimentalOptions, options);
|
|
4298
|
+
return this;
|
|
4299
|
+
}
|
|
4300
|
+
options(options) {
|
|
4301
|
+
if (options.client !== void 0) {
|
|
4302
|
+
this.clientName = options.client;
|
|
4303
|
+
}
|
|
4304
|
+
if (options.backend !== void 0) {
|
|
4305
|
+
this.backendConfig = toBackendConfig(options.backend);
|
|
4306
|
+
}
|
|
4307
|
+
if (options.headers !== void 0) {
|
|
4308
|
+
this.defaultHeaders = {
|
|
4309
|
+
...this.defaultHeaders ?? {},
|
|
4310
|
+
...options.headers
|
|
4311
|
+
};
|
|
4312
|
+
}
|
|
4313
|
+
if (options.auth !== void 0) {
|
|
4314
|
+
this.authConfig = mergeAuthClientConfig(this.authConfig, options.auth);
|
|
4315
|
+
}
|
|
4316
|
+
if (options.experimental !== void 0) {
|
|
4317
|
+
this.experimentalOptions = mergeExperimentalOptions(this.experimentalOptions, options.experimental);
|
|
4318
|
+
}
|
|
4319
|
+
return this;
|
|
4320
|
+
}
|
|
2854
4321
|
healthTracking(enabled) {
|
|
2855
4322
|
this.isHealthTrackingEnabled = enabled;
|
|
2856
4323
|
return this;
|
|
@@ -2865,7 +4332,9 @@ var AthenaClientBuilderImpl = class {
|
|
|
2865
4332
|
client: this.clientName,
|
|
2866
4333
|
backend: this.backendConfig,
|
|
2867
4334
|
headers: this.defaultHeaders,
|
|
2868
|
-
healthTracking: this.isHealthTrackingEnabled
|
|
4335
|
+
healthTracking: this.isHealthTrackingEnabled,
|
|
4336
|
+
auth: this.authConfig,
|
|
4337
|
+
experimental: this.experimentalOptions
|
|
2869
4338
|
});
|
|
2870
4339
|
}
|
|
2871
4340
|
};
|
|
@@ -3480,7 +4949,7 @@ function resolveNullishValue(mode) {
|
|
|
3480
4949
|
if (mode === "null") return null;
|
|
3481
4950
|
return "";
|
|
3482
4951
|
}
|
|
3483
|
-
function
|
|
4952
|
+
function isRecord7(value) {
|
|
3484
4953
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3485
4954
|
}
|
|
3486
4955
|
function isNullableColumn(model, key) {
|
|
@@ -3489,7 +4958,7 @@ function isNullableColumn(model, key) {
|
|
|
3489
4958
|
}
|
|
3490
4959
|
function toModelFormDefaults(model, values, options) {
|
|
3491
4960
|
const source = values;
|
|
3492
|
-
if (!
|
|
4961
|
+
if (!isRecord7(source)) {
|
|
3493
4962
|
return {};
|
|
3494
4963
|
}
|
|
3495
4964
|
const mode = options?.nullishMode ?? "empty-string";
|
|
@@ -3745,7 +5214,7 @@ function normalizeBooleanFlag(rawValue, fallback) {
|
|
|
3745
5214
|
return rawValue;
|
|
3746
5215
|
}
|
|
3747
5216
|
if (typeof rawValue === "string") {
|
|
3748
|
-
return
|
|
5217
|
+
return parseBooleanFlag2(rawValue, fallback);
|
|
3749
5218
|
}
|
|
3750
5219
|
return fallback;
|
|
3751
5220
|
}
|
|
@@ -3920,6 +5389,11 @@ async function loadGeneratorConfig(options = {}) {
|
|
|
3920
5389
|
}
|
|
3921
5390
|
}
|
|
3922
5391
|
|
|
5392
|
+
// src/utils/slugify.ts
|
|
5393
|
+
function slugify(input) {
|
|
5394
|
+
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
5395
|
+
}
|
|
5396
|
+
|
|
3923
5397
|
// src/generator/naming.ts
|
|
3924
5398
|
var IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
3925
5399
|
var RESERVED_IDENTIFIERS = /* @__PURE__ */ new Set([
|
|
@@ -4015,7 +5489,7 @@ function applyNamingStyle(input, style) {
|
|
|
4015
5489
|
case "snake":
|
|
4016
5490
|
return words.map((word) => word.toLowerCase()).join("_");
|
|
4017
5491
|
case "kebab":
|
|
4018
|
-
return words.
|
|
5492
|
+
return slugify(words.join("-"));
|
|
4019
5493
|
default:
|
|
4020
5494
|
return input;
|
|
4021
5495
|
}
|
|
@@ -4533,7 +6007,7 @@ var AthenaGatewayCatalogClient = class {
|
|
|
4533
6007
|
async queryRows(query) {
|
|
4534
6008
|
const result = await this.client.query(query);
|
|
4535
6009
|
if (result.error || result.status < 200 || result.status >= 300) {
|
|
4536
|
-
throw new Error(result.error ?? `Gateway query failed with status ${result.status}`);
|
|
6010
|
+
throw new Error(result.error?.message ?? `Gateway query failed with status ${result.status}`);
|
|
4537
6011
|
}
|
|
4538
6012
|
return result.data ?? [];
|
|
4539
6013
|
}
|
|
@@ -4628,10 +6102,24 @@ function resolveGeneratorProvider(providerConfig, experimentalFlags) {
|
|
|
4628
6102
|
}
|
|
4629
6103
|
throw new Error(`Unsupported generator provider kind: ${providerConfig.kind ?? "unknown"}`);
|
|
4630
6104
|
}
|
|
6105
|
+
function canOverwriteArtifact(file) {
|
|
6106
|
+
return file.kind === "model" || file.kind === "schema";
|
|
6107
|
+
}
|
|
6108
|
+
async function fileExists(path) {
|
|
6109
|
+
try {
|
|
6110
|
+
await stat(path);
|
|
6111
|
+
return true;
|
|
6112
|
+
} catch {
|
|
6113
|
+
return false;
|
|
6114
|
+
}
|
|
6115
|
+
}
|
|
4631
6116
|
async function writeArtifacts(files, cwd) {
|
|
4632
6117
|
const writtenFiles = [];
|
|
4633
6118
|
for (const file of files) {
|
|
4634
6119
|
const absolutePath = resolve(cwd, file.path);
|
|
6120
|
+
if (!canOverwriteArtifact(file) && await fileExists(absolutePath)) {
|
|
6121
|
+
continue;
|
|
6122
|
+
}
|
|
4635
6123
|
await mkdir(dirname(absolutePath), { recursive: true });
|
|
4636
6124
|
await writeFile(absolutePath, file.content, "utf8");
|
|
4637
6125
|
writtenFiles.push(file.path);
|
|
@@ -4658,6 +6146,6 @@ async function runSchemaGenerator(options = {}) {
|
|
|
4658
6146
|
};
|
|
4659
6147
|
}
|
|
4660
6148
|
|
|
4661
|
-
export { AthenaClient, AthenaError, AthenaErrorCategory, AthenaErrorCode, AthenaErrorKind, AthenaGatewayError, Backend, DEFAULT_POSTGRES_SCHEMAS, assertInt, coerceInt, createAuthClient, createClient, createModelFormAdapter, createPostgresIntrospectionProvider, createTypedClient, defineDatabase, defineGeneratorConfig, defineModel, defineRegistry, defineSchema, findGeneratorConfigPath, generateArtifactsFromSnapshot, identifier, isAthenaGatewayError, isOk, loadGeneratorConfig, normalizeAthenaError, normalizeGeneratorConfig, normalizeSchemaSelection, parseBooleanFlag, requireAffected, requireSuccess, resolveGeneratorProvider, resolvePostgresColumnType, resolveProviderSchemas, runSchemaGenerator, toModelFormDefaults, toModelPayload, unwrap, unwrapOne, unwrapRows, withRetry };
|
|
6149
|
+
export { AthenaClient, AthenaError, AthenaErrorCategory, AthenaErrorCode, AthenaErrorKind, AthenaGatewayError, Backend, DEFAULT_POSTGRES_SCHEMAS, assertInt, coerceInt, createAuthClient, createAuthReactEmailInput, createClient, createModelFormAdapter, createPostgresIntrospectionProvider, createTypedClient, defineAuthEmailTemplate, defineDatabase, defineGeneratorConfig, defineModel, defineRegistry, defineSchema, findGeneratorConfigPath, generateArtifactsFromSnapshot, identifier, isAthenaGatewayError, isOk, loadGeneratorConfig, normalizeAthenaError, normalizeGeneratorConfig, normalizeSchemaSelection, parseBooleanFlag2 as parseBooleanFlag, renderAthenaReactEmail, requireAffected, requireSuccess, resolveGeneratorProvider, resolvePostgresColumnType, resolveProviderSchemas, runSchemaGenerator, toModelFormDefaults, toModelPayload, unwrap, unwrapOne, unwrapRows, withRetry };
|
|
4662
6150
|
//# sourceMappingURL=index.js.map
|
|
4663
6151
|
//# sourceMappingURL=index.js.map
|