@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/cli/index.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import { mkdir, writeFile } from 'fs/promises';
|
|
1
|
+
import { mkdir, writeFile, stat } from 'fs/promises';
|
|
2
2
|
import { resolve, dirname, posix } from 'path';
|
|
3
3
|
import { existsSync, readFileSync } from 'fs';
|
|
4
4
|
import { pathToFileURL } from 'url';
|
|
5
5
|
|
|
6
6
|
// src/generator/pipeline.ts
|
|
7
7
|
|
|
8
|
+
// src/utils/slugify.ts
|
|
9
|
+
function slugify(input) {
|
|
10
|
+
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
11
|
+
}
|
|
12
|
+
|
|
8
13
|
// src/generator/naming.ts
|
|
9
14
|
var IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
10
15
|
var RESERVED_IDENTIFIERS = /* @__PURE__ */ new Set([
|
|
@@ -100,7 +105,7 @@ function applyNamingStyle(input, style) {
|
|
|
100
105
|
case "snake":
|
|
101
106
|
return words.map((word) => word.toLowerCase()).join("_");
|
|
102
107
|
case "kebab":
|
|
103
|
-
return words.
|
|
108
|
+
return slugify(words.join("-"));
|
|
104
109
|
default:
|
|
105
110
|
return input;
|
|
106
111
|
}
|
|
@@ -353,6 +358,19 @@ function isAthenaGatewayError(error) {
|
|
|
353
358
|
return error instanceof AthenaGatewayError;
|
|
354
359
|
}
|
|
355
360
|
|
|
361
|
+
// src/utils/parse-boolean-flag.ts
|
|
362
|
+
function parseBooleanFlag(rawValue, fallback) {
|
|
363
|
+
if (!rawValue) return fallback;
|
|
364
|
+
const normalized = rawValue.trim().toLowerCase();
|
|
365
|
+
if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
|
|
366
|
+
return true;
|
|
367
|
+
}
|
|
368
|
+
if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
return fallback;
|
|
372
|
+
}
|
|
373
|
+
|
|
356
374
|
// src/auxiliaries.ts
|
|
357
375
|
var AthenaErrorCode = {
|
|
358
376
|
UniqueViolation: "UNIQUE_VIOLATION",
|
|
@@ -373,20 +391,41 @@ var AthenaErrorCategory = {
|
|
|
373
391
|
Database: "database",
|
|
374
392
|
Unknown: "unknown"
|
|
375
393
|
};
|
|
376
|
-
function
|
|
377
|
-
|
|
378
|
-
const normalized = rawValue.trim().toLowerCase();
|
|
379
|
-
if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
|
|
380
|
-
return true;
|
|
381
|
-
}
|
|
382
|
-
if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
|
|
383
|
-
return false;
|
|
384
|
-
}
|
|
385
|
-
return fallback;
|
|
394
|
+
function parseBooleanFlag2(rawValue, fallback) {
|
|
395
|
+
return parseBooleanFlag(rawValue, fallback);
|
|
386
396
|
}
|
|
387
397
|
function isRecord(value) {
|
|
388
398
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
389
399
|
}
|
|
400
|
+
function firstNonEmptyString(...values) {
|
|
401
|
+
for (const value of values) {
|
|
402
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
403
|
+
return value.trim();
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return void 0;
|
|
407
|
+
}
|
|
408
|
+
function messageFromUnknownError(error) {
|
|
409
|
+
if (typeof error === "string" && error.trim().length > 0) {
|
|
410
|
+
return error.trim();
|
|
411
|
+
}
|
|
412
|
+
if (error instanceof Error && error.message.trim().length > 0) {
|
|
413
|
+
return error.message.trim();
|
|
414
|
+
}
|
|
415
|
+
if (!isRecord(error)) {
|
|
416
|
+
return void 0;
|
|
417
|
+
}
|
|
418
|
+
return firstNonEmptyString(error.message, error.error, error.details);
|
|
419
|
+
}
|
|
420
|
+
function gatewayCodeFromUnknownError(error) {
|
|
421
|
+
if (!isRecord(error) || typeof error.gatewayCode !== "string") {
|
|
422
|
+
return void 0;
|
|
423
|
+
}
|
|
424
|
+
return error.gatewayCode;
|
|
425
|
+
}
|
|
426
|
+
function isAthenaResultErrorLike(value) {
|
|
427
|
+
return isRecord(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");
|
|
428
|
+
}
|
|
390
429
|
function isAthenaErrorKind(value) {
|
|
391
430
|
return value === "unique_violation" || value === "not_found" || value === "validation" || value === "auth" || value === "rate_limit" || value === "transient" || value === "unknown";
|
|
392
431
|
}
|
|
@@ -508,13 +547,50 @@ function normalizeAthenaError(resultOrError, context) {
|
|
|
508
547
|
return withContextOverrides(attached, context);
|
|
509
548
|
}
|
|
510
549
|
if (isAthenaResultLike(resultOrError)) {
|
|
550
|
+
if (isAthenaResultErrorLike(resultOrError.error)) {
|
|
551
|
+
return {
|
|
552
|
+
kind: resultOrError.error.kind ?? classifyKind(resultOrError.status, gatewayCodeFromUnknownError(resultOrError.error), resultOrError.error.message),
|
|
553
|
+
code: resultOrError.error.athenaCode ?? toAthenaErrorCode(
|
|
554
|
+
resultOrError.error.kind ?? classifyKind(
|
|
555
|
+
resultOrError.status,
|
|
556
|
+
gatewayCodeFromUnknownError(resultOrError.error),
|
|
557
|
+
resultOrError.error.message
|
|
558
|
+
),
|
|
559
|
+
resultOrError.error.status ?? resultOrError.status,
|
|
560
|
+
gatewayCodeFromUnknownError(resultOrError.error)
|
|
561
|
+
),
|
|
562
|
+
category: resultOrError.error.category ?? toAthenaErrorCategory(
|
|
563
|
+
resultOrError.error.kind ?? classifyKind(
|
|
564
|
+
resultOrError.status,
|
|
565
|
+
gatewayCodeFromUnknownError(resultOrError.error),
|
|
566
|
+
resultOrError.error.message
|
|
567
|
+
),
|
|
568
|
+
resultOrError.error.status ?? resultOrError.status
|
|
569
|
+
),
|
|
570
|
+
retryable: resultOrError.error.retryable ?? isRetryable(
|
|
571
|
+
resultOrError.error.kind ?? classifyKind(
|
|
572
|
+
resultOrError.status,
|
|
573
|
+
gatewayCodeFromUnknownError(resultOrError.error),
|
|
574
|
+
resultOrError.error.message
|
|
575
|
+
),
|
|
576
|
+
resultOrError.error.status ?? resultOrError.status
|
|
577
|
+
),
|
|
578
|
+
status: resultOrError.error.status ?? resultOrError.status,
|
|
579
|
+
constraint: resultOrError.error.constraint,
|
|
580
|
+
table: context?.table ?? resultOrError.error.table,
|
|
581
|
+
operation: context?.operation ?? resultOrError.error.operation,
|
|
582
|
+
message: resultOrError.error.message,
|
|
583
|
+
raw: resultOrError.error.raw ?? resultOrError.raw
|
|
584
|
+
};
|
|
585
|
+
}
|
|
511
586
|
const details = resultOrError.errorDetails;
|
|
512
|
-
const message2 = resultOrError.error ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
|
|
587
|
+
const message2 = messageFromUnknownError(resultOrError.error) ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
|
|
513
588
|
const operation = context?.operation ?? operationFromDetails(details);
|
|
514
589
|
const table = context?.table ?? extractTable(message2);
|
|
515
590
|
const constraint = extractConstraint(message2);
|
|
516
|
-
const
|
|
517
|
-
const
|
|
591
|
+
const gatewayCode = details?.code ?? gatewayCodeFromUnknownError(resultOrError.error);
|
|
592
|
+
const kind2 = classifyKind(resultOrError.status, gatewayCode, message2);
|
|
593
|
+
const code = toAthenaErrorCode(kind2, resultOrError.status, gatewayCode);
|
|
518
594
|
const category = toAthenaErrorCategory(kind2, resultOrError.status);
|
|
519
595
|
return {
|
|
520
596
|
kind: kind2,
|
|
@@ -792,7 +868,7 @@ function normalizeBooleanFlag(rawValue, fallback) {
|
|
|
792
868
|
return rawValue;
|
|
793
869
|
}
|
|
794
870
|
if (typeof rawValue === "string") {
|
|
795
|
-
return
|
|
871
|
+
return parseBooleanFlag2(rawValue, fallback);
|
|
796
872
|
}
|
|
797
873
|
return fallback;
|
|
798
874
|
}
|
|
@@ -1309,23 +1385,39 @@ function normalizeHeaderValue(value) {
|
|
|
1309
1385
|
function isRecord2(value) {
|
|
1310
1386
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1311
1387
|
}
|
|
1388
|
+
function nonEmptyString(value) {
|
|
1389
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
1390
|
+
}
|
|
1391
|
+
function resolveStructuredErrorPayload(payload) {
|
|
1392
|
+
if (!isRecord2(payload)) return null;
|
|
1393
|
+
return isRecord2(payload.error) ? payload.error : payload;
|
|
1394
|
+
}
|
|
1312
1395
|
function resolveRequestId(headers) {
|
|
1313
1396
|
return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
|
|
1314
1397
|
}
|
|
1315
1398
|
function resolveErrorMessage(payload, fallback) {
|
|
1316
|
-
|
|
1317
|
-
|
|
1399
|
+
const structuredPayload = resolveStructuredErrorPayload(payload);
|
|
1400
|
+
if (structuredPayload) {
|
|
1401
|
+
const messageCandidates = [structuredPayload.message, structuredPayload.error, structuredPayload.details];
|
|
1318
1402
|
for (const candidate of messageCandidates) {
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
}
|
|
1403
|
+
const resolved = nonEmptyString(candidate);
|
|
1404
|
+
if (resolved) return resolved;
|
|
1322
1405
|
}
|
|
1323
1406
|
}
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
}
|
|
1407
|
+
const rawMessage = nonEmptyString(payload);
|
|
1408
|
+
if (rawMessage) return rawMessage;
|
|
1327
1409
|
return fallback;
|
|
1328
1410
|
}
|
|
1411
|
+
function resolveErrorHint(payload) {
|
|
1412
|
+
const structuredPayload = resolveStructuredErrorPayload(payload);
|
|
1413
|
+
return structuredPayload ? nonEmptyString(structuredPayload.hint) : void 0;
|
|
1414
|
+
}
|
|
1415
|
+
function resolveStatusText(response, payload) {
|
|
1416
|
+
const rawStatusText = nonEmptyString(response.statusText);
|
|
1417
|
+
if (rawStatusText) return rawStatusText;
|
|
1418
|
+
const payloadRecord = isRecord2(payload) ? payload : null;
|
|
1419
|
+
return payloadRecord ? nonEmptyString(payloadRecord.statusText) ?? null : null;
|
|
1420
|
+
}
|
|
1329
1421
|
function detailsFromError(error) {
|
|
1330
1422
|
return error.toDetails();
|
|
1331
1423
|
}
|
|
@@ -1496,6 +1588,7 @@ async function callAthena(config, endpoint, method, payload, options) {
|
|
|
1496
1588
|
return {
|
|
1497
1589
|
ok: false,
|
|
1498
1590
|
status: response.status,
|
|
1591
|
+
statusText: resolveStatusText(response, parsedBody.parsed),
|
|
1499
1592
|
data: null,
|
|
1500
1593
|
error: invalidJsonError.message,
|
|
1501
1594
|
errorDetails: detailsFromError(invalidJsonError),
|
|
@@ -1514,11 +1607,13 @@ async function callAthena(config, endpoint, method, payload, options) {
|
|
|
1514
1607
|
status: response.status,
|
|
1515
1608
|
endpoint,
|
|
1516
1609
|
method,
|
|
1517
|
-
requestId
|
|
1610
|
+
requestId,
|
|
1611
|
+
hint: resolveErrorHint(parsed)
|
|
1518
1612
|
});
|
|
1519
1613
|
return {
|
|
1520
1614
|
ok: false,
|
|
1521
1615
|
status: response.status,
|
|
1616
|
+
statusText: resolveStatusText(response, parsed),
|
|
1522
1617
|
data: null,
|
|
1523
1618
|
error: httpError.message,
|
|
1524
1619
|
errorDetails: detailsFromError(httpError),
|
|
@@ -1530,6 +1625,7 @@ async function callAthena(config, endpoint, method, payload, options) {
|
|
|
1530
1625
|
return {
|
|
1531
1626
|
ok: true,
|
|
1532
1627
|
status: response.status,
|
|
1628
|
+
statusText: resolveStatusText(response, parsed),
|
|
1533
1629
|
data: payloadData ?? null,
|
|
1534
1630
|
count: payloadCount,
|
|
1535
1631
|
error: void 0,
|
|
@@ -1549,6 +1645,7 @@ async function callAthena(config, endpoint, method, payload, options) {
|
|
|
1549
1645
|
return {
|
|
1550
1646
|
ok: false,
|
|
1551
1647
|
status: 0,
|
|
1648
|
+
statusText: null,
|
|
1552
1649
|
data: null,
|
|
1553
1650
|
error: networkError.message,
|
|
1554
1651
|
errorDetails: detailsFromError(networkError),
|
|
@@ -1590,10 +1687,29 @@ function createAthenaGatewayClient(config = {}) {
|
|
|
1590
1687
|
// src/sql-identifiers.ts
|
|
1591
1688
|
var SIMPLE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
1592
1689
|
var COMPOSITE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/;
|
|
1593
|
-
var
|
|
1690
|
+
var SQL_ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
|
|
1691
|
+
var RESPONSE_ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([A-Za-z_][A-Za-z0-9_.]*)$/i;
|
|
1594
1692
|
function quoteIdentifierSegment(identifier) {
|
|
1595
1693
|
return `"${identifier.replace(/"/g, '""')}"`;
|
|
1596
1694
|
}
|
|
1695
|
+
function parseAliasedIdentifierToken(token) {
|
|
1696
|
+
const responseAliasMatch = RESPONSE_ALIAS_PATTERN.exec(token);
|
|
1697
|
+
if (responseAliasMatch) {
|
|
1698
|
+
const [, aliasIdentifier2, baseIdentifier2] = responseAliasMatch;
|
|
1699
|
+
if (COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier2) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier2)) {
|
|
1700
|
+
return { baseIdentifier: baseIdentifier2, aliasIdentifier: aliasIdentifier2 };
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
const sqlAliasMatch = SQL_ALIAS_PATTERN.exec(token);
|
|
1704
|
+
if (!sqlAliasMatch) {
|
|
1705
|
+
return null;
|
|
1706
|
+
}
|
|
1707
|
+
const [, baseIdentifier, aliasIdentifier] = sqlAliasMatch;
|
|
1708
|
+
if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
|
|
1709
|
+
return null;
|
|
1710
|
+
}
|
|
1711
|
+
return { baseIdentifier, aliasIdentifier };
|
|
1712
|
+
}
|
|
1597
1713
|
function quoteQualifiedIdentifier(identifier) {
|
|
1598
1714
|
return identifier.split(".").map((segment) => quoteIdentifierSegment(segment)).join(".");
|
|
1599
1715
|
}
|
|
@@ -1602,23 +1718,27 @@ function quoteSelectToken(token) {
|
|
|
1602
1718
|
if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) {
|
|
1603
1719
|
return quoteQualifiedIdentifier(token);
|
|
1604
1720
|
}
|
|
1605
|
-
const
|
|
1606
|
-
if (!
|
|
1607
|
-
return token;
|
|
1608
|
-
}
|
|
1609
|
-
const [, baseIdentifier, aliasIdentifier] = aliasMatch;
|
|
1610
|
-
if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
|
|
1721
|
+
const aliasedIdentifier = parseAliasedIdentifierToken(token);
|
|
1722
|
+
if (!aliasedIdentifier) {
|
|
1611
1723
|
return token;
|
|
1612
1724
|
}
|
|
1725
|
+
const { baseIdentifier, aliasIdentifier } = aliasedIdentifier;
|
|
1613
1726
|
return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
|
|
1614
1727
|
}
|
|
1728
|
+
function quoteSelectColumnToken(token) {
|
|
1729
|
+
const trimmed = token.trim();
|
|
1730
|
+
if (!trimmed || trimmed === "*") return trimmed || "*";
|
|
1731
|
+
const responseAliasMatch = RESPONSE_ALIAS_PATTERN.exec(trimmed);
|
|
1732
|
+
if (responseAliasMatch) {
|
|
1733
|
+
const [, aliasIdentifier, baseIdentifier] = responseAliasMatch;
|
|
1734
|
+
return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
|
|
1735
|
+
}
|
|
1736
|
+
return quoteQualifiedIdentifier(trimmed);
|
|
1737
|
+
}
|
|
1615
1738
|
function canAutoQuoteToken(token) {
|
|
1616
1739
|
if (token === "*") return true;
|
|
1617
1740
|
if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) return true;
|
|
1618
|
-
|
|
1619
|
-
if (!aliasMatch) return false;
|
|
1620
|
-
const [, baseIdentifier, aliasIdentifier] = aliasMatch;
|
|
1621
|
-
return COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier);
|
|
1741
|
+
return parseAliasedIdentifierToken(token) != null;
|
|
1622
1742
|
}
|
|
1623
1743
|
function splitTopLevelCommaSeparated(input) {
|
|
1624
1744
|
const parts = [];
|
|
@@ -1702,6 +1822,190 @@ function quoteSelectColumnsExpression(columns) {
|
|
|
1702
1822
|
return tokens.map(quoteSelectToken).join(", ");
|
|
1703
1823
|
}
|
|
1704
1824
|
|
|
1825
|
+
// src/auth/react-email.ts
|
|
1826
|
+
var reactEmailRenderModulePromise;
|
|
1827
|
+
function isRecord3(value) {
|
|
1828
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1829
|
+
}
|
|
1830
|
+
function isFunction(value) {
|
|
1831
|
+
return typeof value === "function";
|
|
1832
|
+
}
|
|
1833
|
+
function toStringOrUndefined(value) {
|
|
1834
|
+
if (typeof value !== "string") return void 0;
|
|
1835
|
+
return value;
|
|
1836
|
+
}
|
|
1837
|
+
function nowIsoString() {
|
|
1838
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1839
|
+
}
|
|
1840
|
+
function emitReactEmailEvent(observe, phase, input = {}) {
|
|
1841
|
+
if (!observe) return;
|
|
1842
|
+
try {
|
|
1843
|
+
observe({
|
|
1844
|
+
phase,
|
|
1845
|
+
timestamp: nowIsoString(),
|
|
1846
|
+
...input
|
|
1847
|
+
});
|
|
1848
|
+
} catch {
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
function mergeRenderDefaults(input, defaults) {
|
|
1852
|
+
return {
|
|
1853
|
+
...input,
|
|
1854
|
+
pretty: input.pretty ?? defaults?.pretty,
|
|
1855
|
+
includePlainText: input.includePlainText ?? defaults?.includePlainText
|
|
1856
|
+
};
|
|
1857
|
+
}
|
|
1858
|
+
function mergeRuntimeOptions(options) {
|
|
1859
|
+
if (!options) return void 0;
|
|
1860
|
+
return {
|
|
1861
|
+
defaults: options.defaults,
|
|
1862
|
+
observe: options.observe,
|
|
1863
|
+
route: "route" in options ? options.route : void 0
|
|
1864
|
+
};
|
|
1865
|
+
}
|
|
1866
|
+
async function resolveReactEmailRenderModule() {
|
|
1867
|
+
if (!reactEmailRenderModulePromise) {
|
|
1868
|
+
reactEmailRenderModulePromise = (async () => {
|
|
1869
|
+
try {
|
|
1870
|
+
const loaded = await import('@react-email/render');
|
|
1871
|
+
if (!isFunction(loaded.render)) {
|
|
1872
|
+
throw new Error("missing render(...) export");
|
|
1873
|
+
}
|
|
1874
|
+
return {
|
|
1875
|
+
render: loaded.render,
|
|
1876
|
+
toPlainText: isFunction(loaded.toPlainText) ? loaded.toPlainText : void 0,
|
|
1877
|
+
pretty: isFunction(loaded.pretty) ? loaded.pretty : void 0
|
|
1878
|
+
};
|
|
1879
|
+
} catch (error) {
|
|
1880
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1881
|
+
throw new Error(
|
|
1882
|
+
`React Email rendering requires @react-email/render. Install it in your project (for example: pnpm add @react-email/render). Loader error: ${message}`
|
|
1883
|
+
);
|
|
1884
|
+
}
|
|
1885
|
+
})();
|
|
1886
|
+
}
|
|
1887
|
+
if (!reactEmailRenderModulePromise) {
|
|
1888
|
+
throw new Error("React Email renderer module failed to initialize");
|
|
1889
|
+
}
|
|
1890
|
+
return reactEmailRenderModulePromise;
|
|
1891
|
+
}
|
|
1892
|
+
async function resolveReactEmailElement(input) {
|
|
1893
|
+
if (input.element != null) {
|
|
1894
|
+
return input.element;
|
|
1895
|
+
}
|
|
1896
|
+
if (!input.component) {
|
|
1897
|
+
throw new Error("react email payload requires either `element` or `component`");
|
|
1898
|
+
}
|
|
1899
|
+
try {
|
|
1900
|
+
const reactModule = await import('react');
|
|
1901
|
+
if (typeof reactModule.createElement !== "function") {
|
|
1902
|
+
throw new Error("react createElement(...) export is unavailable");
|
|
1903
|
+
}
|
|
1904
|
+
return reactModule.createElement(
|
|
1905
|
+
input.component,
|
|
1906
|
+
input.props ?? {}
|
|
1907
|
+
);
|
|
1908
|
+
} catch (error) {
|
|
1909
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1910
|
+
throw new Error(
|
|
1911
|
+
`React Email component rendering requires react runtime support. Install react in your project. Loader error: ${message}`
|
|
1912
|
+
);
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
async function renderAthenaReactEmail(input, options) {
|
|
1916
|
+
if (!isRecord3(input)) {
|
|
1917
|
+
throw new Error("react email payload must be an object");
|
|
1918
|
+
}
|
|
1919
|
+
const runtimeOptions = mergeRuntimeOptions(options);
|
|
1920
|
+
const start = Date.now();
|
|
1921
|
+
emitReactEmailEvent(runtimeOptions?.observe, "render:start", {
|
|
1922
|
+
route: runtimeOptions?.route,
|
|
1923
|
+
message: "Rendering react email payload"
|
|
1924
|
+
});
|
|
1925
|
+
try {
|
|
1926
|
+
const normalizedInput = mergeRenderDefaults(input, runtimeOptions?.defaults);
|
|
1927
|
+
const element = await resolveReactEmailElement(normalizedInput);
|
|
1928
|
+
const renderModule = await resolveReactEmailRenderModule();
|
|
1929
|
+
const htmlValue = await renderModule.render(element);
|
|
1930
|
+
const renderedHtml = typeof htmlValue === "string" ? htmlValue : String(htmlValue ?? "");
|
|
1931
|
+
if (!renderedHtml.trim()) {
|
|
1932
|
+
throw new Error("react email renderer returned an empty HTML string");
|
|
1933
|
+
}
|
|
1934
|
+
let html = renderedHtml;
|
|
1935
|
+
if (normalizedInput.pretty && renderModule.pretty) {
|
|
1936
|
+
const prettyValue = await renderModule.pretty(renderedHtml);
|
|
1937
|
+
if (typeof prettyValue === "string" && prettyValue.trim().length > 0) {
|
|
1938
|
+
html = prettyValue;
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
const explicitText = toStringOrUndefined(normalizedInput.text);
|
|
1942
|
+
if (explicitText !== void 0) {
|
|
1943
|
+
emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
|
|
1944
|
+
route: runtimeOptions?.route,
|
|
1945
|
+
durationMs: Date.now() - start,
|
|
1946
|
+
message: "Rendered react email with explicit text"
|
|
1947
|
+
});
|
|
1948
|
+
return {
|
|
1949
|
+
html,
|
|
1950
|
+
text: explicitText
|
|
1951
|
+
};
|
|
1952
|
+
}
|
|
1953
|
+
if (normalizedInput.includePlainText === false || !renderModule.toPlainText) {
|
|
1954
|
+
emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
|
|
1955
|
+
route: runtimeOptions?.route,
|
|
1956
|
+
durationMs: Date.now() - start,
|
|
1957
|
+
message: "Rendered react email without plain-text derivation"
|
|
1958
|
+
});
|
|
1959
|
+
return { html };
|
|
1960
|
+
}
|
|
1961
|
+
const plainTextValue = await renderModule.toPlainText(html);
|
|
1962
|
+
const plainText = toStringOrUndefined(plainTextValue);
|
|
1963
|
+
emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
|
|
1964
|
+
route: runtimeOptions?.route,
|
|
1965
|
+
durationMs: Date.now() - start,
|
|
1966
|
+
message: plainText ? "Rendered react email with derived plain text" : "Rendered react email HTML only"
|
|
1967
|
+
});
|
|
1968
|
+
if (plainText === void 0) {
|
|
1969
|
+
return { html };
|
|
1970
|
+
}
|
|
1971
|
+
return {
|
|
1972
|
+
html,
|
|
1973
|
+
text: plainText
|
|
1974
|
+
};
|
|
1975
|
+
} catch (error) {
|
|
1976
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1977
|
+
emitReactEmailEvent(runtimeOptions?.observe, "render:error", {
|
|
1978
|
+
route: runtimeOptions?.route,
|
|
1979
|
+
durationMs: Date.now() - start,
|
|
1980
|
+
error: message,
|
|
1981
|
+
message: "Failed to render react email payload"
|
|
1982
|
+
});
|
|
1983
|
+
throw error;
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
async function resolveReactEmailPayloadFields(input, fields, options) {
|
|
1987
|
+
const { react, ...payloadWithoutReact } = input;
|
|
1988
|
+
if (!react) {
|
|
1989
|
+
return payloadWithoutReact;
|
|
1990
|
+
}
|
|
1991
|
+
const rendered = await renderAthenaReactEmail(react, options);
|
|
1992
|
+
const payload = {
|
|
1993
|
+
...payloadWithoutReact
|
|
1994
|
+
};
|
|
1995
|
+
payload[fields.htmlField] = rendered.html;
|
|
1996
|
+
const currentTextValue = payload[fields.textField];
|
|
1997
|
+
if (rendered.text !== void 0 && (currentTextValue === void 0 || currentTextValue === null || currentTextValue === "")) {
|
|
1998
|
+
payload[fields.textField] = rendered.text;
|
|
1999
|
+
}
|
|
2000
|
+
if (fields.variablesField && (payload[fields.variablesField] === void 0 || payload[fields.variablesField] === null) && isRecord3(react.props)) {
|
|
2001
|
+
const derivedVariables = Object.keys(react.props);
|
|
2002
|
+
if (derivedVariables.length > 0) {
|
|
2003
|
+
payload[fields.variablesField] = derivedVariables;
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
return payload;
|
|
2007
|
+
}
|
|
2008
|
+
|
|
1705
2009
|
// src/auth/client.ts
|
|
1706
2010
|
var DEFAULT_AUTH_BASE_URL = "http://localhost:3001/api/auth";
|
|
1707
2011
|
var FALLBACK_SDK_VERSION2 = "1.0.0";
|
|
@@ -1711,7 +2015,7 @@ var SDK_HEADER_VALUE2 = `${SDK_NAME2} ${SDK_VERSION2}`;
|
|
|
1711
2015
|
function normalizeBaseUrl(baseUrl) {
|
|
1712
2016
|
return (baseUrl ?? DEFAULT_AUTH_BASE_URL).replace(/\/$/, "");
|
|
1713
2017
|
}
|
|
1714
|
-
function
|
|
2018
|
+
function isRecord4(value) {
|
|
1715
2019
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1716
2020
|
}
|
|
1717
2021
|
function normalizeHeaderValue2(value) {
|
|
@@ -1736,7 +2040,7 @@ function resolveRequestId2(headers) {
|
|
|
1736
2040
|
return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
|
|
1737
2041
|
}
|
|
1738
2042
|
function resolveErrorMessage2(payload, fallback) {
|
|
1739
|
-
if (
|
|
2043
|
+
if (isRecord4(payload)) {
|
|
1740
2044
|
const messageCandidates = [payload.error, payload.message, payload.details];
|
|
1741
2045
|
for (const candidate of messageCandidates) {
|
|
1742
2046
|
if (typeof candidate === "string" && candidate.trim().length > 0) {
|
|
@@ -2062,6 +2366,19 @@ function createAuthClient(config = {}) {
|
|
|
2062
2366
|
options
|
|
2063
2367
|
);
|
|
2064
2368
|
};
|
|
2369
|
+
const withReactEmailRoute = (route) => ({
|
|
2370
|
+
...resolvedConfig.reactEmail,
|
|
2371
|
+
route
|
|
2372
|
+
});
|
|
2373
|
+
const resolveAdminEmailPayload = (route, input) => resolveReactEmailPayloadFields(input, {
|
|
2374
|
+
htmlField: "htmlBody",
|
|
2375
|
+
textField: "textBody"
|
|
2376
|
+
}, withReactEmailRoute(route));
|
|
2377
|
+
const resolveAdminEmailTemplatePayload = (route, input) => resolveReactEmailPayloadFields(input, {
|
|
2378
|
+
htmlField: "htmlTemplate",
|
|
2379
|
+
textField: "textTemplate",
|
|
2380
|
+
variablesField: "variables"
|
|
2381
|
+
}, withReactEmailRoute(route));
|
|
2065
2382
|
const listUserEmailsWithFallback = async (input, options) => {
|
|
2066
2383
|
const primary = await getWithQuery(
|
|
2067
2384
|
"/email/list",
|
|
@@ -2089,7 +2406,7 @@ function createAuthClient(config = {}) {
|
|
|
2089
2406
|
data: null
|
|
2090
2407
|
};
|
|
2091
2408
|
}
|
|
2092
|
-
const fallbackStatus =
|
|
2409
|
+
const fallbackStatus = isRecord4(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
|
|
2093
2410
|
return {
|
|
2094
2411
|
...fallback,
|
|
2095
2412
|
data: {
|
|
@@ -2525,8 +2842,16 @@ function createAuthClient(config = {}) {
|
|
|
2525
2842
|
email: {
|
|
2526
2843
|
list: (input, options) => getWithQuery("/admin/email/list", input, options),
|
|
2527
2844
|
get: (input, options) => getWithQuery("/admin/email/get", input, options),
|
|
2528
|
-
create: (input, options) => postGeneric(
|
|
2529
|
-
|
|
2845
|
+
create: async (input, options) => postGeneric(
|
|
2846
|
+
"/admin/email/create",
|
|
2847
|
+
await resolveAdminEmailPayload("/admin/email/create", input),
|
|
2848
|
+
options
|
|
2849
|
+
),
|
|
2850
|
+
update: async (input, options) => postGeneric(
|
|
2851
|
+
"/admin/email/update",
|
|
2852
|
+
await resolveAdminEmailPayload("/admin/email/update", input),
|
|
2853
|
+
options
|
|
2854
|
+
),
|
|
2530
2855
|
delete: (input, options) => postGeneric("/admin/email/delete", input, options),
|
|
2531
2856
|
failure: {
|
|
2532
2857
|
list: (input, options) => getWithQuery("/admin/email-failure/list", input, options),
|
|
@@ -2538,17 +2863,33 @@ function createAuthClient(config = {}) {
|
|
|
2538
2863
|
template: {
|
|
2539
2864
|
list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
|
|
2540
2865
|
get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
|
|
2541
|
-
create: (input, options) => postGeneric(
|
|
2542
|
-
|
|
2866
|
+
create: async (input, options) => postGeneric(
|
|
2867
|
+
"/admin/email-template/create",
|
|
2868
|
+
await resolveAdminEmailTemplatePayload("/admin/email-template/create", input),
|
|
2869
|
+
options
|
|
2870
|
+
),
|
|
2871
|
+
update: async (input, options) => postGeneric(
|
|
2872
|
+
"/admin/email-template/update",
|
|
2873
|
+
await resolveAdminEmailTemplatePayload("/admin/email-template/update", input),
|
|
2874
|
+
options
|
|
2875
|
+
),
|
|
2543
2876
|
delete: (input, options) => postGeneric("/admin/email-template/delete", input, options)
|
|
2544
2877
|
}
|
|
2545
2878
|
},
|
|
2546
2879
|
emailTemplate: {
|
|
2547
2880
|
get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
|
|
2548
|
-
create: (input, options) => postGeneric(
|
|
2881
|
+
create: async (input, options) => postGeneric(
|
|
2882
|
+
"/admin/email-template/create",
|
|
2883
|
+
await resolveAdminEmailTemplatePayload("/admin/email-template/create", input),
|
|
2884
|
+
options
|
|
2885
|
+
),
|
|
2549
2886
|
delete: (input, options) => postGeneric("/admin/email-template/delete", input, options),
|
|
2550
2887
|
list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
|
|
2551
|
-
update: (input, options) => postGeneric(
|
|
2888
|
+
update: async (input, options) => postGeneric(
|
|
2889
|
+
"/admin/email-template/update",
|
|
2890
|
+
await resolveAdminEmailTemplatePayload("/admin/email-template/update", input),
|
|
2891
|
+
options
|
|
2892
|
+
)
|
|
2552
2893
|
}
|
|
2553
2894
|
},
|
|
2554
2895
|
apiKey: {
|
|
@@ -2771,17 +3112,282 @@ function createDbModule(input) {
|
|
|
2771
3112
|
return db;
|
|
2772
3113
|
}
|
|
2773
3114
|
|
|
3115
|
+
// src/query-ast.ts
|
|
3116
|
+
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;
|
|
3117
|
+
var FILTER_OPERATORS = /* @__PURE__ */ new Set([
|
|
3118
|
+
"eq",
|
|
3119
|
+
"neq",
|
|
3120
|
+
"gt",
|
|
3121
|
+
"gte",
|
|
3122
|
+
"lt",
|
|
3123
|
+
"lte",
|
|
3124
|
+
"like",
|
|
3125
|
+
"ilike",
|
|
3126
|
+
"is",
|
|
3127
|
+
"in",
|
|
3128
|
+
"contains",
|
|
3129
|
+
"containedBy"
|
|
3130
|
+
]);
|
|
3131
|
+
var BOOLEAN_SAFE_OPERATORS = /* @__PURE__ */ new Set([
|
|
3132
|
+
"eq",
|
|
3133
|
+
"neq",
|
|
3134
|
+
"gt",
|
|
3135
|
+
"gte",
|
|
3136
|
+
"lt",
|
|
3137
|
+
"lte",
|
|
3138
|
+
"like",
|
|
3139
|
+
"ilike",
|
|
3140
|
+
"is"
|
|
3141
|
+
]);
|
|
3142
|
+
function isRecord5(value) {
|
|
3143
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3144
|
+
}
|
|
3145
|
+
function isUuidString(value) {
|
|
3146
|
+
return UUID_PATTERN.test(value.trim());
|
|
3147
|
+
}
|
|
3148
|
+
function isUuidIdentifierColumn(column) {
|
|
3149
|
+
return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
|
|
3150
|
+
}
|
|
3151
|
+
function shouldUseUuidTextComparison(column, value) {
|
|
3152
|
+
return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
|
|
3153
|
+
}
|
|
3154
|
+
function isRelationSelectNode(value) {
|
|
3155
|
+
return isRecord5(value) && isRecord5(value.select);
|
|
3156
|
+
}
|
|
3157
|
+
function normalizeIdentifier(value, label) {
|
|
3158
|
+
const normalized = value.trim();
|
|
3159
|
+
if (!normalized) {
|
|
3160
|
+
throw new Error(`${label} must be a non-empty string`);
|
|
3161
|
+
}
|
|
3162
|
+
return normalized;
|
|
3163
|
+
}
|
|
3164
|
+
function stringifyFilterValue(value) {
|
|
3165
|
+
if (Array.isArray(value)) {
|
|
3166
|
+
return value.join(",");
|
|
3167
|
+
}
|
|
3168
|
+
return String(value);
|
|
3169
|
+
}
|
|
3170
|
+
function buildGatewayCondition(operator, column, value) {
|
|
3171
|
+
const condition = { operator };
|
|
3172
|
+
if (column) {
|
|
3173
|
+
condition.column = column;
|
|
3174
|
+
if (operator === "eq") {
|
|
3175
|
+
condition.eq_column = column;
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
if (value !== void 0) {
|
|
3179
|
+
condition.value = value;
|
|
3180
|
+
if (operator === "eq") {
|
|
3181
|
+
condition.eq_value = value;
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
if (operator === "eq" && column && value !== void 0 && shouldUseUuidTextComparison(column, value)) {
|
|
3185
|
+
condition.column_cast = "text";
|
|
3186
|
+
condition.eq_column_cast = "text";
|
|
3187
|
+
}
|
|
3188
|
+
return condition;
|
|
3189
|
+
}
|
|
3190
|
+
function compileRelationToken(key, node) {
|
|
3191
|
+
const nested = compileSelectShape(node.select);
|
|
3192
|
+
const propertyKey = normalizeIdentifier(key, "select relation key");
|
|
3193
|
+
const relationToken = normalizeIdentifier(node.via ?? propertyKey, "select relation token");
|
|
3194
|
+
const alias = node.as?.trim() || (relationToken !== propertyKey ? propertyKey : "");
|
|
3195
|
+
const prefix = alias ? `${alias}:` : "";
|
|
3196
|
+
return `${prefix}${relationToken}(${nested})`;
|
|
3197
|
+
}
|
|
3198
|
+
function compileSelectShape(select) {
|
|
3199
|
+
if (!isRecord5(select)) {
|
|
3200
|
+
throw new Error("findMany select must be an object");
|
|
3201
|
+
}
|
|
3202
|
+
const tokens = [];
|
|
3203
|
+
for (const [rawKey, rawValue] of Object.entries(select)) {
|
|
3204
|
+
if (rawValue === void 0) {
|
|
3205
|
+
continue;
|
|
3206
|
+
}
|
|
3207
|
+
if (rawValue === true) {
|
|
3208
|
+
tokens.push(normalizeIdentifier(rawKey, "select column"));
|
|
3209
|
+
continue;
|
|
3210
|
+
}
|
|
3211
|
+
if (isRelationSelectNode(rawValue)) {
|
|
3212
|
+
tokens.push(compileRelationToken(rawKey, rawValue));
|
|
3213
|
+
continue;
|
|
3214
|
+
}
|
|
3215
|
+
throw new Error(`Unsupported select node for "${rawKey}"`);
|
|
3216
|
+
}
|
|
3217
|
+
if (tokens.length === 0) {
|
|
3218
|
+
throw new Error("findMany select requires at least one field");
|
|
3219
|
+
}
|
|
3220
|
+
return tokens.join(",");
|
|
3221
|
+
}
|
|
3222
|
+
function compileColumnWhere(column, input) {
|
|
3223
|
+
const normalizedColumn = normalizeIdentifier(column, "where column");
|
|
3224
|
+
if (!isRecord5(input)) {
|
|
3225
|
+
return [buildGatewayCondition("eq", normalizedColumn, input)];
|
|
3226
|
+
}
|
|
3227
|
+
const conditions = [];
|
|
3228
|
+
for (const [rawOperator, rawValue] of Object.entries(input)) {
|
|
3229
|
+
if (rawValue === void 0) {
|
|
3230
|
+
continue;
|
|
3231
|
+
}
|
|
3232
|
+
if (!FILTER_OPERATORS.has(rawOperator)) {
|
|
3233
|
+
throw new Error(`Unsupported where operator "${rawOperator}" on "${normalizedColumn}"`);
|
|
3234
|
+
}
|
|
3235
|
+
if ((rawOperator === "in" || rawOperator === "contains" || rawOperator === "containedBy") && !Array.isArray(rawValue)) {
|
|
3236
|
+
throw new Error(`where.${normalizedColumn}.${rawOperator} requires an array value`);
|
|
3237
|
+
}
|
|
3238
|
+
conditions.push(
|
|
3239
|
+
buildGatewayCondition(
|
|
3240
|
+
rawOperator,
|
|
3241
|
+
normalizedColumn,
|
|
3242
|
+
rawValue
|
|
3243
|
+
)
|
|
3244
|
+
);
|
|
3245
|
+
}
|
|
3246
|
+
if (conditions.length === 0) {
|
|
3247
|
+
throw new Error(`where.${normalizedColumn} requires at least one operator`);
|
|
3248
|
+
}
|
|
3249
|
+
return conditions;
|
|
3250
|
+
}
|
|
3251
|
+
function compileBooleanExpressionTerms(clause, label) {
|
|
3252
|
+
if (!isRecord5(clause)) {
|
|
3253
|
+
throw new Error(`findMany where.${label} clauses must be objects`);
|
|
3254
|
+
}
|
|
3255
|
+
const entries = Object.entries(clause).filter(([, value]) => value !== void 0);
|
|
3256
|
+
if (entries.length !== 1) {
|
|
3257
|
+
throw new Error(`findMany where.${label} clauses must target exactly one column`);
|
|
3258
|
+
}
|
|
3259
|
+
const [rawColumn, rawValue] = entries[0];
|
|
3260
|
+
const column = normalizeIdentifier(rawColumn, `where.${label} column`);
|
|
3261
|
+
if (!isRecord5(rawValue)) {
|
|
3262
|
+
return [`${column}.eq.${stringifyFilterValue(rawValue)}`];
|
|
3263
|
+
}
|
|
3264
|
+
const operatorEntries = Object.entries(rawValue).filter(([, value]) => value !== void 0);
|
|
3265
|
+
if (operatorEntries.length === 0) {
|
|
3266
|
+
throw new Error(`findMany where.${label}.${column} requires at least one operator`);
|
|
3267
|
+
}
|
|
3268
|
+
if (label === "not" && operatorEntries.length > 1) {
|
|
3269
|
+
throw new Error("findMany where.not only supports a single lossless operator expression");
|
|
3270
|
+
}
|
|
3271
|
+
return operatorEntries.map(([rawOperator, rawOperand]) => {
|
|
3272
|
+
if (!BOOLEAN_SAFE_OPERATORS.has(rawOperator)) {
|
|
3273
|
+
throw new Error(`findMany where.${label} only supports lossless scalar operators`);
|
|
3274
|
+
}
|
|
3275
|
+
if (Array.isArray(rawOperand)) {
|
|
3276
|
+
throw new Error(`findMany where.${label} does not support array-valued operators`);
|
|
3277
|
+
}
|
|
3278
|
+
return `${column}.${rawOperator}.${stringifyFilterValue(rawOperand)}`;
|
|
3279
|
+
});
|
|
3280
|
+
}
|
|
3281
|
+
function compileWhere(where) {
|
|
3282
|
+
if (where === void 0) {
|
|
3283
|
+
return void 0;
|
|
3284
|
+
}
|
|
3285
|
+
if (!isRecord5(where)) {
|
|
3286
|
+
throw new Error("findMany where must be an object");
|
|
3287
|
+
}
|
|
3288
|
+
const conditions = [];
|
|
3289
|
+
for (const [rawKey, rawValue] of Object.entries(where)) {
|
|
3290
|
+
if (rawValue === void 0) {
|
|
3291
|
+
continue;
|
|
3292
|
+
}
|
|
3293
|
+
if (rawKey === "or") {
|
|
3294
|
+
if (!Array.isArray(rawValue) || rawValue.length === 0) {
|
|
3295
|
+
throw new Error("findMany where.or must be a non-empty array");
|
|
3296
|
+
}
|
|
3297
|
+
const expressions = rawValue.flatMap(
|
|
3298
|
+
(value) => compileBooleanExpressionTerms(value, "or")
|
|
3299
|
+
);
|
|
3300
|
+
conditions.push(buildGatewayCondition("or", void 0, expressions.join(",")));
|
|
3301
|
+
continue;
|
|
3302
|
+
}
|
|
3303
|
+
if (rawKey === "not") {
|
|
3304
|
+
const expressions = compileBooleanExpressionTerms(rawValue, "not");
|
|
3305
|
+
if (expressions.length !== 1) {
|
|
3306
|
+
throw new Error("findMany where.not must compile to exactly one lossless expression");
|
|
3307
|
+
}
|
|
3308
|
+
conditions.push(buildGatewayCondition("not", void 0, expressions[0]));
|
|
3309
|
+
continue;
|
|
3310
|
+
}
|
|
3311
|
+
conditions.push(...compileColumnWhere(rawKey, rawValue));
|
|
3312
|
+
}
|
|
3313
|
+
return conditions.length > 0 ? conditions : void 0;
|
|
3314
|
+
}
|
|
3315
|
+
function resolveOrderDirection(input) {
|
|
3316
|
+
if (typeof input === "boolean") {
|
|
3317
|
+
return input === false ? "descending" : "ascending";
|
|
3318
|
+
}
|
|
3319
|
+
if (typeof input === "string") {
|
|
3320
|
+
const normalized = input.trim().toLowerCase();
|
|
3321
|
+
if (normalized === "asc" || normalized === "ascending") {
|
|
3322
|
+
return "ascending";
|
|
3323
|
+
}
|
|
3324
|
+
if (normalized === "desc" || normalized === "descending") {
|
|
3325
|
+
return "descending";
|
|
3326
|
+
}
|
|
3327
|
+
throw new Error(`Unsupported orderBy direction "${input}"`);
|
|
3328
|
+
}
|
|
3329
|
+
return input.ascending === false ? "descending" : "ascending";
|
|
3330
|
+
}
|
|
3331
|
+
function compileOrderBy(orderBy) {
|
|
3332
|
+
if (orderBy === void 0) {
|
|
3333
|
+
return void 0;
|
|
3334
|
+
}
|
|
3335
|
+
if (!isRecord5(orderBy)) {
|
|
3336
|
+
throw new Error("findMany orderBy must be an object");
|
|
3337
|
+
}
|
|
3338
|
+
if ("column" in orderBy) {
|
|
3339
|
+
return {
|
|
3340
|
+
field: normalizeIdentifier(String(orderBy.column), "orderBy column"),
|
|
3341
|
+
direction: orderBy.ascending === false ? "descending" : "ascending"
|
|
3342
|
+
};
|
|
3343
|
+
}
|
|
3344
|
+
const entries = Object.entries(orderBy).filter(([, value]) => value !== void 0);
|
|
3345
|
+
if (entries.length === 0) {
|
|
3346
|
+
return void 0;
|
|
3347
|
+
}
|
|
3348
|
+
if (entries.length > 1) {
|
|
3349
|
+
throw new Error("findMany orderBy only supports a single column in v1");
|
|
3350
|
+
}
|
|
3351
|
+
const [column, input] = entries[0];
|
|
3352
|
+
return {
|
|
3353
|
+
field: normalizeIdentifier(column, "orderBy column"),
|
|
3354
|
+
direction: resolveOrderDirection(input)
|
|
3355
|
+
};
|
|
3356
|
+
}
|
|
3357
|
+
|
|
2774
3358
|
// src/client.ts
|
|
2775
3359
|
var DEFAULT_COLUMNS = "*";
|
|
2776
|
-
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;
|
|
2777
3360
|
var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
|
|
2778
3361
|
var ATHENA_NORMALIZED_ERROR_KEY = "__athenaNormalizedError";
|
|
3362
|
+
var QUERY_TRACE_STACK_SKIP_PATTERNS = [
|
|
3363
|
+
"src\\client.ts",
|
|
3364
|
+
"src/client.ts",
|
|
3365
|
+
"dist\\client.",
|
|
3366
|
+
"dist/client.",
|
|
3367
|
+
"node_modules\\@xylex-group\\athena",
|
|
3368
|
+
"node_modules/@xylex-group/athena",
|
|
3369
|
+
"node:internal",
|
|
3370
|
+
"internal/process"
|
|
3371
|
+
];
|
|
3372
|
+
function canUseFindManyAstTransport(state) {
|
|
3373
|
+
return state.conditions.length === 0 && state.offset === void 0 && state.currentPage === void 0 && state.pageSize === void 0 && state.totalPages === void 0;
|
|
3374
|
+
}
|
|
3375
|
+
function toFindManyAstOrder(order) {
|
|
3376
|
+
if (!order) {
|
|
3377
|
+
return void 0;
|
|
3378
|
+
}
|
|
3379
|
+
return {
|
|
3380
|
+
column: order.field,
|
|
3381
|
+
ascending: order.direction !== "descending"
|
|
3382
|
+
};
|
|
3383
|
+
}
|
|
2779
3384
|
function formatResult(response) {
|
|
2780
3385
|
const result = {
|
|
2781
3386
|
data: response.data ?? null,
|
|
2782
|
-
error:
|
|
3387
|
+
error: null,
|
|
2783
3388
|
errorDetails: response.errorDetails ?? null,
|
|
2784
3389
|
status: response.status,
|
|
3390
|
+
statusText: response.statusText ?? null,
|
|
2785
3391
|
raw: response.raw
|
|
2786
3392
|
};
|
|
2787
3393
|
if (response.count !== void 0) {
|
|
@@ -2798,26 +3404,243 @@ function attachNormalizedError(result, normalizedError) {
|
|
|
2798
3404
|
});
|
|
2799
3405
|
}
|
|
2800
3406
|
function createResultFormatter(experimental) {
|
|
2801
|
-
if (!experimental?.enableErrorNormalization) {
|
|
2802
|
-
return formatResult;
|
|
2803
|
-
}
|
|
2804
3407
|
return (response, context) => {
|
|
2805
3408
|
const result = formatResult(response);
|
|
2806
|
-
if (
|
|
3409
|
+
if (response.error == null && response.errorDetails == null) {
|
|
2807
3410
|
return result;
|
|
2808
3411
|
}
|
|
2809
|
-
const normalizedError = normalizeAthenaError(
|
|
3412
|
+
const normalizedError = normalizeAthenaError(
|
|
3413
|
+
{
|
|
3414
|
+
...result,
|
|
3415
|
+
error: response.error ?? response.errorDetails?.message ?? null
|
|
3416
|
+
},
|
|
3417
|
+
context
|
|
3418
|
+
);
|
|
3419
|
+
result.error = createResultError(response, result, normalizedError);
|
|
2810
3420
|
attachNormalizedError(result, normalizedError);
|
|
2811
3421
|
return result;
|
|
2812
3422
|
};
|
|
2813
3423
|
}
|
|
2814
|
-
function
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
3424
|
+
function isRecord6(value) {
|
|
3425
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3426
|
+
}
|
|
3427
|
+
function firstNonEmptyString2(...values) {
|
|
3428
|
+
for (const value of values) {
|
|
3429
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
3430
|
+
return value.trim();
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3433
|
+
return void 0;
|
|
3434
|
+
}
|
|
3435
|
+
function resolveStructuredErrorPayload2(raw) {
|
|
3436
|
+
if (!isRecord6(raw)) return null;
|
|
3437
|
+
return isRecord6(raw.error) ? raw.error : raw;
|
|
3438
|
+
}
|
|
3439
|
+
function resolveStructuredErrorDetails(payload, message) {
|
|
3440
|
+
if (!payload || !("details" in payload)) {
|
|
3441
|
+
return null;
|
|
3442
|
+
}
|
|
3443
|
+
const details = payload.details;
|
|
3444
|
+
if (details == null) {
|
|
3445
|
+
return null;
|
|
3446
|
+
}
|
|
3447
|
+
if (typeof details === "string" && details.trim() === message.trim()) {
|
|
3448
|
+
return null;
|
|
3449
|
+
}
|
|
3450
|
+
return details;
|
|
3451
|
+
}
|
|
3452
|
+
function createResultError(response, result, normalized) {
|
|
3453
|
+
const rawRecord = isRecord6(response.raw) ? response.raw : null;
|
|
3454
|
+
const payload = resolveStructuredErrorPayload2(response.raw);
|
|
3455
|
+
const message = firstNonEmptyString2(
|
|
3456
|
+
response.error,
|
|
3457
|
+
payload?.message,
|
|
3458
|
+
payload?.error,
|
|
3459
|
+
payload?.details,
|
|
3460
|
+
response.errorDetails?.message,
|
|
3461
|
+
normalized.message
|
|
3462
|
+
) ?? normalized.message;
|
|
3463
|
+
const statusText = firstNonEmptyString2(response.statusText, rawRecord?.statusText) ?? null;
|
|
3464
|
+
const hint = firstNonEmptyString2(payload?.hint, response.errorDetails?.hint) ?? null;
|
|
3465
|
+
const code = firstNonEmptyString2(payload?.code) ?? normalized.code;
|
|
3466
|
+
const details = resolveStructuredErrorDetails(payload, message) ?? response.errorDetails?.cause ?? null;
|
|
3467
|
+
return {
|
|
3468
|
+
message,
|
|
3469
|
+
code,
|
|
3470
|
+
athenaCode: normalized.code,
|
|
3471
|
+
gatewayCode: response.errorDetails?.code ?? null,
|
|
3472
|
+
kind: normalized.kind,
|
|
3473
|
+
category: normalized.category,
|
|
3474
|
+
retryable: normalized.retryable,
|
|
3475
|
+
details,
|
|
3476
|
+
hint,
|
|
3477
|
+
status: result.status,
|
|
3478
|
+
statusText,
|
|
3479
|
+
constraint: normalized.constraint,
|
|
3480
|
+
table: normalized.table,
|
|
3481
|
+
operation: normalized.operation,
|
|
3482
|
+
endpoint: response.errorDetails?.endpoint,
|
|
3483
|
+
method: response.errorDetails?.method,
|
|
3484
|
+
requestId: response.errorDetails?.requestId,
|
|
3485
|
+
cause: response.errorDetails?.cause,
|
|
3486
|
+
raw: result.raw
|
|
3487
|
+
};
|
|
3488
|
+
}
|
|
3489
|
+
function parseQueryTraceCallsiteFrame(frame) {
|
|
3490
|
+
const trimmed = frame.trim();
|
|
3491
|
+
if (!trimmed) {
|
|
3492
|
+
return null;
|
|
3493
|
+
}
|
|
3494
|
+
let body = trimmed.replace(/^at\s+/, "");
|
|
3495
|
+
if (body.startsWith("async ")) {
|
|
3496
|
+
body = body.slice(6);
|
|
3497
|
+
}
|
|
3498
|
+
let functionName;
|
|
3499
|
+
let location = body;
|
|
3500
|
+
const wrappedMatch = body.match(/^(.*?)\s+\((.*)\)$/);
|
|
3501
|
+
if (wrappedMatch) {
|
|
3502
|
+
functionName = wrappedMatch[1].trim() || void 0;
|
|
3503
|
+
location = wrappedMatch[2].trim();
|
|
3504
|
+
}
|
|
3505
|
+
const locationMatch = location.match(/^(.*):(\d+):(\d+)$/);
|
|
3506
|
+
if (!locationMatch) {
|
|
3507
|
+
return null;
|
|
3508
|
+
}
|
|
3509
|
+
const filePath = locationMatch[1].replace(/^file:\/\//, "");
|
|
3510
|
+
const line = Number(locationMatch[2]);
|
|
3511
|
+
const column = Number(locationMatch[3]);
|
|
3512
|
+
if (!Number.isFinite(line) || !Number.isFinite(column)) {
|
|
3513
|
+
return null;
|
|
3514
|
+
}
|
|
3515
|
+
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
3516
|
+
const fileName = normalizedPath.split("/").at(-1) ?? filePath;
|
|
3517
|
+
return {
|
|
3518
|
+
filePath,
|
|
3519
|
+
fileName,
|
|
3520
|
+
line,
|
|
3521
|
+
column,
|
|
3522
|
+
frame: trimmed,
|
|
3523
|
+
functionName
|
|
3524
|
+
};
|
|
3525
|
+
}
|
|
3526
|
+
function captureQueryTraceCallsite() {
|
|
3527
|
+
const stack = new Error().stack;
|
|
3528
|
+
if (!stack) return null;
|
|
3529
|
+
const frames = stack.split("\n").slice(2).map((frame) => frame.trim()).filter(Boolean);
|
|
3530
|
+
for (const frame of frames) {
|
|
3531
|
+
if (QUERY_TRACE_STACK_SKIP_PATTERNS.some((pattern) => frame.includes(pattern))) {
|
|
3532
|
+
continue;
|
|
3533
|
+
}
|
|
3534
|
+
const callsite = parseQueryTraceCallsiteFrame(frame);
|
|
3535
|
+
if (callsite) return callsite;
|
|
3536
|
+
}
|
|
3537
|
+
const fallback = frames.find((frame) => !frame.includes("captureQueryTraceCallsite"));
|
|
3538
|
+
return fallback ? parseQueryTraceCallsiteFrame(fallback) : null;
|
|
3539
|
+
}
|
|
3540
|
+
function defaultQueryTraceLogger(event) {
|
|
3541
|
+
const target = event.table ?? event.functionName ?? "gateway";
|
|
3542
|
+
const outcomeState = event.outcome?.error ? "error" : "ok";
|
|
3543
|
+
const banner = `[athena-js][trace] ${event.operation.toUpperCase()} ${event.endpoint} ${target} ${event.durationMs}ms ${outcomeState}`;
|
|
3544
|
+
console.info(banner, event);
|
|
3545
|
+
}
|
|
3546
|
+
function captureTraceCallsite(tracer) {
|
|
3547
|
+
return tracer?.captureCallsite() ?? null;
|
|
3548
|
+
}
|
|
3549
|
+
function createTraceCallsiteStore(tracer, initialCallsite) {
|
|
3550
|
+
let storedCallsite = initialCallsite ?? void 0;
|
|
3551
|
+
return {
|
|
3552
|
+
resolve(callsite) {
|
|
3553
|
+
if (callsite) {
|
|
3554
|
+
storedCallsite = callsite;
|
|
3555
|
+
return callsite;
|
|
3556
|
+
}
|
|
3557
|
+
if (storedCallsite !== void 0) {
|
|
3558
|
+
return storedCallsite;
|
|
3559
|
+
}
|
|
3560
|
+
const capturedCallsite = captureTraceCallsite(tracer);
|
|
3561
|
+
if (capturedCallsite) {
|
|
3562
|
+
storedCallsite = capturedCallsite;
|
|
3563
|
+
}
|
|
3564
|
+
return capturedCallsite;
|
|
3565
|
+
}
|
|
3566
|
+
};
|
|
3567
|
+
}
|
|
3568
|
+
function createQueryTracer(experimental) {
|
|
3569
|
+
const traceOption = experimental?.traceQueries;
|
|
3570
|
+
if (!traceOption) {
|
|
3571
|
+
return void 0;
|
|
3572
|
+
}
|
|
3573
|
+
const logger = typeof traceOption === "object" && traceOption.logger ? traceOption.logger : defaultQueryTraceLogger;
|
|
3574
|
+
const emit = (event) => {
|
|
3575
|
+
try {
|
|
3576
|
+
logger(event);
|
|
3577
|
+
} catch (error) {
|
|
3578
|
+
console.warn("[athena-js][trace] logger failed", error);
|
|
3579
|
+
}
|
|
3580
|
+
};
|
|
3581
|
+
return {
|
|
3582
|
+
captureCallsite: captureQueryTraceCallsite,
|
|
3583
|
+
publishSuccess(context, result, durationMs, callsite) {
|
|
3584
|
+
emit({
|
|
3585
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3586
|
+
durationMs,
|
|
3587
|
+
operation: context.operation,
|
|
3588
|
+
endpoint: context.endpoint,
|
|
3589
|
+
table: context.table,
|
|
3590
|
+
functionName: context.functionName,
|
|
3591
|
+
sql: context.sql,
|
|
3592
|
+
payload: context.payload,
|
|
3593
|
+
options: context.options,
|
|
3594
|
+
callsite,
|
|
3595
|
+
outcome: {
|
|
3596
|
+
status: result.status,
|
|
3597
|
+
error: result.error,
|
|
3598
|
+
errorDetails: result.errorDetails ?? null,
|
|
3599
|
+
count: result.count ?? null,
|
|
3600
|
+
data: result.data,
|
|
3601
|
+
raw: result.raw
|
|
3602
|
+
}
|
|
3603
|
+
});
|
|
3604
|
+
},
|
|
3605
|
+
publishFailure(context, error, durationMs, callsite) {
|
|
3606
|
+
emit({
|
|
3607
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3608
|
+
durationMs,
|
|
3609
|
+
operation: context.operation,
|
|
3610
|
+
endpoint: context.endpoint,
|
|
3611
|
+
table: context.table,
|
|
3612
|
+
functionName: context.functionName,
|
|
3613
|
+
sql: context.sql,
|
|
3614
|
+
payload: context.payload,
|
|
3615
|
+
options: context.options,
|
|
3616
|
+
callsite,
|
|
3617
|
+
thrownError: error
|
|
3618
|
+
});
|
|
3619
|
+
}
|
|
3620
|
+
};
|
|
3621
|
+
}
|
|
3622
|
+
async function executeWithQueryTrace(tracer, context, runner, callsiteOverride) {
|
|
3623
|
+
if (!tracer) {
|
|
3624
|
+
return runner();
|
|
3625
|
+
}
|
|
3626
|
+
const callsite = callsiteOverride ?? tracer.captureCallsite();
|
|
3627
|
+
const startedAt = Date.now();
|
|
3628
|
+
try {
|
|
3629
|
+
const result = await runner();
|
|
3630
|
+
tracer.publishSuccess(context, result, Date.now() - startedAt, callsite);
|
|
3631
|
+
return result;
|
|
3632
|
+
} catch (error) {
|
|
3633
|
+
tracer.publishFailure(context, error, Date.now() - startedAt, callsite);
|
|
3634
|
+
throw error;
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
function toSingleResult(response) {
|
|
3638
|
+
const payload = response.data;
|
|
3639
|
+
const singleData = Array.isArray(payload) ? payload.length ? payload[0] : null : payload ?? null;
|
|
3640
|
+
return {
|
|
3641
|
+
...response,
|
|
3642
|
+
data: singleData
|
|
3643
|
+
};
|
|
2821
3644
|
}
|
|
2822
3645
|
function mergeOptions(...options) {
|
|
2823
3646
|
return options.reduce((acc, next) => {
|
|
@@ -2831,15 +3654,16 @@ function asAthenaJsonObject(value) {
|
|
|
2831
3654
|
function asAthenaJsonObjectArray(values) {
|
|
2832
3655
|
return values;
|
|
2833
3656
|
}
|
|
2834
|
-
function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
|
|
3657
|
+
function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS, tracer, initialCallsite) {
|
|
2835
3658
|
let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
|
|
2836
3659
|
let selectedOptions;
|
|
2837
3660
|
let promise = null;
|
|
2838
|
-
const
|
|
3661
|
+
const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
|
|
3662
|
+
const run = (columns, options, callsite) => {
|
|
2839
3663
|
const payloadColumns = columns ?? selectedColumns;
|
|
2840
3664
|
const payloadOptions = options ?? selectedOptions;
|
|
2841
3665
|
if (!promise) {
|
|
2842
|
-
promise = executor(payloadColumns, payloadOptions);
|
|
3666
|
+
promise = executor(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
|
|
2843
3667
|
}
|
|
2844
3668
|
return promise;
|
|
2845
3669
|
};
|
|
@@ -2847,7 +3671,7 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
|
|
|
2847
3671
|
select(columns = selectedColumns, options) {
|
|
2848
3672
|
selectedColumns = columns;
|
|
2849
3673
|
selectedOptions = options ?? selectedOptions;
|
|
2850
|
-
return run(columns, options);
|
|
3674
|
+
return run(columns, options, captureTraceCallsite(tracer));
|
|
2851
3675
|
},
|
|
2852
3676
|
returning(columns = selectedColumns, options) {
|
|
2853
3677
|
return mutationQuery.select(columns, options);
|
|
@@ -2855,7 +3679,7 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
|
|
|
2855
3679
|
single(columns = selectedColumns, options) {
|
|
2856
3680
|
selectedColumns = columns;
|
|
2857
3681
|
selectedOptions = options ?? selectedOptions;
|
|
2858
|
-
return run(columns, options).then(toSingleResult);
|
|
3682
|
+
return run(columns, options, captureTraceCallsite(tracer)).then(toSingleResult);
|
|
2859
3683
|
},
|
|
2860
3684
|
maybeSingle(columns = selectedColumns, options) {
|
|
2861
3685
|
return mutationQuery.single(columns, options);
|
|
@@ -2878,21 +3702,12 @@ function getResourceId(state) {
|
|
|
2878
3702
|
);
|
|
2879
3703
|
return candidate?.value?.toString();
|
|
2880
3704
|
}
|
|
2881
|
-
function
|
|
3705
|
+
function stringifyFilterValue2(value) {
|
|
2882
3706
|
if (Array.isArray(value)) {
|
|
2883
3707
|
return value.join(",");
|
|
2884
3708
|
}
|
|
2885
3709
|
return String(value);
|
|
2886
3710
|
}
|
|
2887
|
-
function isUuidString(value) {
|
|
2888
|
-
return UUID_PATTERN.test(value.trim());
|
|
2889
|
-
}
|
|
2890
|
-
function isUuidIdentifierColumn(column) {
|
|
2891
|
-
return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
|
|
2892
|
-
}
|
|
2893
|
-
function shouldUseUuidTextComparison(column, value) {
|
|
2894
|
-
return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
|
|
2895
|
-
}
|
|
2896
3711
|
function normalizeCast(cast) {
|
|
2897
3712
|
const normalized = cast.trim().toLowerCase();
|
|
2898
3713
|
if (!SAFE_CAST_PATTERN.test(normalized)) {
|
|
@@ -2915,25 +3730,92 @@ function withCast(expression, cast) {
|
|
|
2915
3730
|
}
|
|
2916
3731
|
function buildSelectColumnsClause(columns) {
|
|
2917
3732
|
if (Array.isArray(columns)) {
|
|
2918
|
-
return columns.map((column) =>
|
|
3733
|
+
return columns.map((column) => quoteSelectColumnToken(column)).join(", ");
|
|
2919
3734
|
}
|
|
2920
3735
|
return quoteSelectColumnsExpression(columns);
|
|
2921
3736
|
}
|
|
3737
|
+
function parseIdentifierSegment(input) {
|
|
3738
|
+
const trimmed = input.trim();
|
|
3739
|
+
if (!trimmed) return null;
|
|
3740
|
+
if (!trimmed.startsWith('"')) {
|
|
3741
|
+
return {
|
|
3742
|
+
normalizedValue: trimmed.toLowerCase()
|
|
3743
|
+
};
|
|
3744
|
+
}
|
|
3745
|
+
let value = "";
|
|
3746
|
+
let index = 1;
|
|
3747
|
+
let closed = false;
|
|
3748
|
+
while (index < trimmed.length) {
|
|
3749
|
+
const char = trimmed[index];
|
|
3750
|
+
const next = index + 1 < trimmed.length ? trimmed[index + 1] : "";
|
|
3751
|
+
if (char === '"' && next === '"') {
|
|
3752
|
+
value += '"';
|
|
3753
|
+
index += 2;
|
|
3754
|
+
continue;
|
|
3755
|
+
}
|
|
3756
|
+
if (char === '"') {
|
|
3757
|
+
closed = true;
|
|
3758
|
+
index += 1;
|
|
3759
|
+
break;
|
|
3760
|
+
}
|
|
3761
|
+
value += char;
|
|
3762
|
+
index += 1;
|
|
3763
|
+
}
|
|
3764
|
+
if (!closed || trimmed.slice(index).trim().length > 0 || !value.trim()) {
|
|
3765
|
+
return null;
|
|
3766
|
+
}
|
|
3767
|
+
return {
|
|
3768
|
+
normalizedValue: value
|
|
3769
|
+
};
|
|
3770
|
+
}
|
|
3771
|
+
function splitQualifiedTableName(tableName) {
|
|
3772
|
+
const trimmed = tableName.trim();
|
|
3773
|
+
let inQuotes = false;
|
|
3774
|
+
for (let index = 0; index < trimmed.length; index += 1) {
|
|
3775
|
+
const char = trimmed[index];
|
|
3776
|
+
const next = index + 1 < trimmed.length ? trimmed[index + 1] : "";
|
|
3777
|
+
if (char === '"') {
|
|
3778
|
+
if (inQuotes && next === '"') {
|
|
3779
|
+
index += 1;
|
|
3780
|
+
continue;
|
|
3781
|
+
}
|
|
3782
|
+
inQuotes = !inQuotes;
|
|
3783
|
+
continue;
|
|
3784
|
+
}
|
|
3785
|
+
if (char === "." && !inQuotes) {
|
|
3786
|
+
const schemaSegment = trimmed.slice(0, index).trim();
|
|
3787
|
+
const tableSegment = trimmed.slice(index + 1).trim();
|
|
3788
|
+
if (!schemaSegment || !tableSegment) {
|
|
3789
|
+
return null;
|
|
3790
|
+
}
|
|
3791
|
+
return { schemaSegment };
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
return null;
|
|
3795
|
+
}
|
|
2922
3796
|
function resolveTableNameForCall(tableName, schema) {
|
|
2923
3797
|
if (!schema) return tableName;
|
|
2924
3798
|
const normalizedSchema = schema.trim();
|
|
2925
3799
|
if (!normalizedSchema) {
|
|
2926
3800
|
throw new Error("schema option must be a non-empty string");
|
|
2927
3801
|
}
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
3802
|
+
const normalizedTableName = tableName.trim();
|
|
3803
|
+
const parsedSchema = parseIdentifierSegment(normalizedSchema);
|
|
3804
|
+
if (!parsedSchema) {
|
|
3805
|
+
throw new Error("schema option must be a non-empty string");
|
|
3806
|
+
}
|
|
3807
|
+
const qualified = splitQualifiedTableName(normalizedTableName);
|
|
3808
|
+
if (qualified) {
|
|
3809
|
+
const parsedTableSchema = parseIdentifierSegment(qualified.schemaSegment);
|
|
3810
|
+
const sameSchema = parsedTableSchema ? parsedTableSchema.normalizedValue === parsedSchema.normalizedValue : normalizedTableName.startsWith(`${normalizedSchema}.`);
|
|
3811
|
+
if (sameSchema) {
|
|
3812
|
+
return normalizedTableName;
|
|
2931
3813
|
}
|
|
2932
3814
|
throw new Error(
|
|
2933
|
-
`schema option "${normalizedSchema}" conflicts with schema-qualified table "${
|
|
3815
|
+
`schema option "${normalizedSchema}" conflicts with schema-qualified table "${normalizedTableName}"`
|
|
2934
3816
|
);
|
|
2935
3817
|
}
|
|
2936
|
-
return `${normalizedSchema}.${
|
|
3818
|
+
return `${normalizedSchema}.${normalizedTableName}`;
|
|
2937
3819
|
}
|
|
2938
3820
|
function conditionToSqlClause(condition) {
|
|
2939
3821
|
if (!condition.column) return null;
|
|
@@ -3011,6 +3893,237 @@ function buildTypedSelectQuery(input) {
|
|
|
3011
3893
|
}
|
|
3012
3894
|
return `${sqlParts.join(" ")};`;
|
|
3013
3895
|
}
|
|
3896
|
+
function sanitizeSqlComment(comment) {
|
|
3897
|
+
return comment.replace(/\*\//g, "* /");
|
|
3898
|
+
}
|
|
3899
|
+
function toSqlJsonLiteral(value) {
|
|
3900
|
+
if (value === void 0) return "DEFAULT";
|
|
3901
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
3902
|
+
return toSqlLiteral(value);
|
|
3903
|
+
}
|
|
3904
|
+
return `'${escapeSqlStringLiteral(JSON.stringify(value))}'::jsonb`;
|
|
3905
|
+
}
|
|
3906
|
+
function conditionToDebugSqlClause(condition) {
|
|
3907
|
+
const exact = conditionToSqlClause(condition);
|
|
3908
|
+
if (exact) return exact;
|
|
3909
|
+
const rawCondition = sanitizeSqlComment(JSON.stringify(condition));
|
|
3910
|
+
if (!condition.column) {
|
|
3911
|
+
return `TRUE /* unsupported condition: ${rawCondition} */`;
|
|
3912
|
+
}
|
|
3913
|
+
const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
|
|
3914
|
+
const value = condition.value;
|
|
3915
|
+
const rhs = withCast(toSqlJsonLiteral(value), condition.value_cast);
|
|
3916
|
+
switch (condition.operator) {
|
|
3917
|
+
case "contains":
|
|
3918
|
+
return `${column} @> ${rhs}`;
|
|
3919
|
+
case "containedBy":
|
|
3920
|
+
return `${column} <@ ${rhs}`;
|
|
3921
|
+
case "not":
|
|
3922
|
+
return `TRUE /* NOT expression passthrough: ${rawCondition} */`;
|
|
3923
|
+
case "or":
|
|
3924
|
+
return `TRUE /* OR expression passthrough: ${rawCondition} */`;
|
|
3925
|
+
default:
|
|
3926
|
+
return `TRUE /* unsupported condition: ${rawCondition} */`;
|
|
3927
|
+
}
|
|
3928
|
+
}
|
|
3929
|
+
function resolvePagination(input) {
|
|
3930
|
+
let limit = input.limit;
|
|
3931
|
+
let offset = input.offset;
|
|
3932
|
+
if (limit === void 0 && input.pageSize !== void 0) {
|
|
3933
|
+
limit = input.pageSize;
|
|
3934
|
+
}
|
|
3935
|
+
if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
|
|
3936
|
+
offset = (input.currentPage - 1) * input.pageSize;
|
|
3937
|
+
}
|
|
3938
|
+
return { limit, offset };
|
|
3939
|
+
}
|
|
3940
|
+
function appendOrderLimitOffset(sqlParts, order, limit, offset) {
|
|
3941
|
+
if (order?.field) {
|
|
3942
|
+
const direction = order.direction === "descending" ? "DESC" : "ASC";
|
|
3943
|
+
sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(order.field)} ${direction}`);
|
|
3944
|
+
}
|
|
3945
|
+
if (limit !== void 0) {
|
|
3946
|
+
sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(limit))}`);
|
|
3947
|
+
}
|
|
3948
|
+
if (offset !== void 0) {
|
|
3949
|
+
sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
|
|
3950
|
+
}
|
|
3951
|
+
}
|
|
3952
|
+
function buildDebugSelectQuery(input) {
|
|
3953
|
+
const sqlParts = [
|
|
3954
|
+
`SELECT ${buildSelectColumnsClause(input.columns)} FROM ${quoteQualifiedIdentifier(input.tableName)}`
|
|
3955
|
+
];
|
|
3956
|
+
if (input.conditions?.length) {
|
|
3957
|
+
const whereClauses = input.conditions.map(conditionToDebugSqlClause);
|
|
3958
|
+
sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
|
|
3959
|
+
}
|
|
3960
|
+
const pagination = resolvePagination(input);
|
|
3961
|
+
appendOrderLimitOffset(sqlParts, input.order, pagination.limit, pagination.offset);
|
|
3962
|
+
return `${sqlParts.join(" ")};`;
|
|
3963
|
+
}
|
|
3964
|
+
function resolveDebugTableIdentifier(tableName) {
|
|
3965
|
+
if (!tableName?.trim()) {
|
|
3966
|
+
return '"__unknown_table__"';
|
|
3967
|
+
}
|
|
3968
|
+
return quoteQualifiedIdentifier(tableName);
|
|
3969
|
+
}
|
|
3970
|
+
function buildInsertDebugSql(payload) {
|
|
3971
|
+
const rows = Array.isArray(payload.insert_body) ? payload.insert_body : [payload.insert_body];
|
|
3972
|
+
const columns = [];
|
|
3973
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3974
|
+
for (const row of rows) {
|
|
3975
|
+
for (const column of Object.keys(row)) {
|
|
3976
|
+
if (seen.has(column)) continue;
|
|
3977
|
+
seen.add(column);
|
|
3978
|
+
columns.push(column);
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
const sqlParts = [`INSERT INTO ${quoteQualifiedIdentifier(payload.table_name)}`];
|
|
3982
|
+
if (!rows.length || !columns.length) {
|
|
3983
|
+
sqlParts.push("DEFAULT VALUES");
|
|
3984
|
+
if (rows.length > 1) {
|
|
3985
|
+
sqlParts.push(`/* trace: ${rows.length} rows collapsed to DEFAULT VALUES */`);
|
|
3986
|
+
}
|
|
3987
|
+
} else {
|
|
3988
|
+
const valuesClause = rows.map((row) => {
|
|
3989
|
+
const values = columns.map((column) => {
|
|
3990
|
+
const hasColumn = Object.prototype.hasOwnProperty.call(row, column);
|
|
3991
|
+
if (!hasColumn) {
|
|
3992
|
+
return payload.default_to_null ? "NULL" : "DEFAULT";
|
|
3993
|
+
}
|
|
3994
|
+
const rowValue = row[column];
|
|
3995
|
+
return toSqlJsonLiteral(rowValue);
|
|
3996
|
+
});
|
|
3997
|
+
return `(${values.join(", ")})`;
|
|
3998
|
+
}).join(", ");
|
|
3999
|
+
const columnClause = columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
|
|
4000
|
+
sqlParts.push(`(${columnClause})`);
|
|
4001
|
+
sqlParts.push(`VALUES ${valuesClause}`);
|
|
4002
|
+
}
|
|
4003
|
+
if (payload.on_conflict) {
|
|
4004
|
+
const conflictColumns = Array.isArray(payload.on_conflict) ? payload.on_conflict.map((column) => quoteQualifiedIdentifier(column)).join(", ") : payload.on_conflict;
|
|
4005
|
+
if (payload.update_body && Object.keys(payload.update_body).length > 0) {
|
|
4006
|
+
const assignments = Object.entries(payload.update_body).map(
|
|
4007
|
+
([column, value]) => `${quoteQualifiedIdentifier(column)} = ${toSqlJsonLiteral(value)}`
|
|
4008
|
+
);
|
|
4009
|
+
sqlParts.push(`ON CONFLICT (${conflictColumns}) DO UPDATE SET ${assignments.join(", ")}`);
|
|
4010
|
+
} else {
|
|
4011
|
+
sqlParts.push(`ON CONFLICT (${conflictColumns}) DO NOTHING`);
|
|
4012
|
+
}
|
|
4013
|
+
}
|
|
4014
|
+
if (payload.columns) {
|
|
4015
|
+
sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
|
|
4016
|
+
}
|
|
4017
|
+
return `${sqlParts.join(" ")};`;
|
|
4018
|
+
}
|
|
4019
|
+
function buildUpdateDebugSql(payload) {
|
|
4020
|
+
const set = payload.set ?? payload.data ?? {};
|
|
4021
|
+
const assignments = Object.entries(set).map(
|
|
4022
|
+
([column, value]) => `${quoteQualifiedIdentifier(column)} = ${toSqlJsonLiteral(value)}`
|
|
4023
|
+
);
|
|
4024
|
+
const sqlParts = [
|
|
4025
|
+
`UPDATE ${resolveDebugTableIdentifier(payload.table_name)} SET ${assignments.length ? assignments.join(", ") : "/* empty set */"}`
|
|
4026
|
+
];
|
|
4027
|
+
if (payload.conditions?.length) {
|
|
4028
|
+
const whereClauses = payload.conditions.map(conditionToDebugSqlClause);
|
|
4029
|
+
sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
|
|
4030
|
+
}
|
|
4031
|
+
const pagination = resolvePagination({
|
|
4032
|
+
currentPage: payload.current_page,
|
|
4033
|
+
pageSize: payload.page_size
|
|
4034
|
+
});
|
|
4035
|
+
appendOrderLimitOffset(sqlParts, payload.sort_by, pagination.limit, pagination.offset);
|
|
4036
|
+
if (payload.columns) {
|
|
4037
|
+
sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
|
|
4038
|
+
}
|
|
4039
|
+
return `${sqlParts.join(" ")};`;
|
|
4040
|
+
}
|
|
4041
|
+
function buildDeleteDebugSql(payload) {
|
|
4042
|
+
const sqlParts = [`DELETE FROM ${quoteQualifiedIdentifier(payload.table_name)}`];
|
|
4043
|
+
const whereClauses = [];
|
|
4044
|
+
if (payload.resource_id) {
|
|
4045
|
+
whereClauses.push(`"resource_id" = ${toSqlLiteral(payload.resource_id)}`);
|
|
4046
|
+
}
|
|
4047
|
+
if (payload.conditions?.length) {
|
|
4048
|
+
whereClauses.push(...payload.conditions.map(conditionToDebugSqlClause));
|
|
4049
|
+
}
|
|
4050
|
+
if (whereClauses.length) {
|
|
4051
|
+
sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
|
|
4052
|
+
}
|
|
4053
|
+
const pagination = resolvePagination({
|
|
4054
|
+
currentPage: payload.current_page,
|
|
4055
|
+
pageSize: payload.page_size
|
|
4056
|
+
});
|
|
4057
|
+
appendOrderLimitOffset(sqlParts, payload.sort_by, pagination.limit, pagination.offset);
|
|
4058
|
+
if (payload.columns) {
|
|
4059
|
+
sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
|
|
4060
|
+
}
|
|
4061
|
+
return `${sqlParts.join(" ")};`;
|
|
4062
|
+
}
|
|
4063
|
+
function rpcFilterToSqlClause(filter) {
|
|
4064
|
+
const column = quoteQualifiedIdentifier(filter.column);
|
|
4065
|
+
const value = filter.value;
|
|
4066
|
+
switch (filter.operator) {
|
|
4067
|
+
case "eq":
|
|
4068
|
+
case "neq":
|
|
4069
|
+
case "gt":
|
|
4070
|
+
case "gte":
|
|
4071
|
+
case "lt":
|
|
4072
|
+
case "lte":
|
|
4073
|
+
case "like":
|
|
4074
|
+
case "ilike": {
|
|
4075
|
+
if (value === void 0 || Array.isArray(value)) {
|
|
4076
|
+
return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
|
|
4077
|
+
}
|
|
4078
|
+
const operatorMap = {
|
|
4079
|
+
eq: "=",
|
|
4080
|
+
neq: "!=",
|
|
4081
|
+
gt: ">",
|
|
4082
|
+
gte: ">=",
|
|
4083
|
+
lt: "<",
|
|
4084
|
+
lte: "<=",
|
|
4085
|
+
like: "LIKE",
|
|
4086
|
+
ilike: "ILIKE"
|
|
4087
|
+
};
|
|
4088
|
+
return `${column} ${operatorMap[filter.operator]} ${toSqlLiteral(value)}`;
|
|
4089
|
+
}
|
|
4090
|
+
case "is":
|
|
4091
|
+
if (value === null) return `${column} IS NULL`;
|
|
4092
|
+
if (value === true) return `${column} IS TRUE`;
|
|
4093
|
+
if (value === false) return `${column} IS FALSE`;
|
|
4094
|
+
return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
|
|
4095
|
+
case "in":
|
|
4096
|
+
if (!Array.isArray(value)) {
|
|
4097
|
+
return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
|
|
4098
|
+
}
|
|
4099
|
+
if (value.length === 0) return "FALSE";
|
|
4100
|
+
return `${column} IN (${value.map((item) => toSqlLiteral(item)).join(", ")})`;
|
|
4101
|
+
default:
|
|
4102
|
+
return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
function buildRpcDebugSql(payload) {
|
|
4106
|
+
const argsEntries = payload.args ? Object.entries(payload.args) : [];
|
|
4107
|
+
const argsClause = argsEntries.map(([key, value]) => `${quoteQualifiedIdentifier(key)} => ${toSqlJsonLiteral(value)}`).join(", ");
|
|
4108
|
+
const functionRef = payload.schema ? `${quoteQualifiedIdentifier(payload.schema)}.${quoteQualifiedIdentifier(payload.function)}` : quoteQualifiedIdentifier(payload.function);
|
|
4109
|
+
const sqlParts = [
|
|
4110
|
+
`SELECT ${payload.select ? quoteSelectColumnsExpression(payload.select) : "*"} FROM ${functionRef}(${argsClause})`
|
|
4111
|
+
];
|
|
4112
|
+
if (payload.filters?.length) {
|
|
4113
|
+
sqlParts.push(`WHERE ${payload.filters.map(rpcFilterToSqlClause).join(" AND ")}`);
|
|
4114
|
+
}
|
|
4115
|
+
if (payload.order?.column) {
|
|
4116
|
+
const direction = payload.order.ascending === false ? "DESC" : "ASC";
|
|
4117
|
+
sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(payload.order.column)} ${direction}`);
|
|
4118
|
+
}
|
|
4119
|
+
if (payload.limit !== void 0) {
|
|
4120
|
+
sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(payload.limit))}`);
|
|
4121
|
+
}
|
|
4122
|
+
if (payload.offset !== void 0) {
|
|
4123
|
+
sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(payload.offset))}`);
|
|
4124
|
+
}
|
|
4125
|
+
return `${sqlParts.join(" ")};`;
|
|
4126
|
+
}
|
|
3014
4127
|
function createFilterMethods(state, addCondition, self) {
|
|
3015
4128
|
return {
|
|
3016
4129
|
eq(column, value) {
|
|
@@ -3122,7 +4235,7 @@ function createFilterMethods(state, addCondition, self) {
|
|
|
3122
4235
|
not(columnOrExpression, operator, value) {
|
|
3123
4236
|
const expression = String(columnOrExpression);
|
|
3124
4237
|
if (operator != null && value !== void 0) {
|
|
3125
|
-
addCondition("not", void 0, `${expression}.${operator}.${
|
|
4238
|
+
addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue2(value)}`);
|
|
3126
4239
|
} else {
|
|
3127
4240
|
addCondition("not", void 0, expression);
|
|
3128
4241
|
}
|
|
@@ -3185,14 +4298,15 @@ function createRpcFilterMethods(filters, self) {
|
|
|
3185
4298
|
}
|
|
3186
4299
|
};
|
|
3187
4300
|
}
|
|
3188
|
-
function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult) {
|
|
4301
|
+
function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult, tracer, initialCallsite) {
|
|
3189
4302
|
const state = {
|
|
3190
4303
|
filters: []
|
|
3191
4304
|
};
|
|
3192
4305
|
let selectedColumns;
|
|
3193
4306
|
let selectedOptions;
|
|
3194
4307
|
let promise = null;
|
|
3195
|
-
const
|
|
4308
|
+
const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
|
|
4309
|
+
const executeRpc = async (columns, options, callsite) => {
|
|
3196
4310
|
const mergedOptions = mergeOptions(baseOptions, options);
|
|
3197
4311
|
const payload = {
|
|
3198
4312
|
function: functionName,
|
|
@@ -3206,14 +4320,30 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
|
|
|
3206
4320
|
offset: state.offset,
|
|
3207
4321
|
order: state.order
|
|
3208
4322
|
};
|
|
3209
|
-
const
|
|
3210
|
-
|
|
4323
|
+
const endpoint = mergedOptions?.get ? `/rpc/${functionName}` : "/gateway/rpc";
|
|
4324
|
+
const sql = buildRpcDebugSql(payload);
|
|
4325
|
+
return executeWithQueryTrace(
|
|
4326
|
+
tracer,
|
|
4327
|
+
{
|
|
4328
|
+
operation: "rpc",
|
|
4329
|
+
endpoint,
|
|
4330
|
+
functionName,
|
|
4331
|
+
sql,
|
|
4332
|
+
payload,
|
|
4333
|
+
options: mergedOptions
|
|
4334
|
+
},
|
|
4335
|
+
async () => {
|
|
4336
|
+
const response = await client.rpcGateway(payload, mergedOptions);
|
|
4337
|
+
return formatGatewayResult(response, { operation: "rpc" });
|
|
4338
|
+
},
|
|
4339
|
+
callsite
|
|
4340
|
+
);
|
|
3211
4341
|
};
|
|
3212
|
-
const run = (columns, options) => {
|
|
4342
|
+
const run = (columns, options, callsite) => {
|
|
3213
4343
|
const payloadColumns = columns ?? selectedColumns;
|
|
3214
4344
|
const payloadOptions = options ?? selectedOptions;
|
|
3215
4345
|
if (!promise) {
|
|
3216
|
-
promise = executeRpc(payloadColumns, payloadOptions);
|
|
4346
|
+
promise = executeRpc(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
|
|
3217
4347
|
}
|
|
3218
4348
|
return promise;
|
|
3219
4349
|
};
|
|
@@ -3223,10 +4353,10 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
|
|
|
3223
4353
|
select(columns = selectedColumns, options) {
|
|
3224
4354
|
selectedColumns = columns;
|
|
3225
4355
|
selectedOptions = options ?? selectedOptions;
|
|
3226
|
-
return run(columns, options);
|
|
4356
|
+
return run(columns, options, captureTraceCallsite(tracer));
|
|
3227
4357
|
},
|
|
3228
4358
|
async single(columns, options) {
|
|
3229
|
-
const result = await run(columns, options);
|
|
4359
|
+
const result = await run(columns, options, captureTraceCallsite(tracer));
|
|
3230
4360
|
return toSingleResult(result);
|
|
3231
4361
|
},
|
|
3232
4362
|
maybeSingle(columns, options) {
|
|
@@ -3261,7 +4391,7 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
|
|
|
3261
4391
|
});
|
|
3262
4392
|
return builder;
|
|
3263
4393
|
}
|
|
3264
|
-
function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
4394
|
+
function createTableBuilder(tableName, client, formatGatewayResult, tracer, experimental) {
|
|
3265
4395
|
const state = {
|
|
3266
4396
|
conditions: []
|
|
3267
4397
|
};
|
|
@@ -3293,15 +4423,24 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
3293
4423
|
}
|
|
3294
4424
|
state.conditions.push(condition);
|
|
3295
4425
|
};
|
|
4426
|
+
const snapshotState = () => ({
|
|
4427
|
+
conditions: state.conditions.map((condition) => ({ ...condition })),
|
|
4428
|
+
limit: state.limit,
|
|
4429
|
+
offset: state.offset,
|
|
4430
|
+
order: state.order ? { ...state.order } : void 0,
|
|
4431
|
+
currentPage: state.currentPage,
|
|
4432
|
+
pageSize: state.pageSize,
|
|
4433
|
+
totalPages: state.totalPages
|
|
4434
|
+
});
|
|
3296
4435
|
const builder = {};
|
|
3297
4436
|
const filterMethods = createFilterMethods(
|
|
3298
4437
|
state,
|
|
3299
4438
|
addCondition,
|
|
3300
4439
|
builder
|
|
3301
4440
|
);
|
|
3302
|
-
const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
|
|
4441
|
+
const runSelect = async (columns = DEFAULT_COLUMNS, options, executionState = snapshotState(), callsite) => {
|
|
3303
4442
|
const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
|
|
3304
|
-
const conditions =
|
|
4443
|
+
const conditions = executionState.conditions.length ? executionState.conditions.map((condition) => ({ ...condition })) : void 0;
|
|
3305
4444
|
const hasTypedEqualityComparison = conditions?.some(
|
|
3306
4445
|
(condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
|
|
3307
4446
|
) ?? false;
|
|
@@ -3310,53 +4449,107 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
3310
4449
|
tableName: resolvedTableName,
|
|
3311
4450
|
columns,
|
|
3312
4451
|
conditions,
|
|
3313
|
-
limit:
|
|
3314
|
-
offset:
|
|
3315
|
-
currentPage:
|
|
3316
|
-
pageSize:
|
|
3317
|
-
order:
|
|
4452
|
+
limit: executionState.limit,
|
|
4453
|
+
offset: executionState.offset,
|
|
4454
|
+
currentPage: executionState.currentPage,
|
|
4455
|
+
pageSize: executionState.pageSize,
|
|
4456
|
+
order: executionState.order
|
|
3318
4457
|
});
|
|
3319
4458
|
if (query) {
|
|
3320
|
-
const
|
|
3321
|
-
return
|
|
4459
|
+
const payload2 = { query };
|
|
4460
|
+
return executeWithQueryTrace(
|
|
4461
|
+
tracer,
|
|
4462
|
+
{
|
|
4463
|
+
operation: "select",
|
|
4464
|
+
endpoint: "/gateway/query",
|
|
4465
|
+
table: resolvedTableName,
|
|
4466
|
+
sql: query,
|
|
4467
|
+
payload: payload2,
|
|
4468
|
+
options
|
|
4469
|
+
},
|
|
4470
|
+
async () => {
|
|
4471
|
+
const queryResponse = await client.queryGateway(payload2, options);
|
|
4472
|
+
return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
|
|
4473
|
+
},
|
|
4474
|
+
callsite
|
|
4475
|
+
);
|
|
3322
4476
|
}
|
|
3323
4477
|
}
|
|
3324
4478
|
const payload = {
|
|
3325
4479
|
table_name: resolvedTableName,
|
|
3326
4480
|
columns,
|
|
3327
4481
|
conditions,
|
|
3328
|
-
limit:
|
|
3329
|
-
offset:
|
|
3330
|
-
current_page:
|
|
3331
|
-
page_size:
|
|
3332
|
-
total_pages:
|
|
3333
|
-
sort_by:
|
|
4482
|
+
limit: executionState.limit,
|
|
4483
|
+
offset: executionState.offset,
|
|
4484
|
+
current_page: executionState.currentPage,
|
|
4485
|
+
page_size: executionState.pageSize,
|
|
4486
|
+
total_pages: executionState.totalPages,
|
|
4487
|
+
sort_by: executionState.order,
|
|
3334
4488
|
strip_nulls: options?.stripNulls ?? true,
|
|
3335
4489
|
count: options?.count,
|
|
3336
4490
|
head: options?.head
|
|
3337
4491
|
};
|
|
3338
|
-
const
|
|
3339
|
-
|
|
4492
|
+
const sql = buildDebugSelectQuery({
|
|
4493
|
+
tableName: resolvedTableName,
|
|
4494
|
+
columns,
|
|
4495
|
+
conditions,
|
|
4496
|
+
limit: executionState.limit,
|
|
4497
|
+
offset: executionState.offset,
|
|
4498
|
+
currentPage: executionState.currentPage,
|
|
4499
|
+
pageSize: executionState.pageSize,
|
|
4500
|
+
order: executionState.order
|
|
4501
|
+
});
|
|
4502
|
+
return executeWithQueryTrace(
|
|
4503
|
+
tracer,
|
|
4504
|
+
{
|
|
4505
|
+
operation: "select",
|
|
4506
|
+
endpoint: "/gateway/fetch",
|
|
4507
|
+
table: resolvedTableName,
|
|
4508
|
+
sql,
|
|
4509
|
+
payload,
|
|
4510
|
+
options
|
|
4511
|
+
},
|
|
4512
|
+
async () => {
|
|
4513
|
+
const response = await client.fetchGateway(payload, options);
|
|
4514
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
|
|
4515
|
+
},
|
|
4516
|
+
callsite
|
|
4517
|
+
);
|
|
3340
4518
|
};
|
|
3341
|
-
const createSelectChain = (columns, options) => {
|
|
4519
|
+
const createSelectChain = (columns, options, initialCallsite) => {
|
|
3342
4520
|
const chain = {};
|
|
4521
|
+
const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
|
|
3343
4522
|
const filterMethods2 = createFilterMethods(state, addCondition, chain);
|
|
3344
4523
|
Object.assign(chain, filterMethods2, {
|
|
3345
4524
|
async single(cols, opts) {
|
|
3346
|
-
const r = await runSelect(
|
|
4525
|
+
const r = await runSelect(
|
|
4526
|
+
cols ?? columns,
|
|
4527
|
+
opts ?? options,
|
|
4528
|
+
snapshotState(),
|
|
4529
|
+
callsiteStore.resolve(captureTraceCallsite(tracer))
|
|
4530
|
+
);
|
|
3347
4531
|
return toSingleResult(r);
|
|
3348
4532
|
},
|
|
3349
4533
|
maybeSingle(cols, opts) {
|
|
3350
4534
|
return chain.single(cols, opts);
|
|
3351
4535
|
},
|
|
3352
4536
|
then(onfulfilled, onrejected) {
|
|
3353
|
-
return runSelect(
|
|
4537
|
+
return runSelect(
|
|
4538
|
+
columns,
|
|
4539
|
+
options,
|
|
4540
|
+
snapshotState(),
|
|
4541
|
+
callsiteStore.resolve()
|
|
4542
|
+
).then(onfulfilled, onrejected);
|
|
3354
4543
|
},
|
|
3355
4544
|
catch(onrejected) {
|
|
3356
|
-
return runSelect(columns, options).catch(
|
|
4545
|
+
return runSelect(columns, options, snapshotState(), callsiteStore.resolve()).catch(
|
|
4546
|
+
onrejected
|
|
4547
|
+
);
|
|
3357
4548
|
},
|
|
3358
4549
|
finally(onfinally) {
|
|
3359
|
-
return runSelect(columns, options).finally(
|
|
4550
|
+
return runSelect(columns, options, snapshotState(), callsiteStore.resolve()).finally(
|
|
4551
|
+
onfinally
|
|
4552
|
+
);
|
|
3360
4553
|
}
|
|
3361
4554
|
});
|
|
3362
4555
|
return chain;
|
|
@@ -3373,11 +4566,75 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
3373
4566
|
return builder;
|
|
3374
4567
|
},
|
|
3375
4568
|
select(columns = DEFAULT_COLUMNS, options) {
|
|
3376
|
-
return createSelectChain(columns, options);
|
|
4569
|
+
return createSelectChain(columns, options, captureTraceCallsite(tracer));
|
|
4570
|
+
},
|
|
4571
|
+
async findMany(options) {
|
|
4572
|
+
const columns = compileSelectShape(options.select);
|
|
4573
|
+
const baseState = snapshotState();
|
|
4574
|
+
const executionState = snapshotState();
|
|
4575
|
+
const callsite = captureTraceCallsite(tracer);
|
|
4576
|
+
const compiledWhere = compileWhere(options.where);
|
|
4577
|
+
if (compiledWhere?.length) {
|
|
4578
|
+
executionState.conditions.push(...compiledWhere);
|
|
4579
|
+
}
|
|
4580
|
+
if (options.orderBy !== void 0) {
|
|
4581
|
+
executionState.order = compileOrderBy(options.orderBy);
|
|
4582
|
+
}
|
|
4583
|
+
if (options.limit !== void 0) {
|
|
4584
|
+
executionState.limit = options.limit;
|
|
4585
|
+
}
|
|
4586
|
+
if (experimental?.findManyAst && canUseFindManyAstTransport(baseState)) {
|
|
4587
|
+
const resolvedTableName = resolveTableNameForCall(tableName, void 0);
|
|
4588
|
+
const payload = {
|
|
4589
|
+
table_name: resolvedTableName,
|
|
4590
|
+
select: options.select
|
|
4591
|
+
};
|
|
4592
|
+
if (options.where !== void 0) {
|
|
4593
|
+
payload.where = options.where;
|
|
4594
|
+
}
|
|
4595
|
+
const astOrder = toFindManyAstOrder(executionState.order);
|
|
4596
|
+
if (astOrder !== void 0) {
|
|
4597
|
+
payload.orderBy = astOrder;
|
|
4598
|
+
}
|
|
4599
|
+
if (executionState.limit !== void 0) {
|
|
4600
|
+
payload.limit = executionState.limit;
|
|
4601
|
+
}
|
|
4602
|
+
const sql = buildDebugSelectQuery({
|
|
4603
|
+
tableName: resolvedTableName,
|
|
4604
|
+
columns,
|
|
4605
|
+
conditions: executionState.conditions,
|
|
4606
|
+
limit: executionState.limit,
|
|
4607
|
+
order: executionState.order
|
|
4608
|
+
});
|
|
4609
|
+
return executeWithQueryTrace(
|
|
4610
|
+
tracer,
|
|
4611
|
+
{
|
|
4612
|
+
operation: "select",
|
|
4613
|
+
endpoint: "/gateway/fetch",
|
|
4614
|
+
table: resolvedTableName,
|
|
4615
|
+
sql,
|
|
4616
|
+
payload
|
|
4617
|
+
},
|
|
4618
|
+
async () => {
|
|
4619
|
+
const response = await client.fetchGateway(
|
|
4620
|
+
payload
|
|
4621
|
+
);
|
|
4622
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
|
|
4623
|
+
},
|
|
4624
|
+
callsite
|
|
4625
|
+
);
|
|
4626
|
+
}
|
|
4627
|
+
return runSelect(
|
|
4628
|
+
columns,
|
|
4629
|
+
void 0,
|
|
4630
|
+
executionState,
|
|
4631
|
+
callsite
|
|
4632
|
+
);
|
|
3377
4633
|
},
|
|
3378
4634
|
insert(values, options) {
|
|
4635
|
+
const mutationCallsite = captureTraceCallsite(tracer);
|
|
3379
4636
|
if (Array.isArray(values)) {
|
|
3380
|
-
const executeInsertMany = async (columns, selectOptions) => {
|
|
4637
|
+
const executeInsertMany = async (columns, selectOptions, callsite) => {
|
|
3381
4638
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
3382
4639
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
3383
4640
|
const payload = {
|
|
@@ -3390,12 +4647,27 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
3390
4647
|
if (mergedOptions?.defaultToNull !== void 0) {
|
|
3391
4648
|
payload.default_to_null = mergedOptions.defaultToNull;
|
|
3392
4649
|
}
|
|
3393
|
-
const
|
|
3394
|
-
return
|
|
4650
|
+
const sql = buildInsertDebugSql(payload);
|
|
4651
|
+
return executeWithQueryTrace(
|
|
4652
|
+
tracer,
|
|
4653
|
+
{
|
|
4654
|
+
operation: "insert",
|
|
4655
|
+
endpoint: "/gateway/insert",
|
|
4656
|
+
table: resolvedTableName,
|
|
4657
|
+
sql,
|
|
4658
|
+
payload,
|
|
4659
|
+
options: mergedOptions
|
|
4660
|
+
},
|
|
4661
|
+
async () => {
|
|
4662
|
+
const response = await client.insertGateway(payload, mergedOptions);
|
|
4663
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
4664
|
+
},
|
|
4665
|
+
callsite
|
|
4666
|
+
);
|
|
3395
4667
|
};
|
|
3396
|
-
return createMutationQuery(executeInsertMany);
|
|
4668
|
+
return createMutationQuery(executeInsertMany, DEFAULT_COLUMNS, tracer, mutationCallsite);
|
|
3397
4669
|
}
|
|
3398
|
-
const executeInsertOne = async (columns, selectOptions) => {
|
|
4670
|
+
const executeInsertOne = async (columns, selectOptions, callsite) => {
|
|
3399
4671
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
3400
4672
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
3401
4673
|
const payload = {
|
|
@@ -3408,14 +4680,30 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
3408
4680
|
if (mergedOptions?.defaultToNull !== void 0) {
|
|
3409
4681
|
payload.default_to_null = mergedOptions.defaultToNull;
|
|
3410
4682
|
}
|
|
3411
|
-
const
|
|
3412
|
-
return
|
|
4683
|
+
const sql = buildInsertDebugSql(payload);
|
|
4684
|
+
return executeWithQueryTrace(
|
|
4685
|
+
tracer,
|
|
4686
|
+
{
|
|
4687
|
+
operation: "insert",
|
|
4688
|
+
endpoint: "/gateway/insert",
|
|
4689
|
+
table: resolvedTableName,
|
|
4690
|
+
sql,
|
|
4691
|
+
payload,
|
|
4692
|
+
options: mergedOptions
|
|
4693
|
+
},
|
|
4694
|
+
async () => {
|
|
4695
|
+
const response = await client.insertGateway(payload, mergedOptions);
|
|
4696
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
4697
|
+
},
|
|
4698
|
+
callsite
|
|
4699
|
+
);
|
|
3413
4700
|
};
|
|
3414
|
-
return createMutationQuery(executeInsertOne);
|
|
4701
|
+
return createMutationQuery(executeInsertOne, DEFAULT_COLUMNS, tracer, mutationCallsite);
|
|
3415
4702
|
},
|
|
3416
4703
|
upsert(values, options) {
|
|
4704
|
+
const mutationCallsite = captureTraceCallsite(tracer);
|
|
3417
4705
|
if (Array.isArray(values)) {
|
|
3418
|
-
const executeUpsertMany = async (columns, selectOptions) => {
|
|
4706
|
+
const executeUpsertMany = async (columns, selectOptions, callsite) => {
|
|
3419
4707
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
3420
4708
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
3421
4709
|
const payload = {
|
|
@@ -3430,12 +4718,27 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
3430
4718
|
if (mergedOptions?.defaultToNull !== void 0) {
|
|
3431
4719
|
payload.default_to_null = mergedOptions.defaultToNull;
|
|
3432
4720
|
}
|
|
3433
|
-
const
|
|
3434
|
-
return
|
|
4721
|
+
const sql = buildInsertDebugSql(payload);
|
|
4722
|
+
return executeWithQueryTrace(
|
|
4723
|
+
tracer,
|
|
4724
|
+
{
|
|
4725
|
+
operation: "upsert",
|
|
4726
|
+
endpoint: "/gateway/insert",
|
|
4727
|
+
table: resolvedTableName,
|
|
4728
|
+
sql,
|
|
4729
|
+
payload,
|
|
4730
|
+
options: mergedOptions
|
|
4731
|
+
},
|
|
4732
|
+
async () => {
|
|
4733
|
+
const response = await client.insertGateway(payload, mergedOptions);
|
|
4734
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
4735
|
+
},
|
|
4736
|
+
callsite
|
|
4737
|
+
);
|
|
3435
4738
|
};
|
|
3436
|
-
return createMutationQuery(executeUpsertMany);
|
|
4739
|
+
return createMutationQuery(executeUpsertMany, DEFAULT_COLUMNS, tracer, mutationCallsite);
|
|
3437
4740
|
}
|
|
3438
|
-
const executeUpsertOne = async (columns, selectOptions) => {
|
|
4741
|
+
const executeUpsertOne = async (columns, selectOptions, callsite) => {
|
|
3439
4742
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
3440
4743
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
3441
4744
|
const payload = {
|
|
@@ -3450,13 +4753,29 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
3450
4753
|
if (mergedOptions?.defaultToNull !== void 0) {
|
|
3451
4754
|
payload.default_to_null = mergedOptions.defaultToNull;
|
|
3452
4755
|
}
|
|
3453
|
-
const
|
|
3454
|
-
return
|
|
4756
|
+
const sql = buildInsertDebugSql(payload);
|
|
4757
|
+
return executeWithQueryTrace(
|
|
4758
|
+
tracer,
|
|
4759
|
+
{
|
|
4760
|
+
operation: "upsert",
|
|
4761
|
+
endpoint: "/gateway/insert",
|
|
4762
|
+
table: resolvedTableName,
|
|
4763
|
+
sql,
|
|
4764
|
+
payload,
|
|
4765
|
+
options: mergedOptions
|
|
4766
|
+
},
|
|
4767
|
+
async () => {
|
|
4768
|
+
const response = await client.insertGateway(payload, mergedOptions);
|
|
4769
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
4770
|
+
},
|
|
4771
|
+
callsite
|
|
4772
|
+
);
|
|
3455
4773
|
};
|
|
3456
|
-
return createMutationQuery(executeUpsertOne);
|
|
4774
|
+
return createMutationQuery(executeUpsertOne, DEFAULT_COLUMNS, tracer, mutationCallsite);
|
|
3457
4775
|
},
|
|
3458
4776
|
update(values, options) {
|
|
3459
|
-
const
|
|
4777
|
+
const mutationCallsite = captureTraceCallsite(tracer);
|
|
4778
|
+
const executeUpdate = async (columns, selectOptions, callsite) => {
|
|
3460
4779
|
const filters = state.conditions.length ? [...state.conditions] : void 0;
|
|
3461
4780
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
3462
4781
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
@@ -3471,10 +4790,25 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
3471
4790
|
if (state.pageSize !== void 0) payload.page_size = state.pageSize;
|
|
3472
4791
|
if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
|
|
3473
4792
|
if (columns) payload.columns = columns;
|
|
3474
|
-
const
|
|
3475
|
-
return
|
|
4793
|
+
const sql = buildUpdateDebugSql(payload);
|
|
4794
|
+
return executeWithQueryTrace(
|
|
4795
|
+
tracer,
|
|
4796
|
+
{
|
|
4797
|
+
operation: "update",
|
|
4798
|
+
endpoint: "/gateway/update",
|
|
4799
|
+
table: resolvedTableName,
|
|
4800
|
+
sql,
|
|
4801
|
+
payload,
|
|
4802
|
+
options: mergedOptions
|
|
4803
|
+
},
|
|
4804
|
+
async () => {
|
|
4805
|
+
const response = await client.updateGateway(payload, mergedOptions);
|
|
4806
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "update" });
|
|
4807
|
+
},
|
|
4808
|
+
callsite
|
|
4809
|
+
);
|
|
3476
4810
|
};
|
|
3477
|
-
const mutation = createMutationQuery(executeUpdate, null);
|
|
4811
|
+
const mutation = createMutationQuery(executeUpdate, null, tracer, mutationCallsite);
|
|
3478
4812
|
const updateChain = {};
|
|
3479
4813
|
const filterMethods2 = createFilterMethods(state, addCondition, updateChain);
|
|
3480
4814
|
Object.assign(updateChain, filterMethods2, mutation);
|
|
@@ -3486,7 +4820,8 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
3486
4820
|
if (!resourceId && !filters?.length) {
|
|
3487
4821
|
throw new Error('delete requires a resource_id either via eq("resource_id", ...) or options.resourceId');
|
|
3488
4822
|
}
|
|
3489
|
-
const
|
|
4823
|
+
const mutationCallsite = captureTraceCallsite(tracer);
|
|
4824
|
+
const executeDelete = async (columns, selectOptions, callsite) => {
|
|
3490
4825
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
3491
4826
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
3492
4827
|
const payload = {
|
|
@@ -3499,13 +4834,33 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
3499
4834
|
if (state.pageSize !== void 0) payload.page_size = state.pageSize;
|
|
3500
4835
|
if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
|
|
3501
4836
|
if (columns) payload.columns = columns;
|
|
3502
|
-
const
|
|
3503
|
-
return
|
|
4837
|
+
const sql = buildDeleteDebugSql(payload);
|
|
4838
|
+
return executeWithQueryTrace(
|
|
4839
|
+
tracer,
|
|
4840
|
+
{
|
|
4841
|
+
operation: "delete",
|
|
4842
|
+
endpoint: "/gateway/delete",
|
|
4843
|
+
table: resolvedTableName,
|
|
4844
|
+
sql,
|
|
4845
|
+
payload,
|
|
4846
|
+
options: mergedOptions
|
|
4847
|
+
},
|
|
4848
|
+
async () => {
|
|
4849
|
+
const response = await client.deleteGateway(payload, mergedOptions);
|
|
4850
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "delete" });
|
|
4851
|
+
},
|
|
4852
|
+
callsite
|
|
4853
|
+
);
|
|
3504
4854
|
};
|
|
3505
|
-
return createMutationQuery(executeDelete, null);
|
|
4855
|
+
return createMutationQuery(executeDelete, null, tracer, mutationCallsite);
|
|
3506
4856
|
},
|
|
3507
4857
|
async single(columns, options) {
|
|
3508
|
-
const response = await
|
|
4858
|
+
const response = await runSelect(
|
|
4859
|
+
columns ?? DEFAULT_COLUMNS,
|
|
4860
|
+
options,
|
|
4861
|
+
snapshotState(),
|
|
4862
|
+
captureTraceCallsite(tracer)
|
|
4863
|
+
);
|
|
3509
4864
|
return toSingleResult(response);
|
|
3510
4865
|
},
|
|
3511
4866
|
async maybeSingle(columns, options) {
|
|
@@ -3514,14 +4869,29 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
3514
4869
|
});
|
|
3515
4870
|
return builder;
|
|
3516
4871
|
}
|
|
3517
|
-
function createQueryBuilder(client, formatGatewayResult) {
|
|
4872
|
+
function createQueryBuilder(client, formatGatewayResult, tracer) {
|
|
3518
4873
|
return async function query(query, options) {
|
|
3519
4874
|
const normalizedQuery = query.trim();
|
|
3520
4875
|
if (!normalizedQuery) {
|
|
3521
4876
|
throw new Error("query requires a non-empty string");
|
|
3522
4877
|
}
|
|
3523
|
-
const
|
|
3524
|
-
|
|
4878
|
+
const payload = { query: normalizedQuery };
|
|
4879
|
+
const callsite = captureTraceCallsite(tracer);
|
|
4880
|
+
return executeWithQueryTrace(
|
|
4881
|
+
tracer,
|
|
4882
|
+
{
|
|
4883
|
+
operation: "query",
|
|
4884
|
+
endpoint: "/gateway/query",
|
|
4885
|
+
sql: normalizedQuery,
|
|
4886
|
+
payload,
|
|
4887
|
+
options
|
|
4888
|
+
},
|
|
4889
|
+
async () => {
|
|
4890
|
+
const response = await client.queryGateway(payload, options);
|
|
4891
|
+
return formatGatewayResult(response, { operation: "query" });
|
|
4892
|
+
},
|
|
4893
|
+
callsite
|
|
4894
|
+
);
|
|
3525
4895
|
};
|
|
3526
4896
|
}
|
|
3527
4897
|
function createClientFromConfig(config) {
|
|
@@ -3532,9 +4902,10 @@ function createClientFromConfig(config) {
|
|
|
3532
4902
|
backend: config.backend,
|
|
3533
4903
|
headers: config.headers
|
|
3534
4904
|
});
|
|
3535
|
-
const formatGatewayResult = createResultFormatter(
|
|
4905
|
+
const formatGatewayResult = createResultFormatter();
|
|
4906
|
+
const queryTracer = createQueryTracer(config.experimental);
|
|
3536
4907
|
const auth = createAuthClient(config.auth);
|
|
3537
|
-
const from = (table) => createTableBuilder(table, gateway, formatGatewayResult);
|
|
4908
|
+
const from = (table) => createTableBuilder(table, gateway, formatGatewayResult, queryTracer, config.experimental);
|
|
3538
4909
|
const rpc = (fn, args, options) => {
|
|
3539
4910
|
const normalizedFn = fn.trim();
|
|
3540
4911
|
if (!normalizedFn) {
|
|
@@ -3545,10 +4916,12 @@ function createClientFromConfig(config) {
|
|
|
3545
4916
|
args,
|
|
3546
4917
|
options,
|
|
3547
4918
|
gateway,
|
|
3548
|
-
formatGatewayResult
|
|
4919
|
+
formatGatewayResult,
|
|
4920
|
+
queryTracer,
|
|
4921
|
+
captureTraceCallsite(queryTracer)
|
|
3549
4922
|
);
|
|
3550
4923
|
};
|
|
3551
|
-
const query = createQueryBuilder(gateway, formatGatewayResult);
|
|
4924
|
+
const query = createQueryBuilder(gateway, formatGatewayResult, queryTracer);
|
|
3552
4925
|
const db = createDbModule({ from, rpc, query });
|
|
3553
4926
|
return {
|
|
3554
4927
|
from,
|
|
@@ -4018,7 +5391,7 @@ var AthenaGatewayCatalogClient = class {
|
|
|
4018
5391
|
async queryRows(query) {
|
|
4019
5392
|
const result = await this.client.query(query);
|
|
4020
5393
|
if (result.error || result.status < 200 || result.status >= 300) {
|
|
4021
|
-
throw new Error(result.error ?? `Gateway query failed with status ${result.status}`);
|
|
5394
|
+
throw new Error(result.error?.message ?? `Gateway query failed with status ${result.status}`);
|
|
4022
5395
|
}
|
|
4023
5396
|
return result.data ?? [];
|
|
4024
5397
|
}
|
|
@@ -4115,10 +5488,24 @@ function resolveGeneratorProvider(providerConfig, experimentalFlags) {
|
|
|
4115
5488
|
}
|
|
4116
5489
|
|
|
4117
5490
|
// src/generator/pipeline.ts
|
|
5491
|
+
function canOverwriteArtifact(file) {
|
|
5492
|
+
return file.kind === "model" || file.kind === "schema";
|
|
5493
|
+
}
|
|
5494
|
+
async function fileExists(path) {
|
|
5495
|
+
try {
|
|
5496
|
+
await stat(path);
|
|
5497
|
+
return true;
|
|
5498
|
+
} catch {
|
|
5499
|
+
return false;
|
|
5500
|
+
}
|
|
5501
|
+
}
|
|
4118
5502
|
async function writeArtifacts(files, cwd) {
|
|
4119
5503
|
const writtenFiles = [];
|
|
4120
5504
|
for (const file of files) {
|
|
4121
5505
|
const absolutePath = resolve(cwd, file.path);
|
|
5506
|
+
if (!canOverwriteArtifact(file) && await fileExists(absolutePath)) {
|
|
5507
|
+
continue;
|
|
5508
|
+
}
|
|
4122
5509
|
await mkdir(dirname(absolutePath), { recursive: true });
|
|
4123
5510
|
await writeFile(absolutePath, file.content, "utf8");
|
|
4124
5511
|
writtenFiles.push(file.path);
|