@xylex-group/athena 2.0.0 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -26
- package/dist/browser.cjs +3319 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.cts +25 -0
- package/dist/browser.d.ts +25 -0
- package/dist/browser.js +3276 -0
- package/dist/browser.js.map +1 -0
- package/dist/cli/index.cjs +599 -119
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +3 -2
- package/dist/cli/index.d.ts +3 -2
- package/dist/cli/index.js +600 -120
- package/dist/cli/index.js.map +1 -1
- package/dist/client-BX0NQqOn.d.ts +435 -0
- package/dist/client-dpAp-NZK.d.cts +435 -0
- package/dist/cookies.cjs +890 -0
- package/dist/cookies.cjs.map +1 -0
- package/dist/cookies.d.cts +174 -0
- package/dist/cookies.d.ts +174 -0
- package/dist/cookies.js +869 -0
- package/dist/cookies.js.map +1 -0
- package/dist/index.cjs +1378 -1023
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -408
- package/dist/index.d.ts +8 -408
- package/dist/index.js +1379 -1024
- package/dist/index.js.map +1 -1
- package/dist/{model-form-CVOtC8jq.d.ts → model-form-2hqmoOUX.d.ts} +2 -2
- package/dist/{model-form-hXkvHS_3.d.cts → model-form-Cy-zaO0u.d.cts} +2 -2
- package/dist/pipeline-BOPszLsL.d.ts +8 -0
- package/dist/pipeline-E3FDbs4W.d.cts +8 -0
- package/dist/react.d.cts +4 -4
- package/dist/react.d.ts +4 -4
- package/dist/{types-BnzoaNRC.d.cts → types-BaBzjwXr.d.cts} +1 -1
- package/dist/{types-BnzoaNRC.d.ts → types-BaBzjwXr.d.ts} +1 -1
- package/dist/{pipeline-CQgV-Yfo.d.ts → types-CeBPrnGj.d.ts} +2 -7
- package/dist/{pipeline-C-cN0ACi.d.cts → types-CpqL-pZx.d.cts} +2 -7
- package/package.json +21 -1
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var pg = require('pg');
|
|
4
3
|
var fs = require('fs');
|
|
5
4
|
var path = require('path');
|
|
6
5
|
var url = require('url');
|
|
@@ -1541,460 +1540,588 @@ function createAuthClient(config = {}) {
|
|
|
1541
1540
|
};
|
|
1542
1541
|
}
|
|
1543
1542
|
|
|
1544
|
-
// src/
|
|
1545
|
-
var
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1543
|
+
// src/auxiliaries.ts
|
|
1544
|
+
var AthenaErrorKind = {
|
|
1545
|
+
UniqueViolation: "unique_violation",
|
|
1546
|
+
NotFound: "not_found",
|
|
1547
|
+
Validation: "validation",
|
|
1548
|
+
Auth: "auth",
|
|
1549
|
+
RateLimit: "rate_limit",
|
|
1550
|
+
Transient: "transient",
|
|
1551
|
+
Unknown: "unknown"
|
|
1552
|
+
};
|
|
1553
|
+
var AthenaErrorCode = {
|
|
1554
|
+
UniqueViolation: "UNIQUE_VIOLATION",
|
|
1555
|
+
NotFound: "NOT_FOUND",
|
|
1556
|
+
ValidationFailed: "VALIDATION_FAILED",
|
|
1557
|
+
AuthUnauthorized: "AUTH_UNAUTHORIZED",
|
|
1558
|
+
AuthForbidden: "AUTH_FORBIDDEN",
|
|
1559
|
+
RateLimited: "RATE_LIMITED",
|
|
1560
|
+
NetworkUnavailable: "NETWORK_UNAVAILABLE",
|
|
1561
|
+
TransientFailure: "TRANSIENT_FAILURE",
|
|
1562
|
+
HttpFailure: "HTTP_FAILURE",
|
|
1563
|
+
Unknown: "UNKNOWN"
|
|
1564
|
+
};
|
|
1565
|
+
var AthenaErrorCategory = {
|
|
1566
|
+
Transport: "transport",
|
|
1567
|
+
Client: "client",
|
|
1568
|
+
Server: "server",
|
|
1569
|
+
Database: "database",
|
|
1570
|
+
Unknown: "unknown"
|
|
1571
|
+
};
|
|
1572
|
+
function parseBooleanFlag(rawValue, fallback) {
|
|
1573
|
+
if (!rawValue) return fallback;
|
|
1574
|
+
const normalized = rawValue.trim().toLowerCase();
|
|
1575
|
+
if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
|
|
1576
|
+
return true;
|
|
1558
1577
|
}
|
|
1559
|
-
|
|
1578
|
+
if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
|
|
1579
|
+
return false;
|
|
1580
|
+
}
|
|
1581
|
+
return fallback;
|
|
1560
1582
|
}
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1583
|
+
var AthenaError = class extends Error {
|
|
1584
|
+
code;
|
|
1585
|
+
kind;
|
|
1586
|
+
category;
|
|
1587
|
+
status;
|
|
1588
|
+
retryable;
|
|
1589
|
+
requestId;
|
|
1590
|
+
context;
|
|
1591
|
+
raw;
|
|
1592
|
+
constructor(input) {
|
|
1593
|
+
super(input.message);
|
|
1594
|
+
this.name = "AthenaError";
|
|
1595
|
+
this.code = input.code;
|
|
1596
|
+
this.kind = input.kind;
|
|
1597
|
+
this.category = input.category;
|
|
1598
|
+
this.status = input.status;
|
|
1599
|
+
this.retryable = input.retryable ?? false;
|
|
1600
|
+
this.requestId = input.requestId;
|
|
1601
|
+
this.context = input.context;
|
|
1602
|
+
this.raw = input.raw;
|
|
1603
|
+
}
|
|
1604
|
+
};
|
|
1605
|
+
function isRecord3(value) {
|
|
1606
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1568
1607
|
}
|
|
1569
|
-
function
|
|
1570
|
-
return
|
|
1571
|
-
if (!next) return acc;
|
|
1572
|
-
return { ...acc, ...next };
|
|
1573
|
-
}, void 0);
|
|
1608
|
+
function isAthenaErrorKind(value) {
|
|
1609
|
+
return value === "unique_violation" || value === "not_found" || value === "validation" || value === "auth" || value === "rate_limit" || value === "transient" || value === "unknown";
|
|
1574
1610
|
}
|
|
1575
|
-
function
|
|
1576
|
-
return value;
|
|
1611
|
+
function isAthenaErrorCode(value) {
|
|
1612
|
+
return value === "UNIQUE_VIOLATION" || value === "NOT_FOUND" || value === "VALIDATION_FAILED" || value === "AUTH_UNAUTHORIZED" || value === "AUTH_FORBIDDEN" || value === "RATE_LIMITED" || value === "NETWORK_UNAVAILABLE" || value === "TRANSIENT_FAILURE" || value === "HTTP_FAILURE" || value === "UNKNOWN";
|
|
1577
1613
|
}
|
|
1578
|
-
function
|
|
1579
|
-
return
|
|
1614
|
+
function isAthenaErrorCategory(value) {
|
|
1615
|
+
return value === "transport" || value === "client" || value === "server" || value === "database" || value === "unknown";
|
|
1580
1616
|
}
|
|
1581
|
-
function
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
};
|
|
1593
|
-
const mutationQuery = {
|
|
1594
|
-
select(columns = selectedColumns, options) {
|
|
1595
|
-
selectedColumns = columns;
|
|
1596
|
-
selectedOptions = options ?? selectedOptions;
|
|
1597
|
-
return run(columns, options);
|
|
1598
|
-
},
|
|
1599
|
-
returning(columns = selectedColumns, options) {
|
|
1600
|
-
return mutationQuery.select(columns, options);
|
|
1601
|
-
},
|
|
1602
|
-
single(columns = selectedColumns, options) {
|
|
1603
|
-
selectedColumns = columns;
|
|
1604
|
-
selectedOptions = options ?? selectedOptions;
|
|
1605
|
-
return run(columns, options).then(toSingleResult);
|
|
1606
|
-
},
|
|
1607
|
-
maybeSingle(columns = selectedColumns, options) {
|
|
1608
|
-
return mutationQuery.single(columns, options);
|
|
1609
|
-
},
|
|
1610
|
-
then(onfulfilled, onrejected) {
|
|
1611
|
-
return run(selectedColumns, selectedOptions).then(onfulfilled, onrejected);
|
|
1612
|
-
},
|
|
1613
|
-
catch(onrejected) {
|
|
1614
|
-
return run(selectedColumns, selectedOptions).catch(onrejected);
|
|
1615
|
-
},
|
|
1616
|
-
finally(onfinally) {
|
|
1617
|
-
return run(selectedColumns, selectedOptions).finally(onfinally);
|
|
1618
|
-
}
|
|
1617
|
+
function isNormalizedAthenaError(value) {
|
|
1618
|
+
return isRecord3(value) && isAthenaErrorKind(value.kind) && isAthenaErrorCode(value.code) && isAthenaErrorCategory(value.category) && typeof value.retryable === "boolean" && typeof value.message === "string" && "raw" in value;
|
|
1619
|
+
}
|
|
1620
|
+
function withContextOverrides(normalized, context) {
|
|
1621
|
+
if (!context?.table && !context?.operation) {
|
|
1622
|
+
return normalized;
|
|
1623
|
+
}
|
|
1624
|
+
return {
|
|
1625
|
+
...normalized,
|
|
1626
|
+
table: context.table ?? normalized.table,
|
|
1627
|
+
operation: context.operation ?? normalized.operation
|
|
1619
1628
|
};
|
|
1620
|
-
return mutationQuery;
|
|
1621
1629
|
}
|
|
1622
|
-
function
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
return candidate
|
|
1630
|
+
function resolveAttachedNormalizedError(resultOrError) {
|
|
1631
|
+
if (!isRecord3(resultOrError)) return void 0;
|
|
1632
|
+
if (!("__athenaNormalizedError" in resultOrError)) return void 0;
|
|
1633
|
+
const candidate = resultOrError.__athenaNormalizedError;
|
|
1634
|
+
return isNormalizedAthenaError(candidate) ? candidate : void 0;
|
|
1627
1635
|
}
|
|
1628
|
-
function
|
|
1629
|
-
|
|
1630
|
-
|
|
1636
|
+
function safeStringify(value) {
|
|
1637
|
+
try {
|
|
1638
|
+
const serialized = JSON.stringify(value);
|
|
1639
|
+
return serialized ?? String(value);
|
|
1640
|
+
} catch {
|
|
1641
|
+
return "[unserializable]";
|
|
1631
1642
|
}
|
|
1632
|
-
return String(value);
|
|
1633
1643
|
}
|
|
1634
|
-
function
|
|
1635
|
-
|
|
1644
|
+
function contextHint(context) {
|
|
1645
|
+
if (!context?.identity) return void 0;
|
|
1646
|
+
const identity = typeof context.identity === "string" ? context.identity : safeStringify(context.identity);
|
|
1647
|
+
return `Identity: ${identity}`;
|
|
1636
1648
|
}
|
|
1637
|
-
function
|
|
1638
|
-
return
|
|
1649
|
+
function isAthenaResultLike(value) {
|
|
1650
|
+
return isRecord3(value) && "status" in value && "error" in value && "data" in value && typeof value.status === "number";
|
|
1639
1651
|
}
|
|
1640
|
-
function
|
|
1641
|
-
|
|
1652
|
+
function operationFromDetails(details) {
|
|
1653
|
+
if (!details?.endpoint) return void 0;
|
|
1654
|
+
if (details.endpoint === "/gateway/fetch" || details.endpoint === "/gateway/query") return "select";
|
|
1655
|
+
if (details.endpoint === "/gateway/insert") return "insert";
|
|
1656
|
+
if (details.endpoint === "/gateway/update") return "update";
|
|
1657
|
+
if (details.endpoint === "/gateway/delete") return "delete";
|
|
1658
|
+
if (details.endpoint === "/gateway/rpc" || details.endpoint.startsWith("/rpc/")) return "rpc";
|
|
1659
|
+
return void 0;
|
|
1642
1660
|
}
|
|
1643
|
-
function
|
|
1644
|
-
const
|
|
1645
|
-
|
|
1646
|
-
|
|
1661
|
+
function matchRegex(input, patterns) {
|
|
1662
|
+
for (const pattern of patterns) {
|
|
1663
|
+
const match = pattern.exec(input);
|
|
1664
|
+
if (match?.[1]) return match[1];
|
|
1647
1665
|
}
|
|
1648
|
-
return
|
|
1649
|
-
}
|
|
1650
|
-
function escapeSqlStringLiteral(value) {
|
|
1651
|
-
return value.replace(/'/g, "''");
|
|
1666
|
+
return void 0;
|
|
1652
1667
|
}
|
|
1653
|
-
function
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1668
|
+
function extractConstraint(message) {
|
|
1669
|
+
return matchRegex(message, [
|
|
1670
|
+
/unique constraint\s+["'`]([^"'`]+)["'`]/i,
|
|
1671
|
+
/constraint\s+["'`]([^"'`]+)["'`]/i
|
|
1672
|
+
]);
|
|
1658
1673
|
}
|
|
1659
|
-
function
|
|
1660
|
-
|
|
1661
|
-
|
|
1674
|
+
function extractTable(message) {
|
|
1675
|
+
return matchRegex(message, [
|
|
1676
|
+
/(?:table|relation)\s+["'`]([^"'`]+)["'`]/i,
|
|
1677
|
+
/on\s+table\s+([a-zA-Z0-9_.]+)/i
|
|
1678
|
+
]);
|
|
1662
1679
|
}
|
|
1663
|
-
function
|
|
1664
|
-
|
|
1665
|
-
|
|
1680
|
+
function classifyKind(status, code, message) {
|
|
1681
|
+
const lower = message.toLowerCase();
|
|
1682
|
+
const hasUniquePattern = lower.includes("unique constraint") || lower.includes("duplicate key") || lower.includes("already exists") || lower.includes("duplicate");
|
|
1683
|
+
const hasNotFoundPattern = lower.includes("not found") || lower.includes("no rows");
|
|
1684
|
+
const hasValidationPattern = lower.includes("validation") || lower.includes("invalid") || lower.includes("malformed");
|
|
1685
|
+
const hasAuthPattern = lower.includes("unauthorized") || lower.includes("forbidden") || lower.includes("auth");
|
|
1686
|
+
const hasRateLimitPattern = lower.includes("rate limit") || lower.includes("too many requests");
|
|
1687
|
+
const hasTransientPattern = lower.includes("timeout") || lower.includes("temporar") || lower.includes("connection reset") || lower.includes("socket") || lower.includes("deadlock");
|
|
1688
|
+
if (status === 409 || hasUniquePattern) return "unique_violation";
|
|
1689
|
+
if (status === 404 || hasNotFoundPattern) return "not_found";
|
|
1690
|
+
if (status === 401 || status === 403 || hasAuthPattern) return "auth";
|
|
1691
|
+
if (status === 429 || hasRateLimitPattern) return "rate_limit";
|
|
1692
|
+
if (status === 400 || status === 422 || hasValidationPattern) return "validation";
|
|
1693
|
+
if (code === "NETWORK_ERROR" || status === 0 || status !== void 0 && status >= 500 || hasTransientPattern) {
|
|
1694
|
+
return "transient";
|
|
1666
1695
|
}
|
|
1667
|
-
return
|
|
1696
|
+
return "unknown";
|
|
1668
1697
|
}
|
|
1669
|
-
function
|
|
1670
|
-
if (
|
|
1671
|
-
|
|
1672
|
-
if (!normalizedSchema) {
|
|
1673
|
-
throw new Error("schema option must be a non-empty string");
|
|
1698
|
+
function toAthenaErrorCode(kind, status, gatewayCode) {
|
|
1699
|
+
if (gatewayCode === "NETWORK_ERROR" || kind === "transient" && status === 0) {
|
|
1700
|
+
return AthenaErrorCode.NetworkUnavailable;
|
|
1674
1701
|
}
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
return
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1702
|
+
switch (kind) {
|
|
1703
|
+
case "unique_violation":
|
|
1704
|
+
return AthenaErrorCode.UniqueViolation;
|
|
1705
|
+
case "not_found":
|
|
1706
|
+
return AthenaErrorCode.NotFound;
|
|
1707
|
+
case "validation":
|
|
1708
|
+
return AthenaErrorCode.ValidationFailed;
|
|
1709
|
+
case "rate_limit":
|
|
1710
|
+
return AthenaErrorCode.RateLimited;
|
|
1711
|
+
case "auth":
|
|
1712
|
+
if (status === 403) {
|
|
1713
|
+
return AthenaErrorCode.AuthForbidden;
|
|
1714
|
+
}
|
|
1715
|
+
return AthenaErrorCode.AuthUnauthorized;
|
|
1716
|
+
case "transient":
|
|
1717
|
+
return status !== void 0 && status >= 500 ? AthenaErrorCode.HttpFailure : AthenaErrorCode.TransientFailure;
|
|
1718
|
+
case "unknown":
|
|
1719
|
+
default:
|
|
1720
|
+
return status !== void 0 && status >= 400 ? AthenaErrorCode.HttpFailure : AthenaErrorCode.Unknown;
|
|
1682
1721
|
}
|
|
1683
|
-
return `${normalizedSchema}.${tableName}`;
|
|
1684
1722
|
}
|
|
1685
|
-
function
|
|
1686
|
-
if (
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1723
|
+
function toAthenaErrorCategory(kind, status) {
|
|
1724
|
+
if (kind === "transient" && (status === 0 || status === void 0)) {
|
|
1725
|
+
return AthenaErrorCategory.Transport;
|
|
1726
|
+
}
|
|
1727
|
+
if (kind === "unique_violation") return AthenaErrorCategory.Database;
|
|
1728
|
+
if (kind === "validation" || kind === "auth" || kind === "not_found") return AthenaErrorCategory.Client;
|
|
1729
|
+
if (kind === "rate_limit" || kind === "transient") return AthenaErrorCategory.Server;
|
|
1730
|
+
return AthenaErrorCategory.Unknown;
|
|
1731
|
+
}
|
|
1732
|
+
function isRetryable(kind, status) {
|
|
1733
|
+
if (kind === "rate_limit" || kind === "transient") return true;
|
|
1734
|
+
return status !== void 0 && status >= 500;
|
|
1735
|
+
}
|
|
1736
|
+
function toGatewayCode(kind, status) {
|
|
1737
|
+
if (kind === "transient" && (status === 0 || status === void 0)) return "NETWORK_ERROR";
|
|
1738
|
+
if (kind === "validation") return "INVALID_JSON";
|
|
1739
|
+
if (status !== void 0 && status >= 400) return "HTTP_ERROR";
|
|
1740
|
+
return "UNKNOWN_ERROR";
|
|
1741
|
+
}
|
|
1742
|
+
function toAthenaGatewayError(source, fallbackMessage, context) {
|
|
1743
|
+
if (isAthenaGatewayError(source)) {
|
|
1744
|
+
return source;
|
|
1745
|
+
}
|
|
1746
|
+
if (isAthenaResultLike(source) && source.errorDetails) {
|
|
1747
|
+
return new AthenaGatewayError({
|
|
1748
|
+
code: source.errorDetails.code,
|
|
1749
|
+
message: source.error ?? source.errorDetails.message,
|
|
1750
|
+
status: source.status,
|
|
1751
|
+
endpoint: source.errorDetails.endpoint,
|
|
1752
|
+
method: source.errorDetails.method,
|
|
1753
|
+
requestId: source.errorDetails.requestId,
|
|
1754
|
+
hint: source.errorDetails.hint,
|
|
1755
|
+
cause: source.errorDetails.cause
|
|
1756
|
+
});
|
|
1757
|
+
}
|
|
1758
|
+
const normalized = normalizeAthenaError(source, context);
|
|
1759
|
+
const message = isAthenaResultLike(source) && source.error == null && source.errorDetails == null ? fallbackMessage : normalized.message || fallbackMessage;
|
|
1760
|
+
return new AthenaGatewayError({
|
|
1761
|
+
code: toGatewayCode(normalized.kind, normalized.status),
|
|
1762
|
+
message,
|
|
1763
|
+
status: normalized.status ?? 0,
|
|
1764
|
+
hint: normalized.constraint != null ? `Constraint: ${normalized.constraint}` : contextHint(context),
|
|
1765
|
+
cause: typeof normalized.raw === "string" ? normalized.raw : safeStringify(normalized.raw)
|
|
1766
|
+
});
|
|
1767
|
+
}
|
|
1768
|
+
function isOk(result) {
|
|
1769
|
+
return result.error == null && result.status >= 200 && result.status < 300;
|
|
1770
|
+
}
|
|
1771
|
+
function normalizeAthenaError(resultOrError, context) {
|
|
1772
|
+
const attached = resolveAttachedNormalizedError(resultOrError);
|
|
1773
|
+
if (attached) {
|
|
1774
|
+
return withContextOverrides(attached, context);
|
|
1775
|
+
}
|
|
1776
|
+
if (isAthenaResultLike(resultOrError)) {
|
|
1777
|
+
const details = resultOrError.errorDetails;
|
|
1778
|
+
const message2 = resultOrError.error ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
|
|
1779
|
+
const operation = context?.operation ?? operationFromDetails(details);
|
|
1780
|
+
const table = context?.table ?? extractTable(message2);
|
|
1781
|
+
const constraint = extractConstraint(message2);
|
|
1782
|
+
const kind2 = classifyKind(resultOrError.status, details?.code, message2);
|
|
1783
|
+
const code = toAthenaErrorCode(kind2, resultOrError.status, details?.code);
|
|
1784
|
+
const category = toAthenaErrorCategory(kind2, resultOrError.status);
|
|
1785
|
+
return {
|
|
1786
|
+
kind: kind2,
|
|
1787
|
+
code,
|
|
1788
|
+
category,
|
|
1789
|
+
retryable: isRetryable(kind2, resultOrError.status),
|
|
1790
|
+
status: resultOrError.status,
|
|
1791
|
+
constraint,
|
|
1792
|
+
table,
|
|
1793
|
+
operation,
|
|
1794
|
+
message: message2,
|
|
1795
|
+
raw: resultOrError.raw
|
|
1796
|
+
};
|
|
1797
|
+
}
|
|
1798
|
+
if (isAthenaGatewayError(resultOrError)) {
|
|
1799
|
+
const details = resultOrError.toDetails();
|
|
1800
|
+
const operation = context?.operation ?? operationFromDetails(details);
|
|
1801
|
+
const table = context?.table ?? extractTable(resultOrError.message);
|
|
1802
|
+
const constraint = extractConstraint(resultOrError.message);
|
|
1803
|
+
const kind2 = classifyKind(resultOrError.status, resultOrError.code, resultOrError.message);
|
|
1804
|
+
const code = toAthenaErrorCode(kind2, resultOrError.status, resultOrError.code);
|
|
1805
|
+
const category = toAthenaErrorCategory(kind2, resultOrError.status);
|
|
1806
|
+
return {
|
|
1807
|
+
kind: kind2,
|
|
1808
|
+
code,
|
|
1809
|
+
category,
|
|
1810
|
+
retryable: isRetryable(kind2, resultOrError.status),
|
|
1811
|
+
status: resultOrError.status,
|
|
1812
|
+
constraint,
|
|
1813
|
+
table,
|
|
1814
|
+
operation,
|
|
1815
|
+
message: resultOrError.message,
|
|
1816
|
+
raw: resultOrError
|
|
1817
|
+
};
|
|
1818
|
+
}
|
|
1819
|
+
if (resultOrError instanceof Error) {
|
|
1820
|
+
const maybeStatus = isRecord3(resultOrError) && typeof resultOrError.status === "number" ? resultOrError.status : void 0;
|
|
1821
|
+
const kind2 = classifyKind(maybeStatus, void 0, resultOrError.message);
|
|
1822
|
+
return {
|
|
1823
|
+
kind: kind2,
|
|
1824
|
+
code: toAthenaErrorCode(kind2, maybeStatus),
|
|
1825
|
+
category: toAthenaErrorCategory(kind2, maybeStatus),
|
|
1826
|
+
retryable: isRetryable(kind2, maybeStatus),
|
|
1827
|
+
status: maybeStatus,
|
|
1828
|
+
constraint: extractConstraint(resultOrError.message),
|
|
1829
|
+
table: context?.table ?? extractTable(resultOrError.message),
|
|
1830
|
+
operation: context?.operation,
|
|
1831
|
+
message: resultOrError.message,
|
|
1832
|
+
raw: resultOrError
|
|
1833
|
+
};
|
|
1834
|
+
}
|
|
1835
|
+
const message = typeof resultOrError === "string" ? resultOrError : "Unknown Athena error";
|
|
1836
|
+
const kind = classifyKind(void 0, void 0, message);
|
|
1837
|
+
return {
|
|
1838
|
+
kind,
|
|
1839
|
+
code: toAthenaErrorCode(kind, void 0),
|
|
1840
|
+
category: toAthenaErrorCategory(kind, void 0),
|
|
1841
|
+
retryable: isRetryable(kind, void 0),
|
|
1842
|
+
status: void 0,
|
|
1843
|
+
constraint: extractConstraint(message),
|
|
1844
|
+
table: context?.table ?? extractTable(message),
|
|
1845
|
+
operation: context?.operation,
|
|
1846
|
+
message,
|
|
1847
|
+
raw: resultOrError
|
|
1698
1848
|
};
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
case "gte":
|
|
1704
|
-
case "lt":
|
|
1705
|
-
case "lte":
|
|
1706
|
-
case "like":
|
|
1707
|
-
case "ilike": {
|
|
1708
|
-
if (Array.isArray(value) || value === void 0) return null;
|
|
1709
|
-
const rhs = withCast(toSqlLiteral(value), condition.value_cast);
|
|
1710
|
-
return `${column} ${sqlOperator[condition.operator]} ${rhs}`;
|
|
1711
|
-
}
|
|
1712
|
-
case "is": {
|
|
1713
|
-
if (value === null) return `${column} IS NULL`;
|
|
1714
|
-
if (value === true) return `${column} IS TRUE`;
|
|
1715
|
-
if (value === false) return `${column} IS FALSE`;
|
|
1716
|
-
return null;
|
|
1717
|
-
}
|
|
1718
|
-
case "in": {
|
|
1719
|
-
if (!Array.isArray(value)) return null;
|
|
1720
|
-
if (value.length === 0) return "FALSE";
|
|
1721
|
-
const values = value.map((item) => withCast(toSqlLiteral(item), condition.value_cast));
|
|
1722
|
-
return `${column} IN (${values.join(", ")})`;
|
|
1723
|
-
}
|
|
1724
|
-
default:
|
|
1725
|
-
return null;
|
|
1849
|
+
}
|
|
1850
|
+
function unwrapRows(result, options) {
|
|
1851
|
+
if (!isOk(result)) {
|
|
1852
|
+
throw toAthenaGatewayError(result, "Athena request failed", options?.context);
|
|
1726
1853
|
}
|
|
1854
|
+
if (result.data == null) return [];
|
|
1855
|
+
return Array.isArray(result.data) ? result.data : [result.data];
|
|
1727
1856
|
}
|
|
1728
|
-
function
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
const clause = conditionToSqlClause(condition);
|
|
1732
|
-
if (!clause) return null;
|
|
1733
|
-
whereClauses.push(clause);
|
|
1857
|
+
function unwrap(result, options) {
|
|
1858
|
+
if (!isOk(result)) {
|
|
1859
|
+
throw toAthenaGatewayError(result, "Athena request failed", options?.context);
|
|
1734
1860
|
}
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
if (limit === void 0 && input.pageSize !== void 0) {
|
|
1738
|
-
limit = input.pageSize;
|
|
1861
|
+
if (result.data == null && !options?.allowNull) {
|
|
1862
|
+
throw toAthenaGatewayError(result, "Expected data but received null", options?.context);
|
|
1739
1863
|
}
|
|
1740
|
-
|
|
1741
|
-
|
|
1864
|
+
return result.data;
|
|
1865
|
+
}
|
|
1866
|
+
function unwrapOne(result, options) {
|
|
1867
|
+
const rows = unwrapRows(result, options);
|
|
1868
|
+
if (!rows.length) {
|
|
1869
|
+
if (options?.allowNull) return null;
|
|
1870
|
+
throw toAthenaGatewayError(result, "Expected one row but received none", options?.context);
|
|
1742
1871
|
}
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1872
|
+
if (options?.requireExactlyOne && rows.length !== 1) {
|
|
1873
|
+
throw toAthenaGatewayError(
|
|
1874
|
+
result,
|
|
1875
|
+
`Expected exactly one row but received ${rows.length}`,
|
|
1876
|
+
options.context
|
|
1877
|
+
);
|
|
1748
1878
|
}
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1879
|
+
return rows[0];
|
|
1880
|
+
}
|
|
1881
|
+
function requireSuccess(result, context) {
|
|
1882
|
+
if (!isOk(result)) {
|
|
1883
|
+
throw toAthenaGatewayError(
|
|
1884
|
+
result,
|
|
1885
|
+
`Athena ${context?.operation ?? "request"} failed`,
|
|
1886
|
+
context
|
|
1887
|
+
);
|
|
1752
1888
|
}
|
|
1753
|
-
|
|
1754
|
-
|
|
1889
|
+
return result;
|
|
1890
|
+
}
|
|
1891
|
+
function requireAffected(result, options, context) {
|
|
1892
|
+
requireSuccess(result, context);
|
|
1893
|
+
const minimum = options?.min ?? 1;
|
|
1894
|
+
const count = result.count;
|
|
1895
|
+
if (count == null) {
|
|
1896
|
+
throw new AthenaGatewayError({
|
|
1897
|
+
code: "UNKNOWN_ERROR",
|
|
1898
|
+
status: result.status,
|
|
1899
|
+
message: "Expected affected row count but response.count is missing",
|
|
1900
|
+
hint: 'Set call option { count: "exact" } for mutation postcondition checks.',
|
|
1901
|
+
cause: safeStringify(result.raw)
|
|
1902
|
+
});
|
|
1755
1903
|
}
|
|
1756
|
-
if (
|
|
1757
|
-
|
|
1904
|
+
if (count < minimum) {
|
|
1905
|
+
throw new AthenaGatewayError({
|
|
1906
|
+
code: "UNKNOWN_ERROR",
|
|
1907
|
+
status: result.status,
|
|
1908
|
+
message: `Expected at least ${minimum} affected rows but received ${count}`,
|
|
1909
|
+
hint: contextHint(context),
|
|
1910
|
+
cause: safeStringify(result.raw)
|
|
1911
|
+
});
|
|
1758
1912
|
}
|
|
1759
|
-
return
|
|
1913
|
+
return count;
|
|
1760
1914
|
}
|
|
1761
|
-
function
|
|
1762
|
-
return
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
addCondition("eq", column, value);
|
|
1789
|
-
}
|
|
1790
|
-
});
|
|
1791
|
-
return self;
|
|
1792
|
-
},
|
|
1793
|
-
range(from, to) {
|
|
1794
|
-
state.offset = from;
|
|
1795
|
-
state.limit = to - from + 1;
|
|
1796
|
-
return self;
|
|
1797
|
-
},
|
|
1798
|
-
limit(count) {
|
|
1799
|
-
state.limit = count;
|
|
1800
|
-
return self;
|
|
1801
|
-
},
|
|
1802
|
-
offset(count) {
|
|
1803
|
-
state.offset = count;
|
|
1804
|
-
return self;
|
|
1805
|
-
},
|
|
1806
|
-
currentPage(value) {
|
|
1807
|
-
state.currentPage = value;
|
|
1808
|
-
return self;
|
|
1809
|
-
},
|
|
1810
|
-
pageSize(value) {
|
|
1811
|
-
state.pageSize = value;
|
|
1812
|
-
return self;
|
|
1813
|
-
},
|
|
1814
|
-
totalPages(value) {
|
|
1815
|
-
state.totalPages = value;
|
|
1816
|
-
return self;
|
|
1817
|
-
},
|
|
1818
|
-
order(column, options) {
|
|
1819
|
-
state.order = {
|
|
1820
|
-
field: String(column),
|
|
1821
|
-
direction: options?.ascending === false ? "descending" : "ascending"
|
|
1822
|
-
};
|
|
1823
|
-
return self;
|
|
1824
|
-
},
|
|
1825
|
-
gt(column, value) {
|
|
1826
|
-
addCondition("gt", String(column), value);
|
|
1827
|
-
return self;
|
|
1828
|
-
},
|
|
1829
|
-
gte(column, value) {
|
|
1830
|
-
addCondition("gte", String(column), value);
|
|
1831
|
-
return self;
|
|
1832
|
-
},
|
|
1833
|
-
lt(column, value) {
|
|
1834
|
-
addCondition("lt", String(column), value);
|
|
1835
|
-
return self;
|
|
1836
|
-
},
|
|
1837
|
-
lte(column, value) {
|
|
1838
|
-
addCondition("lte", String(column), value);
|
|
1839
|
-
return self;
|
|
1840
|
-
},
|
|
1841
|
-
neq(column, value) {
|
|
1842
|
-
addCondition("neq", String(column), value);
|
|
1843
|
-
return self;
|
|
1844
|
-
},
|
|
1845
|
-
like(column, value) {
|
|
1846
|
-
addCondition("like", String(column), value);
|
|
1847
|
-
return self;
|
|
1848
|
-
},
|
|
1849
|
-
ilike(column, value) {
|
|
1850
|
-
addCondition("ilike", String(column), value);
|
|
1851
|
-
return self;
|
|
1852
|
-
},
|
|
1853
|
-
is(column, value) {
|
|
1854
|
-
addCondition("is", String(column), value);
|
|
1855
|
-
return self;
|
|
1856
|
-
},
|
|
1857
|
-
in(column, values) {
|
|
1858
|
-
addCondition("in", String(column), values);
|
|
1859
|
-
return self;
|
|
1860
|
-
},
|
|
1861
|
-
contains(column, values) {
|
|
1862
|
-
addCondition("contains", String(column), values);
|
|
1863
|
-
return self;
|
|
1864
|
-
},
|
|
1865
|
-
containedBy(column, values) {
|
|
1866
|
-
addCondition("containedBy", String(column), values);
|
|
1867
|
-
return self;
|
|
1868
|
-
},
|
|
1869
|
-
not(columnOrExpression, operator, value) {
|
|
1870
|
-
const expression = String(columnOrExpression);
|
|
1871
|
-
if (operator != null && value !== void 0) {
|
|
1872
|
-
addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue(value)}`);
|
|
1873
|
-
} else {
|
|
1874
|
-
addCondition("not", void 0, expression);
|
|
1915
|
+
function applyBounds(value, options) {
|
|
1916
|
+
if (options?.min !== void 0 && value < options.min) return null;
|
|
1917
|
+
if (options?.max !== void 0 && value > options.max) return null;
|
|
1918
|
+
return value;
|
|
1919
|
+
}
|
|
1920
|
+
function parseIntegerString(value) {
|
|
1921
|
+
const normalized = value.trim();
|
|
1922
|
+
if (!/^[-+]?\d+$/.test(normalized)) return null;
|
|
1923
|
+
const parsed = Number(normalized);
|
|
1924
|
+
if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) return null;
|
|
1925
|
+
return parsed;
|
|
1926
|
+
}
|
|
1927
|
+
function coerceInt(value, options) {
|
|
1928
|
+
if (value == null) return null;
|
|
1929
|
+
if (typeof value === "number") {
|
|
1930
|
+
if (!Number.isFinite(value) || !Number.isInteger(value)) return null;
|
|
1931
|
+
return applyBounds(value, options);
|
|
1932
|
+
}
|
|
1933
|
+
if (typeof value === "string") {
|
|
1934
|
+
const parsed = parseIntegerString(value);
|
|
1935
|
+
if (parsed == null) return null;
|
|
1936
|
+
return applyBounds(parsed, options);
|
|
1937
|
+
}
|
|
1938
|
+
if (typeof value === "bigint") {
|
|
1939
|
+
if (options?.strictBigInt) {
|
|
1940
|
+
if (value > BigInt(Number.MAX_SAFE_INTEGER) || value < BigInt(Number.MIN_SAFE_INTEGER)) {
|
|
1941
|
+
return null;
|
|
1875
1942
|
}
|
|
1876
|
-
return self;
|
|
1877
|
-
},
|
|
1878
|
-
or(expression) {
|
|
1879
|
-
addCondition("or", void 0, expression);
|
|
1880
|
-
return self;
|
|
1881
1943
|
}
|
|
1882
|
-
|
|
1944
|
+
const parsed = Number(value);
|
|
1945
|
+
if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) return null;
|
|
1946
|
+
return applyBounds(parsed, options);
|
|
1947
|
+
}
|
|
1948
|
+
return null;
|
|
1883
1949
|
}
|
|
1884
|
-
function
|
|
1885
|
-
|
|
1886
|
-
|
|
1950
|
+
function assertInt(value, label = "value", options) {
|
|
1951
|
+
const parsed = coerceInt(value, options);
|
|
1952
|
+
if (parsed == null) {
|
|
1953
|
+
throw new TypeError(`${label} must be a finite integer`);
|
|
1954
|
+
}
|
|
1955
|
+
return parsed;
|
|
1887
1956
|
}
|
|
1888
|
-
function
|
|
1889
|
-
const
|
|
1890
|
-
|
|
1957
|
+
function defaultShouldRetry(error) {
|
|
1958
|
+
const normalized = normalizeAthenaError(error);
|
|
1959
|
+
return normalized.kind === "transient" || normalized.kind === "rate_limit";
|
|
1960
|
+
}
|
|
1961
|
+
function computeDelayMs(attempt, error, config) {
|
|
1962
|
+
const baseDelay = config.baseDelayMs;
|
|
1963
|
+
const rawDelay = typeof config.backoff === "function" ? config.backoff(attempt, error) : config.backoff === "linear" ? baseDelay * attempt : baseDelay * Math.pow(2, attempt - 1);
|
|
1964
|
+
const safeDelay = Number.isFinite(rawDelay) ? Math.max(0, rawDelay) : 0;
|
|
1965
|
+
const clamped = Math.min(config.maxDelayMs, safeDelay);
|
|
1966
|
+
const jitterFactor = typeof config.jitter === "number" ? Math.max(0, Math.min(1, config.jitter)) : config.jitter ? 0.2 : 0;
|
|
1967
|
+
if (!jitterFactor) return clamped;
|
|
1968
|
+
const deviation = clamped * jitterFactor;
|
|
1969
|
+
const offset = (Math.random() * 2 - 1) * deviation;
|
|
1970
|
+
return Math.max(0, clamped + offset);
|
|
1971
|
+
}
|
|
1972
|
+
function sleep(ms) {
|
|
1973
|
+
if (ms <= 0) return Promise.resolve();
|
|
1974
|
+
return new Promise((resolve3) => {
|
|
1975
|
+
setTimeout(resolve3, ms);
|
|
1976
|
+
});
|
|
1977
|
+
}
|
|
1978
|
+
async function withRetry(config, fn) {
|
|
1979
|
+
const retries = Math.max(0, Math.trunc(config.retries));
|
|
1980
|
+
const shouldRetry = config.shouldRetry ?? defaultShouldRetry;
|
|
1981
|
+
const resolvedConfig = {
|
|
1982
|
+
baseDelayMs: config.baseDelayMs ?? 100,
|
|
1983
|
+
maxDelayMs: config.maxDelayMs ?? 1e4,
|
|
1984
|
+
backoff: config.backoff ?? "exponential",
|
|
1985
|
+
jitter: config.jitter ?? false
|
|
1891
1986
|
};
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1987
|
+
for (let attempts = 0; attempts <= retries; attempts += 1) {
|
|
1988
|
+
try {
|
|
1989
|
+
return await fn();
|
|
1990
|
+
} catch (error) {
|
|
1991
|
+
if (attempts >= retries) {
|
|
1992
|
+
throw error;
|
|
1993
|
+
}
|
|
1994
|
+
const currentAttempt = attempts + 1;
|
|
1995
|
+
const retry = await shouldRetry(error, currentAttempt);
|
|
1996
|
+
if (!retry) {
|
|
1997
|
+
throw error;
|
|
1998
|
+
}
|
|
1999
|
+
const delay = computeDelayMs(currentAttempt, error, resolvedConfig);
|
|
2000
|
+
await sleep(delay);
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
throw new Error("withRetry reached an unexpected state");
|
|
2004
|
+
}
|
|
2005
|
+
|
|
2006
|
+
// src/db/module.ts
|
|
2007
|
+
function createDbModule(input) {
|
|
2008
|
+
const db = {
|
|
2009
|
+
from(table) {
|
|
2010
|
+
return input.from(table);
|
|
1904
2011
|
},
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
return self;
|
|
2012
|
+
select(table, columns, options) {
|
|
2013
|
+
return input.from(table).select(columns, options);
|
|
1908
2014
|
},
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
return self;
|
|
2015
|
+
insert(table, values, options) {
|
|
2016
|
+
return Array.isArray(values) ? input.from(table).insert(values, options) : input.from(table).insert(values, options);
|
|
1912
2017
|
},
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
return self;
|
|
2018
|
+
upsert(table, values, options) {
|
|
2019
|
+
return Array.isArray(values) ? input.from(table).upsert(values, options) : input.from(table).upsert(values, options);
|
|
1916
2020
|
},
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
return self;
|
|
2021
|
+
update(table, values, options) {
|
|
2022
|
+
return input.from(table).update(values, options);
|
|
1920
2023
|
},
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
return self;
|
|
2024
|
+
delete(table, options) {
|
|
2025
|
+
return input.from(table).delete(options);
|
|
1924
2026
|
},
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
return self;
|
|
2027
|
+
rpc(fn, args, options) {
|
|
2028
|
+
return input.rpc(fn, args, options);
|
|
1928
2029
|
},
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
return self;
|
|
2030
|
+
query(query, options) {
|
|
2031
|
+
return input.query(query, options);
|
|
1932
2032
|
}
|
|
1933
2033
|
};
|
|
2034
|
+
return db;
|
|
1934
2035
|
}
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
2036
|
+
|
|
2037
|
+
// src/client.ts
|
|
2038
|
+
var DEFAULT_COLUMNS = "*";
|
|
2039
|
+
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
2040
|
+
var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
|
|
2041
|
+
var ATHENA_NORMALIZED_ERROR_KEY = "__athenaNormalizedError";
|
|
2042
|
+
function formatResult(response) {
|
|
2043
|
+
const result = {
|
|
2044
|
+
data: response.data ?? null,
|
|
2045
|
+
error: response.error ?? null,
|
|
2046
|
+
errorDetails: response.errorDetails ?? null,
|
|
2047
|
+
status: response.status,
|
|
2048
|
+
raw: response.raw
|
|
1938
2049
|
};
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
2050
|
+
if (response.count !== void 0) {
|
|
2051
|
+
result.count = response.count;
|
|
2052
|
+
}
|
|
2053
|
+
return result;
|
|
2054
|
+
}
|
|
2055
|
+
function attachNormalizedError(result, normalizedError) {
|
|
2056
|
+
Object.defineProperty(result, ATHENA_NORMALIZED_ERROR_KEY, {
|
|
2057
|
+
value: normalizedError,
|
|
2058
|
+
enumerable: false,
|
|
2059
|
+
configurable: true,
|
|
2060
|
+
writable: false
|
|
2061
|
+
});
|
|
2062
|
+
}
|
|
2063
|
+
function createResultFormatter(experimental) {
|
|
2064
|
+
if (!experimental?.enableErrorNormalization) {
|
|
2065
|
+
return formatResult;
|
|
2066
|
+
}
|
|
2067
|
+
return (response, context) => {
|
|
2068
|
+
const result = formatResult(response);
|
|
2069
|
+
if (result.error == null) {
|
|
2070
|
+
return result;
|
|
2071
|
+
}
|
|
2072
|
+
const normalizedError = normalizeAthenaError(result, context);
|
|
2073
|
+
attachNormalizedError(result, normalizedError);
|
|
2074
|
+
return result;
|
|
2075
|
+
};
|
|
2076
|
+
}
|
|
2077
|
+
function toSingleResult(response) {
|
|
2078
|
+
const payload = response.data;
|
|
2079
|
+
const singleData = Array.isArray(payload) ? payload.length ? payload[0] : null : payload ?? null;
|
|
2080
|
+
return {
|
|
2081
|
+
...response,
|
|
2082
|
+
data: singleData
|
|
1958
2083
|
};
|
|
2084
|
+
}
|
|
2085
|
+
function mergeOptions(...options) {
|
|
2086
|
+
return options.reduce((acc, next) => {
|
|
2087
|
+
if (!next) return acc;
|
|
2088
|
+
return { ...acc, ...next };
|
|
2089
|
+
}, void 0);
|
|
2090
|
+
}
|
|
2091
|
+
function asAthenaJsonObject(value) {
|
|
2092
|
+
return value;
|
|
2093
|
+
}
|
|
2094
|
+
function asAthenaJsonObjectArray(values) {
|
|
2095
|
+
return values;
|
|
2096
|
+
}
|
|
2097
|
+
function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
|
|
2098
|
+
let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
|
|
2099
|
+
let selectedOptions;
|
|
2100
|
+
let promise = null;
|
|
1959
2101
|
const run = (columns, options) => {
|
|
1960
2102
|
const payloadColumns = columns ?? selectedColumns;
|
|
1961
2103
|
const payloadOptions = options ?? selectedOptions;
|
|
1962
2104
|
if (!promise) {
|
|
1963
|
-
promise =
|
|
2105
|
+
promise = executor(payloadColumns, payloadOptions);
|
|
1964
2106
|
}
|
|
1965
2107
|
return promise;
|
|
1966
2108
|
};
|
|
1967
|
-
const
|
|
1968
|
-
const filterMethods = createRpcFilterMethods(state.filters, builder);
|
|
1969
|
-
Object.assign(builder, filterMethods, {
|
|
2109
|
+
const mutationQuery = {
|
|
1970
2110
|
select(columns = selectedColumns, options) {
|
|
1971
2111
|
selectedColumns = columns;
|
|
1972
2112
|
selectedOptions = options ?? selectedOptions;
|
|
1973
2113
|
return run(columns, options);
|
|
1974
2114
|
},
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
return toSingleResult(result);
|
|
1978
|
-
},
|
|
1979
|
-
maybeSingle(columns, options) {
|
|
1980
|
-
return builder.single(columns, options);
|
|
1981
|
-
},
|
|
1982
|
-
order(column, options) {
|
|
1983
|
-
state.order = { column, ascending: options?.ascending ?? true };
|
|
1984
|
-
return builder;
|
|
1985
|
-
},
|
|
1986
|
-
limit(count) {
|
|
1987
|
-
state.limit = count;
|
|
1988
|
-
return builder;
|
|
2115
|
+
returning(columns = selectedColumns, options) {
|
|
2116
|
+
return mutationQuery.select(columns, options);
|
|
1989
2117
|
},
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
2118
|
+
single(columns = selectedColumns, options) {
|
|
2119
|
+
selectedColumns = columns;
|
|
2120
|
+
selectedOptions = options ?? selectedOptions;
|
|
2121
|
+
return run(columns, options).then(toSingleResult);
|
|
1993
2122
|
},
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
state.limit = to - from + 1;
|
|
1997
|
-
return builder;
|
|
2123
|
+
maybeSingle(columns = selectedColumns, options) {
|
|
2124
|
+
return mutationQuery.single(columns, options);
|
|
1998
2125
|
},
|
|
1999
2126
|
then(onfulfilled, onrejected) {
|
|
2000
2127
|
return run(selectedColumns, selectedOptions).then(onfulfilled, onrejected);
|
|
@@ -2005,122 +2132,511 @@ function createRpcBuilder(functionName, args, baseOptions, client) {
|
|
|
2005
2132
|
finally(onfinally) {
|
|
2006
2133
|
return run(selectedColumns, selectedOptions).finally(onfinally);
|
|
2007
2134
|
}
|
|
2008
|
-
}
|
|
2009
|
-
return
|
|
2135
|
+
};
|
|
2136
|
+
return mutationQuery;
|
|
2010
2137
|
}
|
|
2011
|
-
function
|
|
2012
|
-
const
|
|
2013
|
-
|
|
2138
|
+
function getResourceId(state) {
|
|
2139
|
+
const candidate = state.conditions.find(
|
|
2140
|
+
(condition) => condition.operator === "eq" && (condition.column === "resource_id" || condition.column === "id")
|
|
2141
|
+
);
|
|
2142
|
+
return candidate?.value?.toString();
|
|
2143
|
+
}
|
|
2144
|
+
function stringifyFilterValue(value) {
|
|
2145
|
+
if (Array.isArray(value)) {
|
|
2146
|
+
return value.join(",");
|
|
2147
|
+
}
|
|
2148
|
+
return String(value);
|
|
2149
|
+
}
|
|
2150
|
+
function isUuidString(value) {
|
|
2151
|
+
return UUID_PATTERN.test(value.trim());
|
|
2152
|
+
}
|
|
2153
|
+
function isUuidIdentifierColumn(column) {
|
|
2154
|
+
return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
|
|
2155
|
+
}
|
|
2156
|
+
function shouldUseUuidTextComparison(column, value) {
|
|
2157
|
+
return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
|
|
2158
|
+
}
|
|
2159
|
+
function normalizeCast(cast) {
|
|
2160
|
+
const normalized = cast.trim().toLowerCase();
|
|
2161
|
+
if (!SAFE_CAST_PATTERN.test(normalized)) {
|
|
2162
|
+
throw new Error(`Invalid cast type "${cast}"`);
|
|
2163
|
+
}
|
|
2164
|
+
return normalized;
|
|
2165
|
+
}
|
|
2166
|
+
function escapeSqlStringLiteral(value) {
|
|
2167
|
+
return value.replace(/'/g, "''");
|
|
2168
|
+
}
|
|
2169
|
+
function toSqlLiteral(value) {
|
|
2170
|
+
if (value === null) return "NULL";
|
|
2171
|
+
if (typeof value === "number") return Number.isFinite(value) ? String(value) : "NULL";
|
|
2172
|
+
if (typeof value === "boolean") return value ? "TRUE" : "FALSE";
|
|
2173
|
+
return `'${escapeSqlStringLiteral(value)}'`;
|
|
2174
|
+
}
|
|
2175
|
+
function withCast(expression, cast) {
|
|
2176
|
+
if (!cast) return expression;
|
|
2177
|
+
return `${expression}::${normalizeCast(cast)}`;
|
|
2178
|
+
}
|
|
2179
|
+
function buildSelectColumnsClause(columns) {
|
|
2180
|
+
if (Array.isArray(columns)) {
|
|
2181
|
+
return columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
|
|
2182
|
+
}
|
|
2183
|
+
return quoteSelectColumnsExpression(columns);
|
|
2184
|
+
}
|
|
2185
|
+
function resolveTableNameForCall(tableName, schema) {
|
|
2186
|
+
if (!schema) return tableName;
|
|
2187
|
+
const normalizedSchema = schema.trim();
|
|
2188
|
+
if (!normalizedSchema) {
|
|
2189
|
+
throw new Error("schema option must be a non-empty string");
|
|
2190
|
+
}
|
|
2191
|
+
if (tableName.includes(".")) {
|
|
2192
|
+
if (tableName.startsWith(`${normalizedSchema}.`)) {
|
|
2193
|
+
return tableName;
|
|
2194
|
+
}
|
|
2195
|
+
throw new Error(
|
|
2196
|
+
`schema option "${normalizedSchema}" conflicts with schema-qualified table "${tableName}"`
|
|
2197
|
+
);
|
|
2198
|
+
}
|
|
2199
|
+
return `${normalizedSchema}.${tableName}`;
|
|
2200
|
+
}
|
|
2201
|
+
function conditionToSqlClause(condition) {
|
|
2202
|
+
if (!condition.column) return null;
|
|
2203
|
+
const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
|
|
2204
|
+
const value = condition.value;
|
|
2205
|
+
const sqlOperator = {
|
|
2206
|
+
eq: "=",
|
|
2207
|
+
neq: "!=",
|
|
2208
|
+
gt: ">",
|
|
2209
|
+
gte: ">=",
|
|
2210
|
+
lt: "<",
|
|
2211
|
+
lte: "<=",
|
|
2212
|
+
like: "LIKE",
|
|
2213
|
+
ilike: "ILIKE"
|
|
2014
2214
|
};
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2215
|
+
switch (condition.operator) {
|
|
2216
|
+
case "eq":
|
|
2217
|
+
case "neq":
|
|
2218
|
+
case "gt":
|
|
2219
|
+
case "gte":
|
|
2220
|
+
case "lt":
|
|
2221
|
+
case "lte":
|
|
2222
|
+
case "like":
|
|
2223
|
+
case "ilike": {
|
|
2224
|
+
if (Array.isArray(value) || value === void 0) return null;
|
|
2225
|
+
const rhs = withCast(toSqlLiteral(value), condition.value_cast);
|
|
2226
|
+
return `${column} ${sqlOperator[condition.operator]} ${rhs}`;
|
|
2022
2227
|
}
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
if (
|
|
2026
|
-
|
|
2027
|
-
|
|
2228
|
+
case "is": {
|
|
2229
|
+
if (value === null) return `${column} IS NULL`;
|
|
2230
|
+
if (value === true) return `${column} IS TRUE`;
|
|
2231
|
+
if (value === false) return `${column} IS FALSE`;
|
|
2232
|
+
return null;
|
|
2028
2233
|
}
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
if (
|
|
2032
|
-
|
|
2033
|
-
}
|
|
2234
|
+
case "in": {
|
|
2235
|
+
if (!Array.isArray(value)) return null;
|
|
2236
|
+
if (value.length === 0) return "FALSE";
|
|
2237
|
+
const values = value.map((item) => withCast(toSqlLiteral(item), condition.value_cast));
|
|
2238
|
+
return `${column} IN (${values.join(", ")})`;
|
|
2034
2239
|
}
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2240
|
+
default:
|
|
2241
|
+
return null;
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
function buildTypedSelectQuery(input) {
|
|
2245
|
+
const whereClauses = [];
|
|
2246
|
+
for (const condition of input.conditions) {
|
|
2247
|
+
const clause = conditionToSqlClause(condition);
|
|
2248
|
+
if (!clause) return null;
|
|
2249
|
+
whereClauses.push(clause);
|
|
2250
|
+
}
|
|
2251
|
+
let limit = input.limit;
|
|
2252
|
+
let offset = input.offset;
|
|
2253
|
+
if (limit === void 0 && input.pageSize !== void 0) {
|
|
2254
|
+
limit = input.pageSize;
|
|
2255
|
+
}
|
|
2256
|
+
if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
|
|
2257
|
+
offset = (input.currentPage - 1) * input.pageSize;
|
|
2258
|
+
}
|
|
2259
|
+
const sqlParts = [
|
|
2260
|
+
`SELECT ${buildSelectColumnsClause(input.columns)} FROM ${quoteQualifiedIdentifier(input.tableName)}`
|
|
2261
|
+
];
|
|
2262
|
+
if (whereClauses.length > 0) {
|
|
2263
|
+
sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
|
|
2264
|
+
}
|
|
2265
|
+
if (input.order?.field) {
|
|
2266
|
+
const direction = input.order.direction === "descending" ? "DESC" : "ASC";
|
|
2267
|
+
sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(input.order.field)} ${direction}`);
|
|
2268
|
+
}
|
|
2269
|
+
if (limit !== void 0) {
|
|
2270
|
+
sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(limit))}`);
|
|
2271
|
+
}
|
|
2272
|
+
if (offset !== void 0) {
|
|
2273
|
+
sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
|
|
2274
|
+
}
|
|
2275
|
+
return `${sqlParts.join(" ")};`;
|
|
2276
|
+
}
|
|
2277
|
+
function createFilterMethods(state, addCondition, self) {
|
|
2278
|
+
return {
|
|
2279
|
+
eq(column, value) {
|
|
2280
|
+
const columnName = String(column);
|
|
2281
|
+
if (shouldUseUuidTextComparison(columnName, value)) {
|
|
2282
|
+
addCondition("eq", columnName, value, { columnCast: "text" });
|
|
2283
|
+
} else {
|
|
2284
|
+
addCondition("eq", columnName, value);
|
|
2039
2285
|
}
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
limit: state.limit,
|
|
2061
|
-
offset: state.offset,
|
|
2062
|
-
currentPage: state.currentPage,
|
|
2063
|
-
pageSize: state.pageSize,
|
|
2064
|
-
order: state.order
|
|
2286
|
+
return self;
|
|
2287
|
+
},
|
|
2288
|
+
eqCast(column, value, cast) {
|
|
2289
|
+
addCondition("eq", String(column), value, { valueCast: cast });
|
|
2290
|
+
return self;
|
|
2291
|
+
},
|
|
2292
|
+
eqUuid(column, value) {
|
|
2293
|
+
addCondition("eq", String(column), value, { valueCast: "uuid" });
|
|
2294
|
+
return self;
|
|
2295
|
+
},
|
|
2296
|
+
match(filters) {
|
|
2297
|
+
Object.entries(filters).forEach(([column, value]) => {
|
|
2298
|
+
if (value === void 0) {
|
|
2299
|
+
return;
|
|
2300
|
+
}
|
|
2301
|
+
if (shouldUseUuidTextComparison(column, value)) {
|
|
2302
|
+
addCondition("eq", column, value, { columnCast: "text" });
|
|
2303
|
+
} else {
|
|
2304
|
+
addCondition("eq", column, value);
|
|
2305
|
+
}
|
|
2065
2306
|
});
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2307
|
+
return self;
|
|
2308
|
+
},
|
|
2309
|
+
range(from, to) {
|
|
2310
|
+
state.offset = from;
|
|
2311
|
+
state.limit = to - from + 1;
|
|
2312
|
+
return self;
|
|
2313
|
+
},
|
|
2314
|
+
limit(count) {
|
|
2315
|
+
state.limit = count;
|
|
2316
|
+
return self;
|
|
2317
|
+
},
|
|
2318
|
+
offset(count) {
|
|
2319
|
+
state.offset = count;
|
|
2320
|
+
return self;
|
|
2321
|
+
},
|
|
2322
|
+
currentPage(value) {
|
|
2323
|
+
state.currentPage = value;
|
|
2324
|
+
return self;
|
|
2325
|
+
},
|
|
2326
|
+
pageSize(value) {
|
|
2327
|
+
state.pageSize = value;
|
|
2328
|
+
return self;
|
|
2329
|
+
},
|
|
2330
|
+
totalPages(value) {
|
|
2331
|
+
state.totalPages = value;
|
|
2332
|
+
return self;
|
|
2333
|
+
},
|
|
2334
|
+
order(column, options) {
|
|
2335
|
+
state.order = {
|
|
2336
|
+
field: String(column),
|
|
2337
|
+
direction: options?.ascending === false ? "descending" : "ascending"
|
|
2338
|
+
};
|
|
2339
|
+
return self;
|
|
2340
|
+
},
|
|
2341
|
+
gt(column, value) {
|
|
2342
|
+
addCondition("gt", String(column), value);
|
|
2343
|
+
return self;
|
|
2344
|
+
},
|
|
2345
|
+
gte(column, value) {
|
|
2346
|
+
addCondition("gte", String(column), value);
|
|
2347
|
+
return self;
|
|
2348
|
+
},
|
|
2349
|
+
lt(column, value) {
|
|
2350
|
+
addCondition("lt", String(column), value);
|
|
2351
|
+
return self;
|
|
2352
|
+
},
|
|
2353
|
+
lte(column, value) {
|
|
2354
|
+
addCondition("lte", String(column), value);
|
|
2355
|
+
return self;
|
|
2356
|
+
},
|
|
2357
|
+
neq(column, value) {
|
|
2358
|
+
addCondition("neq", String(column), value);
|
|
2359
|
+
return self;
|
|
2360
|
+
},
|
|
2361
|
+
like(column, value) {
|
|
2362
|
+
addCondition("like", String(column), value);
|
|
2363
|
+
return self;
|
|
2364
|
+
},
|
|
2365
|
+
ilike(column, value) {
|
|
2366
|
+
addCondition("ilike", String(column), value);
|
|
2367
|
+
return self;
|
|
2368
|
+
},
|
|
2369
|
+
is(column, value) {
|
|
2370
|
+
addCondition("is", String(column), value);
|
|
2371
|
+
return self;
|
|
2372
|
+
},
|
|
2373
|
+
in(column, values) {
|
|
2374
|
+
addCondition("in", String(column), values);
|
|
2375
|
+
return self;
|
|
2376
|
+
},
|
|
2377
|
+
contains(column, values) {
|
|
2378
|
+
addCondition("contains", String(column), values);
|
|
2379
|
+
return self;
|
|
2380
|
+
},
|
|
2381
|
+
containedBy(column, values) {
|
|
2382
|
+
addCondition("containedBy", String(column), values);
|
|
2383
|
+
return self;
|
|
2384
|
+
},
|
|
2385
|
+
not(columnOrExpression, operator, value) {
|
|
2386
|
+
const expression = String(columnOrExpression);
|
|
2387
|
+
if (operator != null && value !== void 0) {
|
|
2388
|
+
addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue(value)}`);
|
|
2389
|
+
} else {
|
|
2390
|
+
addCondition("not", void 0, expression);
|
|
2069
2391
|
}
|
|
2392
|
+
return self;
|
|
2393
|
+
},
|
|
2394
|
+
or(expression) {
|
|
2395
|
+
addCondition("or", void 0, expression);
|
|
2396
|
+
return self;
|
|
2397
|
+
}
|
|
2398
|
+
};
|
|
2399
|
+
}
|
|
2400
|
+
function toRpcSelect(columns) {
|
|
2401
|
+
if (!columns) return void 0;
|
|
2402
|
+
return Array.isArray(columns) ? columns.join(",") : columns;
|
|
2403
|
+
}
|
|
2404
|
+
function createRpcFilterMethods(filters, self) {
|
|
2405
|
+
const addFilter = (operator, column, value) => {
|
|
2406
|
+
filters.push({ column, operator, value });
|
|
2407
|
+
};
|
|
2408
|
+
return {
|
|
2409
|
+
eq(column, value) {
|
|
2410
|
+
addFilter("eq", column, value);
|
|
2411
|
+
return self;
|
|
2412
|
+
},
|
|
2413
|
+
neq(column, value) {
|
|
2414
|
+
addFilter("neq", column, value);
|
|
2415
|
+
return self;
|
|
2416
|
+
},
|
|
2417
|
+
gt(column, value) {
|
|
2418
|
+
addFilter("gt", column, value);
|
|
2419
|
+
return self;
|
|
2420
|
+
},
|
|
2421
|
+
gte(column, value) {
|
|
2422
|
+
addFilter("gte", column, value);
|
|
2423
|
+
return self;
|
|
2424
|
+
},
|
|
2425
|
+
lt(column, value) {
|
|
2426
|
+
addFilter("lt", column, value);
|
|
2427
|
+
return self;
|
|
2428
|
+
},
|
|
2429
|
+
lte(column, value) {
|
|
2430
|
+
addFilter("lte", column, value);
|
|
2431
|
+
return self;
|
|
2432
|
+
},
|
|
2433
|
+
like(column, value) {
|
|
2434
|
+
addFilter("like", column, value);
|
|
2435
|
+
return self;
|
|
2436
|
+
},
|
|
2437
|
+
ilike(column, value) {
|
|
2438
|
+
addFilter("ilike", column, value);
|
|
2439
|
+
return self;
|
|
2440
|
+
},
|
|
2441
|
+
is(column, value) {
|
|
2442
|
+
addFilter("is", column, value);
|
|
2443
|
+
return self;
|
|
2444
|
+
},
|
|
2445
|
+
in(column, values) {
|
|
2446
|
+
addFilter("in", column, values);
|
|
2447
|
+
return self;
|
|
2070
2448
|
}
|
|
2449
|
+
};
|
|
2450
|
+
}
|
|
2451
|
+
function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult) {
|
|
2452
|
+
const state = {
|
|
2453
|
+
filters: []
|
|
2454
|
+
};
|
|
2455
|
+
let selectedColumns;
|
|
2456
|
+
let selectedOptions;
|
|
2457
|
+
let promise = null;
|
|
2458
|
+
const executeRpc = async (columns, options) => {
|
|
2459
|
+
const mergedOptions = mergeOptions(baseOptions, options);
|
|
2071
2460
|
const payload = {
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2461
|
+
function: functionName,
|
|
2462
|
+
args,
|
|
2463
|
+
schema: mergedOptions?.schema,
|
|
2464
|
+
select: toRpcSelect(columns),
|
|
2465
|
+
filters: state.filters.length ? [...state.filters] : void 0,
|
|
2466
|
+
count: mergedOptions?.count,
|
|
2467
|
+
head: mergedOptions?.head,
|
|
2075
2468
|
limit: state.limit,
|
|
2076
2469
|
offset: state.offset,
|
|
2077
|
-
|
|
2078
|
-
page_size: state.pageSize,
|
|
2079
|
-
total_pages: state.totalPages,
|
|
2080
|
-
sort_by: state.order,
|
|
2081
|
-
strip_nulls: options?.stripNulls ?? true,
|
|
2082
|
-
count: options?.count,
|
|
2083
|
-
head: options?.head
|
|
2470
|
+
order: state.order
|
|
2084
2471
|
};
|
|
2085
|
-
const response = await client.
|
|
2086
|
-
return
|
|
2472
|
+
const response = await client.rpcGateway(payload, mergedOptions);
|
|
2473
|
+
return formatGatewayResult(response, { operation: "rpc" });
|
|
2087
2474
|
};
|
|
2088
|
-
const
|
|
2089
|
-
const
|
|
2090
|
-
const
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
},
|
|
2096
|
-
maybeSingle(cols, opts) {
|
|
2097
|
-
return chain.single(cols, opts);
|
|
2098
|
-
},
|
|
2099
|
-
then(onfulfilled, onrejected) {
|
|
2100
|
-
return runSelect(columns, options).then(onfulfilled, onrejected);
|
|
2101
|
-
},
|
|
2102
|
-
catch(onrejected) {
|
|
2103
|
-
return runSelect(columns, options).catch(onrejected);
|
|
2104
|
-
},
|
|
2105
|
-
finally(onfinally) {
|
|
2106
|
-
return runSelect(columns, options).finally(onfinally);
|
|
2107
|
-
}
|
|
2108
|
-
});
|
|
2109
|
-
return chain;
|
|
2475
|
+
const run = (columns, options) => {
|
|
2476
|
+
const payloadColumns = columns ?? selectedColumns;
|
|
2477
|
+
const payloadOptions = options ?? selectedOptions;
|
|
2478
|
+
if (!promise) {
|
|
2479
|
+
promise = executeRpc(payloadColumns, payloadOptions);
|
|
2480
|
+
}
|
|
2481
|
+
return promise;
|
|
2110
2482
|
};
|
|
2483
|
+
const builder = {};
|
|
2484
|
+
const filterMethods = createRpcFilterMethods(state.filters, builder);
|
|
2111
2485
|
Object.assign(builder, filterMethods, {
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
state.order = void 0;
|
|
2117
|
-
state.currentPage = void 0;
|
|
2118
|
-
state.pageSize = void 0;
|
|
2119
|
-
state.totalPages = void 0;
|
|
2120
|
-
return builder;
|
|
2486
|
+
select(columns = selectedColumns, options) {
|
|
2487
|
+
selectedColumns = columns;
|
|
2488
|
+
selectedOptions = options ?? selectedOptions;
|
|
2489
|
+
return run(columns, options);
|
|
2121
2490
|
},
|
|
2122
|
-
|
|
2123
|
-
|
|
2491
|
+
async single(columns, options) {
|
|
2492
|
+
const result = await run(columns, options);
|
|
2493
|
+
return toSingleResult(result);
|
|
2494
|
+
},
|
|
2495
|
+
maybeSingle(columns, options) {
|
|
2496
|
+
return builder.single(columns, options);
|
|
2497
|
+
},
|
|
2498
|
+
order(column, options) {
|
|
2499
|
+
state.order = { column, ascending: options?.ascending ?? true };
|
|
2500
|
+
return builder;
|
|
2501
|
+
},
|
|
2502
|
+
limit(count) {
|
|
2503
|
+
state.limit = count;
|
|
2504
|
+
return builder;
|
|
2505
|
+
},
|
|
2506
|
+
offset(count) {
|
|
2507
|
+
state.offset = count;
|
|
2508
|
+
return builder;
|
|
2509
|
+
},
|
|
2510
|
+
range(from, to) {
|
|
2511
|
+
state.offset = from;
|
|
2512
|
+
state.limit = to - from + 1;
|
|
2513
|
+
return builder;
|
|
2514
|
+
},
|
|
2515
|
+
then(onfulfilled, onrejected) {
|
|
2516
|
+
return run(selectedColumns, selectedOptions).then(onfulfilled, onrejected);
|
|
2517
|
+
},
|
|
2518
|
+
catch(onrejected) {
|
|
2519
|
+
return run(selectedColumns, selectedOptions).catch(onrejected);
|
|
2520
|
+
},
|
|
2521
|
+
finally(onfinally) {
|
|
2522
|
+
return run(selectedColumns, selectedOptions).finally(onfinally);
|
|
2523
|
+
}
|
|
2524
|
+
});
|
|
2525
|
+
return builder;
|
|
2526
|
+
}
|
|
2527
|
+
function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
2528
|
+
const state = {
|
|
2529
|
+
conditions: []
|
|
2530
|
+
};
|
|
2531
|
+
const addCondition = (operator, column, value, hints) => {
|
|
2532
|
+
const condition = { operator };
|
|
2533
|
+
if (column) {
|
|
2534
|
+
condition.column = column;
|
|
2535
|
+
if (operator === "eq") {
|
|
2536
|
+
condition.eq_column = column;
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
if (value !== void 0) {
|
|
2540
|
+
condition.value = value;
|
|
2541
|
+
if (operator === "eq") {
|
|
2542
|
+
condition.eq_value = value;
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
if (hints?.valueCast) {
|
|
2546
|
+
condition.value_cast = hints.valueCast;
|
|
2547
|
+
if (operator === "eq") {
|
|
2548
|
+
condition.eq_value_cast = hints.valueCast;
|
|
2549
|
+
}
|
|
2550
|
+
}
|
|
2551
|
+
if (hints?.columnCast) {
|
|
2552
|
+
condition.column_cast = hints.columnCast;
|
|
2553
|
+
if (operator === "eq") {
|
|
2554
|
+
condition.eq_column_cast = hints.columnCast;
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
state.conditions.push(condition);
|
|
2558
|
+
};
|
|
2559
|
+
const builder = {};
|
|
2560
|
+
const filterMethods = createFilterMethods(
|
|
2561
|
+
state,
|
|
2562
|
+
addCondition,
|
|
2563
|
+
builder
|
|
2564
|
+
);
|
|
2565
|
+
const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
|
|
2566
|
+
const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
|
|
2567
|
+
const conditions = state.conditions.length ? state.conditions.map((condition) => ({ ...condition })) : void 0;
|
|
2568
|
+
const hasTypedEqualityComparison = conditions?.some(
|
|
2569
|
+
(condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
|
|
2570
|
+
) ?? false;
|
|
2571
|
+
if (hasTypedEqualityComparison && !options?.head && !options?.count && conditions) {
|
|
2572
|
+
const query = buildTypedSelectQuery({
|
|
2573
|
+
tableName: resolvedTableName,
|
|
2574
|
+
columns,
|
|
2575
|
+
conditions,
|
|
2576
|
+
limit: state.limit,
|
|
2577
|
+
offset: state.offset,
|
|
2578
|
+
currentPage: state.currentPage,
|
|
2579
|
+
pageSize: state.pageSize,
|
|
2580
|
+
order: state.order
|
|
2581
|
+
});
|
|
2582
|
+
if (query) {
|
|
2583
|
+
const queryResponse = await client.queryGateway({ query }, options);
|
|
2584
|
+
return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
const payload = {
|
|
2588
|
+
table_name: resolvedTableName,
|
|
2589
|
+
columns,
|
|
2590
|
+
conditions,
|
|
2591
|
+
limit: state.limit,
|
|
2592
|
+
offset: state.offset,
|
|
2593
|
+
current_page: state.currentPage,
|
|
2594
|
+
page_size: state.pageSize,
|
|
2595
|
+
total_pages: state.totalPages,
|
|
2596
|
+
sort_by: state.order,
|
|
2597
|
+
strip_nulls: options?.stripNulls ?? true,
|
|
2598
|
+
count: options?.count,
|
|
2599
|
+
head: options?.head
|
|
2600
|
+
};
|
|
2601
|
+
const response = await client.fetchGateway(payload, options);
|
|
2602
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
|
|
2603
|
+
};
|
|
2604
|
+
const createSelectChain = (columns, options) => {
|
|
2605
|
+
const chain = {};
|
|
2606
|
+
const filterMethods2 = createFilterMethods(state, addCondition, chain);
|
|
2607
|
+
Object.assign(chain, filterMethods2, {
|
|
2608
|
+
async single(cols, opts) {
|
|
2609
|
+
const r = await runSelect(cols ?? columns, opts ?? options);
|
|
2610
|
+
return toSingleResult(r);
|
|
2611
|
+
},
|
|
2612
|
+
maybeSingle(cols, opts) {
|
|
2613
|
+
return chain.single(cols, opts);
|
|
2614
|
+
},
|
|
2615
|
+
then(onfulfilled, onrejected) {
|
|
2616
|
+
return runSelect(columns, options).then(onfulfilled, onrejected);
|
|
2617
|
+
},
|
|
2618
|
+
catch(onrejected) {
|
|
2619
|
+
return runSelect(columns, options).catch(onrejected);
|
|
2620
|
+
},
|
|
2621
|
+
finally(onfinally) {
|
|
2622
|
+
return runSelect(columns, options).finally(onfinally);
|
|
2623
|
+
}
|
|
2624
|
+
});
|
|
2625
|
+
return chain;
|
|
2626
|
+
};
|
|
2627
|
+
Object.assign(builder, filterMethods, {
|
|
2628
|
+
reset() {
|
|
2629
|
+
state.conditions = [];
|
|
2630
|
+
state.limit = void 0;
|
|
2631
|
+
state.offset = void 0;
|
|
2632
|
+
state.order = void 0;
|
|
2633
|
+
state.currentPage = void 0;
|
|
2634
|
+
state.pageSize = void 0;
|
|
2635
|
+
state.totalPages = void 0;
|
|
2636
|
+
return builder;
|
|
2637
|
+
},
|
|
2638
|
+
select(columns = DEFAULT_COLUMNS, options) {
|
|
2639
|
+
return createSelectChain(columns, options);
|
|
2124
2640
|
},
|
|
2125
2641
|
insert(values, options) {
|
|
2126
2642
|
if (Array.isArray(values)) {
|
|
@@ -2138,7 +2654,7 @@ function createTableBuilder(tableName, client) {
|
|
|
2138
2654
|
payload.default_to_null = mergedOptions.defaultToNull;
|
|
2139
2655
|
}
|
|
2140
2656
|
const response = await client.insertGateway(payload, mergedOptions);
|
|
2141
|
-
return
|
|
2657
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
2142
2658
|
};
|
|
2143
2659
|
return createMutationQuery(executeInsertMany);
|
|
2144
2660
|
}
|
|
@@ -2156,7 +2672,7 @@ function createTableBuilder(tableName, client) {
|
|
|
2156
2672
|
payload.default_to_null = mergedOptions.defaultToNull;
|
|
2157
2673
|
}
|
|
2158
2674
|
const response = await client.insertGateway(payload, mergedOptions);
|
|
2159
|
-
return
|
|
2675
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
2160
2676
|
};
|
|
2161
2677
|
return createMutationQuery(executeInsertOne);
|
|
2162
2678
|
},
|
|
@@ -2178,7 +2694,7 @@ function createTableBuilder(tableName, client) {
|
|
|
2178
2694
|
payload.default_to_null = mergedOptions.defaultToNull;
|
|
2179
2695
|
}
|
|
2180
2696
|
const response = await client.insertGateway(payload, mergedOptions);
|
|
2181
|
-
return
|
|
2697
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
2182
2698
|
};
|
|
2183
2699
|
return createMutationQuery(executeUpsertMany);
|
|
2184
2700
|
}
|
|
@@ -2198,7 +2714,7 @@ function createTableBuilder(tableName, client) {
|
|
|
2198
2714
|
payload.default_to_null = mergedOptions.defaultToNull;
|
|
2199
2715
|
}
|
|
2200
2716
|
const response = await client.insertGateway(payload, mergedOptions);
|
|
2201
|
-
return
|
|
2717
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
2202
2718
|
};
|
|
2203
2719
|
return createMutationQuery(executeUpsertOne);
|
|
2204
2720
|
},
|
|
@@ -2219,7 +2735,7 @@ function createTableBuilder(tableName, client) {
|
|
|
2219
2735
|
if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
|
|
2220
2736
|
if (columns) payload.columns = columns;
|
|
2221
2737
|
const response = await client.updateGateway(payload, mergedOptions);
|
|
2222
|
-
return
|
|
2738
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "update" });
|
|
2223
2739
|
};
|
|
2224
2740
|
const mutation = createMutationQuery(executeUpdate, null);
|
|
2225
2741
|
const updateChain = {};
|
|
@@ -2247,7 +2763,7 @@ function createTableBuilder(tableName, client) {
|
|
|
2247
2763
|
if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
|
|
2248
2764
|
if (columns) payload.columns = columns;
|
|
2249
2765
|
const response = await client.deleteGateway(payload, mergedOptions);
|
|
2250
|
-
return
|
|
2766
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "delete" });
|
|
2251
2767
|
};
|
|
2252
2768
|
return createMutationQuery(executeDelete, null);
|
|
2253
2769
|
},
|
|
@@ -2261,14 +2777,14 @@ function createTableBuilder(tableName, client) {
|
|
|
2261
2777
|
});
|
|
2262
2778
|
return builder;
|
|
2263
2779
|
}
|
|
2264
|
-
function createQueryBuilder(client) {
|
|
2780
|
+
function createQueryBuilder(client, formatGatewayResult) {
|
|
2265
2781
|
return async function query(query, options) {
|
|
2266
2782
|
const normalizedQuery = query.trim();
|
|
2267
2783
|
if (!normalizedQuery) {
|
|
2268
2784
|
throw new Error("query requires a non-empty string");
|
|
2269
2785
|
}
|
|
2270
2786
|
const response = await client.queryGateway({ query: normalizedQuery }, options);
|
|
2271
|
-
return
|
|
2787
|
+
return formatGatewayResult(response, { operation: "query" });
|
|
2272
2788
|
};
|
|
2273
2789
|
}
|
|
2274
2790
|
function createClientFromConfig(config) {
|
|
@@ -2279,24 +2795,29 @@ function createClientFromConfig(config) {
|
|
|
2279
2795
|
backend: config.backend,
|
|
2280
2796
|
headers: config.headers
|
|
2281
2797
|
});
|
|
2798
|
+
const formatGatewayResult = createResultFormatter(config.experimental);
|
|
2282
2799
|
const auth = createAuthClient(config.auth);
|
|
2800
|
+
const from = (table) => createTableBuilder(table, gateway, formatGatewayResult);
|
|
2801
|
+
const rpc = (fn, args, options) => {
|
|
2802
|
+
const normalizedFn = fn.trim();
|
|
2803
|
+
if (!normalizedFn) {
|
|
2804
|
+
throw new Error("rpc requires a function name");
|
|
2805
|
+
}
|
|
2806
|
+
return createRpcBuilder(
|
|
2807
|
+
normalizedFn,
|
|
2808
|
+
args,
|
|
2809
|
+
options,
|
|
2810
|
+
gateway,
|
|
2811
|
+
formatGatewayResult
|
|
2812
|
+
);
|
|
2813
|
+
};
|
|
2814
|
+
const query = createQueryBuilder(gateway, formatGatewayResult);
|
|
2815
|
+
const db = createDbModule({ from, rpc, query });
|
|
2283
2816
|
return {
|
|
2284
|
-
from
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
const normalizedFn = fn.trim();
|
|
2289
|
-
if (!normalizedFn) {
|
|
2290
|
-
throw new Error("rpc requires a function name");
|
|
2291
|
-
}
|
|
2292
|
-
return createRpcBuilder(
|
|
2293
|
-
normalizedFn,
|
|
2294
|
-
args,
|
|
2295
|
-
options,
|
|
2296
|
-
gateway
|
|
2297
|
-
);
|
|
2298
|
-
},
|
|
2299
|
-
query: createQueryBuilder(gateway),
|
|
2817
|
+
from,
|
|
2818
|
+
db,
|
|
2819
|
+
rpc,
|
|
2820
|
+
query,
|
|
2300
2821
|
auth: auth.auth
|
|
2301
2822
|
};
|
|
2302
2823
|
}
|
|
@@ -2307,516 +2828,86 @@ function toBackendConfig(b) {
|
|
|
2307
2828
|
}
|
|
2308
2829
|
var AthenaClientBuilderImpl = class {
|
|
2309
2830
|
baseUrl;
|
|
2310
|
-
apiKey;
|
|
2311
|
-
backendConfig = DEFAULT_BACKEND;
|
|
2312
|
-
clientName;
|
|
2313
|
-
defaultHeaders;
|
|
2314
|
-
isHealthTrackingEnabled = false;
|
|
2315
|
-
url(url) {
|
|
2316
|
-
this.baseUrl = url;
|
|
2317
|
-
return this;
|
|
2318
|
-
}
|
|
2319
|
-
key(apiKey) {
|
|
2320
|
-
this.apiKey = apiKey;
|
|
2321
|
-
return this;
|
|
2322
|
-
}
|
|
2323
|
-
backend(backend) {
|
|
2324
|
-
this.backendConfig = toBackendConfig(backend);
|
|
2325
|
-
return this;
|
|
2326
|
-
}
|
|
2327
|
-
client(clientName) {
|
|
2328
|
-
this.clientName = clientName;
|
|
2329
|
-
return this;
|
|
2330
|
-
}
|
|
2331
|
-
headers(headers) {
|
|
2332
|
-
this.defaultHeaders = headers;
|
|
2333
|
-
return this;
|
|
2334
|
-
}
|
|
2335
|
-
healthTracking(enabled) {
|
|
2336
|
-
this.isHealthTrackingEnabled = enabled;
|
|
2337
|
-
return this;
|
|
2338
|
-
}
|
|
2339
|
-
build() {
|
|
2340
|
-
if (!this.baseUrl || !this.apiKey) {
|
|
2341
|
-
throw new Error("AthenaClient requires url and key; call .url() and .key() before .build()");
|
|
2342
|
-
}
|
|
2343
|
-
return createClientFromConfig({
|
|
2344
|
-
baseUrl: this.baseUrl,
|
|
2345
|
-
apiKey: this.apiKey,
|
|
2346
|
-
client: this.clientName,
|
|
2347
|
-
backend: this.backendConfig,
|
|
2348
|
-
headers: this.defaultHeaders,
|
|
2349
|
-
healthTracking: this.isHealthTrackingEnabled
|
|
2350
|
-
});
|
|
2351
|
-
}
|
|
2352
|
-
};
|
|
2353
|
-
var AthenaClient = class _AthenaClient {
|
|
2354
|
-
/** Create a fluent builder for a strongly-typed Athena SDK client. */
|
|
2355
|
-
static builder() {
|
|
2356
|
-
return new AthenaClientBuilderImpl();
|
|
2357
|
-
}
|
|
2358
|
-
/** Build a client from process environment variables. */
|
|
2359
|
-
static fromEnvironment() {
|
|
2360
|
-
const url = process.env.ATHENA_URL ?? process.env.ATHENA_GATEWAY_URL;
|
|
2361
|
-
const key = process.env.ATHENA_API_KEY ?? process.env.ATHENA_GATEWAY_API_KEY;
|
|
2362
|
-
if (!url || !key) {
|
|
2363
|
-
throw new Error(
|
|
2364
|
-
"ATHENA_URL and ATHENA_API_KEY (or ATHENA_GATEWAY_URL and ATHENA_GATEWAY_API_KEY) are required"
|
|
2365
|
-
);
|
|
2366
|
-
}
|
|
2367
|
-
return _AthenaClient.builder().url(url).key(key).build();
|
|
2368
|
-
}
|
|
2369
|
-
};
|
|
2370
|
-
function createClient(url, apiKey, options) {
|
|
2371
|
-
const b = AthenaClient.builder().url(url).key(apiKey).backend(toBackendConfig(options?.backend));
|
|
2372
|
-
if (options?.client) b.client(options.client);
|
|
2373
|
-
if (options?.headers && Object.keys(options.headers).length > 0) b.headers(options.headers);
|
|
2374
|
-
const client = b.build();
|
|
2375
|
-
if (options?.auth) {
|
|
2376
|
-
client.auth = createAuthClient(options.auth).auth;
|
|
2377
|
-
}
|
|
2378
|
-
return client;
|
|
2379
|
-
}
|
|
2380
|
-
|
|
2381
|
-
// src/gateway/types.ts
|
|
2382
|
-
var Backend = {
|
|
2383
|
-
Athena: { type: "athena" },
|
|
2384
|
-
Postgrest: { type: "postgrest" },
|
|
2385
|
-
PostgreSQL: { type: "postgresql" },
|
|
2386
|
-
ScyllaDB: { type: "scylladb" }
|
|
2387
|
-
};
|
|
2388
|
-
|
|
2389
|
-
// src/auxiliaries.ts
|
|
2390
|
-
var AthenaErrorKind = {
|
|
2391
|
-
UniqueViolation: "unique_violation",
|
|
2392
|
-
NotFound: "not_found",
|
|
2393
|
-
Validation: "validation",
|
|
2394
|
-
Auth: "auth",
|
|
2395
|
-
RateLimit: "rate_limit",
|
|
2396
|
-
Transient: "transient",
|
|
2397
|
-
Unknown: "unknown"
|
|
2398
|
-
};
|
|
2399
|
-
var AthenaErrorCode = {
|
|
2400
|
-
UniqueViolation: "UNIQUE_VIOLATION",
|
|
2401
|
-
NotFound: "NOT_FOUND",
|
|
2402
|
-
ValidationFailed: "VALIDATION_FAILED",
|
|
2403
|
-
AuthUnauthorized: "AUTH_UNAUTHORIZED",
|
|
2404
|
-
AuthForbidden: "AUTH_FORBIDDEN",
|
|
2405
|
-
RateLimited: "RATE_LIMITED",
|
|
2406
|
-
NetworkUnavailable: "NETWORK_UNAVAILABLE",
|
|
2407
|
-
TransientFailure: "TRANSIENT_FAILURE",
|
|
2408
|
-
HttpFailure: "HTTP_FAILURE",
|
|
2409
|
-
Unknown: "UNKNOWN"
|
|
2410
|
-
};
|
|
2411
|
-
var AthenaErrorCategory = {
|
|
2412
|
-
Transport: "transport",
|
|
2413
|
-
Client: "client",
|
|
2414
|
-
Server: "server",
|
|
2415
|
-
Database: "database",
|
|
2416
|
-
Unknown: "unknown"
|
|
2417
|
-
};
|
|
2418
|
-
function parseBooleanFlag(rawValue, fallback) {
|
|
2419
|
-
if (!rawValue) return fallback;
|
|
2420
|
-
const normalized = rawValue.trim().toLowerCase();
|
|
2421
|
-
if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
|
|
2422
|
-
return true;
|
|
2423
|
-
}
|
|
2424
|
-
if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
|
|
2425
|
-
return false;
|
|
2426
|
-
}
|
|
2427
|
-
return fallback;
|
|
2428
|
-
}
|
|
2429
|
-
var AthenaError = class extends Error {
|
|
2430
|
-
code;
|
|
2431
|
-
kind;
|
|
2432
|
-
category;
|
|
2433
|
-
status;
|
|
2434
|
-
retryable;
|
|
2435
|
-
requestId;
|
|
2436
|
-
context;
|
|
2437
|
-
raw;
|
|
2438
|
-
constructor(input) {
|
|
2439
|
-
super(input.message);
|
|
2440
|
-
this.name = "AthenaError";
|
|
2441
|
-
this.code = input.code;
|
|
2442
|
-
this.kind = input.kind;
|
|
2443
|
-
this.category = input.category;
|
|
2444
|
-
this.status = input.status;
|
|
2445
|
-
this.retryable = input.retryable ?? false;
|
|
2446
|
-
this.requestId = input.requestId;
|
|
2447
|
-
this.context = input.context;
|
|
2448
|
-
this.raw = input.raw;
|
|
2449
|
-
}
|
|
2450
|
-
};
|
|
2451
|
-
function isRecord3(value) {
|
|
2452
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2453
|
-
}
|
|
2454
|
-
function safeStringify(value) {
|
|
2455
|
-
try {
|
|
2456
|
-
const serialized = JSON.stringify(value);
|
|
2457
|
-
return serialized ?? String(value);
|
|
2458
|
-
} catch {
|
|
2459
|
-
return "[unserializable]";
|
|
2460
|
-
}
|
|
2461
|
-
}
|
|
2462
|
-
function contextHint(context) {
|
|
2463
|
-
if (!context?.identity) return void 0;
|
|
2464
|
-
const identity = typeof context.identity === "string" ? context.identity : safeStringify(context.identity);
|
|
2465
|
-
return `Identity: ${identity}`;
|
|
2466
|
-
}
|
|
2467
|
-
function isAthenaResultLike(value) {
|
|
2468
|
-
return isRecord3(value) && "status" in value && "error" in value && "data" in value && typeof value.status === "number";
|
|
2469
|
-
}
|
|
2470
|
-
function operationFromDetails(details) {
|
|
2471
|
-
if (!details?.endpoint) return void 0;
|
|
2472
|
-
if (details.endpoint === "/gateway/fetch" || details.endpoint === "/gateway/query") return "select";
|
|
2473
|
-
if (details.endpoint === "/gateway/insert") return "insert";
|
|
2474
|
-
if (details.endpoint === "/gateway/update") return "update";
|
|
2475
|
-
if (details.endpoint === "/gateway/delete") return "delete";
|
|
2476
|
-
if (details.endpoint === "/gateway/rpc" || details.endpoint.startsWith("/rpc/")) return "rpc";
|
|
2477
|
-
return void 0;
|
|
2478
|
-
}
|
|
2479
|
-
function matchRegex(input, patterns) {
|
|
2480
|
-
for (const pattern of patterns) {
|
|
2481
|
-
const match = pattern.exec(input);
|
|
2482
|
-
if (match?.[1]) return match[1];
|
|
2483
|
-
}
|
|
2484
|
-
return void 0;
|
|
2485
|
-
}
|
|
2486
|
-
function extractConstraint(message) {
|
|
2487
|
-
return matchRegex(message, [
|
|
2488
|
-
/unique constraint\s+["'`]([^"'`]+)["'`]/i,
|
|
2489
|
-
/constraint\s+["'`]([^"'`]+)["'`]/i
|
|
2490
|
-
]);
|
|
2491
|
-
}
|
|
2492
|
-
function extractTable(message) {
|
|
2493
|
-
return matchRegex(message, [
|
|
2494
|
-
/(?:table|relation)\s+["'`]([^"'`]+)["'`]/i,
|
|
2495
|
-
/on\s+table\s+([a-zA-Z0-9_.]+)/i
|
|
2496
|
-
]);
|
|
2497
|
-
}
|
|
2498
|
-
function classifyKind(status, code, message) {
|
|
2499
|
-
const lower = message.toLowerCase();
|
|
2500
|
-
const hasUniquePattern = lower.includes("unique constraint") || lower.includes("duplicate key") || lower.includes("already exists") || lower.includes("duplicate");
|
|
2501
|
-
const hasNotFoundPattern = lower.includes("not found") || lower.includes("no rows");
|
|
2502
|
-
const hasValidationPattern = lower.includes("validation") || lower.includes("invalid") || lower.includes("malformed");
|
|
2503
|
-
const hasAuthPattern = lower.includes("unauthorized") || lower.includes("forbidden") || lower.includes("auth");
|
|
2504
|
-
const hasRateLimitPattern = lower.includes("rate limit") || lower.includes("too many requests");
|
|
2505
|
-
const hasTransientPattern = lower.includes("timeout") || lower.includes("temporar") || lower.includes("connection reset") || lower.includes("socket") || lower.includes("deadlock");
|
|
2506
|
-
if (status === 409 || hasUniquePattern) return "unique_violation";
|
|
2507
|
-
if (status === 404 || hasNotFoundPattern) return "not_found";
|
|
2508
|
-
if (status === 401 || status === 403 || hasAuthPattern) return "auth";
|
|
2509
|
-
if (status === 429 || hasRateLimitPattern) return "rate_limit";
|
|
2510
|
-
if (status === 400 || status === 422 || hasValidationPattern) return "validation";
|
|
2511
|
-
if (code === "NETWORK_ERROR" || status === 0 || status !== void 0 && status >= 500 || hasTransientPattern) {
|
|
2512
|
-
return "transient";
|
|
2513
|
-
}
|
|
2514
|
-
return "unknown";
|
|
2515
|
-
}
|
|
2516
|
-
function toAthenaErrorCode(kind, status, gatewayCode) {
|
|
2517
|
-
if (gatewayCode === "NETWORK_ERROR" || kind === "transient" && status === 0) {
|
|
2518
|
-
return AthenaErrorCode.NetworkUnavailable;
|
|
2519
|
-
}
|
|
2520
|
-
switch (kind) {
|
|
2521
|
-
case "unique_violation":
|
|
2522
|
-
return AthenaErrorCode.UniqueViolation;
|
|
2523
|
-
case "not_found":
|
|
2524
|
-
return AthenaErrorCode.NotFound;
|
|
2525
|
-
case "validation":
|
|
2526
|
-
return AthenaErrorCode.ValidationFailed;
|
|
2527
|
-
case "rate_limit":
|
|
2528
|
-
return AthenaErrorCode.RateLimited;
|
|
2529
|
-
case "auth":
|
|
2530
|
-
if (status === 403) {
|
|
2531
|
-
return AthenaErrorCode.AuthForbidden;
|
|
2532
|
-
}
|
|
2533
|
-
return AthenaErrorCode.AuthUnauthorized;
|
|
2534
|
-
case "transient":
|
|
2535
|
-
return status !== void 0 && status >= 500 ? AthenaErrorCode.HttpFailure : AthenaErrorCode.TransientFailure;
|
|
2536
|
-
case "unknown":
|
|
2537
|
-
default:
|
|
2538
|
-
return status !== void 0 && status >= 400 ? AthenaErrorCode.HttpFailure : AthenaErrorCode.Unknown;
|
|
2539
|
-
}
|
|
2540
|
-
}
|
|
2541
|
-
function toAthenaErrorCategory(kind, status) {
|
|
2542
|
-
if (kind === "transient" && (status === 0 || status === void 0)) {
|
|
2543
|
-
return AthenaErrorCategory.Transport;
|
|
2544
|
-
}
|
|
2545
|
-
if (kind === "unique_violation") return AthenaErrorCategory.Database;
|
|
2546
|
-
if (kind === "validation" || kind === "auth" || kind === "not_found") return AthenaErrorCategory.Client;
|
|
2547
|
-
if (kind === "rate_limit" || kind === "transient") return AthenaErrorCategory.Server;
|
|
2548
|
-
return AthenaErrorCategory.Unknown;
|
|
2549
|
-
}
|
|
2550
|
-
function isRetryable(kind, status) {
|
|
2551
|
-
if (kind === "rate_limit" || kind === "transient") return true;
|
|
2552
|
-
return status !== void 0 && status >= 500;
|
|
2553
|
-
}
|
|
2554
|
-
function toGatewayCode(kind, status) {
|
|
2555
|
-
if (kind === "transient" && (status === 0 || status === void 0)) return "NETWORK_ERROR";
|
|
2556
|
-
if (kind === "validation") return "INVALID_JSON";
|
|
2557
|
-
if (status !== void 0 && status >= 400) return "HTTP_ERROR";
|
|
2558
|
-
return "UNKNOWN_ERROR";
|
|
2559
|
-
}
|
|
2560
|
-
function toAthenaGatewayError(source, fallbackMessage, context) {
|
|
2561
|
-
if (isAthenaGatewayError(source)) {
|
|
2562
|
-
return source;
|
|
2563
|
-
}
|
|
2564
|
-
if (isAthenaResultLike(source) && source.errorDetails) {
|
|
2565
|
-
return new AthenaGatewayError({
|
|
2566
|
-
code: source.errorDetails.code,
|
|
2567
|
-
message: source.error ?? source.errorDetails.message,
|
|
2568
|
-
status: source.status,
|
|
2569
|
-
endpoint: source.errorDetails.endpoint,
|
|
2570
|
-
method: source.errorDetails.method,
|
|
2571
|
-
requestId: source.errorDetails.requestId,
|
|
2572
|
-
hint: source.errorDetails.hint,
|
|
2573
|
-
cause: source.errorDetails.cause
|
|
2574
|
-
});
|
|
2575
|
-
}
|
|
2576
|
-
const normalized = normalizeAthenaError(source, context);
|
|
2577
|
-
const message = isAthenaResultLike(source) && source.error == null && source.errorDetails == null ? fallbackMessage : normalized.message || fallbackMessage;
|
|
2578
|
-
return new AthenaGatewayError({
|
|
2579
|
-
code: toGatewayCode(normalized.kind, normalized.status),
|
|
2580
|
-
message,
|
|
2581
|
-
status: normalized.status ?? 0,
|
|
2582
|
-
hint: normalized.constraint != null ? `Constraint: ${normalized.constraint}` : contextHint(context),
|
|
2583
|
-
cause: typeof normalized.raw === "string" ? normalized.raw : safeStringify(normalized.raw)
|
|
2584
|
-
});
|
|
2585
|
-
}
|
|
2586
|
-
function isOk(result) {
|
|
2587
|
-
return result.error == null && result.status >= 200 && result.status < 300;
|
|
2588
|
-
}
|
|
2589
|
-
function normalizeAthenaError(resultOrError, context) {
|
|
2590
|
-
if (isAthenaResultLike(resultOrError)) {
|
|
2591
|
-
const details = resultOrError.errorDetails;
|
|
2592
|
-
const message2 = resultOrError.error ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
|
|
2593
|
-
const operation = context?.operation ?? operationFromDetails(details);
|
|
2594
|
-
const table = context?.table ?? extractTable(message2);
|
|
2595
|
-
const constraint = extractConstraint(message2);
|
|
2596
|
-
const kind2 = classifyKind(resultOrError.status, details?.code, message2);
|
|
2597
|
-
const code = toAthenaErrorCode(kind2, resultOrError.status, details?.code);
|
|
2598
|
-
const category = toAthenaErrorCategory(kind2, resultOrError.status);
|
|
2599
|
-
return {
|
|
2600
|
-
kind: kind2,
|
|
2601
|
-
code,
|
|
2602
|
-
category,
|
|
2603
|
-
retryable: isRetryable(kind2, resultOrError.status),
|
|
2604
|
-
status: resultOrError.status,
|
|
2605
|
-
constraint,
|
|
2606
|
-
table,
|
|
2607
|
-
operation,
|
|
2608
|
-
message: message2,
|
|
2609
|
-
raw: resultOrError.raw
|
|
2610
|
-
};
|
|
2611
|
-
}
|
|
2612
|
-
if (isAthenaGatewayError(resultOrError)) {
|
|
2613
|
-
const details = resultOrError.toDetails();
|
|
2614
|
-
const operation = context?.operation ?? operationFromDetails(details);
|
|
2615
|
-
const table = context?.table ?? extractTable(resultOrError.message);
|
|
2616
|
-
const constraint = extractConstraint(resultOrError.message);
|
|
2617
|
-
const kind2 = classifyKind(resultOrError.status, resultOrError.code, resultOrError.message);
|
|
2618
|
-
const code = toAthenaErrorCode(kind2, resultOrError.status, resultOrError.code);
|
|
2619
|
-
const category = toAthenaErrorCategory(kind2, resultOrError.status);
|
|
2620
|
-
return {
|
|
2621
|
-
kind: kind2,
|
|
2622
|
-
code,
|
|
2623
|
-
category,
|
|
2624
|
-
retryable: isRetryable(kind2, resultOrError.status),
|
|
2625
|
-
status: resultOrError.status,
|
|
2626
|
-
constraint,
|
|
2627
|
-
table,
|
|
2628
|
-
operation,
|
|
2629
|
-
message: resultOrError.message,
|
|
2630
|
-
raw: resultOrError
|
|
2631
|
-
};
|
|
2632
|
-
}
|
|
2633
|
-
if (resultOrError instanceof Error) {
|
|
2634
|
-
const maybeStatus = isRecord3(resultOrError) && typeof resultOrError.status === "number" ? resultOrError.status : void 0;
|
|
2635
|
-
const kind2 = classifyKind(maybeStatus, void 0, resultOrError.message);
|
|
2636
|
-
return {
|
|
2637
|
-
kind: kind2,
|
|
2638
|
-
code: toAthenaErrorCode(kind2, maybeStatus),
|
|
2639
|
-
category: toAthenaErrorCategory(kind2, maybeStatus),
|
|
2640
|
-
retryable: isRetryable(kind2, maybeStatus),
|
|
2641
|
-
status: maybeStatus,
|
|
2642
|
-
constraint: extractConstraint(resultOrError.message),
|
|
2643
|
-
table: context?.table ?? extractTable(resultOrError.message),
|
|
2644
|
-
operation: context?.operation,
|
|
2645
|
-
message: resultOrError.message,
|
|
2646
|
-
raw: resultOrError
|
|
2647
|
-
};
|
|
2648
|
-
}
|
|
2649
|
-
const message = typeof resultOrError === "string" ? resultOrError : "Unknown Athena error";
|
|
2650
|
-
const kind = classifyKind(void 0, void 0, message);
|
|
2651
|
-
return {
|
|
2652
|
-
kind,
|
|
2653
|
-
code: toAthenaErrorCode(kind, void 0),
|
|
2654
|
-
category: toAthenaErrorCategory(kind, void 0),
|
|
2655
|
-
retryable: isRetryable(kind, void 0),
|
|
2656
|
-
status: void 0,
|
|
2657
|
-
constraint: extractConstraint(message),
|
|
2658
|
-
table: context?.table ?? extractTable(message),
|
|
2659
|
-
operation: context?.operation,
|
|
2660
|
-
message,
|
|
2661
|
-
raw: resultOrError
|
|
2662
|
-
};
|
|
2663
|
-
}
|
|
2664
|
-
function unwrapRows(result, options) {
|
|
2665
|
-
if (!isOk(result)) {
|
|
2666
|
-
throw toAthenaGatewayError(result, "Athena request failed", options?.context);
|
|
2667
|
-
}
|
|
2668
|
-
if (result.data == null) return [];
|
|
2669
|
-
return Array.isArray(result.data) ? result.data : [result.data];
|
|
2670
|
-
}
|
|
2671
|
-
function unwrap(result, options) {
|
|
2672
|
-
if (!isOk(result)) {
|
|
2673
|
-
throw toAthenaGatewayError(result, "Athena request failed", options?.context);
|
|
2674
|
-
}
|
|
2675
|
-
if (result.data == null && !options?.allowNull) {
|
|
2676
|
-
throw toAthenaGatewayError(result, "Expected data but received null", options?.context);
|
|
2677
|
-
}
|
|
2678
|
-
return result.data;
|
|
2679
|
-
}
|
|
2680
|
-
function unwrapOne(result, options) {
|
|
2681
|
-
const rows = unwrapRows(result, options);
|
|
2682
|
-
if (!rows.length) {
|
|
2683
|
-
if (options?.allowNull) return null;
|
|
2684
|
-
throw toAthenaGatewayError(result, "Expected one row but received none", options?.context);
|
|
2685
|
-
}
|
|
2686
|
-
if (options?.requireExactlyOne && rows.length !== 1) {
|
|
2687
|
-
throw toAthenaGatewayError(
|
|
2688
|
-
result,
|
|
2689
|
-
`Expected exactly one row but received ${rows.length}`,
|
|
2690
|
-
options.context
|
|
2691
|
-
);
|
|
2831
|
+
apiKey;
|
|
2832
|
+
backendConfig = DEFAULT_BACKEND;
|
|
2833
|
+
clientName;
|
|
2834
|
+
defaultHeaders;
|
|
2835
|
+
isHealthTrackingEnabled = false;
|
|
2836
|
+
url(url) {
|
|
2837
|
+
this.baseUrl = url;
|
|
2838
|
+
return this;
|
|
2692
2839
|
}
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
if (!isOk(result)) {
|
|
2697
|
-
throw toAthenaGatewayError(
|
|
2698
|
-
result,
|
|
2699
|
-
`Athena ${context?.operation ?? "request"} failed`,
|
|
2700
|
-
context
|
|
2701
|
-
);
|
|
2840
|
+
key(apiKey) {
|
|
2841
|
+
this.apiKey = apiKey;
|
|
2842
|
+
return this;
|
|
2702
2843
|
}
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
requireSuccess(result, context);
|
|
2707
|
-
const minimum = options?.min ?? 1;
|
|
2708
|
-
const count = result.count;
|
|
2709
|
-
if (count == null) {
|
|
2710
|
-
throw new AthenaGatewayError({
|
|
2711
|
-
code: "UNKNOWN_ERROR",
|
|
2712
|
-
status: result.status,
|
|
2713
|
-
message: "Expected affected row count but response.count is missing",
|
|
2714
|
-
hint: 'Set call option { count: "exact" } for mutation postcondition checks.',
|
|
2715
|
-
cause: safeStringify(result.raw)
|
|
2716
|
-
});
|
|
2844
|
+
backend(backend) {
|
|
2845
|
+
this.backendConfig = toBackendConfig(backend);
|
|
2846
|
+
return this;
|
|
2717
2847
|
}
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
status: result.status,
|
|
2722
|
-
message: `Expected at least ${minimum} affected rows but received ${count}`,
|
|
2723
|
-
hint: contextHint(context),
|
|
2724
|
-
cause: safeStringify(result.raw)
|
|
2725
|
-
});
|
|
2848
|
+
client(clientName) {
|
|
2849
|
+
this.clientName = clientName;
|
|
2850
|
+
return this;
|
|
2726
2851
|
}
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
if (options?.min !== void 0 && value < options.min) return null;
|
|
2731
|
-
if (options?.max !== void 0 && value > options.max) return null;
|
|
2732
|
-
return value;
|
|
2733
|
-
}
|
|
2734
|
-
function parseIntegerString(value) {
|
|
2735
|
-
const normalized = value.trim();
|
|
2736
|
-
if (!/^[-+]?\d+$/.test(normalized)) return null;
|
|
2737
|
-
const parsed = Number(normalized);
|
|
2738
|
-
if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) return null;
|
|
2739
|
-
return parsed;
|
|
2740
|
-
}
|
|
2741
|
-
function coerceInt(value, options) {
|
|
2742
|
-
if (value == null) return null;
|
|
2743
|
-
if (typeof value === "number") {
|
|
2744
|
-
if (!Number.isFinite(value) || !Number.isInteger(value)) return null;
|
|
2745
|
-
return applyBounds(value, options);
|
|
2852
|
+
headers(headers) {
|
|
2853
|
+
this.defaultHeaders = headers;
|
|
2854
|
+
return this;
|
|
2746
2855
|
}
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
return applyBounds(parsed, options);
|
|
2856
|
+
healthTracking(enabled) {
|
|
2857
|
+
this.isHealthTrackingEnabled = enabled;
|
|
2858
|
+
return this;
|
|
2751
2859
|
}
|
|
2752
|
-
|
|
2753
|
-
if (
|
|
2754
|
-
|
|
2755
|
-
return null;
|
|
2756
|
-
}
|
|
2860
|
+
build() {
|
|
2861
|
+
if (!this.baseUrl || !this.apiKey) {
|
|
2862
|
+
throw new Error("AthenaClient requires url and key; call .url() and .key() before .build()");
|
|
2757
2863
|
}
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2864
|
+
return createClientFromConfig({
|
|
2865
|
+
baseUrl: this.baseUrl,
|
|
2866
|
+
apiKey: this.apiKey,
|
|
2867
|
+
client: this.clientName,
|
|
2868
|
+
backend: this.backendConfig,
|
|
2869
|
+
headers: this.defaultHeaders,
|
|
2870
|
+
healthTracking: this.isHealthTrackingEnabled
|
|
2871
|
+
});
|
|
2761
2872
|
}
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
throw new TypeError(`${label} must be a finite integer`);
|
|
2873
|
+
};
|
|
2874
|
+
var AthenaClient = class _AthenaClient {
|
|
2875
|
+
/** Create a fluent builder for a strongly-typed Athena SDK client. */
|
|
2876
|
+
static builder() {
|
|
2877
|
+
return new AthenaClientBuilderImpl();
|
|
2768
2878
|
}
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
const rawDelay = typeof config.backoff === "function" ? config.backoff(attempt, error) : config.backoff === "linear" ? baseDelay * attempt : baseDelay * Math.pow(2, attempt - 1);
|
|
2778
|
-
const safeDelay = Number.isFinite(rawDelay) ? Math.max(0, rawDelay) : 0;
|
|
2779
|
-
const clamped = Math.min(config.maxDelayMs, safeDelay);
|
|
2780
|
-
const jitterFactor = typeof config.jitter === "number" ? Math.max(0, Math.min(1, config.jitter)) : config.jitter ? 0.2 : 0;
|
|
2781
|
-
if (!jitterFactor) return clamped;
|
|
2782
|
-
const deviation = clamped * jitterFactor;
|
|
2783
|
-
const offset = (Math.random() * 2 - 1) * deviation;
|
|
2784
|
-
return Math.max(0, clamped + offset);
|
|
2785
|
-
}
|
|
2786
|
-
function sleep(ms) {
|
|
2787
|
-
if (ms <= 0) return Promise.resolve();
|
|
2788
|
-
return new Promise((resolve3) => {
|
|
2789
|
-
setTimeout(resolve3, ms);
|
|
2790
|
-
});
|
|
2791
|
-
}
|
|
2792
|
-
async function withRetry(config, fn) {
|
|
2793
|
-
const retries = Math.max(0, Math.trunc(config.retries));
|
|
2794
|
-
const shouldRetry = config.shouldRetry ?? defaultShouldRetry;
|
|
2795
|
-
const resolvedConfig = {
|
|
2796
|
-
baseDelayMs: config.baseDelayMs ?? 100,
|
|
2797
|
-
maxDelayMs: config.maxDelayMs ?? 1e4,
|
|
2798
|
-
backoff: config.backoff ?? "exponential",
|
|
2799
|
-
jitter: config.jitter ?? false
|
|
2800
|
-
};
|
|
2801
|
-
for (let attempts = 0; attempts <= retries; attempts += 1) {
|
|
2802
|
-
try {
|
|
2803
|
-
return await fn();
|
|
2804
|
-
} catch (error) {
|
|
2805
|
-
if (attempts >= retries) {
|
|
2806
|
-
throw error;
|
|
2807
|
-
}
|
|
2808
|
-
const currentAttempt = attempts + 1;
|
|
2809
|
-
const retry = await shouldRetry(error, currentAttempt);
|
|
2810
|
-
if (!retry) {
|
|
2811
|
-
throw error;
|
|
2812
|
-
}
|
|
2813
|
-
const delay = computeDelayMs(currentAttempt, error, resolvedConfig);
|
|
2814
|
-
await sleep(delay);
|
|
2879
|
+
/** Build a client from process environment variables. */
|
|
2880
|
+
static fromEnvironment() {
|
|
2881
|
+
const url = process.env.ATHENA_URL ?? process.env.ATHENA_GATEWAY_URL;
|
|
2882
|
+
const key = process.env.ATHENA_API_KEY ?? process.env.ATHENA_GATEWAY_API_KEY;
|
|
2883
|
+
if (!url || !key) {
|
|
2884
|
+
throw new Error(
|
|
2885
|
+
"ATHENA_URL and ATHENA_API_KEY (or ATHENA_GATEWAY_URL and ATHENA_GATEWAY_API_KEY) are required"
|
|
2886
|
+
);
|
|
2815
2887
|
}
|
|
2888
|
+
return _AthenaClient.builder().url(url).key(key).build();
|
|
2816
2889
|
}
|
|
2817
|
-
|
|
2890
|
+
};
|
|
2891
|
+
function createClient(url, apiKey, options) {
|
|
2892
|
+
return createClientFromConfig({
|
|
2893
|
+
baseUrl: url,
|
|
2894
|
+
apiKey,
|
|
2895
|
+
client: options?.client,
|
|
2896
|
+
backend: toBackendConfig(options?.backend),
|
|
2897
|
+
headers: options?.headers,
|
|
2898
|
+
auth: options?.auth,
|
|
2899
|
+
experimental: options?.experimental
|
|
2900
|
+
});
|
|
2818
2901
|
}
|
|
2819
2902
|
|
|
2903
|
+
// src/gateway/types.ts
|
|
2904
|
+
var Backend = {
|
|
2905
|
+
Athena: { type: "athena" },
|
|
2906
|
+
Postgrest: { type: "postgrest" },
|
|
2907
|
+
PostgreSQL: { type: "postgresql" },
|
|
2908
|
+
ScyllaDB: { type: "scylladb" }
|
|
2909
|
+
};
|
|
2910
|
+
|
|
2820
2911
|
// src/schema/definitions.ts
|
|
2821
2912
|
function defineModel(input) {
|
|
2822
2913
|
return input;
|
|
@@ -2882,6 +2973,7 @@ var TypedAthenaClientImpl = class _TypedAthenaClientImpl {
|
|
|
2882
2973
|
registry;
|
|
2883
2974
|
tenantKeyMap;
|
|
2884
2975
|
tenantContext;
|
|
2976
|
+
db;
|
|
2885
2977
|
baseClient;
|
|
2886
2978
|
registryNavigator;
|
|
2887
2979
|
tenantHeaderMapper;
|
|
@@ -2908,6 +3000,7 @@ var TypedAthenaClientImpl = class _TypedAthenaClientImpl {
|
|
|
2908
3000
|
client: this.clientOptions.client,
|
|
2909
3001
|
headers: this.tenantHeaderMapper.apply(this.clientOptions.headers, tenantContext)
|
|
2910
3002
|
});
|
|
3003
|
+
this.db = this.baseClient.db;
|
|
2911
3004
|
}
|
|
2912
3005
|
from(table) {
|
|
2913
3006
|
return this.baseClient.from(table);
|
|
@@ -3297,6 +3390,21 @@ var PostgresCatalogSnapshotAssembler = class {
|
|
|
3297
3390
|
};
|
|
3298
3391
|
|
|
3299
3392
|
// src/schema/postgres-provider.ts
|
|
3393
|
+
var pgPoolConstructorPromise;
|
|
3394
|
+
async function loadPgPoolConstructor() {
|
|
3395
|
+
if (!pgPoolConstructorPromise) {
|
|
3396
|
+
pgPoolConstructorPromise = import('pg').then((module) => {
|
|
3397
|
+
const poolConstructor = module.Pool ?? module.default?.Pool;
|
|
3398
|
+
if (!poolConstructor) {
|
|
3399
|
+
throw new Error(
|
|
3400
|
+
'@xylex-group/athena: Unable to load the PostgreSQL driver. Ensure "pg" is installed and this API runs in a Node.js server runtime.'
|
|
3401
|
+
);
|
|
3402
|
+
}
|
|
3403
|
+
return poolConstructor;
|
|
3404
|
+
});
|
|
3405
|
+
}
|
|
3406
|
+
return pgPoolConstructorPromise;
|
|
3407
|
+
}
|
|
3300
3408
|
var PgCatalogClient = class {
|
|
3301
3409
|
constructor(pool) {
|
|
3302
3410
|
this.pool = pool;
|
|
@@ -3336,7 +3444,8 @@ var PostgresIntrospectionProvider = class {
|
|
|
3336
3444
|
}
|
|
3337
3445
|
async inspect(options) {
|
|
3338
3446
|
const schemas = options?.schemas && options.schemas.length > 0 ? normalizePostgresCatalogSchemas(options.schemas) : this.schemas;
|
|
3339
|
-
const
|
|
3447
|
+
const PoolConstructor = await loadPgPoolConstructor();
|
|
3448
|
+
const pool = new PoolConstructor({
|
|
3340
3449
|
connectionString: this.connectionString
|
|
3341
3450
|
});
|
|
3342
3451
|
const catalogClient = new PgCatalogClient(pool);
|
|
@@ -3458,6 +3567,7 @@ function resolveProviderSchemas(providerConfig) {
|
|
|
3458
3567
|
}
|
|
3459
3568
|
|
|
3460
3569
|
// src/generator/config.ts
|
|
3570
|
+
var POSTGRES_PROTOCOLS = /* @__PURE__ */ new Set(["postgres:", "postgresql:"]);
|
|
3461
3571
|
var DEFAULT_CONFIG_CANDIDATES = [
|
|
3462
3572
|
"athena.config.ts",
|
|
3463
3573
|
"athena.config.js",
|
|
@@ -3487,6 +3597,151 @@ var DEFAULT_EXPERIMENTAL_FLAGS = {
|
|
|
3487
3597
|
postgresGatewayIntrospection: false,
|
|
3488
3598
|
scyllaProviderContracts: true
|
|
3489
3599
|
};
|
|
3600
|
+
var PROJECT_ENV_FILENAMES = [".env", ".env.local"];
|
|
3601
|
+
var DIRECT_CONNECTION_STRING_ENV_KEYS = [
|
|
3602
|
+
"ATHENA_GENERATOR_PG_URL",
|
|
3603
|
+
"DATABASE_URL",
|
|
3604
|
+
"PG_URL",
|
|
3605
|
+
"POSTGRES_URL",
|
|
3606
|
+
"POSTGRESQL_URL"
|
|
3607
|
+
];
|
|
3608
|
+
var POSTGRES_DATABASE_ENV_KEYS = ["ATHENA_GENERATOR_DB", "ATHENA_DATABASE", "PGDATABASE"];
|
|
3609
|
+
var POSTGRES_PASSWORD_ENV_KEYS = ["ATHENA_GENERATOR_PG_PASSWORD", "PGPASSWORD"];
|
|
3610
|
+
var GATEWAY_URL_ENV_KEYS = ["ATHENA_URL", "ATHENA_GATEWAY_URL", "ATHENA_GENERATOR_URL"];
|
|
3611
|
+
var GATEWAY_API_KEY_ENV_KEYS = [
|
|
3612
|
+
"ATHENA_API_KEY",
|
|
3613
|
+
"ATHENA_GATEWAY_API_KEY",
|
|
3614
|
+
"ATHENA_GENERATOR_API_KEY"
|
|
3615
|
+
];
|
|
3616
|
+
function normalizeRawEnvValue(rawValue) {
|
|
3617
|
+
if (rawValue.startsWith('"') && rawValue.endsWith('"') && rawValue.length >= 2) {
|
|
3618
|
+
const inner = rawValue.slice(1, -1);
|
|
3619
|
+
return inner.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
3620
|
+
}
|
|
3621
|
+
if (rawValue.startsWith("'") && rawValue.endsWith("'") && rawValue.length >= 2) {
|
|
3622
|
+
return rawValue.slice(1, -1);
|
|
3623
|
+
}
|
|
3624
|
+
const commentIndex = rawValue.search(/\s+#/);
|
|
3625
|
+
const withoutComment = commentIndex >= 0 ? rawValue.slice(0, commentIndex) : rawValue;
|
|
3626
|
+
return withoutComment.trim();
|
|
3627
|
+
}
|
|
3628
|
+
function parseEnvLine(line) {
|
|
3629
|
+
const trimmed = line.trim();
|
|
3630
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
3631
|
+
return void 0;
|
|
3632
|
+
}
|
|
3633
|
+
const match = trimmed.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);
|
|
3634
|
+
if (!match) {
|
|
3635
|
+
return void 0;
|
|
3636
|
+
}
|
|
3637
|
+
const [, key, rawValue] = match;
|
|
3638
|
+
return [key, normalizeRawEnvValue(rawValue.trim())];
|
|
3639
|
+
}
|
|
3640
|
+
function readProjectEnvEntries(cwd) {
|
|
3641
|
+
const nodeEnv = process.env.NODE_ENV?.trim();
|
|
3642
|
+
const filenames = [
|
|
3643
|
+
...PROJECT_ENV_FILENAMES,
|
|
3644
|
+
...nodeEnv ? [`.env.${nodeEnv}`, `.env.${nodeEnv}.local`] : []
|
|
3645
|
+
];
|
|
3646
|
+
const entries = /* @__PURE__ */ new Map();
|
|
3647
|
+
for (const filename of filenames) {
|
|
3648
|
+
const absolutePath = path.resolve(cwd, filename);
|
|
3649
|
+
if (!fs.existsSync(absolutePath)) {
|
|
3650
|
+
continue;
|
|
3651
|
+
}
|
|
3652
|
+
const content = fs.readFileSync(absolutePath, "utf8");
|
|
3653
|
+
const lines = content.split(/\r?\n/g);
|
|
3654
|
+
for (const line of lines) {
|
|
3655
|
+
const parsed = parseEnvLine(line);
|
|
3656
|
+
if (!parsed) {
|
|
3657
|
+
continue;
|
|
3658
|
+
}
|
|
3659
|
+
const [key, value] = parsed;
|
|
3660
|
+
entries.set(key, value);
|
|
3661
|
+
}
|
|
3662
|
+
}
|
|
3663
|
+
return entries;
|
|
3664
|
+
}
|
|
3665
|
+
function applyProjectEnv(cwd) {
|
|
3666
|
+
const envEntries = readProjectEnvEntries(cwd);
|
|
3667
|
+
if (envEntries.size === 0) {
|
|
3668
|
+
return () => {
|
|
3669
|
+
};
|
|
3670
|
+
}
|
|
3671
|
+
const initialKeys = new Set(
|
|
3672
|
+
Object.keys(process.env).filter((key) => process.env[key] !== void 0)
|
|
3673
|
+
);
|
|
3674
|
+
const staged = /* @__PURE__ */ new Map();
|
|
3675
|
+
for (const [key, value] of envEntries.entries()) {
|
|
3676
|
+
if (initialKeys.has(key)) {
|
|
3677
|
+
continue;
|
|
3678
|
+
}
|
|
3679
|
+
staged.set(key, value);
|
|
3680
|
+
}
|
|
3681
|
+
for (const [key, value] of staged.entries()) {
|
|
3682
|
+
process.env[key] = value;
|
|
3683
|
+
}
|
|
3684
|
+
return () => {
|
|
3685
|
+
for (const key of staged.keys()) {
|
|
3686
|
+
delete process.env[key];
|
|
3687
|
+
}
|
|
3688
|
+
};
|
|
3689
|
+
}
|
|
3690
|
+
function readEnvStringValue(key) {
|
|
3691
|
+
const value = process.env[key];
|
|
3692
|
+
if (typeof value !== "string") {
|
|
3693
|
+
return void 0;
|
|
3694
|
+
}
|
|
3695
|
+
const trimmed = value.trim();
|
|
3696
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
3697
|
+
}
|
|
3698
|
+
function resolveFallbackValue(fallbackKeys) {
|
|
3699
|
+
for (const key of fallbackKeys) {
|
|
3700
|
+
const value = readEnvStringValue(key);
|
|
3701
|
+
if (value) {
|
|
3702
|
+
return value;
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
return void 0;
|
|
3706
|
+
}
|
|
3707
|
+
function normalizeOptionalString(value, fallbackKeys) {
|
|
3708
|
+
if (typeof value === "string") {
|
|
3709
|
+
const trimmed = value.trim();
|
|
3710
|
+
if (trimmed.length > 0) {
|
|
3711
|
+
return trimmed;
|
|
3712
|
+
}
|
|
3713
|
+
}
|
|
3714
|
+
return resolveFallbackValue(fallbackKeys);
|
|
3715
|
+
}
|
|
3716
|
+
function normalizeRequiredString(value, fieldLabel, fallbackKeys) {
|
|
3717
|
+
const resolved = normalizeOptionalString(value, fallbackKeys);
|
|
3718
|
+
if (resolved) {
|
|
3719
|
+
return resolved;
|
|
3720
|
+
}
|
|
3721
|
+
throw new Error(
|
|
3722
|
+
`Generator config is missing ${fieldLabel}. Set ${fieldLabel} directly or provide one of: ${fallbackKeys.join(", ")}.`
|
|
3723
|
+
);
|
|
3724
|
+
}
|
|
3725
|
+
function applyPostgresPasswordFallback(connectionString) {
|
|
3726
|
+
let parsedUrl;
|
|
3727
|
+
try {
|
|
3728
|
+
parsedUrl = new URL(connectionString);
|
|
3729
|
+
} catch {
|
|
3730
|
+
return connectionString;
|
|
3731
|
+
}
|
|
3732
|
+
if (!POSTGRES_PROTOCOLS.has(parsedUrl.protocol)) {
|
|
3733
|
+
return connectionString;
|
|
3734
|
+
}
|
|
3735
|
+
if (!parsedUrl.username || parsedUrl.password) {
|
|
3736
|
+
return connectionString;
|
|
3737
|
+
}
|
|
3738
|
+
const fallbackPassword = resolveFallbackValue(POSTGRES_PASSWORD_ENV_KEYS);
|
|
3739
|
+
if (!fallbackPassword) {
|
|
3740
|
+
return connectionString;
|
|
3741
|
+
}
|
|
3742
|
+
parsedUrl.password = fallbackPassword;
|
|
3743
|
+
return parsedUrl.toString();
|
|
3744
|
+
}
|
|
3490
3745
|
function normalizeBooleanFlag(rawValue, fallback) {
|
|
3491
3746
|
if (typeof rawValue === "boolean") {
|
|
3492
3747
|
return rawValue;
|
|
@@ -3532,9 +3787,41 @@ function normalizeOutputConfig(output) {
|
|
|
3532
3787
|
};
|
|
3533
3788
|
}
|
|
3534
3789
|
function normalizeProviderConfig(provider) {
|
|
3535
|
-
if (provider.kind === "postgres") {
|
|
3790
|
+
if (provider.kind === "postgres" && provider.mode === "direct") {
|
|
3791
|
+
const connectionString = normalizeRequiredString(
|
|
3792
|
+
provider.connectionString,
|
|
3793
|
+
"provider.connectionString",
|
|
3794
|
+
DIRECT_CONNECTION_STRING_ENV_KEYS
|
|
3795
|
+
);
|
|
3796
|
+
const database = normalizeOptionalString(provider.database, POSTGRES_DATABASE_ENV_KEYS);
|
|
3536
3797
|
return {
|
|
3537
3798
|
...provider,
|
|
3799
|
+
connectionString: applyPostgresPasswordFallback(connectionString),
|
|
3800
|
+
database,
|
|
3801
|
+
schemas: normalizeSchemaSelection(provider.schemas)
|
|
3802
|
+
};
|
|
3803
|
+
}
|
|
3804
|
+
if (provider.kind === "postgres" && provider.mode === "gateway") {
|
|
3805
|
+
const gatewayUrl = normalizeRequiredString(
|
|
3806
|
+
provider.gatewayUrl,
|
|
3807
|
+
"provider.gatewayUrl",
|
|
3808
|
+
GATEWAY_URL_ENV_KEYS
|
|
3809
|
+
);
|
|
3810
|
+
const apiKey = normalizeRequiredString(
|
|
3811
|
+
provider.apiKey,
|
|
3812
|
+
"provider.apiKey",
|
|
3813
|
+
GATEWAY_API_KEY_ENV_KEYS
|
|
3814
|
+
);
|
|
3815
|
+
const database = normalizeRequiredString(
|
|
3816
|
+
provider.database,
|
|
3817
|
+
"provider.database",
|
|
3818
|
+
POSTGRES_DATABASE_ENV_KEYS
|
|
3819
|
+
);
|
|
3820
|
+
return {
|
|
3821
|
+
...provider,
|
|
3822
|
+
gatewayUrl,
|
|
3823
|
+
apiKey,
|
|
3824
|
+
database,
|
|
3538
3825
|
schemas: normalizeSchemaSelection(provider.schemas)
|
|
3539
3826
|
};
|
|
3540
3827
|
}
|
|
@@ -3596,6 +3883,11 @@ function extractConfigExport(module) {
|
|
|
3596
3883
|
if (moduleExports && typeof moduleExports === "object") {
|
|
3597
3884
|
queue.push(moduleExports);
|
|
3598
3885
|
}
|
|
3886
|
+
for (const value of Object.values(record)) {
|
|
3887
|
+
if (value && typeof value === "object") {
|
|
3888
|
+
queue.push(value);
|
|
3889
|
+
}
|
|
3890
|
+
}
|
|
3599
3891
|
}
|
|
3600
3892
|
throw new Error(
|
|
3601
3893
|
"Generator config file must export a config object as default export or `config`."
|
|
@@ -3610,19 +3902,24 @@ function importConfigModule(moduleSpecifier) {
|
|
|
3610
3902
|
}
|
|
3611
3903
|
async function loadGeneratorConfig(options = {}) {
|
|
3612
3904
|
const cwd = options.cwd ?? process.cwd();
|
|
3905
|
+
const restoreProjectEnv = applyProjectEnv(cwd);
|
|
3613
3906
|
const resolvedPath = options.configPath ? path.resolve(cwd, options.configPath) : findGeneratorConfigPath(cwd);
|
|
3614
3907
|
if (!resolvedPath) {
|
|
3615
3908
|
throw new Error(
|
|
3616
3909
|
`No generator config found in ${cwd}. Expected one of: ${DEFAULT_CONFIG_CANDIDATES.join(", ")}`
|
|
3617
3910
|
);
|
|
3618
3911
|
}
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3912
|
+
try {
|
|
3913
|
+
const moduleUrl = url.pathToFileURL(resolvedPath);
|
|
3914
|
+
const module = await importConfigModule(`${moduleUrl.href}?cacheBust=${Date.now()}`);
|
|
3915
|
+
const rawConfig = extractConfigExport(module);
|
|
3916
|
+
return {
|
|
3917
|
+
configPath: resolvedPath,
|
|
3918
|
+
config: normalizeGeneratorConfig(rawConfig)
|
|
3919
|
+
};
|
|
3920
|
+
} finally {
|
|
3921
|
+
restoreProjectEnv();
|
|
3922
|
+
}
|
|
3626
3923
|
}
|
|
3627
3924
|
|
|
3628
3925
|
// src/generator/naming.ts
|
|
@@ -3766,9 +4063,13 @@ function resolvePlaceholderMap(baseTokens, outputConfig) {
|
|
|
3766
4063
|
const resolved = {
|
|
3767
4064
|
...baseTokens
|
|
3768
4065
|
};
|
|
4066
|
+
const reservedTokenKeys = new Set(Object.keys(baseTokens));
|
|
3769
4067
|
const entries = Object.entries(outputConfig.placeholderMap ?? {});
|
|
3770
4068
|
for (let index = 0; index < entries.length; index += 1) {
|
|
3771
4069
|
const [key, value] = entries[index];
|
|
4070
|
+
if (reservedTokenKeys.has(key)) {
|
|
4071
|
+
continue;
|
|
4072
|
+
}
|
|
3772
4073
|
let current = value;
|
|
3773
4074
|
for (let depth = 0; depth < 8; depth += 1) {
|
|
3774
4075
|
const next = renderTemplate(current, resolved);
|
|
@@ -4048,13 +4349,65 @@ function assertNoDuplicatePaths(files) {
|
|
|
4048
4349
|
[
|
|
4049
4350
|
`Generator output collision detected for path: ${file.path}`,
|
|
4050
4351
|
`Collision: ${existing.kind} and ${file.kind}.`,
|
|
4051
|
-
"
|
|
4352
|
+
"Use explicit placeholders such as {model}, {model_kebab}, {schema}, or {schema_kebab} in output targets so each artifact resolves to a unique path."
|
|
4052
4353
|
].join(" ")
|
|
4053
4354
|
);
|
|
4054
4355
|
}
|
|
4055
4356
|
seen.set(file.path, file);
|
|
4056
4357
|
}
|
|
4057
4358
|
}
|
|
4359
|
+
function addSchemaSegmentToPath(pathValue, schemaName) {
|
|
4360
|
+
const normalizedPath = normalizePath(pathValue);
|
|
4361
|
+
const parsedPath = path.posix.parse(normalizedPath);
|
|
4362
|
+
const schemaSegment = applyNamingStyle(schemaName, "kebab");
|
|
4363
|
+
if (!schemaSegment) {
|
|
4364
|
+
return normalizedPath;
|
|
4365
|
+
}
|
|
4366
|
+
const dir = parsedPath.dir.length > 0 ? `${parsedPath.dir}/${schemaSegment}` : schemaSegment;
|
|
4367
|
+
return normalizePath(path.posix.join(dir, parsedPath.base));
|
|
4368
|
+
}
|
|
4369
|
+
function scopeDuplicateDescriptorPathsBySchema(descriptors) {
|
|
4370
|
+
const nextDescriptors = descriptors.map((descriptor) => ({ ...descriptor }));
|
|
4371
|
+
const duplicates = /* @__PURE__ */ new Map();
|
|
4372
|
+
for (let index = 0; index < nextDescriptors.length; index += 1) {
|
|
4373
|
+
const descriptor = nextDescriptors[index];
|
|
4374
|
+
const indexes = duplicates.get(descriptor.filePath) ?? [];
|
|
4375
|
+
indexes.push(index);
|
|
4376
|
+
duplicates.set(descriptor.filePath, indexes);
|
|
4377
|
+
}
|
|
4378
|
+
let appliedSchemaScoping = false;
|
|
4379
|
+
for (const indexes of duplicates.values()) {
|
|
4380
|
+
if (indexes.length <= 1) {
|
|
4381
|
+
continue;
|
|
4382
|
+
}
|
|
4383
|
+
const schemaNames = new Set(indexes.map((index) => nextDescriptors[index].schemaName));
|
|
4384
|
+
if (schemaNames.size <= 1) {
|
|
4385
|
+
continue;
|
|
4386
|
+
}
|
|
4387
|
+
for (const index of indexes) {
|
|
4388
|
+
const descriptor = nextDescriptors[index];
|
|
4389
|
+
descriptor.filePath = addSchemaSegmentToPath(descriptor.filePath, descriptor.schemaName);
|
|
4390
|
+
}
|
|
4391
|
+
appliedSchemaScoping = true;
|
|
4392
|
+
}
|
|
4393
|
+
if (!appliedSchemaScoping) {
|
|
4394
|
+
return nextDescriptors;
|
|
4395
|
+
}
|
|
4396
|
+
const normalizedPaths = /* @__PURE__ */ new Set();
|
|
4397
|
+
for (const descriptor of nextDescriptors) {
|
|
4398
|
+
if (normalizedPaths.has(descriptor.filePath)) {
|
|
4399
|
+
throw new Error(
|
|
4400
|
+
[
|
|
4401
|
+
`Generator output collision detected for path: ${descriptor.filePath}`,
|
|
4402
|
+
"Automatic schema path scoping was applied but collisions remain.",
|
|
4403
|
+
"Add explicit placeholders such as {model}, {model_kebab}, {schema}, or {schema_kebab} to your output targets."
|
|
4404
|
+
].join(" ")
|
|
4405
|
+
);
|
|
4406
|
+
}
|
|
4407
|
+
normalizedPaths.add(descriptor.filePath);
|
|
4408
|
+
}
|
|
4409
|
+
return nextDescriptors;
|
|
4410
|
+
}
|
|
4058
4411
|
var ArtifactComposer = class {
|
|
4059
4412
|
constructor(snapshot, config) {
|
|
4060
4413
|
this.snapshot = snapshot;
|
|
@@ -4093,7 +4446,8 @@ var ArtifactComposer = class {
|
|
|
4093
4446
|
});
|
|
4094
4447
|
}
|
|
4095
4448
|
}
|
|
4096
|
-
const
|
|
4449
|
+
const scopedModelDescriptors = scopeDuplicateDescriptorPathsBySchema(modelDescriptors);
|
|
4450
|
+
let schemaDescriptors = Object.keys(this.snapshot.schemas).sort().map((schemaName) => {
|
|
4097
4451
|
const schemaPath = normalizePath(
|
|
4098
4452
|
renderOutputPath(this.config.output.targets.schema, {
|
|
4099
4453
|
provider: providerName,
|
|
@@ -4111,9 +4465,10 @@ var ArtifactComposer = class {
|
|
|
4111
4465
|
this.config.naming.schemaConst,
|
|
4112
4466
|
"schema"
|
|
4113
4467
|
),
|
|
4114
|
-
models:
|
|
4468
|
+
models: scopedModelDescriptors.filter((model) => model.schemaName === schemaName)
|
|
4115
4469
|
};
|
|
4116
4470
|
});
|
|
4471
|
+
schemaDescriptors = scopeDuplicateDescriptorPathsBySchema(schemaDescriptors);
|
|
4117
4472
|
const databasePath = normalizePath(
|
|
4118
4473
|
renderOutputPath(this.config.output.targets.database, {
|
|
4119
4474
|
provider: providerName,
|
|
@@ -4133,7 +4488,7 @@ var ArtifactComposer = class {
|
|
|
4133
4488
|
schemas: schemaDescriptors
|
|
4134
4489
|
};
|
|
4135
4490
|
const files = [];
|
|
4136
|
-
for (const modelDescriptor of
|
|
4491
|
+
for (const modelDescriptor of scopedModelDescriptors) {
|
|
4137
4492
|
files.push(renderModelArtifact(this.snapshot, modelDescriptor, this.config));
|
|
4138
4493
|
}
|
|
4139
4494
|
for (const schemaDescriptor of schemaDescriptors) {
|