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