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