@xylex-group/athena 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +124 -106
- package/dist/browser.cjs +584 -99
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +7 -7
- package/dist/browser.d.ts +7 -7
- package/dist/browser.js +583 -100
- package/dist/browser.js.map +1 -1
- package/dist/cli/index.cjs +573 -97
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +3 -3
- package/dist/cli/index.d.ts +3 -3
- package/dist/cli/index.js +573 -97
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +584 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +583 -100
- package/dist/index.js.map +1 -1
- package/dist/{model-form-BpDXlbxb.d.ts → model-form-C0FAbOaf.d.ts} +1 -1
- package/dist/{model-form-hoE2jHIi.d.cts → model-form-GzTqhEzM.d.cts} +1 -1
- package/dist/{pipeline-BNIw8pDQ.d.ts → pipeline-CR4V15jF.d.ts} +1 -1
- package/dist/{pipeline-DNIpEsN8.d.cts → pipeline-DZeExYMA.d.cts} +1 -1
- package/dist/{react-email-BvyCZnfW.d.cts → react-email-BuApZuyG.d.ts} +19 -6
- package/dist/{react-email-qPA1wjFV.d.ts → react-email-CQJq92zQ.d.cts} +19 -6
- package/dist/react.cjs +249 -12
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +4 -4
- package/dist/react.d.ts +4 -4
- package/dist/react.js +249 -12
- package/dist/react.js.map +1 -1
- package/dist/{types-A5e97acl.d.cts → types-09Q4D86N.d.cts} +23 -2
- package/dist/{types-A5e97acl.d.ts → types-09Q4D86N.d.ts} +23 -2
- package/dist/{types-bDlr4u7p.d.cts → types-D1JvL21V.d.cts} +1 -1
- package/dist/{types-BnD22-vb.d.ts → types-DU3gNdFv.d.ts} +1 -1
- package/package.json +40 -40
package/dist/cli/index.cjs
CHANGED
|
@@ -499,6 +499,7 @@ function classifyKind(status, code, message) {
|
|
|
499
499
|
if (status === 404 || hasNotFoundPattern) return "not_found";
|
|
500
500
|
if (status === 401 || status === 403 || hasAuthPattern) return "auth";
|
|
501
501
|
if (status === 429 || hasRateLimitPattern) return "rate_limit";
|
|
502
|
+
if (code === "INVALID_URL") return "validation";
|
|
502
503
|
if (status === 400 || status === 422 || hasValidationPattern) return "validation";
|
|
503
504
|
if (code === "NETWORK_ERROR" || status === 0 || status !== void 0 && status >= 500 || hasTransientPattern) {
|
|
504
505
|
return "transient";
|
|
@@ -506,6 +507,9 @@ function classifyKind(status, code, message) {
|
|
|
506
507
|
return "unknown";
|
|
507
508
|
}
|
|
508
509
|
function toAthenaErrorCode(kind, status, gatewayCode) {
|
|
510
|
+
if (gatewayCode === "INVALID_URL") {
|
|
511
|
+
return AthenaErrorCode.ValidationFailed;
|
|
512
|
+
}
|
|
509
513
|
if (gatewayCode === "NETWORK_ERROR" || kind === "transient" && status === 0) {
|
|
510
514
|
return AthenaErrorCode.NetworkUnavailable;
|
|
511
515
|
}
|
|
@@ -1359,8 +1363,74 @@ function generateArtifactsFromSnapshot(snapshot, config) {
|
|
|
1359
1363
|
return new ArtifactComposer(snapshot, normalizedConfig).compose();
|
|
1360
1364
|
}
|
|
1361
1365
|
|
|
1366
|
+
// src/gateway/url.ts
|
|
1367
|
+
var ATHENA_DEFAULT_BASE_URL = "https://athena-db.com";
|
|
1368
|
+
function describeReceivedValue(value) {
|
|
1369
|
+
if (value === void 0) return "undefined";
|
|
1370
|
+
if (value === null) return "null";
|
|
1371
|
+
if (typeof value === "string") {
|
|
1372
|
+
return value.trim().length > 0 ? JSON.stringify(value) : "an empty string";
|
|
1373
|
+
}
|
|
1374
|
+
return `${typeof value} ${JSON.stringify(value)}`;
|
|
1375
|
+
}
|
|
1376
|
+
function invalidBaseUrlError(message, hint) {
|
|
1377
|
+
return new AthenaGatewayError({
|
|
1378
|
+
code: "INVALID_URL",
|
|
1379
|
+
message,
|
|
1380
|
+
status: 0,
|
|
1381
|
+
hint
|
|
1382
|
+
});
|
|
1383
|
+
}
|
|
1384
|
+
function normalizeAthenaGatewayBaseUrl(input, options = {}) {
|
|
1385
|
+
const label = options.label ?? "Athena gateway base URL";
|
|
1386
|
+
const candidate = input ?? options.defaultBaseUrl;
|
|
1387
|
+
if (candidate === void 0 || candidate === null) {
|
|
1388
|
+
throw invalidBaseUrlError(
|
|
1389
|
+
`${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(input)}.`,
|
|
1390
|
+
'Set ATHENA_URL (or pass createClient(url, ...)) to a full URL such as "https://mirror3.athena-db.com".'
|
|
1391
|
+
);
|
|
1392
|
+
}
|
|
1393
|
+
const trimmed = candidate.trim();
|
|
1394
|
+
if (!trimmed) {
|
|
1395
|
+
throw invalidBaseUrlError(
|
|
1396
|
+
`${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
|
|
1397
|
+
'Set ATHENA_URL (or pass createClient(url, ...)) to a full URL such as "https://mirror3.athena-db.com".'
|
|
1398
|
+
);
|
|
1399
|
+
}
|
|
1400
|
+
let parsed;
|
|
1401
|
+
try {
|
|
1402
|
+
parsed = new URL(trimmed);
|
|
1403
|
+
} catch {
|
|
1404
|
+
throw invalidBaseUrlError(
|
|
1405
|
+
`${label} must be a valid absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
|
|
1406
|
+
'Use a full URL including the protocol, for example "https://mirror3.athena-db.com".'
|
|
1407
|
+
);
|
|
1408
|
+
}
|
|
1409
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
1410
|
+
throw invalidBaseUrlError(
|
|
1411
|
+
`${label} must use http or https. Received ${JSON.stringify(trimmed)}.`,
|
|
1412
|
+
'Use an Athena gateway URL such as "https://mirror3.athena-db.com".'
|
|
1413
|
+
);
|
|
1414
|
+
}
|
|
1415
|
+
if (parsed.search || parsed.hash) {
|
|
1416
|
+
throw invalidBaseUrlError(
|
|
1417
|
+
`${label} must not include query parameters or hash fragments. Received ${JSON.stringify(trimmed)}.`,
|
|
1418
|
+
'Pass only the base URL. Endpoint paths such as "/gateway/fetch" are appended by the SDK.'
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
return parsed.toString().replace(/\/+$/, "");
|
|
1422
|
+
}
|
|
1423
|
+
function buildAthenaGatewayUrl(baseUrl, path) {
|
|
1424
|
+
if (!path.startsWith("/")) {
|
|
1425
|
+
throw invalidBaseUrlError(
|
|
1426
|
+
`Athena gateway path must start with "/". Received ${JSON.stringify(path)}.`,
|
|
1427
|
+
'Use a leading slash such as "/gateway/fetch" or "/".'
|
|
1428
|
+
);
|
|
1429
|
+
}
|
|
1430
|
+
return `${baseUrl}${path}`;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1362
1433
|
// src/gateway/client.ts
|
|
1363
|
-
var DEFAULT_BASE_URL = "https://athena-db.com";
|
|
1364
1434
|
var DEFAULT_CLIENT = "railway_direct";
|
|
1365
1435
|
var FALLBACK_SDK_VERSION = "1.3.0";
|
|
1366
1436
|
var SDK_NAME = "xylex-group/athena";
|
|
@@ -1557,9 +1627,168 @@ function buildHeaders(config, options) {
|
|
|
1557
1627
|
});
|
|
1558
1628
|
return headers;
|
|
1559
1629
|
}
|
|
1630
|
+
function toInvalidUrlResponse(error, endpoint, method) {
|
|
1631
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1632
|
+
const gatewayError = error instanceof AthenaGatewayError ? error : new AthenaGatewayError({
|
|
1633
|
+
code: "INVALID_URL",
|
|
1634
|
+
message,
|
|
1635
|
+
status: 0,
|
|
1636
|
+
endpoint,
|
|
1637
|
+
method,
|
|
1638
|
+
cause: message,
|
|
1639
|
+
hint: "Set ATHENA_URL to a full http(s) URL before running queries."
|
|
1640
|
+
});
|
|
1641
|
+
return {
|
|
1642
|
+
ok: false,
|
|
1643
|
+
status: 0,
|
|
1644
|
+
statusText: null,
|
|
1645
|
+
data: null,
|
|
1646
|
+
error: gatewayError.message,
|
|
1647
|
+
errorDetails: detailsFromError(
|
|
1648
|
+
new AthenaGatewayError({
|
|
1649
|
+
code: gatewayError.code,
|
|
1650
|
+
message: gatewayError.message,
|
|
1651
|
+
status: gatewayError.status,
|
|
1652
|
+
endpoint,
|
|
1653
|
+
method,
|
|
1654
|
+
requestId: gatewayError.requestId,
|
|
1655
|
+
hint: gatewayError.hint,
|
|
1656
|
+
cause: gatewayError.causeDetail
|
|
1657
|
+
})
|
|
1658
|
+
),
|
|
1659
|
+
raw: null
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
function resolveGatewayBaseUrl(input) {
|
|
1663
|
+
return normalizeAthenaGatewayBaseUrl(input, {
|
|
1664
|
+
defaultBaseUrl: ATHENA_DEFAULT_BASE_URL
|
|
1665
|
+
});
|
|
1666
|
+
}
|
|
1667
|
+
function resolveProbePath(path) {
|
|
1668
|
+
if (!path) return "/";
|
|
1669
|
+
if (!path.startsWith("/")) {
|
|
1670
|
+
throw new AthenaGatewayError({
|
|
1671
|
+
code: "INVALID_URL",
|
|
1672
|
+
message: `Athena gateway probe path must start with "/". Received ${JSON.stringify(path)}.`,
|
|
1673
|
+
status: 0,
|
|
1674
|
+
hint: 'Use a leading slash such as "/" or "/health".'
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1677
|
+
return path;
|
|
1678
|
+
}
|
|
1679
|
+
function mergeConnectionHeaders(baseHeaders, headers) {
|
|
1680
|
+
const merged = {
|
|
1681
|
+
...baseHeaders,
|
|
1682
|
+
...headers ?? {}
|
|
1683
|
+
};
|
|
1684
|
+
if (!merged["X-Athena-Sdk"] && !merged["x-athena-sdk"]) {
|
|
1685
|
+
merged["X-Athena-Sdk"] = SDK_HEADER_VALUE;
|
|
1686
|
+
}
|
|
1687
|
+
return merged;
|
|
1688
|
+
}
|
|
1689
|
+
async function performConnectionCheck(baseUrl, requestHeaders, options) {
|
|
1690
|
+
const path = resolveProbePath(options?.path);
|
|
1691
|
+
const url = buildAthenaGatewayUrl(baseUrl, path);
|
|
1692
|
+
try {
|
|
1693
|
+
const response = await fetch(url, {
|
|
1694
|
+
method: "GET",
|
|
1695
|
+
headers: mergeConnectionHeaders(requestHeaders, options?.headers),
|
|
1696
|
+
signal: options?.signal
|
|
1697
|
+
});
|
|
1698
|
+
const rawText = await response.text();
|
|
1699
|
+
const requestId = resolveRequestId(response.headers);
|
|
1700
|
+
const parsedBody = parseResponseBody(
|
|
1701
|
+
rawText ?? "",
|
|
1702
|
+
response.headers.get("content-type")
|
|
1703
|
+
);
|
|
1704
|
+
if (parsedBody.parseFailed) {
|
|
1705
|
+
const invalidJsonError = new AthenaGatewayError({
|
|
1706
|
+
code: "INVALID_JSON",
|
|
1707
|
+
message: "Gateway probe returned malformed JSON",
|
|
1708
|
+
status: response.status,
|
|
1709
|
+
method: "GET",
|
|
1710
|
+
requestId,
|
|
1711
|
+
hint: "Verify the gateway response body is valid JSON.",
|
|
1712
|
+
cause: rawText.slice(0, 300)
|
|
1713
|
+
});
|
|
1714
|
+
return {
|
|
1715
|
+
ok: false,
|
|
1716
|
+
reachable: true,
|
|
1717
|
+
status: response.status,
|
|
1718
|
+
statusText: resolveStatusText(response, parsedBody.parsed),
|
|
1719
|
+
baseUrl,
|
|
1720
|
+
url,
|
|
1721
|
+
error: invalidJsonError.message,
|
|
1722
|
+
errorDetails: detailsFromError(invalidJsonError),
|
|
1723
|
+
raw: parsedBody.parsed
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1726
|
+
const parsed = parsedBody.parsed;
|
|
1727
|
+
if (!response.ok) {
|
|
1728
|
+
const httpError = new AthenaGatewayError({
|
|
1729
|
+
code: "HTTP_ERROR",
|
|
1730
|
+
message: resolveErrorMessage(
|
|
1731
|
+
parsed,
|
|
1732
|
+
`Athena gateway GET ${path} failed with status ${response.status}`
|
|
1733
|
+
),
|
|
1734
|
+
status: response.status,
|
|
1735
|
+
method: "GET",
|
|
1736
|
+
requestId,
|
|
1737
|
+
hint: resolveErrorHint(parsed)
|
|
1738
|
+
});
|
|
1739
|
+
return {
|
|
1740
|
+
ok: false,
|
|
1741
|
+
reachable: true,
|
|
1742
|
+
status: response.status,
|
|
1743
|
+
statusText: resolveStatusText(response, parsed),
|
|
1744
|
+
baseUrl,
|
|
1745
|
+
url,
|
|
1746
|
+
error: httpError.message,
|
|
1747
|
+
errorDetails: detailsFromError(httpError),
|
|
1748
|
+
raw: parsed
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1751
|
+
return {
|
|
1752
|
+
ok: true,
|
|
1753
|
+
reachable: true,
|
|
1754
|
+
status: response.status,
|
|
1755
|
+
statusText: resolveStatusText(response, parsed),
|
|
1756
|
+
baseUrl,
|
|
1757
|
+
url,
|
|
1758
|
+
error: void 0,
|
|
1759
|
+
errorDetails: null,
|
|
1760
|
+
raw: parsed
|
|
1761
|
+
};
|
|
1762
|
+
} catch (callError) {
|
|
1763
|
+
const message = callError instanceof Error ? callError.message : String(callError);
|
|
1764
|
+
const networkError = new AthenaGatewayError({
|
|
1765
|
+
code: "NETWORK_ERROR",
|
|
1766
|
+
message: `Network error while probing Athena gateway ${url}: ${message}`,
|
|
1767
|
+
method: "GET",
|
|
1768
|
+
cause: message,
|
|
1769
|
+
hint: "Check gateway URL, DNS, and network reachability."
|
|
1770
|
+
});
|
|
1771
|
+
return {
|
|
1772
|
+
ok: false,
|
|
1773
|
+
reachable: false,
|
|
1774
|
+
status: 0,
|
|
1775
|
+
statusText: null,
|
|
1776
|
+
baseUrl,
|
|
1777
|
+
url,
|
|
1778
|
+
error: networkError.message,
|
|
1779
|
+
errorDetails: detailsFromError(networkError),
|
|
1780
|
+
raw: null
|
|
1781
|
+
};
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1560
1784
|
async function callAthena(config, endpoint, method, payload, options) {
|
|
1561
|
-
|
|
1562
|
-
|
|
1785
|
+
let baseUrl;
|
|
1786
|
+
try {
|
|
1787
|
+
baseUrl = resolveGatewayBaseUrl(options?.baseUrl ?? config.baseUrl);
|
|
1788
|
+
} catch (error) {
|
|
1789
|
+
return toInvalidUrlResponse(error, endpoint, method);
|
|
1790
|
+
}
|
|
1791
|
+
const url = buildAthenaGatewayUrl(baseUrl, endpoint);
|
|
1563
1792
|
const headers = buildHeaders(config, options);
|
|
1564
1793
|
try {
|
|
1565
1794
|
const requestInit = {
|
|
@@ -1656,32 +1885,44 @@ async function callAthena(config, endpoint, method, payload, options) {
|
|
|
1656
1885
|
}
|
|
1657
1886
|
}
|
|
1658
1887
|
function createAthenaGatewayClient(config = {}) {
|
|
1888
|
+
const normalizedBaseUrl = resolveGatewayBaseUrl(config.baseUrl);
|
|
1889
|
+
const normalizedConfig = {
|
|
1890
|
+
...config,
|
|
1891
|
+
baseUrl: normalizedBaseUrl
|
|
1892
|
+
};
|
|
1659
1893
|
return {
|
|
1660
|
-
baseUrl:
|
|
1894
|
+
baseUrl: normalizedBaseUrl,
|
|
1661
1895
|
buildHeaders(options) {
|
|
1662
|
-
return buildHeaders(
|
|
1896
|
+
return buildHeaders(normalizedConfig, options);
|
|
1897
|
+
},
|
|
1898
|
+
verifyConnection(options) {
|
|
1899
|
+
return performConnectionCheck(
|
|
1900
|
+
normalizedBaseUrl,
|
|
1901
|
+
buildHeaders(normalizedConfig),
|
|
1902
|
+
options
|
|
1903
|
+
);
|
|
1663
1904
|
},
|
|
1664
1905
|
fetchGateway(payload, options) {
|
|
1665
|
-
return callAthena(
|
|
1906
|
+
return callAthena(normalizedConfig, "/gateway/fetch", "POST", payload, options);
|
|
1666
1907
|
},
|
|
1667
1908
|
insertGateway(payload, options) {
|
|
1668
|
-
return callAthena(
|
|
1909
|
+
return callAthena(normalizedConfig, "/gateway/insert", "PUT", payload, options);
|
|
1669
1910
|
},
|
|
1670
1911
|
updateGateway(payload, options) {
|
|
1671
|
-
return callAthena(
|
|
1912
|
+
return callAthena(normalizedConfig, "/gateway/update", "POST", payload, options);
|
|
1672
1913
|
},
|
|
1673
1914
|
deleteGateway(payload, options) {
|
|
1674
|
-
return callAthena(
|
|
1915
|
+
return callAthena(normalizedConfig, "/gateway/delete", "DELETE", payload, options);
|
|
1675
1916
|
},
|
|
1676
1917
|
rpcGateway(payload, options) {
|
|
1677
1918
|
if (options?.get) {
|
|
1678
1919
|
const endpoint = buildRpcGetEndpoint(payload);
|
|
1679
|
-
return callAthena(
|
|
1920
|
+
return callAthena(normalizedConfig, endpoint, "GET", null, options);
|
|
1680
1921
|
}
|
|
1681
|
-
return callAthena(
|
|
1922
|
+
return callAthena(normalizedConfig, "/gateway/rpc", "POST", payload, options);
|
|
1682
1923
|
},
|
|
1683
1924
|
queryGateway(payload, options) {
|
|
1684
|
-
return callAthena(
|
|
1925
|
+
return callAthena(normalizedConfig, "/gateway/query", "POST", payload, options);
|
|
1685
1926
|
}
|
|
1686
1927
|
};
|
|
1687
1928
|
}
|
|
@@ -3086,8 +3327,8 @@ function createAuthClient(config = {}) {
|
|
|
3086
3327
|
// src/db/module.ts
|
|
3087
3328
|
function createDbModule(input) {
|
|
3088
3329
|
const db = {
|
|
3089
|
-
from(table) {
|
|
3090
|
-
return input.from(table);
|
|
3330
|
+
from(table, options) {
|
|
3331
|
+
return input.from(table, options);
|
|
3091
3332
|
},
|
|
3092
3333
|
select(table, columns, options) {
|
|
3093
3334
|
return input.from(table).select(columns, options);
|
|
@@ -3192,7 +3433,19 @@ function buildGatewayCondition(operator, column, value) {
|
|
|
3192
3433
|
function compileRelationToken(key, node) {
|
|
3193
3434
|
const nested = compileSelectShape(node.select);
|
|
3194
3435
|
const propertyKey = normalizeIdentifier(key, "select relation key");
|
|
3195
|
-
|
|
3436
|
+
if (node.schema && node.via) {
|
|
3437
|
+
throw new Error(
|
|
3438
|
+
`findMany relation "${propertyKey}" cannot combine schema and via yet; use schema with the relation key, or use via without schema`
|
|
3439
|
+
);
|
|
3440
|
+
}
|
|
3441
|
+
const relationTokenBase = normalizeIdentifier(node.via ?? propertyKey, "select relation token");
|
|
3442
|
+
if (node.schema && relationTokenBase.includes(".")) {
|
|
3443
|
+
throw new Error(
|
|
3444
|
+
`findMany relation "${propertyKey}" already resolves to a qualified relation token; do not also set schema`
|
|
3445
|
+
);
|
|
3446
|
+
}
|
|
3447
|
+
const relationSchema = node.schema?.trim();
|
|
3448
|
+
const relationToken = relationSchema ? `${normalizeIdentifier(relationSchema, "select relation schema")}.${relationTokenBase}` : relationTokenBase;
|
|
3196
3449
|
const alias = node.as?.trim() || (relationToken !== propertyKey ? propertyKey : "");
|
|
3197
3450
|
const prefix = alias ? `${alias}:` : "";
|
|
3198
3451
|
return `${prefix}${relationToken}(${nested})`;
|
|
@@ -3221,6 +3474,23 @@ function compileSelectShape(select) {
|
|
|
3221
3474
|
}
|
|
3222
3475
|
return tokens.join(",");
|
|
3223
3476
|
}
|
|
3477
|
+
function selectShapeUsesRelationSchema(select) {
|
|
3478
|
+
if (!isRecord5(select)) {
|
|
3479
|
+
return false;
|
|
3480
|
+
}
|
|
3481
|
+
for (const rawValue of Object.values(select)) {
|
|
3482
|
+
if (!isRelationSelectNode(rawValue)) {
|
|
3483
|
+
continue;
|
|
3484
|
+
}
|
|
3485
|
+
if (typeof rawValue.schema === "string" && rawValue.schema.trim().length > 0) {
|
|
3486
|
+
return true;
|
|
3487
|
+
}
|
|
3488
|
+
if (selectShapeUsesRelationSchema(rawValue.select)) {
|
|
3489
|
+
return true;
|
|
3490
|
+
}
|
|
3491
|
+
}
|
|
3492
|
+
return false;
|
|
3493
|
+
}
|
|
3224
3494
|
function compileColumnWhere(column, input) {
|
|
3225
3495
|
const normalizedColumn = normalizeIdentifier(column, "where column");
|
|
3226
3496
|
if (!isRecord5(input)) {
|
|
@@ -3357,6 +3627,258 @@ function compileOrderBy(orderBy) {
|
|
|
3357
3627
|
};
|
|
3358
3628
|
}
|
|
3359
3629
|
|
|
3630
|
+
// src/gateway/structured-select.ts
|
|
3631
|
+
var IDENTIFIER_SEGMENT_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
3632
|
+
function isIdentifierPath(value) {
|
|
3633
|
+
const segments = value.split(".").map((segment) => segment.trim());
|
|
3634
|
+
return segments.length > 1 && segments.every((segment) => IDENTIFIER_SEGMENT_PATTERN.test(segment));
|
|
3635
|
+
}
|
|
3636
|
+
function extractRelationHead(raw) {
|
|
3637
|
+
const trimmed = raw.trim();
|
|
3638
|
+
if (!trimmed) return "";
|
|
3639
|
+
const aliasIndex = trimmed.indexOf(":");
|
|
3640
|
+
const withoutAlias = aliasIndex >= 0 ? trimmed.slice(aliasIndex + 1).trim() : trimmed;
|
|
3641
|
+
const modifierIndex = withoutAlias.indexOf("!");
|
|
3642
|
+
return (modifierIndex >= 0 ? withoutAlias.slice(0, modifierIndex) : withoutAlias).trim();
|
|
3643
|
+
}
|
|
3644
|
+
function hasSchemaQualifiedRelationToken(select) {
|
|
3645
|
+
let singleQuoted = false;
|
|
3646
|
+
let doubleQuoted = false;
|
|
3647
|
+
let tokenStart = 0;
|
|
3648
|
+
for (let index = 0; index < select.length; index += 1) {
|
|
3649
|
+
const char = select[index];
|
|
3650
|
+
const next = index + 1 < select.length ? select[index + 1] : "";
|
|
3651
|
+
if (singleQuoted) {
|
|
3652
|
+
if (char === "'" && next === "'") {
|
|
3653
|
+
index += 1;
|
|
3654
|
+
continue;
|
|
3655
|
+
}
|
|
3656
|
+
if (char === "'") {
|
|
3657
|
+
singleQuoted = false;
|
|
3658
|
+
}
|
|
3659
|
+
continue;
|
|
3660
|
+
}
|
|
3661
|
+
if (doubleQuoted) {
|
|
3662
|
+
if (char === '"' && next === '"') {
|
|
3663
|
+
index += 1;
|
|
3664
|
+
continue;
|
|
3665
|
+
}
|
|
3666
|
+
if (char === '"') {
|
|
3667
|
+
doubleQuoted = false;
|
|
3668
|
+
}
|
|
3669
|
+
continue;
|
|
3670
|
+
}
|
|
3671
|
+
if (char === "'") {
|
|
3672
|
+
singleQuoted = true;
|
|
3673
|
+
continue;
|
|
3674
|
+
}
|
|
3675
|
+
if (char === '"') {
|
|
3676
|
+
doubleQuoted = true;
|
|
3677
|
+
continue;
|
|
3678
|
+
}
|
|
3679
|
+
if (char === "(") {
|
|
3680
|
+
const relationHead = extractRelationHead(select.slice(tokenStart, index));
|
|
3681
|
+
if (isIdentifierPath(relationHead)) {
|
|
3682
|
+
return true;
|
|
3683
|
+
}
|
|
3684
|
+
tokenStart = index + 1;
|
|
3685
|
+
continue;
|
|
3686
|
+
}
|
|
3687
|
+
if (char === "," || char === ")") {
|
|
3688
|
+
tokenStart = index + 1;
|
|
3689
|
+
}
|
|
3690
|
+
}
|
|
3691
|
+
return false;
|
|
3692
|
+
}
|
|
3693
|
+
function toStructuredSelectString(columns) {
|
|
3694
|
+
return Array.isArray(columns) ? columns.join(",") : columns;
|
|
3695
|
+
}
|
|
3696
|
+
function buildStructuredWhere(conditions) {
|
|
3697
|
+
if (!conditions?.length) return void 0;
|
|
3698
|
+
const where = {};
|
|
3699
|
+
for (const condition of conditions) {
|
|
3700
|
+
if (!condition.column) {
|
|
3701
|
+
return null;
|
|
3702
|
+
}
|
|
3703
|
+
if (condition.column_cast !== void 0 || condition.value_cast !== void 0) {
|
|
3704
|
+
return null;
|
|
3705
|
+
}
|
|
3706
|
+
const operand = condition.value;
|
|
3707
|
+
const operator = condition.operator;
|
|
3708
|
+
if (operator === "eq") {
|
|
3709
|
+
if (operand === void 0) return null;
|
|
3710
|
+
} else if (operator === "neq" || operator === "gt" || operator === "lt") {
|
|
3711
|
+
if (operand === void 0) return null;
|
|
3712
|
+
} else if (operator === "in") {
|
|
3713
|
+
if (!Array.isArray(operand)) return null;
|
|
3714
|
+
} else {
|
|
3715
|
+
return null;
|
|
3716
|
+
}
|
|
3717
|
+
const existing = where[condition.column];
|
|
3718
|
+
if (existing !== void 0 && (typeof existing !== "object" || existing === null || Array.isArray(existing))) {
|
|
3719
|
+
return null;
|
|
3720
|
+
}
|
|
3721
|
+
const next = existing ?? {};
|
|
3722
|
+
if (Object.prototype.hasOwnProperty.call(next, operator)) {
|
|
3723
|
+
return null;
|
|
3724
|
+
}
|
|
3725
|
+
next[operator] = operand;
|
|
3726
|
+
where[condition.column] = next;
|
|
3727
|
+
}
|
|
3728
|
+
return where;
|
|
3729
|
+
}
|
|
3730
|
+
function buildStructuredOrderBy(order) {
|
|
3731
|
+
if (!order?.field) return void 0;
|
|
3732
|
+
return {
|
|
3733
|
+
[order.field]: order.direction === "descending" ? "desc" : "asc"
|
|
3734
|
+
};
|
|
3735
|
+
}
|
|
3736
|
+
function buildStructuredSelectTransport(input) {
|
|
3737
|
+
const select = toStructuredSelectString(input.columns).trim();
|
|
3738
|
+
if (!select || select === "*") {
|
|
3739
|
+
return null;
|
|
3740
|
+
}
|
|
3741
|
+
if (!hasSchemaQualifiedRelationToken(select)) {
|
|
3742
|
+
return null;
|
|
3743
|
+
}
|
|
3744
|
+
if (input.count !== void 0 || input.head !== void 0) {
|
|
3745
|
+
return {
|
|
3746
|
+
error: "Schema-qualified nested select strings require structured select transport, which does not support count/head options in athena-js yet."
|
|
3747
|
+
};
|
|
3748
|
+
}
|
|
3749
|
+
const where = buildStructuredWhere(input.conditions);
|
|
3750
|
+
if (where === null) {
|
|
3751
|
+
return {
|
|
3752
|
+
error: "Schema-qualified nested select strings only support eq, neq, gt, lt, and in filters in athena-js structured select transport."
|
|
3753
|
+
};
|
|
3754
|
+
}
|
|
3755
|
+
return {
|
|
3756
|
+
select,
|
|
3757
|
+
payload: {
|
|
3758
|
+
table_name: input.tableName,
|
|
3759
|
+
select,
|
|
3760
|
+
where,
|
|
3761
|
+
orderBy: buildStructuredOrderBy(input.order),
|
|
3762
|
+
limit: input.limit,
|
|
3763
|
+
offset: input.offset,
|
|
3764
|
+
strip_nulls: input.stripNulls
|
|
3765
|
+
}
|
|
3766
|
+
};
|
|
3767
|
+
}
|
|
3768
|
+
|
|
3769
|
+
// src/query-transport.ts
|
|
3770
|
+
function canUseFindManyAstTransport(state) {
|
|
3771
|
+
return state.conditions.length === 0 && state.offset === void 0 && state.currentPage === void 0 && state.pageSize === void 0 && state.totalPages === void 0;
|
|
3772
|
+
}
|
|
3773
|
+
function toFindManyAstOrder(order) {
|
|
3774
|
+
if (!order) {
|
|
3775
|
+
return void 0;
|
|
3776
|
+
}
|
|
3777
|
+
return {
|
|
3778
|
+
column: order.field,
|
|
3779
|
+
ascending: order.direction !== "descending"
|
|
3780
|
+
};
|
|
3781
|
+
}
|
|
3782
|
+
function resolvePagination(input) {
|
|
3783
|
+
let limit = input.limit;
|
|
3784
|
+
let offset = input.offset;
|
|
3785
|
+
if (limit === void 0 && input.pageSize !== void 0) {
|
|
3786
|
+
limit = Math.max(0, Math.trunc(input.pageSize));
|
|
3787
|
+
}
|
|
3788
|
+
if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
|
|
3789
|
+
offset = (Math.trunc(input.currentPage) - 1) * Math.max(0, Math.trunc(input.pageSize));
|
|
3790
|
+
}
|
|
3791
|
+
return { limit, offset };
|
|
3792
|
+
}
|
|
3793
|
+
function hasTypedEqualityComparison(conditions) {
|
|
3794
|
+
return conditions?.some(
|
|
3795
|
+
(condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
|
|
3796
|
+
) ?? false;
|
|
3797
|
+
}
|
|
3798
|
+
function createSelectTransportPlan(input) {
|
|
3799
|
+
const conditions = input.state.conditions.length ? input.state.conditions.map((condition) => ({ ...condition })) : void 0;
|
|
3800
|
+
if (hasTypedEqualityComparison(conditions) && !input.options?.head && !input.options?.count && conditions) {
|
|
3801
|
+
const query = input.buildTypedSelectQuery({
|
|
3802
|
+
tableName: input.tableName,
|
|
3803
|
+
columns: input.columns,
|
|
3804
|
+
conditions,
|
|
3805
|
+
limit: input.state.limit,
|
|
3806
|
+
offset: input.state.offset,
|
|
3807
|
+
currentPage: input.state.currentPage,
|
|
3808
|
+
pageSize: input.state.pageSize,
|
|
3809
|
+
order: input.state.order
|
|
3810
|
+
});
|
|
3811
|
+
if (query) {
|
|
3812
|
+
return {
|
|
3813
|
+
kind: "query",
|
|
3814
|
+
query,
|
|
3815
|
+
payload: { query }
|
|
3816
|
+
};
|
|
3817
|
+
}
|
|
3818
|
+
}
|
|
3819
|
+
const pagination = resolvePagination({
|
|
3820
|
+
limit: input.state.limit,
|
|
3821
|
+
offset: input.state.offset,
|
|
3822
|
+
currentPage: input.state.currentPage,
|
|
3823
|
+
pageSize: input.state.pageSize
|
|
3824
|
+
});
|
|
3825
|
+
const stripNulls = input.options?.stripNulls ?? true;
|
|
3826
|
+
const structuredSelectTransport = buildStructuredSelectTransport({
|
|
3827
|
+
tableName: input.tableName,
|
|
3828
|
+
columns: input.columns,
|
|
3829
|
+
conditions,
|
|
3830
|
+
limit: pagination.limit,
|
|
3831
|
+
offset: pagination.offset,
|
|
3832
|
+
order: input.state.order,
|
|
3833
|
+
stripNulls,
|
|
3834
|
+
count: input.options?.count,
|
|
3835
|
+
head: input.options?.head
|
|
3836
|
+
});
|
|
3837
|
+
if (structuredSelectTransport && "error" in structuredSelectTransport) {
|
|
3838
|
+
throw new Error(structuredSelectTransport.error);
|
|
3839
|
+
}
|
|
3840
|
+
if (structuredSelectTransport) {
|
|
3841
|
+
const { payload, select } = structuredSelectTransport;
|
|
3842
|
+
return {
|
|
3843
|
+
kind: "fetch",
|
|
3844
|
+
payload,
|
|
3845
|
+
debug: {
|
|
3846
|
+
columns: select,
|
|
3847
|
+
conditions,
|
|
3848
|
+
limit: pagination.limit,
|
|
3849
|
+
offset: pagination.offset,
|
|
3850
|
+
order: input.state.order
|
|
3851
|
+
}
|
|
3852
|
+
};
|
|
3853
|
+
}
|
|
3854
|
+
return {
|
|
3855
|
+
kind: "fetch",
|
|
3856
|
+
payload: {
|
|
3857
|
+
table_name: input.tableName,
|
|
3858
|
+
columns: input.columns,
|
|
3859
|
+
conditions,
|
|
3860
|
+
limit: input.state.limit,
|
|
3861
|
+
offset: input.state.offset,
|
|
3862
|
+
current_page: input.state.currentPage,
|
|
3863
|
+
page_size: input.state.pageSize,
|
|
3864
|
+
total_pages: input.state.totalPages,
|
|
3865
|
+
sort_by: input.state.order,
|
|
3866
|
+
strip_nulls: stripNulls,
|
|
3867
|
+
count: input.options?.count,
|
|
3868
|
+
head: input.options?.head
|
|
3869
|
+
},
|
|
3870
|
+
debug: {
|
|
3871
|
+
columns: input.columns,
|
|
3872
|
+
conditions,
|
|
3873
|
+
limit: input.state.limit,
|
|
3874
|
+
offset: input.state.offset,
|
|
3875
|
+
currentPage: input.state.currentPage,
|
|
3876
|
+
pageSize: input.state.pageSize,
|
|
3877
|
+
order: input.state.order
|
|
3878
|
+
}
|
|
3879
|
+
};
|
|
3880
|
+
}
|
|
3881
|
+
|
|
3360
3882
|
// src/client.ts
|
|
3361
3883
|
var DEFAULT_COLUMNS = "*";
|
|
3362
3884
|
var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
|
|
@@ -3371,18 +3893,6 @@ var QUERY_TRACE_STACK_SKIP_PATTERNS = [
|
|
|
3371
3893
|
"node:internal",
|
|
3372
3894
|
"internal/process"
|
|
3373
3895
|
];
|
|
3374
|
-
function canUseFindManyAstTransport(state) {
|
|
3375
|
-
return state.conditions.length === 0 && state.offset === void 0 && state.currentPage === void 0 && state.pageSize === void 0 && state.totalPages === void 0;
|
|
3376
|
-
}
|
|
3377
|
-
function toFindManyAstOrder(order) {
|
|
3378
|
-
if (!order) {
|
|
3379
|
-
return void 0;
|
|
3380
|
-
}
|
|
3381
|
-
return {
|
|
3382
|
-
column: order.field,
|
|
3383
|
-
ascending: order.direction !== "descending"
|
|
3384
|
-
};
|
|
3385
|
-
}
|
|
3386
3896
|
function formatResult(response) {
|
|
3387
3897
|
const result = {
|
|
3388
3898
|
data: response.data ?? null,
|
|
@@ -3928,17 +4438,6 @@ function conditionToDebugSqlClause(condition) {
|
|
|
3928
4438
|
return `TRUE /* unsupported condition: ${rawCondition} */`;
|
|
3929
4439
|
}
|
|
3930
4440
|
}
|
|
3931
|
-
function resolvePagination(input) {
|
|
3932
|
-
let limit = input.limit;
|
|
3933
|
-
let offset = input.offset;
|
|
3934
|
-
if (limit === void 0 && input.pageSize !== void 0) {
|
|
3935
|
-
limit = input.pageSize;
|
|
3936
|
-
}
|
|
3937
|
-
if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
|
|
3938
|
-
offset = (input.currentPage - 1) * input.pageSize;
|
|
3939
|
-
}
|
|
3940
|
-
return { limit, offset };
|
|
3941
|
-
}
|
|
3942
4441
|
function appendOrderLimitOffset(sqlParts, order, limit, offset) {
|
|
3943
4442
|
if (order?.field) {
|
|
3944
4443
|
const direction = order.direction === "descending" ? "DESC" : "ASC";
|
|
@@ -4442,64 +4941,34 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
|
|
|
4442
4941
|
);
|
|
4443
4942
|
const runSelect = async (columns = DEFAULT_COLUMNS, options, executionState = snapshotState(), callsite) => {
|
|
4444
4943
|
const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
|
|
4445
|
-
const
|
|
4446
|
-
|
|
4447
|
-
(condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
|
|
4448
|
-
) ?? false;
|
|
4449
|
-
if (hasTypedEqualityComparison && !options?.head && !options?.count && conditions) {
|
|
4450
|
-
const query = buildTypedSelectQuery({
|
|
4451
|
-
tableName: resolvedTableName,
|
|
4452
|
-
columns,
|
|
4453
|
-
conditions,
|
|
4454
|
-
limit: executionState.limit,
|
|
4455
|
-
offset: executionState.offset,
|
|
4456
|
-
currentPage: executionState.currentPage,
|
|
4457
|
-
pageSize: executionState.pageSize,
|
|
4458
|
-
order: executionState.order
|
|
4459
|
-
});
|
|
4460
|
-
if (query) {
|
|
4461
|
-
const payload2 = { query };
|
|
4462
|
-
return executeWithQueryTrace(
|
|
4463
|
-
tracer,
|
|
4464
|
-
{
|
|
4465
|
-
operation: "select",
|
|
4466
|
-
endpoint: "/gateway/query",
|
|
4467
|
-
table: resolvedTableName,
|
|
4468
|
-
sql: query,
|
|
4469
|
-
payload: payload2,
|
|
4470
|
-
options
|
|
4471
|
-
},
|
|
4472
|
-
async () => {
|
|
4473
|
-
const queryResponse = await client.queryGateway(payload2, options);
|
|
4474
|
-
return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
|
|
4475
|
-
},
|
|
4476
|
-
callsite
|
|
4477
|
-
);
|
|
4478
|
-
}
|
|
4479
|
-
}
|
|
4480
|
-
const payload = {
|
|
4481
|
-
table_name: resolvedTableName,
|
|
4944
|
+
const plan = createSelectTransportPlan({
|
|
4945
|
+
tableName: resolvedTableName,
|
|
4482
4946
|
columns,
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4947
|
+
state: executionState,
|
|
4948
|
+
options,
|
|
4949
|
+
buildTypedSelectQuery
|
|
4950
|
+
});
|
|
4951
|
+
if (plan.kind === "query") {
|
|
4952
|
+
return executeWithQueryTrace(
|
|
4953
|
+
tracer,
|
|
4954
|
+
{
|
|
4955
|
+
operation: "select",
|
|
4956
|
+
endpoint: "/gateway/query",
|
|
4957
|
+
table: resolvedTableName,
|
|
4958
|
+
sql: plan.query,
|
|
4959
|
+
payload: plan.payload,
|
|
4960
|
+
options
|
|
4961
|
+
},
|
|
4962
|
+
async () => {
|
|
4963
|
+
const queryResponse = await client.queryGateway(plan.payload, options);
|
|
4964
|
+
return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
|
|
4965
|
+
},
|
|
4966
|
+
callsite
|
|
4967
|
+
);
|
|
4968
|
+
}
|
|
4494
4969
|
const sql = buildDebugSelectQuery({
|
|
4495
4970
|
tableName: resolvedTableName,
|
|
4496
|
-
|
|
4497
|
-
conditions,
|
|
4498
|
-
limit: executionState.limit,
|
|
4499
|
-
offset: executionState.offset,
|
|
4500
|
-
currentPage: executionState.currentPage,
|
|
4501
|
-
pageSize: executionState.pageSize,
|
|
4502
|
-
order: executionState.order
|
|
4971
|
+
...plan.debug
|
|
4503
4972
|
});
|
|
4504
4973
|
return executeWithQueryTrace(
|
|
4505
4974
|
tracer,
|
|
@@ -4508,11 +4977,11 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
|
|
|
4508
4977
|
endpoint: "/gateway/fetch",
|
|
4509
4978
|
table: resolvedTableName,
|
|
4510
4979
|
sql,
|
|
4511
|
-
payload,
|
|
4980
|
+
payload: plan.payload,
|
|
4512
4981
|
options
|
|
4513
4982
|
},
|
|
4514
4983
|
async () => {
|
|
4515
|
-
const response = await client.fetchGateway(payload, options);
|
|
4984
|
+
const response = await client.fetchGateway(plan.payload, options);
|
|
4516
4985
|
return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
|
|
4517
4986
|
},
|
|
4518
4987
|
callsite
|
|
@@ -4585,7 +5054,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
|
|
|
4585
5054
|
if (options.limit !== void 0) {
|
|
4586
5055
|
executionState.limit = options.limit;
|
|
4587
5056
|
}
|
|
4588
|
-
if (experimental?.findManyAst && canUseFindManyAstTransport(baseState)) {
|
|
5057
|
+
if (experimental?.findManyAst && canUseFindManyAstTransport(baseState) && !selectShapeUsesRelationSchema(options.select)) {
|
|
4589
5058
|
const resolvedTableName = resolveTableNameForCall(tableName, void 0);
|
|
4590
5059
|
const payload = {
|
|
4591
5060
|
table_name: resolvedTableName,
|
|
@@ -4907,7 +5376,13 @@ function createClientFromConfig(config) {
|
|
|
4907
5376
|
const formatGatewayResult = createResultFormatter();
|
|
4908
5377
|
const queryTracer = createQueryTracer(config.experimental);
|
|
4909
5378
|
const auth = createAuthClient(config.auth);
|
|
4910
|
-
const from = (table) => createTableBuilder(
|
|
5379
|
+
const from = (table, options) => createTableBuilder(
|
|
5380
|
+
resolveTableNameForCall(table, options?.schema),
|
|
5381
|
+
gateway,
|
|
5382
|
+
formatGatewayResult,
|
|
5383
|
+
queryTracer,
|
|
5384
|
+
config.experimental
|
|
5385
|
+
);
|
|
4911
5386
|
const rpc = (fn, args, options) => {
|
|
4912
5387
|
const normalizedFn = fn.trim();
|
|
4913
5388
|
if (!normalizedFn) {
|
|
@@ -4930,6 +5405,7 @@ function createClientFromConfig(config) {
|
|
|
4930
5405
|
db,
|
|
4931
5406
|
rpc,
|
|
4932
5407
|
query,
|
|
5408
|
+
verifyConnection: gateway.verifyConnection,
|
|
4933
5409
|
auth: auth.auth
|
|
4934
5410
|
};
|
|
4935
5411
|
}
|