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