@xylex-group/athena 2.1.2 → 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 +306 -117
- package/dist/browser.cjs +2151 -194
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +14 -14
- package/dist/browser.d.ts +14 -14
- package/dist/browser.js +2146 -194
- package/dist/browser.js.map +1 -1
- package/dist/cli/index.cjs +2035 -172
- 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 +2036 -173
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +2166 -190
- 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 +2162 -191
- package/dist/index.js.map +1 -1
- package/dist/{model-form-2hqmoOUX.d.ts → model-form-C0FAbOaf.d.ts} +97 -2
- package/dist/{model-form-Cy-zaO0u.d.cts → model-form-GzTqhEzM.d.cts} +97 -2
- package/dist/{pipeline-BOPszLsL.d.ts → pipeline-CR4V15jF.d.ts} +1 -1
- package/dist/{pipeline-E3FDbs4W.d.cts → pipeline-DZeExYMA.d.cts} +1 -1
- package/dist/{client-BX0NQqOn.d.ts → react-email-BuApZuyG.d.ts} +362 -174
- package/dist/{client-dpAp-NZK.d.cts → react-email-CQJq92zQ.d.cts} +362 -174
- package/dist/react.cjs +279 -21
- 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 +279 -21
- package/dist/react.js.map +1 -1
- package/dist/{types-BaBzjwXr.d.cts → types-09Q4D86N.d.cts} +24 -2
- package/dist/{types-BaBzjwXr.d.ts → types-09Q4D86N.d.ts} +24 -2
- package/dist/{types-CpqL-pZx.d.cts → types-D1JvL21V.d.cts} +1 -1
- package/dist/{types-CeBPrnGj.d.ts → types-DU3gNdFv.d.ts} +1 -1
- package/dist/utils.cjs +153 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.cts +23 -0
- package/dist/utils.d.ts +23 -0
- package/dist/utils.js +146 -0
- package/dist/utils.js.map +1 -0
- package/package.json +74 -16
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'fs';
|
|
2
2
|
import { resolve, dirname, posix } from 'path';
|
|
3
3
|
import { pathToFileURL } from 'url';
|
|
4
|
-
import { mkdir, writeFile } from 'fs/promises';
|
|
4
|
+
import { mkdir, writeFile, stat } from 'fs/promises';
|
|
5
5
|
|
|
6
6
|
// src/gateway/errors.ts
|
|
7
7
|
var AthenaGatewayError = class _AthenaGatewayError extends Error {
|
|
@@ -63,8 +63,74 @@ function isAthenaGatewayError(error) {
|
|
|
63
63
|
return error instanceof AthenaGatewayError;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
// src/gateway/url.ts
|
|
67
|
+
var ATHENA_DEFAULT_BASE_URL = "https://athena-db.com";
|
|
68
|
+
function describeReceivedValue(value) {
|
|
69
|
+
if (value === void 0) return "undefined";
|
|
70
|
+
if (value === null) return "null";
|
|
71
|
+
if (typeof value === "string") {
|
|
72
|
+
return value.trim().length > 0 ? JSON.stringify(value) : "an empty string";
|
|
73
|
+
}
|
|
74
|
+
return `${typeof value} ${JSON.stringify(value)}`;
|
|
75
|
+
}
|
|
76
|
+
function invalidBaseUrlError(message, hint) {
|
|
77
|
+
return new AthenaGatewayError({
|
|
78
|
+
code: "INVALID_URL",
|
|
79
|
+
message,
|
|
80
|
+
status: 0,
|
|
81
|
+
hint
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function normalizeAthenaGatewayBaseUrl(input, options = {}) {
|
|
85
|
+
const label = options.label ?? "Athena gateway base URL";
|
|
86
|
+
const candidate = input ?? options.defaultBaseUrl;
|
|
87
|
+
if (candidate === void 0 || candidate === null) {
|
|
88
|
+
throw invalidBaseUrlError(
|
|
89
|
+
`${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(input)}.`,
|
|
90
|
+
'Set ATHENA_URL (or pass createClient(url, ...)) to a full URL such as "https://mirror3.athena-db.com".'
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
const trimmed = candidate.trim();
|
|
94
|
+
if (!trimmed) {
|
|
95
|
+
throw invalidBaseUrlError(
|
|
96
|
+
`${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
|
|
97
|
+
'Set ATHENA_URL (or pass createClient(url, ...)) to a full URL such as "https://mirror3.athena-db.com".'
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
let parsed;
|
|
101
|
+
try {
|
|
102
|
+
parsed = new URL(trimmed);
|
|
103
|
+
} catch {
|
|
104
|
+
throw invalidBaseUrlError(
|
|
105
|
+
`${label} must be a valid absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
|
|
106
|
+
'Use a full URL including the protocol, for example "https://mirror3.athena-db.com".'
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
110
|
+
throw invalidBaseUrlError(
|
|
111
|
+
`${label} must use http or https. Received ${JSON.stringify(trimmed)}.`,
|
|
112
|
+
'Use an Athena gateway URL such as "https://mirror3.athena-db.com".'
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
if (parsed.search || parsed.hash) {
|
|
116
|
+
throw invalidBaseUrlError(
|
|
117
|
+
`${label} must not include query parameters or hash fragments. Received ${JSON.stringify(trimmed)}.`,
|
|
118
|
+
'Pass only the base URL. Endpoint paths such as "/gateway/fetch" are appended by the SDK.'
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
return parsed.toString().replace(/\/+$/, "");
|
|
122
|
+
}
|
|
123
|
+
function buildAthenaGatewayUrl(baseUrl, path) {
|
|
124
|
+
if (!path.startsWith("/")) {
|
|
125
|
+
throw invalidBaseUrlError(
|
|
126
|
+
`Athena gateway path must start with "/". Received ${JSON.stringify(path)}.`,
|
|
127
|
+
'Use a leading slash such as "/gateway/fetch" or "/".'
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
return `${baseUrl}${path}`;
|
|
131
|
+
}
|
|
132
|
+
|
|
66
133
|
// src/gateway/client.ts
|
|
67
|
-
var DEFAULT_BASE_URL = "https://athena-db.com";
|
|
68
134
|
var DEFAULT_CLIENT = "railway_direct";
|
|
69
135
|
var FALLBACK_SDK_VERSION = "1.3.0";
|
|
70
136
|
var SDK_NAME = "xylex-group/athena";
|
|
@@ -91,23 +157,39 @@ function normalizeHeaderValue(value) {
|
|
|
91
157
|
function isRecord(value) {
|
|
92
158
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
93
159
|
}
|
|
160
|
+
function nonEmptyString(value) {
|
|
161
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
162
|
+
}
|
|
163
|
+
function resolveStructuredErrorPayload(payload) {
|
|
164
|
+
if (!isRecord(payload)) return null;
|
|
165
|
+
return isRecord(payload.error) ? payload.error : payload;
|
|
166
|
+
}
|
|
94
167
|
function resolveRequestId(headers) {
|
|
95
168
|
return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
|
|
96
169
|
}
|
|
97
170
|
function resolveErrorMessage(payload, fallback) {
|
|
98
|
-
|
|
99
|
-
|
|
171
|
+
const structuredPayload = resolveStructuredErrorPayload(payload);
|
|
172
|
+
if (structuredPayload) {
|
|
173
|
+
const messageCandidates = [structuredPayload.message, structuredPayload.error, structuredPayload.details];
|
|
100
174
|
for (const candidate of messageCandidates) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
175
|
+
const resolved = nonEmptyString(candidate);
|
|
176
|
+
if (resolved) return resolved;
|
|
104
177
|
}
|
|
105
178
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
179
|
+
const rawMessage = nonEmptyString(payload);
|
|
180
|
+
if (rawMessage) return rawMessage;
|
|
109
181
|
return fallback;
|
|
110
182
|
}
|
|
183
|
+
function resolveErrorHint(payload) {
|
|
184
|
+
const structuredPayload = resolveStructuredErrorPayload(payload);
|
|
185
|
+
return structuredPayload ? nonEmptyString(structuredPayload.hint) : void 0;
|
|
186
|
+
}
|
|
187
|
+
function resolveStatusText(response, payload) {
|
|
188
|
+
const rawStatusText = nonEmptyString(response.statusText);
|
|
189
|
+
if (rawStatusText) return rawStatusText;
|
|
190
|
+
const payloadRecord = isRecord(payload) ? payload : null;
|
|
191
|
+
return payloadRecord ? nonEmptyString(payloadRecord.statusText) ?? null : null;
|
|
192
|
+
}
|
|
111
193
|
function detailsFromError(error) {
|
|
112
194
|
return error.toDetails();
|
|
113
195
|
}
|
|
@@ -245,9 +327,172 @@ function buildHeaders(config, options) {
|
|
|
245
327
|
});
|
|
246
328
|
return headers;
|
|
247
329
|
}
|
|
330
|
+
function toInvalidUrlResponse(error, endpoint, method) {
|
|
331
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
332
|
+
const gatewayError = error instanceof AthenaGatewayError ? error : new AthenaGatewayError({
|
|
333
|
+
code: "INVALID_URL",
|
|
334
|
+
message,
|
|
335
|
+
status: 0,
|
|
336
|
+
endpoint,
|
|
337
|
+
method,
|
|
338
|
+
cause: message,
|
|
339
|
+
hint: "Set ATHENA_URL to a full http(s) URL before running queries."
|
|
340
|
+
});
|
|
341
|
+
return {
|
|
342
|
+
ok: false,
|
|
343
|
+
status: 0,
|
|
344
|
+
statusText: null,
|
|
345
|
+
data: null,
|
|
346
|
+
error: gatewayError.message,
|
|
347
|
+
errorDetails: detailsFromError(
|
|
348
|
+
new AthenaGatewayError({
|
|
349
|
+
code: gatewayError.code,
|
|
350
|
+
message: gatewayError.message,
|
|
351
|
+
status: gatewayError.status,
|
|
352
|
+
endpoint,
|
|
353
|
+
method,
|
|
354
|
+
requestId: gatewayError.requestId,
|
|
355
|
+
hint: gatewayError.hint,
|
|
356
|
+
cause: gatewayError.causeDetail
|
|
357
|
+
})
|
|
358
|
+
),
|
|
359
|
+
raw: null
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function resolveGatewayBaseUrl(input) {
|
|
363
|
+
return normalizeAthenaGatewayBaseUrl(input, {
|
|
364
|
+
defaultBaseUrl: ATHENA_DEFAULT_BASE_URL
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
function resolveProbePath(path) {
|
|
368
|
+
if (!path) return "/";
|
|
369
|
+
if (!path.startsWith("/")) {
|
|
370
|
+
throw new AthenaGatewayError({
|
|
371
|
+
code: "INVALID_URL",
|
|
372
|
+
message: `Athena gateway probe path must start with "/". Received ${JSON.stringify(path)}.`,
|
|
373
|
+
status: 0,
|
|
374
|
+
hint: 'Use a leading slash such as "/" or "/health".'
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
return path;
|
|
378
|
+
}
|
|
379
|
+
function mergeConnectionHeaders(baseHeaders, headers) {
|
|
380
|
+
const merged = {
|
|
381
|
+
...baseHeaders,
|
|
382
|
+
...headers ?? {}
|
|
383
|
+
};
|
|
384
|
+
if (!merged["X-Athena-Sdk"] && !merged["x-athena-sdk"]) {
|
|
385
|
+
merged["X-Athena-Sdk"] = SDK_HEADER_VALUE;
|
|
386
|
+
}
|
|
387
|
+
return merged;
|
|
388
|
+
}
|
|
389
|
+
async function performConnectionCheck(baseUrl, requestHeaders, options) {
|
|
390
|
+
const path = resolveProbePath(options?.path);
|
|
391
|
+
const url = buildAthenaGatewayUrl(baseUrl, path);
|
|
392
|
+
try {
|
|
393
|
+
const response = await fetch(url, {
|
|
394
|
+
method: "GET",
|
|
395
|
+
headers: mergeConnectionHeaders(requestHeaders, options?.headers),
|
|
396
|
+
signal: options?.signal
|
|
397
|
+
});
|
|
398
|
+
const rawText = await response.text();
|
|
399
|
+
const requestId = resolveRequestId(response.headers);
|
|
400
|
+
const parsedBody = parseResponseBody(
|
|
401
|
+
rawText ?? "",
|
|
402
|
+
response.headers.get("content-type")
|
|
403
|
+
);
|
|
404
|
+
if (parsedBody.parseFailed) {
|
|
405
|
+
const invalidJsonError = new AthenaGatewayError({
|
|
406
|
+
code: "INVALID_JSON",
|
|
407
|
+
message: "Gateway probe returned malformed JSON",
|
|
408
|
+
status: response.status,
|
|
409
|
+
method: "GET",
|
|
410
|
+
requestId,
|
|
411
|
+
hint: "Verify the gateway response body is valid JSON.",
|
|
412
|
+
cause: rawText.slice(0, 300)
|
|
413
|
+
});
|
|
414
|
+
return {
|
|
415
|
+
ok: false,
|
|
416
|
+
reachable: true,
|
|
417
|
+
status: response.status,
|
|
418
|
+
statusText: resolveStatusText(response, parsedBody.parsed),
|
|
419
|
+
baseUrl,
|
|
420
|
+
url,
|
|
421
|
+
error: invalidJsonError.message,
|
|
422
|
+
errorDetails: detailsFromError(invalidJsonError),
|
|
423
|
+
raw: parsedBody.parsed
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
const parsed = parsedBody.parsed;
|
|
427
|
+
if (!response.ok) {
|
|
428
|
+
const httpError = new AthenaGatewayError({
|
|
429
|
+
code: "HTTP_ERROR",
|
|
430
|
+
message: resolveErrorMessage(
|
|
431
|
+
parsed,
|
|
432
|
+
`Athena gateway GET ${path} failed with status ${response.status}`
|
|
433
|
+
),
|
|
434
|
+
status: response.status,
|
|
435
|
+
method: "GET",
|
|
436
|
+
requestId,
|
|
437
|
+
hint: resolveErrorHint(parsed)
|
|
438
|
+
});
|
|
439
|
+
return {
|
|
440
|
+
ok: false,
|
|
441
|
+
reachable: true,
|
|
442
|
+
status: response.status,
|
|
443
|
+
statusText: resolveStatusText(response, parsed),
|
|
444
|
+
baseUrl,
|
|
445
|
+
url,
|
|
446
|
+
error: httpError.message,
|
|
447
|
+
errorDetails: detailsFromError(httpError),
|
|
448
|
+
raw: parsed
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
return {
|
|
452
|
+
ok: true,
|
|
453
|
+
reachable: true,
|
|
454
|
+
status: response.status,
|
|
455
|
+
statusText: resolveStatusText(response, parsed),
|
|
456
|
+
baseUrl,
|
|
457
|
+
url,
|
|
458
|
+
error: void 0,
|
|
459
|
+
errorDetails: null,
|
|
460
|
+
raw: parsed
|
|
461
|
+
};
|
|
462
|
+
} catch (callError) {
|
|
463
|
+
const message = callError instanceof Error ? callError.message : String(callError);
|
|
464
|
+
const networkError = new AthenaGatewayError({
|
|
465
|
+
code: "NETWORK_ERROR",
|
|
466
|
+
message: `Network error while probing Athena gateway ${url}: ${message}`,
|
|
467
|
+
method: "GET",
|
|
468
|
+
cause: message,
|
|
469
|
+
hint: "Check gateway URL, DNS, and network reachability."
|
|
470
|
+
});
|
|
471
|
+
return {
|
|
472
|
+
ok: false,
|
|
473
|
+
reachable: false,
|
|
474
|
+
status: 0,
|
|
475
|
+
statusText: null,
|
|
476
|
+
baseUrl,
|
|
477
|
+
url,
|
|
478
|
+
error: networkError.message,
|
|
479
|
+
errorDetails: detailsFromError(networkError),
|
|
480
|
+
raw: null
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
async function verifyAthenaGatewayUrl(baseUrl, options) {
|
|
485
|
+
const normalizedBaseUrl = normalizeAthenaGatewayBaseUrl(baseUrl);
|
|
486
|
+
return performConnectionCheck(normalizedBaseUrl, { "X-Athena-Sdk": SDK_HEADER_VALUE }, options);
|
|
487
|
+
}
|
|
248
488
|
async function callAthena(config, endpoint, method, payload, options) {
|
|
249
|
-
|
|
250
|
-
|
|
489
|
+
let baseUrl;
|
|
490
|
+
try {
|
|
491
|
+
baseUrl = resolveGatewayBaseUrl(options?.baseUrl ?? config.baseUrl);
|
|
492
|
+
} catch (error) {
|
|
493
|
+
return toInvalidUrlResponse(error, endpoint, method);
|
|
494
|
+
}
|
|
495
|
+
const url = buildAthenaGatewayUrl(baseUrl, endpoint);
|
|
251
496
|
const headers = buildHeaders(config, options);
|
|
252
497
|
try {
|
|
253
498
|
const requestInit = {
|
|
@@ -278,6 +523,7 @@ async function callAthena(config, endpoint, method, payload, options) {
|
|
|
278
523
|
return {
|
|
279
524
|
ok: false,
|
|
280
525
|
status: response.status,
|
|
526
|
+
statusText: resolveStatusText(response, parsedBody.parsed),
|
|
281
527
|
data: null,
|
|
282
528
|
error: invalidJsonError.message,
|
|
283
529
|
errorDetails: detailsFromError(invalidJsonError),
|
|
@@ -296,11 +542,13 @@ async function callAthena(config, endpoint, method, payload, options) {
|
|
|
296
542
|
status: response.status,
|
|
297
543
|
endpoint,
|
|
298
544
|
method,
|
|
299
|
-
requestId
|
|
545
|
+
requestId,
|
|
546
|
+
hint: resolveErrorHint(parsed)
|
|
300
547
|
});
|
|
301
548
|
return {
|
|
302
549
|
ok: false,
|
|
303
550
|
status: response.status,
|
|
551
|
+
statusText: resolveStatusText(response, parsed),
|
|
304
552
|
data: null,
|
|
305
553
|
error: httpError.message,
|
|
306
554
|
errorDetails: detailsFromError(httpError),
|
|
@@ -312,6 +560,7 @@ async function callAthena(config, endpoint, method, payload, options) {
|
|
|
312
560
|
return {
|
|
313
561
|
ok: true,
|
|
314
562
|
status: response.status,
|
|
563
|
+
statusText: resolveStatusText(response, parsed),
|
|
315
564
|
data: payloadData ?? null,
|
|
316
565
|
count: payloadCount,
|
|
317
566
|
error: void 0,
|
|
@@ -331,6 +580,7 @@ async function callAthena(config, endpoint, method, payload, options) {
|
|
|
331
580
|
return {
|
|
332
581
|
ok: false,
|
|
333
582
|
status: 0,
|
|
583
|
+
statusText: null,
|
|
334
584
|
data: null,
|
|
335
585
|
error: networkError.message,
|
|
336
586
|
errorDetails: detailsFromError(networkError),
|
|
@@ -339,32 +589,44 @@ async function callAthena(config, endpoint, method, payload, options) {
|
|
|
339
589
|
}
|
|
340
590
|
}
|
|
341
591
|
function createAthenaGatewayClient(config = {}) {
|
|
592
|
+
const normalizedBaseUrl = resolveGatewayBaseUrl(config.baseUrl);
|
|
593
|
+
const normalizedConfig = {
|
|
594
|
+
...config,
|
|
595
|
+
baseUrl: normalizedBaseUrl
|
|
596
|
+
};
|
|
342
597
|
return {
|
|
343
|
-
baseUrl:
|
|
598
|
+
baseUrl: normalizedBaseUrl,
|
|
344
599
|
buildHeaders(options) {
|
|
345
|
-
return buildHeaders(
|
|
600
|
+
return buildHeaders(normalizedConfig, options);
|
|
601
|
+
},
|
|
602
|
+
verifyConnection(options) {
|
|
603
|
+
return performConnectionCheck(
|
|
604
|
+
normalizedBaseUrl,
|
|
605
|
+
buildHeaders(normalizedConfig),
|
|
606
|
+
options
|
|
607
|
+
);
|
|
346
608
|
},
|
|
347
609
|
fetchGateway(payload, options) {
|
|
348
|
-
return callAthena(
|
|
610
|
+
return callAthena(normalizedConfig, "/gateway/fetch", "POST", payload, options);
|
|
349
611
|
},
|
|
350
612
|
insertGateway(payload, options) {
|
|
351
|
-
return callAthena(
|
|
613
|
+
return callAthena(normalizedConfig, "/gateway/insert", "PUT", payload, options);
|
|
352
614
|
},
|
|
353
615
|
updateGateway(payload, options) {
|
|
354
|
-
return callAthena(
|
|
616
|
+
return callAthena(normalizedConfig, "/gateway/update", "POST", payload, options);
|
|
355
617
|
},
|
|
356
618
|
deleteGateway(payload, options) {
|
|
357
|
-
return callAthena(
|
|
619
|
+
return callAthena(normalizedConfig, "/gateway/delete", "DELETE", payload, options);
|
|
358
620
|
},
|
|
359
621
|
rpcGateway(payload, options) {
|
|
360
622
|
if (options?.get) {
|
|
361
623
|
const endpoint = buildRpcGetEndpoint(payload);
|
|
362
|
-
return callAthena(
|
|
624
|
+
return callAthena(normalizedConfig, endpoint, "GET", null, options);
|
|
363
625
|
}
|
|
364
|
-
return callAthena(
|
|
626
|
+
return callAthena(normalizedConfig, "/gateway/rpc", "POST", payload, options);
|
|
365
627
|
},
|
|
366
628
|
queryGateway(payload, options) {
|
|
367
|
-
return callAthena(
|
|
629
|
+
return callAthena(normalizedConfig, "/gateway/query", "POST", payload, options);
|
|
368
630
|
}
|
|
369
631
|
};
|
|
370
632
|
}
|
|
@@ -372,10 +634,29 @@ function createAthenaGatewayClient(config = {}) {
|
|
|
372
634
|
// src/sql-identifiers.ts
|
|
373
635
|
var SIMPLE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
374
636
|
var COMPOSITE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/;
|
|
375
|
-
var
|
|
637
|
+
var SQL_ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
|
|
638
|
+
var RESPONSE_ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([A-Za-z_][A-Za-z0-9_.]*)$/i;
|
|
376
639
|
function quoteIdentifierSegment(identifier2) {
|
|
377
640
|
return `"${identifier2.replace(/"/g, '""')}"`;
|
|
378
641
|
}
|
|
642
|
+
function parseAliasedIdentifierToken(token) {
|
|
643
|
+
const responseAliasMatch = RESPONSE_ALIAS_PATTERN.exec(token);
|
|
644
|
+
if (responseAliasMatch) {
|
|
645
|
+
const [, aliasIdentifier2, baseIdentifier2] = responseAliasMatch;
|
|
646
|
+
if (COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier2) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier2)) {
|
|
647
|
+
return { baseIdentifier: baseIdentifier2, aliasIdentifier: aliasIdentifier2 };
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
const sqlAliasMatch = SQL_ALIAS_PATTERN.exec(token);
|
|
651
|
+
if (!sqlAliasMatch) {
|
|
652
|
+
return null;
|
|
653
|
+
}
|
|
654
|
+
const [, baseIdentifier, aliasIdentifier] = sqlAliasMatch;
|
|
655
|
+
if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
|
|
656
|
+
return null;
|
|
657
|
+
}
|
|
658
|
+
return { baseIdentifier, aliasIdentifier };
|
|
659
|
+
}
|
|
379
660
|
function quoteQualifiedIdentifier(identifier2) {
|
|
380
661
|
return identifier2.split(".").map((segment) => quoteIdentifierSegment(segment)).join(".");
|
|
381
662
|
}
|
|
@@ -384,23 +665,27 @@ function quoteSelectToken(token) {
|
|
|
384
665
|
if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) {
|
|
385
666
|
return quoteQualifiedIdentifier(token);
|
|
386
667
|
}
|
|
387
|
-
const
|
|
388
|
-
if (!
|
|
389
|
-
return token;
|
|
390
|
-
}
|
|
391
|
-
const [, baseIdentifier, aliasIdentifier] = aliasMatch;
|
|
392
|
-
if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
|
|
668
|
+
const aliasedIdentifier = parseAliasedIdentifierToken(token);
|
|
669
|
+
if (!aliasedIdentifier) {
|
|
393
670
|
return token;
|
|
394
671
|
}
|
|
672
|
+
const { baseIdentifier, aliasIdentifier } = aliasedIdentifier;
|
|
395
673
|
return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
|
|
396
674
|
}
|
|
675
|
+
function quoteSelectColumnToken(token) {
|
|
676
|
+
const trimmed = token.trim();
|
|
677
|
+
if (!trimmed || trimmed === "*") return trimmed || "*";
|
|
678
|
+
const responseAliasMatch = RESPONSE_ALIAS_PATTERN.exec(trimmed);
|
|
679
|
+
if (responseAliasMatch) {
|
|
680
|
+
const [, aliasIdentifier, baseIdentifier] = responseAliasMatch;
|
|
681
|
+
return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
|
|
682
|
+
}
|
|
683
|
+
return quoteQualifiedIdentifier(trimmed);
|
|
684
|
+
}
|
|
397
685
|
function canAutoQuoteToken(token) {
|
|
398
686
|
if (token === "*") return true;
|
|
399
687
|
if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) return true;
|
|
400
|
-
|
|
401
|
-
if (!aliasMatch) return false;
|
|
402
|
-
const [, baseIdentifier, aliasIdentifier] = aliasMatch;
|
|
403
|
-
return COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier);
|
|
688
|
+
return parseAliasedIdentifierToken(token) != null;
|
|
404
689
|
}
|
|
405
690
|
function splitTopLevelCommaSeparated(input) {
|
|
406
691
|
const parts = [];
|
|
@@ -500,6 +785,231 @@ function identifier(...segments) {
|
|
|
500
785
|
return new SqlIdentifierPath(expandedSegments);
|
|
501
786
|
}
|
|
502
787
|
|
|
788
|
+
// src/auth/react-email.ts
|
|
789
|
+
var reactEmailRenderModulePromise;
|
|
790
|
+
function isRecord2(value) {
|
|
791
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
792
|
+
}
|
|
793
|
+
function isFunction(value) {
|
|
794
|
+
return typeof value === "function";
|
|
795
|
+
}
|
|
796
|
+
function toStringOrUndefined(value) {
|
|
797
|
+
if (typeof value !== "string") return void 0;
|
|
798
|
+
return value;
|
|
799
|
+
}
|
|
800
|
+
function nowIsoString() {
|
|
801
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
802
|
+
}
|
|
803
|
+
function emitReactEmailEvent(observe, phase, input = {}) {
|
|
804
|
+
if (!observe) return;
|
|
805
|
+
try {
|
|
806
|
+
observe({
|
|
807
|
+
phase,
|
|
808
|
+
timestamp: nowIsoString(),
|
|
809
|
+
...input
|
|
810
|
+
});
|
|
811
|
+
} catch {
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
function mergeRenderDefaults(input, defaults) {
|
|
815
|
+
return {
|
|
816
|
+
...input,
|
|
817
|
+
pretty: input.pretty ?? defaults?.pretty,
|
|
818
|
+
includePlainText: input.includePlainText ?? defaults?.includePlainText
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
function mergeRuntimeOptions(options) {
|
|
822
|
+
if (!options) return void 0;
|
|
823
|
+
return {
|
|
824
|
+
defaults: options.defaults,
|
|
825
|
+
observe: options.observe,
|
|
826
|
+
route: "route" in options ? options.route : void 0
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
async function resolveReactEmailRenderModule() {
|
|
830
|
+
if (!reactEmailRenderModulePromise) {
|
|
831
|
+
reactEmailRenderModulePromise = (async () => {
|
|
832
|
+
try {
|
|
833
|
+
const loaded = await import('@react-email/render');
|
|
834
|
+
if (!isFunction(loaded.render)) {
|
|
835
|
+
throw new Error("missing render(...) export");
|
|
836
|
+
}
|
|
837
|
+
return {
|
|
838
|
+
render: loaded.render,
|
|
839
|
+
toPlainText: isFunction(loaded.toPlainText) ? loaded.toPlainText : void 0,
|
|
840
|
+
pretty: isFunction(loaded.pretty) ? loaded.pretty : void 0
|
|
841
|
+
};
|
|
842
|
+
} catch (error) {
|
|
843
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
844
|
+
throw new Error(
|
|
845
|
+
`React Email rendering requires @react-email/render. Install it in your project (for example: pnpm add @react-email/render). Loader error: ${message}`
|
|
846
|
+
);
|
|
847
|
+
}
|
|
848
|
+
})();
|
|
849
|
+
}
|
|
850
|
+
if (!reactEmailRenderModulePromise) {
|
|
851
|
+
throw new Error("React Email renderer module failed to initialize");
|
|
852
|
+
}
|
|
853
|
+
return reactEmailRenderModulePromise;
|
|
854
|
+
}
|
|
855
|
+
async function resolveReactEmailElement(input) {
|
|
856
|
+
if (input.element != null) {
|
|
857
|
+
return input.element;
|
|
858
|
+
}
|
|
859
|
+
if (!input.component) {
|
|
860
|
+
throw new Error("react email payload requires either `element` or `component`");
|
|
861
|
+
}
|
|
862
|
+
try {
|
|
863
|
+
const reactModule = await import('react');
|
|
864
|
+
if (typeof reactModule.createElement !== "function") {
|
|
865
|
+
throw new Error("react createElement(...) export is unavailable");
|
|
866
|
+
}
|
|
867
|
+
return reactModule.createElement(
|
|
868
|
+
input.component,
|
|
869
|
+
input.props ?? {}
|
|
870
|
+
);
|
|
871
|
+
} catch (error) {
|
|
872
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
873
|
+
throw new Error(
|
|
874
|
+
`React Email component rendering requires react runtime support. Install react in your project. Loader error: ${message}`
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
function createAuthReactEmailInput(component, props, overrides = {}) {
|
|
879
|
+
return {
|
|
880
|
+
...overrides,
|
|
881
|
+
component,
|
|
882
|
+
props
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
function defineAuthEmailTemplate(definition) {
|
|
886
|
+
const react = (props, overrides) => createAuthReactEmailInput(definition.component, props, {
|
|
887
|
+
...definition.defaults,
|
|
888
|
+
...overrides
|
|
889
|
+
});
|
|
890
|
+
return {
|
|
891
|
+
component: definition.component,
|
|
892
|
+
react,
|
|
893
|
+
toTemplateCreate: (input) => {
|
|
894
|
+
const templateKey = input.templateKey ?? definition.templateKey;
|
|
895
|
+
const subjectTemplate = input.subjectTemplate ?? definition.subjectTemplate;
|
|
896
|
+
if (!templateKey) {
|
|
897
|
+
throw new Error("defineAuthEmailTemplate.toTemplateCreate requires templateKey");
|
|
898
|
+
}
|
|
899
|
+
if (!subjectTemplate) {
|
|
900
|
+
throw new Error("defineAuthEmailTemplate.toTemplateCreate requires subjectTemplate");
|
|
901
|
+
}
|
|
902
|
+
const { props, react: reactOverrides, ...rest } = input;
|
|
903
|
+
return {
|
|
904
|
+
...rest,
|
|
905
|
+
templateKey,
|
|
906
|
+
subjectTemplate,
|
|
907
|
+
react: react(props, reactOverrides)
|
|
908
|
+
};
|
|
909
|
+
},
|
|
910
|
+
toTemplateUpdate: (input) => {
|
|
911
|
+
const { props, react: reactOverrides, ...rest } = input;
|
|
912
|
+
return {
|
|
913
|
+
...rest,
|
|
914
|
+
react: react(props, reactOverrides)
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
async function renderAthenaReactEmail(input, options) {
|
|
920
|
+
if (!isRecord2(input)) {
|
|
921
|
+
throw new Error("react email payload must be an object");
|
|
922
|
+
}
|
|
923
|
+
const runtimeOptions = mergeRuntimeOptions(options);
|
|
924
|
+
const start = Date.now();
|
|
925
|
+
emitReactEmailEvent(runtimeOptions?.observe, "render:start", {
|
|
926
|
+
route: runtimeOptions?.route,
|
|
927
|
+
message: "Rendering react email payload"
|
|
928
|
+
});
|
|
929
|
+
try {
|
|
930
|
+
const normalizedInput = mergeRenderDefaults(input, runtimeOptions?.defaults);
|
|
931
|
+
const element = await resolveReactEmailElement(normalizedInput);
|
|
932
|
+
const renderModule = await resolveReactEmailRenderModule();
|
|
933
|
+
const htmlValue = await renderModule.render(element);
|
|
934
|
+
const renderedHtml = typeof htmlValue === "string" ? htmlValue : String(htmlValue ?? "");
|
|
935
|
+
if (!renderedHtml.trim()) {
|
|
936
|
+
throw new Error("react email renderer returned an empty HTML string");
|
|
937
|
+
}
|
|
938
|
+
let html = renderedHtml;
|
|
939
|
+
if (normalizedInput.pretty && renderModule.pretty) {
|
|
940
|
+
const prettyValue = await renderModule.pretty(renderedHtml);
|
|
941
|
+
if (typeof prettyValue === "string" && prettyValue.trim().length > 0) {
|
|
942
|
+
html = prettyValue;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
const explicitText = toStringOrUndefined(normalizedInput.text);
|
|
946
|
+
if (explicitText !== void 0) {
|
|
947
|
+
emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
|
|
948
|
+
route: runtimeOptions?.route,
|
|
949
|
+
durationMs: Date.now() - start,
|
|
950
|
+
message: "Rendered react email with explicit text"
|
|
951
|
+
});
|
|
952
|
+
return {
|
|
953
|
+
html,
|
|
954
|
+
text: explicitText
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
if (normalizedInput.includePlainText === false || !renderModule.toPlainText) {
|
|
958
|
+
emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
|
|
959
|
+
route: runtimeOptions?.route,
|
|
960
|
+
durationMs: Date.now() - start,
|
|
961
|
+
message: "Rendered react email without plain-text derivation"
|
|
962
|
+
});
|
|
963
|
+
return { html };
|
|
964
|
+
}
|
|
965
|
+
const plainTextValue = await renderModule.toPlainText(html);
|
|
966
|
+
const plainText = toStringOrUndefined(plainTextValue);
|
|
967
|
+
emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
|
|
968
|
+
route: runtimeOptions?.route,
|
|
969
|
+
durationMs: Date.now() - start,
|
|
970
|
+
message: plainText ? "Rendered react email with derived plain text" : "Rendered react email HTML only"
|
|
971
|
+
});
|
|
972
|
+
if (plainText === void 0) {
|
|
973
|
+
return { html };
|
|
974
|
+
}
|
|
975
|
+
return {
|
|
976
|
+
html,
|
|
977
|
+
text: plainText
|
|
978
|
+
};
|
|
979
|
+
} catch (error) {
|
|
980
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
981
|
+
emitReactEmailEvent(runtimeOptions?.observe, "render:error", {
|
|
982
|
+
route: runtimeOptions?.route,
|
|
983
|
+
durationMs: Date.now() - start,
|
|
984
|
+
error: message,
|
|
985
|
+
message: "Failed to render react email payload"
|
|
986
|
+
});
|
|
987
|
+
throw error;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
async function resolveReactEmailPayloadFields(input, fields, options) {
|
|
991
|
+
const { react, ...payloadWithoutReact } = input;
|
|
992
|
+
if (!react) {
|
|
993
|
+
return payloadWithoutReact;
|
|
994
|
+
}
|
|
995
|
+
const rendered = await renderAthenaReactEmail(react, options);
|
|
996
|
+
const payload = {
|
|
997
|
+
...payloadWithoutReact
|
|
998
|
+
};
|
|
999
|
+
payload[fields.htmlField] = rendered.html;
|
|
1000
|
+
const currentTextValue = payload[fields.textField];
|
|
1001
|
+
if (rendered.text !== void 0 && (currentTextValue === void 0 || currentTextValue === null || currentTextValue === "")) {
|
|
1002
|
+
payload[fields.textField] = rendered.text;
|
|
1003
|
+
}
|
|
1004
|
+
if (fields.variablesField && (payload[fields.variablesField] === void 0 || payload[fields.variablesField] === null) && isRecord2(react.props)) {
|
|
1005
|
+
const derivedVariables = Object.keys(react.props);
|
|
1006
|
+
if (derivedVariables.length > 0) {
|
|
1007
|
+
payload[fields.variablesField] = derivedVariables;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
return payload;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
503
1013
|
// src/auth/client.ts
|
|
504
1014
|
var DEFAULT_AUTH_BASE_URL = "http://localhost:3001/api/auth";
|
|
505
1015
|
var FALLBACK_SDK_VERSION2 = "1.0.0";
|
|
@@ -509,7 +1019,7 @@ var SDK_HEADER_VALUE2 = `${SDK_NAME2} ${SDK_VERSION2}`;
|
|
|
509
1019
|
function normalizeBaseUrl(baseUrl) {
|
|
510
1020
|
return (baseUrl ?? DEFAULT_AUTH_BASE_URL).replace(/\/$/, "");
|
|
511
1021
|
}
|
|
512
|
-
function
|
|
1022
|
+
function isRecord3(value) {
|
|
513
1023
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
514
1024
|
}
|
|
515
1025
|
function normalizeHeaderValue2(value) {
|
|
@@ -534,7 +1044,7 @@ function resolveRequestId2(headers) {
|
|
|
534
1044
|
return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
|
|
535
1045
|
}
|
|
536
1046
|
function resolveErrorMessage2(payload, fallback) {
|
|
537
|
-
if (
|
|
1047
|
+
if (isRecord3(payload)) {
|
|
538
1048
|
const messageCandidates = [payload.error, payload.message, payload.details];
|
|
539
1049
|
for (const candidate of messageCandidates) {
|
|
540
1050
|
if (typeof candidate === "string" && candidate.trim().length > 0) {
|
|
@@ -860,6 +1370,19 @@ function createAuthClient(config = {}) {
|
|
|
860
1370
|
options
|
|
861
1371
|
);
|
|
862
1372
|
};
|
|
1373
|
+
const withReactEmailRoute = (route) => ({
|
|
1374
|
+
...resolvedConfig.reactEmail,
|
|
1375
|
+
route
|
|
1376
|
+
});
|
|
1377
|
+
const resolveAdminEmailPayload = (route, input) => resolveReactEmailPayloadFields(input, {
|
|
1378
|
+
htmlField: "htmlBody",
|
|
1379
|
+
textField: "textBody"
|
|
1380
|
+
}, withReactEmailRoute(route));
|
|
1381
|
+
const resolveAdminEmailTemplatePayload = (route, input) => resolveReactEmailPayloadFields(input, {
|
|
1382
|
+
htmlField: "htmlTemplate",
|
|
1383
|
+
textField: "textTemplate",
|
|
1384
|
+
variablesField: "variables"
|
|
1385
|
+
}, withReactEmailRoute(route));
|
|
863
1386
|
const listUserEmailsWithFallback = async (input, options) => {
|
|
864
1387
|
const primary = await getWithQuery(
|
|
865
1388
|
"/email/list",
|
|
@@ -887,7 +1410,7 @@ function createAuthClient(config = {}) {
|
|
|
887
1410
|
data: null
|
|
888
1411
|
};
|
|
889
1412
|
}
|
|
890
|
-
const fallbackStatus =
|
|
1413
|
+
const fallbackStatus = isRecord3(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
|
|
891
1414
|
return {
|
|
892
1415
|
...fallback,
|
|
893
1416
|
data: {
|
|
@@ -1323,8 +1846,16 @@ function createAuthClient(config = {}) {
|
|
|
1323
1846
|
email: {
|
|
1324
1847
|
list: (input, options) => getWithQuery("/admin/email/list", input, options),
|
|
1325
1848
|
get: (input, options) => getWithQuery("/admin/email/get", input, options),
|
|
1326
|
-
create: (input, options) => postGeneric(
|
|
1327
|
-
|
|
1849
|
+
create: async (input, options) => postGeneric(
|
|
1850
|
+
"/admin/email/create",
|
|
1851
|
+
await resolveAdminEmailPayload("/admin/email/create", input),
|
|
1852
|
+
options
|
|
1853
|
+
),
|
|
1854
|
+
update: async (input, options) => postGeneric(
|
|
1855
|
+
"/admin/email/update",
|
|
1856
|
+
await resolveAdminEmailPayload("/admin/email/update", input),
|
|
1857
|
+
options
|
|
1858
|
+
),
|
|
1328
1859
|
delete: (input, options) => postGeneric("/admin/email/delete", input, options),
|
|
1329
1860
|
failure: {
|
|
1330
1861
|
list: (input, options) => getWithQuery("/admin/email-failure/list", input, options),
|
|
@@ -1336,17 +1867,33 @@ function createAuthClient(config = {}) {
|
|
|
1336
1867
|
template: {
|
|
1337
1868
|
list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
|
|
1338
1869
|
get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
|
|
1339
|
-
create: (input, options) => postGeneric(
|
|
1340
|
-
|
|
1870
|
+
create: async (input, options) => postGeneric(
|
|
1871
|
+
"/admin/email-template/create",
|
|
1872
|
+
await resolveAdminEmailTemplatePayload("/admin/email-template/create", input),
|
|
1873
|
+
options
|
|
1874
|
+
),
|
|
1875
|
+
update: async (input, options) => postGeneric(
|
|
1876
|
+
"/admin/email-template/update",
|
|
1877
|
+
await resolveAdminEmailTemplatePayload("/admin/email-template/update", input),
|
|
1878
|
+
options
|
|
1879
|
+
),
|
|
1341
1880
|
delete: (input, options) => postGeneric("/admin/email-template/delete", input, options)
|
|
1342
1881
|
}
|
|
1343
1882
|
},
|
|
1344
1883
|
emailTemplate: {
|
|
1345
1884
|
get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
|
|
1346
|
-
create: (input, options) => postGeneric(
|
|
1885
|
+
create: async (input, options) => postGeneric(
|
|
1886
|
+
"/admin/email-template/create",
|
|
1887
|
+
await resolveAdminEmailTemplatePayload("/admin/email-template/create", input),
|
|
1888
|
+
options
|
|
1889
|
+
),
|
|
1347
1890
|
delete: (input, options) => postGeneric("/admin/email-template/delete", input, options),
|
|
1348
1891
|
list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
|
|
1349
|
-
update: (input, options) => postGeneric(
|
|
1892
|
+
update: async (input, options) => postGeneric(
|
|
1893
|
+
"/admin/email-template/update",
|
|
1894
|
+
await resolveAdminEmailTemplatePayload("/admin/email-template/update", input),
|
|
1895
|
+
options
|
|
1896
|
+
)
|
|
1350
1897
|
}
|
|
1351
1898
|
},
|
|
1352
1899
|
apiKey: {
|
|
@@ -1538,6 +2085,19 @@ function createAuthClient(config = {}) {
|
|
|
1538
2085
|
};
|
|
1539
2086
|
}
|
|
1540
2087
|
|
|
2088
|
+
// src/utils/parse-boolean-flag.ts
|
|
2089
|
+
function parseBooleanFlag(rawValue, fallback) {
|
|
2090
|
+
if (!rawValue) return fallback;
|
|
2091
|
+
const normalized = rawValue.trim().toLowerCase();
|
|
2092
|
+
if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
|
|
2093
|
+
return true;
|
|
2094
|
+
}
|
|
2095
|
+
if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
|
|
2096
|
+
return false;
|
|
2097
|
+
}
|
|
2098
|
+
return fallback;
|
|
2099
|
+
}
|
|
2100
|
+
|
|
1541
2101
|
// src/auxiliaries.ts
|
|
1542
2102
|
var AthenaErrorKind = {
|
|
1543
2103
|
UniqueViolation: "unique_violation",
|
|
@@ -1567,16 +2127,8 @@ var AthenaErrorCategory = {
|
|
|
1567
2127
|
Database: "database",
|
|
1568
2128
|
Unknown: "unknown"
|
|
1569
2129
|
};
|
|
1570
|
-
function
|
|
1571
|
-
|
|
1572
|
-
const normalized = rawValue.trim().toLowerCase();
|
|
1573
|
-
if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
|
|
1574
|
-
return true;
|
|
1575
|
-
}
|
|
1576
|
-
if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
|
|
1577
|
-
return false;
|
|
1578
|
-
}
|
|
1579
|
-
return fallback;
|
|
2130
|
+
function parseBooleanFlag2(rawValue, fallback) {
|
|
2131
|
+
return parseBooleanFlag(rawValue, fallback);
|
|
1580
2132
|
}
|
|
1581
2133
|
var AthenaError = class extends Error {
|
|
1582
2134
|
code;
|
|
@@ -1600,9 +2152,38 @@ var AthenaError = class extends Error {
|
|
|
1600
2152
|
this.raw = input.raw;
|
|
1601
2153
|
}
|
|
1602
2154
|
};
|
|
1603
|
-
function
|
|
2155
|
+
function isRecord4(value) {
|
|
1604
2156
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1605
2157
|
}
|
|
2158
|
+
function firstNonEmptyString(...values) {
|
|
2159
|
+
for (const value of values) {
|
|
2160
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
2161
|
+
return value.trim();
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
return void 0;
|
|
2165
|
+
}
|
|
2166
|
+
function messageFromUnknownError(error) {
|
|
2167
|
+
if (typeof error === "string" && error.trim().length > 0) {
|
|
2168
|
+
return error.trim();
|
|
2169
|
+
}
|
|
2170
|
+
if (error instanceof Error && error.message.trim().length > 0) {
|
|
2171
|
+
return error.message.trim();
|
|
2172
|
+
}
|
|
2173
|
+
if (!isRecord4(error)) {
|
|
2174
|
+
return void 0;
|
|
2175
|
+
}
|
|
2176
|
+
return firstNonEmptyString(error.message, error.error, error.details);
|
|
2177
|
+
}
|
|
2178
|
+
function gatewayCodeFromUnknownError(error) {
|
|
2179
|
+
if (!isRecord4(error) || typeof error.gatewayCode !== "string") {
|
|
2180
|
+
return void 0;
|
|
2181
|
+
}
|
|
2182
|
+
return error.gatewayCode;
|
|
2183
|
+
}
|
|
2184
|
+
function isAthenaResultErrorLike(value) {
|
|
2185
|
+
return isRecord4(value) && typeof value.message === "string" && (value.athenaCode === void 0 || isAthenaErrorCode(value.athenaCode)) && (value.kind === void 0 || isAthenaErrorKind(value.kind)) && (value.category === void 0 || isAthenaErrorCategory(value.category)) && (value.retryable === void 0 || typeof value.retryable === "boolean") && (value.status === void 0 || typeof value.status === "number");
|
|
2186
|
+
}
|
|
1606
2187
|
function isAthenaErrorKind(value) {
|
|
1607
2188
|
return value === "unique_violation" || value === "not_found" || value === "validation" || value === "auth" || value === "rate_limit" || value === "transient" || value === "unknown";
|
|
1608
2189
|
}
|
|
@@ -1613,7 +2194,7 @@ function isAthenaErrorCategory(value) {
|
|
|
1613
2194
|
return value === "transport" || value === "client" || value === "server" || value === "database" || value === "unknown";
|
|
1614
2195
|
}
|
|
1615
2196
|
function isNormalizedAthenaError(value) {
|
|
1616
|
-
return
|
|
2197
|
+
return isRecord4(value) && isAthenaErrorKind(value.kind) && isAthenaErrorCode(value.code) && isAthenaErrorCategory(value.category) && typeof value.retryable === "boolean" && typeof value.message === "string" && "raw" in value;
|
|
1617
2198
|
}
|
|
1618
2199
|
function withContextOverrides(normalized, context) {
|
|
1619
2200
|
if (!context?.table && !context?.operation) {
|
|
@@ -1626,7 +2207,7 @@ function withContextOverrides(normalized, context) {
|
|
|
1626
2207
|
};
|
|
1627
2208
|
}
|
|
1628
2209
|
function resolveAttachedNormalizedError(resultOrError) {
|
|
1629
|
-
if (!
|
|
2210
|
+
if (!isRecord4(resultOrError)) return void 0;
|
|
1630
2211
|
if (!("__athenaNormalizedError" in resultOrError)) return void 0;
|
|
1631
2212
|
const candidate = resultOrError.__athenaNormalizedError;
|
|
1632
2213
|
return isNormalizedAthenaError(candidate) ? candidate : void 0;
|
|
@@ -1645,7 +2226,7 @@ function contextHint(context) {
|
|
|
1645
2226
|
return `Identity: ${identity}`;
|
|
1646
2227
|
}
|
|
1647
2228
|
function isAthenaResultLike(value) {
|
|
1648
|
-
return
|
|
2229
|
+
return isRecord4(value) && "status" in value && "error" in value && "data" in value && typeof value.status === "number";
|
|
1649
2230
|
}
|
|
1650
2231
|
function operationFromDetails(details) {
|
|
1651
2232
|
if (!details?.endpoint) return void 0;
|
|
@@ -1687,6 +2268,7 @@ function classifyKind(status, code, message) {
|
|
|
1687
2268
|
if (status === 404 || hasNotFoundPattern) return "not_found";
|
|
1688
2269
|
if (status === 401 || status === 403 || hasAuthPattern) return "auth";
|
|
1689
2270
|
if (status === 429 || hasRateLimitPattern) return "rate_limit";
|
|
2271
|
+
if (code === "INVALID_URL") return "validation";
|
|
1690
2272
|
if (status === 400 || status === 422 || hasValidationPattern) return "validation";
|
|
1691
2273
|
if (code === "NETWORK_ERROR" || status === 0 || status !== void 0 && status >= 500 || hasTransientPattern) {
|
|
1692
2274
|
return "transient";
|
|
@@ -1694,6 +2276,9 @@ function classifyKind(status, code, message) {
|
|
|
1694
2276
|
return "unknown";
|
|
1695
2277
|
}
|
|
1696
2278
|
function toAthenaErrorCode(kind, status, gatewayCode) {
|
|
2279
|
+
if (gatewayCode === "INVALID_URL") {
|
|
2280
|
+
return AthenaErrorCode.ValidationFailed;
|
|
2281
|
+
}
|
|
1697
2282
|
if (gatewayCode === "NETWORK_ERROR" || kind === "transient" && status === 0) {
|
|
1698
2283
|
return AthenaErrorCode.NetworkUnavailable;
|
|
1699
2284
|
}
|
|
@@ -1742,15 +2327,16 @@ function toAthenaGatewayError(source, fallbackMessage, context) {
|
|
|
1742
2327
|
return source;
|
|
1743
2328
|
}
|
|
1744
2329
|
if (isAthenaResultLike(source) && source.errorDetails) {
|
|
2330
|
+
const message2 = messageFromUnknownError(source.error) ?? source.errorDetails.message ?? fallbackMessage;
|
|
1745
2331
|
return new AthenaGatewayError({
|
|
1746
2332
|
code: source.errorDetails.code,
|
|
1747
|
-
message:
|
|
2333
|
+
message: message2,
|
|
1748
2334
|
status: source.status,
|
|
1749
2335
|
endpoint: source.errorDetails.endpoint,
|
|
1750
2336
|
method: source.errorDetails.method,
|
|
1751
2337
|
requestId: source.errorDetails.requestId,
|
|
1752
|
-
hint: source.errorDetails.hint,
|
|
1753
|
-
cause: source.errorDetails.cause
|
|
2338
|
+
hint: (isRecord4(source.error) ? firstNonEmptyString(source.error.hint) : void 0) ?? source.errorDetails.hint,
|
|
2339
|
+
cause: (isRecord4(source.error) ? firstNonEmptyString(source.error.cause) : void 0) ?? source.errorDetails.cause
|
|
1754
2340
|
});
|
|
1755
2341
|
}
|
|
1756
2342
|
const normalized = normalizeAthenaError(source, context);
|
|
@@ -1772,13 +2358,50 @@ function normalizeAthenaError(resultOrError, context) {
|
|
|
1772
2358
|
return withContextOverrides(attached, context);
|
|
1773
2359
|
}
|
|
1774
2360
|
if (isAthenaResultLike(resultOrError)) {
|
|
2361
|
+
if (isAthenaResultErrorLike(resultOrError.error)) {
|
|
2362
|
+
return {
|
|
2363
|
+
kind: resultOrError.error.kind ?? classifyKind(resultOrError.status, gatewayCodeFromUnknownError(resultOrError.error), resultOrError.error.message),
|
|
2364
|
+
code: resultOrError.error.athenaCode ?? toAthenaErrorCode(
|
|
2365
|
+
resultOrError.error.kind ?? classifyKind(
|
|
2366
|
+
resultOrError.status,
|
|
2367
|
+
gatewayCodeFromUnknownError(resultOrError.error),
|
|
2368
|
+
resultOrError.error.message
|
|
2369
|
+
),
|
|
2370
|
+
resultOrError.error.status ?? resultOrError.status,
|
|
2371
|
+
gatewayCodeFromUnknownError(resultOrError.error)
|
|
2372
|
+
),
|
|
2373
|
+
category: resultOrError.error.category ?? toAthenaErrorCategory(
|
|
2374
|
+
resultOrError.error.kind ?? classifyKind(
|
|
2375
|
+
resultOrError.status,
|
|
2376
|
+
gatewayCodeFromUnknownError(resultOrError.error),
|
|
2377
|
+
resultOrError.error.message
|
|
2378
|
+
),
|
|
2379
|
+
resultOrError.error.status ?? resultOrError.status
|
|
2380
|
+
),
|
|
2381
|
+
retryable: resultOrError.error.retryable ?? isRetryable(
|
|
2382
|
+
resultOrError.error.kind ?? classifyKind(
|
|
2383
|
+
resultOrError.status,
|
|
2384
|
+
gatewayCodeFromUnknownError(resultOrError.error),
|
|
2385
|
+
resultOrError.error.message
|
|
2386
|
+
),
|
|
2387
|
+
resultOrError.error.status ?? resultOrError.status
|
|
2388
|
+
),
|
|
2389
|
+
status: resultOrError.error.status ?? resultOrError.status,
|
|
2390
|
+
constraint: resultOrError.error.constraint,
|
|
2391
|
+
table: context?.table ?? resultOrError.error.table,
|
|
2392
|
+
operation: context?.operation ?? resultOrError.error.operation,
|
|
2393
|
+
message: resultOrError.error.message,
|
|
2394
|
+
raw: resultOrError.error.raw ?? resultOrError.raw
|
|
2395
|
+
};
|
|
2396
|
+
}
|
|
1775
2397
|
const details = resultOrError.errorDetails;
|
|
1776
|
-
const message2 = resultOrError.error ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
|
|
2398
|
+
const message2 = messageFromUnknownError(resultOrError.error) ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
|
|
1777
2399
|
const operation = context?.operation ?? operationFromDetails(details);
|
|
1778
2400
|
const table = context?.table ?? extractTable(message2);
|
|
1779
2401
|
const constraint = extractConstraint(message2);
|
|
1780
|
-
const
|
|
1781
|
-
const
|
|
2402
|
+
const gatewayCode = details?.code ?? gatewayCodeFromUnknownError(resultOrError.error);
|
|
2403
|
+
const kind2 = classifyKind(resultOrError.status, gatewayCode, message2);
|
|
2404
|
+
const code = toAthenaErrorCode(kind2, resultOrError.status, gatewayCode);
|
|
1782
2405
|
const category = toAthenaErrorCategory(kind2, resultOrError.status);
|
|
1783
2406
|
return {
|
|
1784
2407
|
kind: kind2,
|
|
@@ -1815,7 +2438,7 @@ function normalizeAthenaError(resultOrError, context) {
|
|
|
1815
2438
|
};
|
|
1816
2439
|
}
|
|
1817
2440
|
if (resultOrError instanceof Error) {
|
|
1818
|
-
const maybeStatus =
|
|
2441
|
+
const maybeStatus = isRecord4(resultOrError) && typeof resultOrError.status === "number" ? resultOrError.status : void 0;
|
|
1819
2442
|
const kind2 = classifyKind(maybeStatus, void 0, resultOrError.message);
|
|
1820
2443
|
return {
|
|
1821
2444
|
kind: kind2,
|
|
@@ -2004,8 +2627,8 @@ async function withRetry(config, fn) {
|
|
|
2004
2627
|
// src/db/module.ts
|
|
2005
2628
|
function createDbModule(input) {
|
|
2006
2629
|
const db = {
|
|
2007
|
-
from(table) {
|
|
2008
|
-
return input.from(table);
|
|
2630
|
+
from(table, options) {
|
|
2631
|
+
return input.from(table, options);
|
|
2009
2632
|
},
|
|
2010
2633
|
select(table, columns, options) {
|
|
2011
2634
|
return input.from(table).select(columns, options);
|
|
@@ -2032,17 +2655,551 @@ function createDbModule(input) {
|
|
|
2032
2655
|
return db;
|
|
2033
2656
|
}
|
|
2034
2657
|
|
|
2658
|
+
// src/query-ast.ts
|
|
2659
|
+
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;
|
|
2660
|
+
var FILTER_OPERATORS = /* @__PURE__ */ new Set([
|
|
2661
|
+
"eq",
|
|
2662
|
+
"neq",
|
|
2663
|
+
"gt",
|
|
2664
|
+
"gte",
|
|
2665
|
+
"lt",
|
|
2666
|
+
"lte",
|
|
2667
|
+
"like",
|
|
2668
|
+
"ilike",
|
|
2669
|
+
"is",
|
|
2670
|
+
"in",
|
|
2671
|
+
"contains",
|
|
2672
|
+
"containedBy"
|
|
2673
|
+
]);
|
|
2674
|
+
var BOOLEAN_SAFE_OPERATORS = /* @__PURE__ */ new Set([
|
|
2675
|
+
"eq",
|
|
2676
|
+
"neq",
|
|
2677
|
+
"gt",
|
|
2678
|
+
"gte",
|
|
2679
|
+
"lt",
|
|
2680
|
+
"lte",
|
|
2681
|
+
"like",
|
|
2682
|
+
"ilike",
|
|
2683
|
+
"is"
|
|
2684
|
+
]);
|
|
2685
|
+
function isRecord5(value) {
|
|
2686
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2687
|
+
}
|
|
2688
|
+
function isUuidString(value) {
|
|
2689
|
+
return UUID_PATTERN.test(value.trim());
|
|
2690
|
+
}
|
|
2691
|
+
function isUuidIdentifierColumn(column) {
|
|
2692
|
+
return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
|
|
2693
|
+
}
|
|
2694
|
+
function shouldUseUuidTextComparison(column, value) {
|
|
2695
|
+
return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
|
|
2696
|
+
}
|
|
2697
|
+
function isRelationSelectNode(value) {
|
|
2698
|
+
return isRecord5(value) && isRecord5(value.select);
|
|
2699
|
+
}
|
|
2700
|
+
function normalizeIdentifier(value, label) {
|
|
2701
|
+
const normalized = value.trim();
|
|
2702
|
+
if (!normalized) {
|
|
2703
|
+
throw new Error(`${label} must be a non-empty string`);
|
|
2704
|
+
}
|
|
2705
|
+
return normalized;
|
|
2706
|
+
}
|
|
2707
|
+
function stringifyFilterValue(value) {
|
|
2708
|
+
if (Array.isArray(value)) {
|
|
2709
|
+
return value.join(",");
|
|
2710
|
+
}
|
|
2711
|
+
return String(value);
|
|
2712
|
+
}
|
|
2713
|
+
function buildGatewayCondition(operator, column, value) {
|
|
2714
|
+
const condition = { operator };
|
|
2715
|
+
if (column) {
|
|
2716
|
+
condition.column = column;
|
|
2717
|
+
if (operator === "eq") {
|
|
2718
|
+
condition.eq_column = column;
|
|
2719
|
+
}
|
|
2720
|
+
}
|
|
2721
|
+
if (value !== void 0) {
|
|
2722
|
+
condition.value = value;
|
|
2723
|
+
if (operator === "eq") {
|
|
2724
|
+
condition.eq_value = value;
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
if (operator === "eq" && column && value !== void 0 && shouldUseUuidTextComparison(column, value)) {
|
|
2728
|
+
condition.column_cast = "text";
|
|
2729
|
+
condition.eq_column_cast = "text";
|
|
2730
|
+
}
|
|
2731
|
+
return condition;
|
|
2732
|
+
}
|
|
2733
|
+
function compileRelationToken(key, node) {
|
|
2734
|
+
const nested = compileSelectShape(node.select);
|
|
2735
|
+
const propertyKey = normalizeIdentifier(key, "select relation key");
|
|
2736
|
+
if (node.schema && node.via) {
|
|
2737
|
+
throw new Error(
|
|
2738
|
+
`findMany relation "${propertyKey}" cannot combine schema and via yet; use schema with the relation key, or use via without schema`
|
|
2739
|
+
);
|
|
2740
|
+
}
|
|
2741
|
+
const relationTokenBase = normalizeIdentifier(node.via ?? propertyKey, "select relation token");
|
|
2742
|
+
if (node.schema && relationTokenBase.includes(".")) {
|
|
2743
|
+
throw new Error(
|
|
2744
|
+
`findMany relation "${propertyKey}" already resolves to a qualified relation token; do not also set schema`
|
|
2745
|
+
);
|
|
2746
|
+
}
|
|
2747
|
+
const relationSchema = node.schema?.trim();
|
|
2748
|
+
const relationToken = relationSchema ? `${normalizeIdentifier(relationSchema, "select relation schema")}.${relationTokenBase}` : relationTokenBase;
|
|
2749
|
+
const alias = node.as?.trim() || (relationToken !== propertyKey ? propertyKey : "");
|
|
2750
|
+
const prefix = alias ? `${alias}:` : "";
|
|
2751
|
+
return `${prefix}${relationToken}(${nested})`;
|
|
2752
|
+
}
|
|
2753
|
+
function compileSelectShape(select) {
|
|
2754
|
+
if (!isRecord5(select)) {
|
|
2755
|
+
throw new Error("findMany select must be an object");
|
|
2756
|
+
}
|
|
2757
|
+
const tokens = [];
|
|
2758
|
+
for (const [rawKey, rawValue] of Object.entries(select)) {
|
|
2759
|
+
if (rawValue === void 0) {
|
|
2760
|
+
continue;
|
|
2761
|
+
}
|
|
2762
|
+
if (rawValue === true) {
|
|
2763
|
+
tokens.push(normalizeIdentifier(rawKey, "select column"));
|
|
2764
|
+
continue;
|
|
2765
|
+
}
|
|
2766
|
+
if (isRelationSelectNode(rawValue)) {
|
|
2767
|
+
tokens.push(compileRelationToken(rawKey, rawValue));
|
|
2768
|
+
continue;
|
|
2769
|
+
}
|
|
2770
|
+
throw new Error(`Unsupported select node for "${rawKey}"`);
|
|
2771
|
+
}
|
|
2772
|
+
if (tokens.length === 0) {
|
|
2773
|
+
throw new Error("findMany select requires at least one field");
|
|
2774
|
+
}
|
|
2775
|
+
return tokens.join(",");
|
|
2776
|
+
}
|
|
2777
|
+
function selectShapeUsesRelationSchema(select) {
|
|
2778
|
+
if (!isRecord5(select)) {
|
|
2779
|
+
return false;
|
|
2780
|
+
}
|
|
2781
|
+
for (const rawValue of Object.values(select)) {
|
|
2782
|
+
if (!isRelationSelectNode(rawValue)) {
|
|
2783
|
+
continue;
|
|
2784
|
+
}
|
|
2785
|
+
if (typeof rawValue.schema === "string" && rawValue.schema.trim().length > 0) {
|
|
2786
|
+
return true;
|
|
2787
|
+
}
|
|
2788
|
+
if (selectShapeUsesRelationSchema(rawValue.select)) {
|
|
2789
|
+
return true;
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
return false;
|
|
2793
|
+
}
|
|
2794
|
+
function compileColumnWhere(column, input) {
|
|
2795
|
+
const normalizedColumn = normalizeIdentifier(column, "where column");
|
|
2796
|
+
if (!isRecord5(input)) {
|
|
2797
|
+
return [buildGatewayCondition("eq", normalizedColumn, input)];
|
|
2798
|
+
}
|
|
2799
|
+
const conditions = [];
|
|
2800
|
+
for (const [rawOperator, rawValue] of Object.entries(input)) {
|
|
2801
|
+
if (rawValue === void 0) {
|
|
2802
|
+
continue;
|
|
2803
|
+
}
|
|
2804
|
+
if (!FILTER_OPERATORS.has(rawOperator)) {
|
|
2805
|
+
throw new Error(`Unsupported where operator "${rawOperator}" on "${normalizedColumn}"`);
|
|
2806
|
+
}
|
|
2807
|
+
if ((rawOperator === "in" || rawOperator === "contains" || rawOperator === "containedBy") && !Array.isArray(rawValue)) {
|
|
2808
|
+
throw new Error(`where.${normalizedColumn}.${rawOperator} requires an array value`);
|
|
2809
|
+
}
|
|
2810
|
+
conditions.push(
|
|
2811
|
+
buildGatewayCondition(
|
|
2812
|
+
rawOperator,
|
|
2813
|
+
normalizedColumn,
|
|
2814
|
+
rawValue
|
|
2815
|
+
)
|
|
2816
|
+
);
|
|
2817
|
+
}
|
|
2818
|
+
if (conditions.length === 0) {
|
|
2819
|
+
throw new Error(`where.${normalizedColumn} requires at least one operator`);
|
|
2820
|
+
}
|
|
2821
|
+
return conditions;
|
|
2822
|
+
}
|
|
2823
|
+
function compileBooleanExpressionTerms(clause, label) {
|
|
2824
|
+
if (!isRecord5(clause)) {
|
|
2825
|
+
throw new Error(`findMany where.${label} clauses must be objects`);
|
|
2826
|
+
}
|
|
2827
|
+
const entries = Object.entries(clause).filter(([, value]) => value !== void 0);
|
|
2828
|
+
if (entries.length !== 1) {
|
|
2829
|
+
throw new Error(`findMany where.${label} clauses must target exactly one column`);
|
|
2830
|
+
}
|
|
2831
|
+
const [rawColumn, rawValue] = entries[0];
|
|
2832
|
+
const column = normalizeIdentifier(rawColumn, `where.${label} column`);
|
|
2833
|
+
if (!isRecord5(rawValue)) {
|
|
2834
|
+
return [`${column}.eq.${stringifyFilterValue(rawValue)}`];
|
|
2835
|
+
}
|
|
2836
|
+
const operatorEntries = Object.entries(rawValue).filter(([, value]) => value !== void 0);
|
|
2837
|
+
if (operatorEntries.length === 0) {
|
|
2838
|
+
throw new Error(`findMany where.${label}.${column} requires at least one operator`);
|
|
2839
|
+
}
|
|
2840
|
+
if (label === "not" && operatorEntries.length > 1) {
|
|
2841
|
+
throw new Error("findMany where.not only supports a single lossless operator expression");
|
|
2842
|
+
}
|
|
2843
|
+
return operatorEntries.map(([rawOperator, rawOperand]) => {
|
|
2844
|
+
if (!BOOLEAN_SAFE_OPERATORS.has(rawOperator)) {
|
|
2845
|
+
throw new Error(`findMany where.${label} only supports lossless scalar operators`);
|
|
2846
|
+
}
|
|
2847
|
+
if (Array.isArray(rawOperand)) {
|
|
2848
|
+
throw new Error(`findMany where.${label} does not support array-valued operators`);
|
|
2849
|
+
}
|
|
2850
|
+
return `${column}.${rawOperator}.${stringifyFilterValue(rawOperand)}`;
|
|
2851
|
+
});
|
|
2852
|
+
}
|
|
2853
|
+
function compileWhere(where) {
|
|
2854
|
+
if (where === void 0) {
|
|
2855
|
+
return void 0;
|
|
2856
|
+
}
|
|
2857
|
+
if (!isRecord5(where)) {
|
|
2858
|
+
throw new Error("findMany where must be an object");
|
|
2859
|
+
}
|
|
2860
|
+
const conditions = [];
|
|
2861
|
+
for (const [rawKey, rawValue] of Object.entries(where)) {
|
|
2862
|
+
if (rawValue === void 0) {
|
|
2863
|
+
continue;
|
|
2864
|
+
}
|
|
2865
|
+
if (rawKey === "or") {
|
|
2866
|
+
if (!Array.isArray(rawValue) || rawValue.length === 0) {
|
|
2867
|
+
throw new Error("findMany where.or must be a non-empty array");
|
|
2868
|
+
}
|
|
2869
|
+
const expressions = rawValue.flatMap(
|
|
2870
|
+
(value) => compileBooleanExpressionTerms(value, "or")
|
|
2871
|
+
);
|
|
2872
|
+
conditions.push(buildGatewayCondition("or", void 0, expressions.join(",")));
|
|
2873
|
+
continue;
|
|
2874
|
+
}
|
|
2875
|
+
if (rawKey === "not") {
|
|
2876
|
+
const expressions = compileBooleanExpressionTerms(rawValue, "not");
|
|
2877
|
+
if (expressions.length !== 1) {
|
|
2878
|
+
throw new Error("findMany where.not must compile to exactly one lossless expression");
|
|
2879
|
+
}
|
|
2880
|
+
conditions.push(buildGatewayCondition("not", void 0, expressions[0]));
|
|
2881
|
+
continue;
|
|
2882
|
+
}
|
|
2883
|
+
conditions.push(...compileColumnWhere(rawKey, rawValue));
|
|
2884
|
+
}
|
|
2885
|
+
return conditions.length > 0 ? conditions : void 0;
|
|
2886
|
+
}
|
|
2887
|
+
function resolveOrderDirection(input) {
|
|
2888
|
+
if (typeof input === "boolean") {
|
|
2889
|
+
return input === false ? "descending" : "ascending";
|
|
2890
|
+
}
|
|
2891
|
+
if (typeof input === "string") {
|
|
2892
|
+
const normalized = input.trim().toLowerCase();
|
|
2893
|
+
if (normalized === "asc" || normalized === "ascending") {
|
|
2894
|
+
return "ascending";
|
|
2895
|
+
}
|
|
2896
|
+
if (normalized === "desc" || normalized === "descending") {
|
|
2897
|
+
return "descending";
|
|
2898
|
+
}
|
|
2899
|
+
throw new Error(`Unsupported orderBy direction "${input}"`);
|
|
2900
|
+
}
|
|
2901
|
+
return input.ascending === false ? "descending" : "ascending";
|
|
2902
|
+
}
|
|
2903
|
+
function compileOrderBy(orderBy) {
|
|
2904
|
+
if (orderBy === void 0) {
|
|
2905
|
+
return void 0;
|
|
2906
|
+
}
|
|
2907
|
+
if (!isRecord5(orderBy)) {
|
|
2908
|
+
throw new Error("findMany orderBy must be an object");
|
|
2909
|
+
}
|
|
2910
|
+
if ("column" in orderBy) {
|
|
2911
|
+
return {
|
|
2912
|
+
field: normalizeIdentifier(String(orderBy.column), "orderBy column"),
|
|
2913
|
+
direction: orderBy.ascending === false ? "descending" : "ascending"
|
|
2914
|
+
};
|
|
2915
|
+
}
|
|
2916
|
+
const entries = Object.entries(orderBy).filter(([, value]) => value !== void 0);
|
|
2917
|
+
if (entries.length === 0) {
|
|
2918
|
+
return void 0;
|
|
2919
|
+
}
|
|
2920
|
+
if (entries.length > 1) {
|
|
2921
|
+
throw new Error("findMany orderBy only supports a single column in v1");
|
|
2922
|
+
}
|
|
2923
|
+
const [column, input] = entries[0];
|
|
2924
|
+
return {
|
|
2925
|
+
field: normalizeIdentifier(column, "orderBy column"),
|
|
2926
|
+
direction: resolveOrderDirection(input)
|
|
2927
|
+
};
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2930
|
+
// src/gateway/structured-select.ts
|
|
2931
|
+
var IDENTIFIER_SEGMENT_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
2932
|
+
function isIdentifierPath(value) {
|
|
2933
|
+
const segments = value.split(".").map((segment) => segment.trim());
|
|
2934
|
+
return segments.length > 1 && segments.every((segment) => IDENTIFIER_SEGMENT_PATTERN.test(segment));
|
|
2935
|
+
}
|
|
2936
|
+
function extractRelationHead(raw) {
|
|
2937
|
+
const trimmed = raw.trim();
|
|
2938
|
+
if (!trimmed) return "";
|
|
2939
|
+
const aliasIndex = trimmed.indexOf(":");
|
|
2940
|
+
const withoutAlias = aliasIndex >= 0 ? trimmed.slice(aliasIndex + 1).trim() : trimmed;
|
|
2941
|
+
const modifierIndex = withoutAlias.indexOf("!");
|
|
2942
|
+
return (modifierIndex >= 0 ? withoutAlias.slice(0, modifierIndex) : withoutAlias).trim();
|
|
2943
|
+
}
|
|
2944
|
+
function hasSchemaQualifiedRelationToken(select) {
|
|
2945
|
+
let singleQuoted = false;
|
|
2946
|
+
let doubleQuoted = false;
|
|
2947
|
+
let tokenStart = 0;
|
|
2948
|
+
for (let index = 0; index < select.length; index += 1) {
|
|
2949
|
+
const char = select[index];
|
|
2950
|
+
const next = index + 1 < select.length ? select[index + 1] : "";
|
|
2951
|
+
if (singleQuoted) {
|
|
2952
|
+
if (char === "'" && next === "'") {
|
|
2953
|
+
index += 1;
|
|
2954
|
+
continue;
|
|
2955
|
+
}
|
|
2956
|
+
if (char === "'") {
|
|
2957
|
+
singleQuoted = false;
|
|
2958
|
+
}
|
|
2959
|
+
continue;
|
|
2960
|
+
}
|
|
2961
|
+
if (doubleQuoted) {
|
|
2962
|
+
if (char === '"' && next === '"') {
|
|
2963
|
+
index += 1;
|
|
2964
|
+
continue;
|
|
2965
|
+
}
|
|
2966
|
+
if (char === '"') {
|
|
2967
|
+
doubleQuoted = false;
|
|
2968
|
+
}
|
|
2969
|
+
continue;
|
|
2970
|
+
}
|
|
2971
|
+
if (char === "'") {
|
|
2972
|
+
singleQuoted = true;
|
|
2973
|
+
continue;
|
|
2974
|
+
}
|
|
2975
|
+
if (char === '"') {
|
|
2976
|
+
doubleQuoted = true;
|
|
2977
|
+
continue;
|
|
2978
|
+
}
|
|
2979
|
+
if (char === "(") {
|
|
2980
|
+
const relationHead = extractRelationHead(select.slice(tokenStart, index));
|
|
2981
|
+
if (isIdentifierPath(relationHead)) {
|
|
2982
|
+
return true;
|
|
2983
|
+
}
|
|
2984
|
+
tokenStart = index + 1;
|
|
2985
|
+
continue;
|
|
2986
|
+
}
|
|
2987
|
+
if (char === "," || char === ")") {
|
|
2988
|
+
tokenStart = index + 1;
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
return false;
|
|
2992
|
+
}
|
|
2993
|
+
function toStructuredSelectString(columns) {
|
|
2994
|
+
return Array.isArray(columns) ? columns.join(",") : columns;
|
|
2995
|
+
}
|
|
2996
|
+
function buildStructuredWhere(conditions) {
|
|
2997
|
+
if (!conditions?.length) return void 0;
|
|
2998
|
+
const where = {};
|
|
2999
|
+
for (const condition of conditions) {
|
|
3000
|
+
if (!condition.column) {
|
|
3001
|
+
return null;
|
|
3002
|
+
}
|
|
3003
|
+
if (condition.column_cast !== void 0 || condition.value_cast !== void 0) {
|
|
3004
|
+
return null;
|
|
3005
|
+
}
|
|
3006
|
+
const operand = condition.value;
|
|
3007
|
+
const operator = condition.operator;
|
|
3008
|
+
if (operator === "eq") {
|
|
3009
|
+
if (operand === void 0) return null;
|
|
3010
|
+
} else if (operator === "neq" || operator === "gt" || operator === "lt") {
|
|
3011
|
+
if (operand === void 0) return null;
|
|
3012
|
+
} else if (operator === "in") {
|
|
3013
|
+
if (!Array.isArray(operand)) return null;
|
|
3014
|
+
} else {
|
|
3015
|
+
return null;
|
|
3016
|
+
}
|
|
3017
|
+
const existing = where[condition.column];
|
|
3018
|
+
if (existing !== void 0 && (typeof existing !== "object" || existing === null || Array.isArray(existing))) {
|
|
3019
|
+
return null;
|
|
3020
|
+
}
|
|
3021
|
+
const next = existing ?? {};
|
|
3022
|
+
if (Object.prototype.hasOwnProperty.call(next, operator)) {
|
|
3023
|
+
return null;
|
|
3024
|
+
}
|
|
3025
|
+
next[operator] = operand;
|
|
3026
|
+
where[condition.column] = next;
|
|
3027
|
+
}
|
|
3028
|
+
return where;
|
|
3029
|
+
}
|
|
3030
|
+
function buildStructuredOrderBy(order) {
|
|
3031
|
+
if (!order?.field) return void 0;
|
|
3032
|
+
return {
|
|
3033
|
+
[order.field]: order.direction === "descending" ? "desc" : "asc"
|
|
3034
|
+
};
|
|
3035
|
+
}
|
|
3036
|
+
function buildStructuredSelectTransport(input) {
|
|
3037
|
+
const select = toStructuredSelectString(input.columns).trim();
|
|
3038
|
+
if (!select || select === "*") {
|
|
3039
|
+
return null;
|
|
3040
|
+
}
|
|
3041
|
+
if (!hasSchemaQualifiedRelationToken(select)) {
|
|
3042
|
+
return null;
|
|
3043
|
+
}
|
|
3044
|
+
if (input.count !== void 0 || input.head !== void 0) {
|
|
3045
|
+
return {
|
|
3046
|
+
error: "Schema-qualified nested select strings require structured select transport, which does not support count/head options in athena-js yet."
|
|
3047
|
+
};
|
|
3048
|
+
}
|
|
3049
|
+
const where = buildStructuredWhere(input.conditions);
|
|
3050
|
+
if (where === null) {
|
|
3051
|
+
return {
|
|
3052
|
+
error: "Schema-qualified nested select strings only support eq, neq, gt, lt, and in filters in athena-js structured select transport."
|
|
3053
|
+
};
|
|
3054
|
+
}
|
|
3055
|
+
return {
|
|
3056
|
+
select,
|
|
3057
|
+
payload: {
|
|
3058
|
+
table_name: input.tableName,
|
|
3059
|
+
select,
|
|
3060
|
+
where,
|
|
3061
|
+
orderBy: buildStructuredOrderBy(input.order),
|
|
3062
|
+
limit: input.limit,
|
|
3063
|
+
offset: input.offset,
|
|
3064
|
+
strip_nulls: input.stripNulls
|
|
3065
|
+
}
|
|
3066
|
+
};
|
|
3067
|
+
}
|
|
3068
|
+
|
|
3069
|
+
// src/query-transport.ts
|
|
3070
|
+
function canUseFindManyAstTransport(state) {
|
|
3071
|
+
return state.conditions.length === 0 && state.offset === void 0 && state.currentPage === void 0 && state.pageSize === void 0 && state.totalPages === void 0;
|
|
3072
|
+
}
|
|
3073
|
+
function toFindManyAstOrder(order) {
|
|
3074
|
+
if (!order) {
|
|
3075
|
+
return void 0;
|
|
3076
|
+
}
|
|
3077
|
+
return {
|
|
3078
|
+
column: order.field,
|
|
3079
|
+
ascending: order.direction !== "descending"
|
|
3080
|
+
};
|
|
3081
|
+
}
|
|
3082
|
+
function resolvePagination(input) {
|
|
3083
|
+
let limit = input.limit;
|
|
3084
|
+
let offset = input.offset;
|
|
3085
|
+
if (limit === void 0 && input.pageSize !== void 0) {
|
|
3086
|
+
limit = Math.max(0, Math.trunc(input.pageSize));
|
|
3087
|
+
}
|
|
3088
|
+
if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
|
|
3089
|
+
offset = (Math.trunc(input.currentPage) - 1) * Math.max(0, Math.trunc(input.pageSize));
|
|
3090
|
+
}
|
|
3091
|
+
return { limit, offset };
|
|
3092
|
+
}
|
|
3093
|
+
function hasTypedEqualityComparison(conditions) {
|
|
3094
|
+
return conditions?.some(
|
|
3095
|
+
(condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
|
|
3096
|
+
) ?? false;
|
|
3097
|
+
}
|
|
3098
|
+
function createSelectTransportPlan(input) {
|
|
3099
|
+
const conditions = input.state.conditions.length ? input.state.conditions.map((condition) => ({ ...condition })) : void 0;
|
|
3100
|
+
if (hasTypedEqualityComparison(conditions) && !input.options?.head && !input.options?.count && conditions) {
|
|
3101
|
+
const query = input.buildTypedSelectQuery({
|
|
3102
|
+
tableName: input.tableName,
|
|
3103
|
+
columns: input.columns,
|
|
3104
|
+
conditions,
|
|
3105
|
+
limit: input.state.limit,
|
|
3106
|
+
offset: input.state.offset,
|
|
3107
|
+
currentPage: input.state.currentPage,
|
|
3108
|
+
pageSize: input.state.pageSize,
|
|
3109
|
+
order: input.state.order
|
|
3110
|
+
});
|
|
3111
|
+
if (query) {
|
|
3112
|
+
return {
|
|
3113
|
+
kind: "query",
|
|
3114
|
+
query,
|
|
3115
|
+
payload: { query }
|
|
3116
|
+
};
|
|
3117
|
+
}
|
|
3118
|
+
}
|
|
3119
|
+
const pagination = resolvePagination({
|
|
3120
|
+
limit: input.state.limit,
|
|
3121
|
+
offset: input.state.offset,
|
|
3122
|
+
currentPage: input.state.currentPage,
|
|
3123
|
+
pageSize: input.state.pageSize
|
|
3124
|
+
});
|
|
3125
|
+
const stripNulls = input.options?.stripNulls ?? true;
|
|
3126
|
+
const structuredSelectTransport = buildStructuredSelectTransport({
|
|
3127
|
+
tableName: input.tableName,
|
|
3128
|
+
columns: input.columns,
|
|
3129
|
+
conditions,
|
|
3130
|
+
limit: pagination.limit,
|
|
3131
|
+
offset: pagination.offset,
|
|
3132
|
+
order: input.state.order,
|
|
3133
|
+
stripNulls,
|
|
3134
|
+
count: input.options?.count,
|
|
3135
|
+
head: input.options?.head
|
|
3136
|
+
});
|
|
3137
|
+
if (structuredSelectTransport && "error" in structuredSelectTransport) {
|
|
3138
|
+
throw new Error(structuredSelectTransport.error);
|
|
3139
|
+
}
|
|
3140
|
+
if (structuredSelectTransport) {
|
|
3141
|
+
const { payload, select } = structuredSelectTransport;
|
|
3142
|
+
return {
|
|
3143
|
+
kind: "fetch",
|
|
3144
|
+
payload,
|
|
3145
|
+
debug: {
|
|
3146
|
+
columns: select,
|
|
3147
|
+
conditions,
|
|
3148
|
+
limit: pagination.limit,
|
|
3149
|
+
offset: pagination.offset,
|
|
3150
|
+
order: input.state.order
|
|
3151
|
+
}
|
|
3152
|
+
};
|
|
3153
|
+
}
|
|
3154
|
+
return {
|
|
3155
|
+
kind: "fetch",
|
|
3156
|
+
payload: {
|
|
3157
|
+
table_name: input.tableName,
|
|
3158
|
+
columns: input.columns,
|
|
3159
|
+
conditions,
|
|
3160
|
+
limit: input.state.limit,
|
|
3161
|
+
offset: input.state.offset,
|
|
3162
|
+
current_page: input.state.currentPage,
|
|
3163
|
+
page_size: input.state.pageSize,
|
|
3164
|
+
total_pages: input.state.totalPages,
|
|
3165
|
+
sort_by: input.state.order,
|
|
3166
|
+
strip_nulls: stripNulls,
|
|
3167
|
+
count: input.options?.count,
|
|
3168
|
+
head: input.options?.head
|
|
3169
|
+
},
|
|
3170
|
+
debug: {
|
|
3171
|
+
columns: input.columns,
|
|
3172
|
+
conditions,
|
|
3173
|
+
limit: input.state.limit,
|
|
3174
|
+
offset: input.state.offset,
|
|
3175
|
+
currentPage: input.state.currentPage,
|
|
3176
|
+
pageSize: input.state.pageSize,
|
|
3177
|
+
order: input.state.order
|
|
3178
|
+
}
|
|
3179
|
+
};
|
|
3180
|
+
}
|
|
3181
|
+
|
|
2035
3182
|
// src/client.ts
|
|
2036
3183
|
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
3184
|
var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
|
|
2039
3185
|
var ATHENA_NORMALIZED_ERROR_KEY = "__athenaNormalizedError";
|
|
3186
|
+
var QUERY_TRACE_STACK_SKIP_PATTERNS = [
|
|
3187
|
+
"src\\client.ts",
|
|
3188
|
+
"src/client.ts",
|
|
3189
|
+
"dist\\client.",
|
|
3190
|
+
"dist/client.",
|
|
3191
|
+
"node_modules\\@xylex-group\\athena",
|
|
3192
|
+
"node_modules/@xylex-group/athena",
|
|
3193
|
+
"node:internal",
|
|
3194
|
+
"internal/process"
|
|
3195
|
+
];
|
|
2040
3196
|
function formatResult(response) {
|
|
2041
3197
|
const result = {
|
|
2042
3198
|
data: response.data ?? null,
|
|
2043
|
-
error:
|
|
3199
|
+
error: null,
|
|
2044
3200
|
errorDetails: response.errorDetails ?? null,
|
|
2045
3201
|
status: response.status,
|
|
3202
|
+
statusText: response.statusText ?? null,
|
|
2046
3203
|
raw: response.raw
|
|
2047
3204
|
};
|
|
2048
3205
|
if (response.count !== void 0) {
|
|
@@ -2058,19 +3215,236 @@ function attachNormalizedError(result, normalizedError) {
|
|
|
2058
3215
|
writable: false
|
|
2059
3216
|
});
|
|
2060
3217
|
}
|
|
2061
|
-
function createResultFormatter(experimental) {
|
|
2062
|
-
|
|
2063
|
-
|
|
3218
|
+
function createResultFormatter(experimental) {
|
|
3219
|
+
return (response, context) => {
|
|
3220
|
+
const result = formatResult(response);
|
|
3221
|
+
if (response.error == null && response.errorDetails == null) {
|
|
3222
|
+
return result;
|
|
3223
|
+
}
|
|
3224
|
+
const normalizedError = normalizeAthenaError(
|
|
3225
|
+
{
|
|
3226
|
+
...result,
|
|
3227
|
+
error: response.error ?? response.errorDetails?.message ?? null
|
|
3228
|
+
},
|
|
3229
|
+
context
|
|
3230
|
+
);
|
|
3231
|
+
result.error = createResultError(response, result, normalizedError);
|
|
3232
|
+
attachNormalizedError(result, normalizedError);
|
|
3233
|
+
return result;
|
|
3234
|
+
};
|
|
3235
|
+
}
|
|
3236
|
+
function isRecord6(value) {
|
|
3237
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3238
|
+
}
|
|
3239
|
+
function firstNonEmptyString2(...values) {
|
|
3240
|
+
for (const value of values) {
|
|
3241
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
3242
|
+
return value.trim();
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
return void 0;
|
|
3246
|
+
}
|
|
3247
|
+
function resolveStructuredErrorPayload2(raw) {
|
|
3248
|
+
if (!isRecord6(raw)) return null;
|
|
3249
|
+
return isRecord6(raw.error) ? raw.error : raw;
|
|
3250
|
+
}
|
|
3251
|
+
function resolveStructuredErrorDetails(payload, message) {
|
|
3252
|
+
if (!payload || !("details" in payload)) {
|
|
3253
|
+
return null;
|
|
3254
|
+
}
|
|
3255
|
+
const details = payload.details;
|
|
3256
|
+
if (details == null) {
|
|
3257
|
+
return null;
|
|
3258
|
+
}
|
|
3259
|
+
if (typeof details === "string" && details.trim() === message.trim()) {
|
|
3260
|
+
return null;
|
|
3261
|
+
}
|
|
3262
|
+
return details;
|
|
3263
|
+
}
|
|
3264
|
+
function createResultError(response, result, normalized) {
|
|
3265
|
+
const rawRecord = isRecord6(response.raw) ? response.raw : null;
|
|
3266
|
+
const payload = resolveStructuredErrorPayload2(response.raw);
|
|
3267
|
+
const message = firstNonEmptyString2(
|
|
3268
|
+
response.error,
|
|
3269
|
+
payload?.message,
|
|
3270
|
+
payload?.error,
|
|
3271
|
+
payload?.details,
|
|
3272
|
+
response.errorDetails?.message,
|
|
3273
|
+
normalized.message
|
|
3274
|
+
) ?? normalized.message;
|
|
3275
|
+
const statusText = firstNonEmptyString2(response.statusText, rawRecord?.statusText) ?? null;
|
|
3276
|
+
const hint = firstNonEmptyString2(payload?.hint, response.errorDetails?.hint) ?? null;
|
|
3277
|
+
const code = firstNonEmptyString2(payload?.code) ?? normalized.code;
|
|
3278
|
+
const details = resolveStructuredErrorDetails(payload, message) ?? response.errorDetails?.cause ?? null;
|
|
3279
|
+
return {
|
|
3280
|
+
message,
|
|
3281
|
+
code,
|
|
3282
|
+
athenaCode: normalized.code,
|
|
3283
|
+
gatewayCode: response.errorDetails?.code ?? null,
|
|
3284
|
+
kind: normalized.kind,
|
|
3285
|
+
category: normalized.category,
|
|
3286
|
+
retryable: normalized.retryable,
|
|
3287
|
+
details,
|
|
3288
|
+
hint,
|
|
3289
|
+
status: result.status,
|
|
3290
|
+
statusText,
|
|
3291
|
+
constraint: normalized.constraint,
|
|
3292
|
+
table: normalized.table,
|
|
3293
|
+
operation: normalized.operation,
|
|
3294
|
+
endpoint: response.errorDetails?.endpoint,
|
|
3295
|
+
method: response.errorDetails?.method,
|
|
3296
|
+
requestId: response.errorDetails?.requestId,
|
|
3297
|
+
cause: response.errorDetails?.cause,
|
|
3298
|
+
raw: result.raw
|
|
3299
|
+
};
|
|
3300
|
+
}
|
|
3301
|
+
function parseQueryTraceCallsiteFrame(frame) {
|
|
3302
|
+
const trimmed = frame.trim();
|
|
3303
|
+
if (!trimmed) {
|
|
3304
|
+
return null;
|
|
3305
|
+
}
|
|
3306
|
+
let body = trimmed.replace(/^at\s+/, "");
|
|
3307
|
+
if (body.startsWith("async ")) {
|
|
3308
|
+
body = body.slice(6);
|
|
3309
|
+
}
|
|
3310
|
+
let functionName;
|
|
3311
|
+
let location = body;
|
|
3312
|
+
const wrappedMatch = body.match(/^(.*?)\s+\((.*)\)$/);
|
|
3313
|
+
if (wrappedMatch) {
|
|
3314
|
+
functionName = wrappedMatch[1].trim() || void 0;
|
|
3315
|
+
location = wrappedMatch[2].trim();
|
|
3316
|
+
}
|
|
3317
|
+
const locationMatch = location.match(/^(.*):(\d+):(\d+)$/);
|
|
3318
|
+
if (!locationMatch) {
|
|
3319
|
+
return null;
|
|
3320
|
+
}
|
|
3321
|
+
const filePath = locationMatch[1].replace(/^file:\/\//, "");
|
|
3322
|
+
const line = Number(locationMatch[2]);
|
|
3323
|
+
const column = Number(locationMatch[3]);
|
|
3324
|
+
if (!Number.isFinite(line) || !Number.isFinite(column)) {
|
|
3325
|
+
return null;
|
|
3326
|
+
}
|
|
3327
|
+
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
3328
|
+
const fileName = normalizedPath.split("/").at(-1) ?? filePath;
|
|
3329
|
+
return {
|
|
3330
|
+
filePath,
|
|
3331
|
+
fileName,
|
|
3332
|
+
line,
|
|
3333
|
+
column,
|
|
3334
|
+
frame: trimmed,
|
|
3335
|
+
functionName
|
|
3336
|
+
};
|
|
3337
|
+
}
|
|
3338
|
+
function captureQueryTraceCallsite() {
|
|
3339
|
+
const stack = new Error().stack;
|
|
3340
|
+
if (!stack) return null;
|
|
3341
|
+
const frames = stack.split("\n").slice(2).map((frame) => frame.trim()).filter(Boolean);
|
|
3342
|
+
for (const frame of frames) {
|
|
3343
|
+
if (QUERY_TRACE_STACK_SKIP_PATTERNS.some((pattern) => frame.includes(pattern))) {
|
|
3344
|
+
continue;
|
|
3345
|
+
}
|
|
3346
|
+
const callsite = parseQueryTraceCallsiteFrame(frame);
|
|
3347
|
+
if (callsite) return callsite;
|
|
3348
|
+
}
|
|
3349
|
+
const fallback = frames.find((frame) => !frame.includes("captureQueryTraceCallsite"));
|
|
3350
|
+
return fallback ? parseQueryTraceCallsiteFrame(fallback) : null;
|
|
3351
|
+
}
|
|
3352
|
+
function defaultQueryTraceLogger(event) {
|
|
3353
|
+
const target = event.table ?? event.functionName ?? "gateway";
|
|
3354
|
+
const outcomeState = event.outcome?.error ? "error" : "ok";
|
|
3355
|
+
const banner = `[athena-js][trace] ${event.operation.toUpperCase()} ${event.endpoint} ${target} ${event.durationMs}ms ${outcomeState}`;
|
|
3356
|
+
console.info(banner, event);
|
|
3357
|
+
}
|
|
3358
|
+
function captureTraceCallsite(tracer) {
|
|
3359
|
+
return tracer?.captureCallsite() ?? null;
|
|
3360
|
+
}
|
|
3361
|
+
function createTraceCallsiteStore(tracer, initialCallsite) {
|
|
3362
|
+
let storedCallsite = initialCallsite ?? void 0;
|
|
3363
|
+
return {
|
|
3364
|
+
resolve(callsite) {
|
|
3365
|
+
if (callsite) {
|
|
3366
|
+
storedCallsite = callsite;
|
|
3367
|
+
return callsite;
|
|
3368
|
+
}
|
|
3369
|
+
if (storedCallsite !== void 0) {
|
|
3370
|
+
return storedCallsite;
|
|
3371
|
+
}
|
|
3372
|
+
const capturedCallsite = captureTraceCallsite(tracer);
|
|
3373
|
+
if (capturedCallsite) {
|
|
3374
|
+
storedCallsite = capturedCallsite;
|
|
3375
|
+
}
|
|
3376
|
+
return capturedCallsite;
|
|
3377
|
+
}
|
|
3378
|
+
};
|
|
3379
|
+
}
|
|
3380
|
+
function createQueryTracer(experimental) {
|
|
3381
|
+
const traceOption = experimental?.traceQueries;
|
|
3382
|
+
if (!traceOption) {
|
|
3383
|
+
return void 0;
|
|
3384
|
+
}
|
|
3385
|
+
const logger = typeof traceOption === "object" && traceOption.logger ? traceOption.logger : defaultQueryTraceLogger;
|
|
3386
|
+
const emit = (event) => {
|
|
3387
|
+
try {
|
|
3388
|
+
logger(event);
|
|
3389
|
+
} catch (error) {
|
|
3390
|
+
console.warn("[athena-js][trace] logger failed", error);
|
|
3391
|
+
}
|
|
3392
|
+
};
|
|
3393
|
+
return {
|
|
3394
|
+
captureCallsite: captureQueryTraceCallsite,
|
|
3395
|
+
publishSuccess(context, result, durationMs, callsite) {
|
|
3396
|
+
emit({
|
|
3397
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3398
|
+
durationMs,
|
|
3399
|
+
operation: context.operation,
|
|
3400
|
+
endpoint: context.endpoint,
|
|
3401
|
+
table: context.table,
|
|
3402
|
+
functionName: context.functionName,
|
|
3403
|
+
sql: context.sql,
|
|
3404
|
+
payload: context.payload,
|
|
3405
|
+
options: context.options,
|
|
3406
|
+
callsite,
|
|
3407
|
+
outcome: {
|
|
3408
|
+
status: result.status,
|
|
3409
|
+
error: result.error,
|
|
3410
|
+
errorDetails: result.errorDetails ?? null,
|
|
3411
|
+
count: result.count ?? null,
|
|
3412
|
+
data: result.data,
|
|
3413
|
+
raw: result.raw
|
|
3414
|
+
}
|
|
3415
|
+
});
|
|
3416
|
+
},
|
|
3417
|
+
publishFailure(context, error, durationMs, callsite) {
|
|
3418
|
+
emit({
|
|
3419
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3420
|
+
durationMs,
|
|
3421
|
+
operation: context.operation,
|
|
3422
|
+
endpoint: context.endpoint,
|
|
3423
|
+
table: context.table,
|
|
3424
|
+
functionName: context.functionName,
|
|
3425
|
+
sql: context.sql,
|
|
3426
|
+
payload: context.payload,
|
|
3427
|
+
options: context.options,
|
|
3428
|
+
callsite,
|
|
3429
|
+
thrownError: error
|
|
3430
|
+
});
|
|
3431
|
+
}
|
|
3432
|
+
};
|
|
3433
|
+
}
|
|
3434
|
+
async function executeWithQueryTrace(tracer, context, runner, callsiteOverride) {
|
|
3435
|
+
if (!tracer) {
|
|
3436
|
+
return runner();
|
|
2064
3437
|
}
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
const normalizedError = normalizeAthenaError(result, context);
|
|
2071
|
-
attachNormalizedError(result, normalizedError);
|
|
3438
|
+
const callsite = callsiteOverride ?? tracer.captureCallsite();
|
|
3439
|
+
const startedAt = Date.now();
|
|
3440
|
+
try {
|
|
3441
|
+
const result = await runner();
|
|
3442
|
+
tracer.publishSuccess(context, result, Date.now() - startedAt, callsite);
|
|
2072
3443
|
return result;
|
|
2073
|
-
}
|
|
3444
|
+
} catch (error) {
|
|
3445
|
+
tracer.publishFailure(context, error, Date.now() - startedAt, callsite);
|
|
3446
|
+
throw error;
|
|
3447
|
+
}
|
|
2074
3448
|
}
|
|
2075
3449
|
function toSingleResult(response) {
|
|
2076
3450
|
const payload = response.data;
|
|
@@ -2092,15 +3466,16 @@ function asAthenaJsonObject(value) {
|
|
|
2092
3466
|
function asAthenaJsonObjectArray(values) {
|
|
2093
3467
|
return values;
|
|
2094
3468
|
}
|
|
2095
|
-
function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
|
|
3469
|
+
function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS, tracer, initialCallsite) {
|
|
2096
3470
|
let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
|
|
2097
3471
|
let selectedOptions;
|
|
2098
3472
|
let promise = null;
|
|
2099
|
-
const
|
|
3473
|
+
const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
|
|
3474
|
+
const run = (columns, options, callsite) => {
|
|
2100
3475
|
const payloadColumns = columns ?? selectedColumns;
|
|
2101
3476
|
const payloadOptions = options ?? selectedOptions;
|
|
2102
3477
|
if (!promise) {
|
|
2103
|
-
promise = executor(payloadColumns, payloadOptions);
|
|
3478
|
+
promise = executor(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
|
|
2104
3479
|
}
|
|
2105
3480
|
return promise;
|
|
2106
3481
|
};
|
|
@@ -2108,7 +3483,7 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
|
|
|
2108
3483
|
select(columns = selectedColumns, options) {
|
|
2109
3484
|
selectedColumns = columns;
|
|
2110
3485
|
selectedOptions = options ?? selectedOptions;
|
|
2111
|
-
return run(columns, options);
|
|
3486
|
+
return run(columns, options, captureTraceCallsite(tracer));
|
|
2112
3487
|
},
|
|
2113
3488
|
returning(columns = selectedColumns, options) {
|
|
2114
3489
|
return mutationQuery.select(columns, options);
|
|
@@ -2116,7 +3491,7 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
|
|
|
2116
3491
|
single(columns = selectedColumns, options) {
|
|
2117
3492
|
selectedColumns = columns;
|
|
2118
3493
|
selectedOptions = options ?? selectedOptions;
|
|
2119
|
-
return run(columns, options).then(toSingleResult);
|
|
3494
|
+
return run(columns, options, captureTraceCallsite(tracer)).then(toSingleResult);
|
|
2120
3495
|
},
|
|
2121
3496
|
maybeSingle(columns = selectedColumns, options) {
|
|
2122
3497
|
return mutationQuery.single(columns, options);
|
|
@@ -2139,21 +3514,12 @@ function getResourceId(state) {
|
|
|
2139
3514
|
);
|
|
2140
3515
|
return candidate?.value?.toString();
|
|
2141
3516
|
}
|
|
2142
|
-
function
|
|
3517
|
+
function stringifyFilterValue2(value) {
|
|
2143
3518
|
if (Array.isArray(value)) {
|
|
2144
3519
|
return value.join(",");
|
|
2145
3520
|
}
|
|
2146
3521
|
return String(value);
|
|
2147
3522
|
}
|
|
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
3523
|
function normalizeCast(cast) {
|
|
2158
3524
|
const normalized = cast.trim().toLowerCase();
|
|
2159
3525
|
if (!SAFE_CAST_PATTERN.test(normalized)) {
|
|
@@ -2176,25 +3542,92 @@ function withCast(expression, cast) {
|
|
|
2176
3542
|
}
|
|
2177
3543
|
function buildSelectColumnsClause(columns) {
|
|
2178
3544
|
if (Array.isArray(columns)) {
|
|
2179
|
-
return columns.map((column) =>
|
|
3545
|
+
return columns.map((column) => quoteSelectColumnToken(column)).join(", ");
|
|
2180
3546
|
}
|
|
2181
3547
|
return quoteSelectColumnsExpression(columns);
|
|
2182
3548
|
}
|
|
3549
|
+
function parseIdentifierSegment(input) {
|
|
3550
|
+
const trimmed = input.trim();
|
|
3551
|
+
if (!trimmed) return null;
|
|
3552
|
+
if (!trimmed.startsWith('"')) {
|
|
3553
|
+
return {
|
|
3554
|
+
normalizedValue: trimmed.toLowerCase()
|
|
3555
|
+
};
|
|
3556
|
+
}
|
|
3557
|
+
let value = "";
|
|
3558
|
+
let index = 1;
|
|
3559
|
+
let closed = false;
|
|
3560
|
+
while (index < trimmed.length) {
|
|
3561
|
+
const char = trimmed[index];
|
|
3562
|
+
const next = index + 1 < trimmed.length ? trimmed[index + 1] : "";
|
|
3563
|
+
if (char === '"' && next === '"') {
|
|
3564
|
+
value += '"';
|
|
3565
|
+
index += 2;
|
|
3566
|
+
continue;
|
|
3567
|
+
}
|
|
3568
|
+
if (char === '"') {
|
|
3569
|
+
closed = true;
|
|
3570
|
+
index += 1;
|
|
3571
|
+
break;
|
|
3572
|
+
}
|
|
3573
|
+
value += char;
|
|
3574
|
+
index += 1;
|
|
3575
|
+
}
|
|
3576
|
+
if (!closed || trimmed.slice(index).trim().length > 0 || !value.trim()) {
|
|
3577
|
+
return null;
|
|
3578
|
+
}
|
|
3579
|
+
return {
|
|
3580
|
+
normalizedValue: value
|
|
3581
|
+
};
|
|
3582
|
+
}
|
|
3583
|
+
function splitQualifiedTableName(tableName) {
|
|
3584
|
+
const trimmed = tableName.trim();
|
|
3585
|
+
let inQuotes = false;
|
|
3586
|
+
for (let index = 0; index < trimmed.length; index += 1) {
|
|
3587
|
+
const char = trimmed[index];
|
|
3588
|
+
const next = index + 1 < trimmed.length ? trimmed[index + 1] : "";
|
|
3589
|
+
if (char === '"') {
|
|
3590
|
+
if (inQuotes && next === '"') {
|
|
3591
|
+
index += 1;
|
|
3592
|
+
continue;
|
|
3593
|
+
}
|
|
3594
|
+
inQuotes = !inQuotes;
|
|
3595
|
+
continue;
|
|
3596
|
+
}
|
|
3597
|
+
if (char === "." && !inQuotes) {
|
|
3598
|
+
const schemaSegment = trimmed.slice(0, index).trim();
|
|
3599
|
+
const tableSegment = trimmed.slice(index + 1).trim();
|
|
3600
|
+
if (!schemaSegment || !tableSegment) {
|
|
3601
|
+
return null;
|
|
3602
|
+
}
|
|
3603
|
+
return { schemaSegment };
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3606
|
+
return null;
|
|
3607
|
+
}
|
|
2183
3608
|
function resolveTableNameForCall(tableName, schema) {
|
|
2184
3609
|
if (!schema) return tableName;
|
|
2185
3610
|
const normalizedSchema = schema.trim();
|
|
2186
3611
|
if (!normalizedSchema) {
|
|
2187
3612
|
throw new Error("schema option must be a non-empty string");
|
|
2188
3613
|
}
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
3614
|
+
const normalizedTableName = tableName.trim();
|
|
3615
|
+
const parsedSchema = parseIdentifierSegment(normalizedSchema);
|
|
3616
|
+
if (!parsedSchema) {
|
|
3617
|
+
throw new Error("schema option must be a non-empty string");
|
|
3618
|
+
}
|
|
3619
|
+
const qualified = splitQualifiedTableName(normalizedTableName);
|
|
3620
|
+
if (qualified) {
|
|
3621
|
+
const parsedTableSchema = parseIdentifierSegment(qualified.schemaSegment);
|
|
3622
|
+
const sameSchema = parsedTableSchema ? parsedTableSchema.normalizedValue === parsedSchema.normalizedValue : normalizedTableName.startsWith(`${normalizedSchema}.`);
|
|
3623
|
+
if (sameSchema) {
|
|
3624
|
+
return normalizedTableName;
|
|
2192
3625
|
}
|
|
2193
3626
|
throw new Error(
|
|
2194
|
-
`schema option "${normalizedSchema}" conflicts with schema-qualified table "${
|
|
3627
|
+
`schema option "${normalizedSchema}" conflicts with schema-qualified table "${normalizedTableName}"`
|
|
2195
3628
|
);
|
|
2196
3629
|
}
|
|
2197
|
-
return `${normalizedSchema}.${
|
|
3630
|
+
return `${normalizedSchema}.${normalizedTableName}`;
|
|
2198
3631
|
}
|
|
2199
3632
|
function conditionToSqlClause(condition) {
|
|
2200
3633
|
if (!condition.column) return null;
|
|
@@ -2272,6 +3705,226 @@ function buildTypedSelectQuery(input) {
|
|
|
2272
3705
|
}
|
|
2273
3706
|
return `${sqlParts.join(" ")};`;
|
|
2274
3707
|
}
|
|
3708
|
+
function sanitizeSqlComment(comment) {
|
|
3709
|
+
return comment.replace(/\*\//g, "* /");
|
|
3710
|
+
}
|
|
3711
|
+
function toSqlJsonLiteral(value) {
|
|
3712
|
+
if (value === void 0) return "DEFAULT";
|
|
3713
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
3714
|
+
return toSqlLiteral(value);
|
|
3715
|
+
}
|
|
3716
|
+
return `'${escapeSqlStringLiteral(JSON.stringify(value))}'::jsonb`;
|
|
3717
|
+
}
|
|
3718
|
+
function conditionToDebugSqlClause(condition) {
|
|
3719
|
+
const exact = conditionToSqlClause(condition);
|
|
3720
|
+
if (exact) return exact;
|
|
3721
|
+
const rawCondition = sanitizeSqlComment(JSON.stringify(condition));
|
|
3722
|
+
if (!condition.column) {
|
|
3723
|
+
return `TRUE /* unsupported condition: ${rawCondition} */`;
|
|
3724
|
+
}
|
|
3725
|
+
const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
|
|
3726
|
+
const value = condition.value;
|
|
3727
|
+
const rhs = withCast(toSqlJsonLiteral(value), condition.value_cast);
|
|
3728
|
+
switch (condition.operator) {
|
|
3729
|
+
case "contains":
|
|
3730
|
+
return `${column} @> ${rhs}`;
|
|
3731
|
+
case "containedBy":
|
|
3732
|
+
return `${column} <@ ${rhs}`;
|
|
3733
|
+
case "not":
|
|
3734
|
+
return `TRUE /* NOT expression passthrough: ${rawCondition} */`;
|
|
3735
|
+
case "or":
|
|
3736
|
+
return `TRUE /* OR expression passthrough: ${rawCondition} */`;
|
|
3737
|
+
default:
|
|
3738
|
+
return `TRUE /* unsupported condition: ${rawCondition} */`;
|
|
3739
|
+
}
|
|
3740
|
+
}
|
|
3741
|
+
function appendOrderLimitOffset(sqlParts, order, limit, offset) {
|
|
3742
|
+
if (order?.field) {
|
|
3743
|
+
const direction = order.direction === "descending" ? "DESC" : "ASC";
|
|
3744
|
+
sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(order.field)} ${direction}`);
|
|
3745
|
+
}
|
|
3746
|
+
if (limit !== void 0) {
|
|
3747
|
+
sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(limit))}`);
|
|
3748
|
+
}
|
|
3749
|
+
if (offset !== void 0) {
|
|
3750
|
+
sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
|
|
3751
|
+
}
|
|
3752
|
+
}
|
|
3753
|
+
function buildDebugSelectQuery(input) {
|
|
3754
|
+
const sqlParts = [
|
|
3755
|
+
`SELECT ${buildSelectColumnsClause(input.columns)} FROM ${quoteQualifiedIdentifier(input.tableName)}`
|
|
3756
|
+
];
|
|
3757
|
+
if (input.conditions?.length) {
|
|
3758
|
+
const whereClauses = input.conditions.map(conditionToDebugSqlClause);
|
|
3759
|
+
sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
|
|
3760
|
+
}
|
|
3761
|
+
const pagination = resolvePagination(input);
|
|
3762
|
+
appendOrderLimitOffset(sqlParts, input.order, pagination.limit, pagination.offset);
|
|
3763
|
+
return `${sqlParts.join(" ")};`;
|
|
3764
|
+
}
|
|
3765
|
+
function resolveDebugTableIdentifier(tableName) {
|
|
3766
|
+
if (!tableName?.trim()) {
|
|
3767
|
+
return '"__unknown_table__"';
|
|
3768
|
+
}
|
|
3769
|
+
return quoteQualifiedIdentifier(tableName);
|
|
3770
|
+
}
|
|
3771
|
+
function buildInsertDebugSql(payload) {
|
|
3772
|
+
const rows = Array.isArray(payload.insert_body) ? payload.insert_body : [payload.insert_body];
|
|
3773
|
+
const columns = [];
|
|
3774
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3775
|
+
for (const row of rows) {
|
|
3776
|
+
for (const column of Object.keys(row)) {
|
|
3777
|
+
if (seen.has(column)) continue;
|
|
3778
|
+
seen.add(column);
|
|
3779
|
+
columns.push(column);
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3782
|
+
const sqlParts = [`INSERT INTO ${quoteQualifiedIdentifier(payload.table_name)}`];
|
|
3783
|
+
if (!rows.length || !columns.length) {
|
|
3784
|
+
sqlParts.push("DEFAULT VALUES");
|
|
3785
|
+
if (rows.length > 1) {
|
|
3786
|
+
sqlParts.push(`/* trace: ${rows.length} rows collapsed to DEFAULT VALUES */`);
|
|
3787
|
+
}
|
|
3788
|
+
} else {
|
|
3789
|
+
const valuesClause = rows.map((row) => {
|
|
3790
|
+
const values = columns.map((column) => {
|
|
3791
|
+
const hasColumn = Object.prototype.hasOwnProperty.call(row, column);
|
|
3792
|
+
if (!hasColumn) {
|
|
3793
|
+
return payload.default_to_null ? "NULL" : "DEFAULT";
|
|
3794
|
+
}
|
|
3795
|
+
const rowValue = row[column];
|
|
3796
|
+
return toSqlJsonLiteral(rowValue);
|
|
3797
|
+
});
|
|
3798
|
+
return `(${values.join(", ")})`;
|
|
3799
|
+
}).join(", ");
|
|
3800
|
+
const columnClause = columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
|
|
3801
|
+
sqlParts.push(`(${columnClause})`);
|
|
3802
|
+
sqlParts.push(`VALUES ${valuesClause}`);
|
|
3803
|
+
}
|
|
3804
|
+
if (payload.on_conflict) {
|
|
3805
|
+
const conflictColumns = Array.isArray(payload.on_conflict) ? payload.on_conflict.map((column) => quoteQualifiedIdentifier(column)).join(", ") : payload.on_conflict;
|
|
3806
|
+
if (payload.update_body && Object.keys(payload.update_body).length > 0) {
|
|
3807
|
+
const assignments = Object.entries(payload.update_body).map(
|
|
3808
|
+
([column, value]) => `${quoteQualifiedIdentifier(column)} = ${toSqlJsonLiteral(value)}`
|
|
3809
|
+
);
|
|
3810
|
+
sqlParts.push(`ON CONFLICT (${conflictColumns}) DO UPDATE SET ${assignments.join(", ")}`);
|
|
3811
|
+
} else {
|
|
3812
|
+
sqlParts.push(`ON CONFLICT (${conflictColumns}) DO NOTHING`);
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
if (payload.columns) {
|
|
3816
|
+
sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
|
|
3817
|
+
}
|
|
3818
|
+
return `${sqlParts.join(" ")};`;
|
|
3819
|
+
}
|
|
3820
|
+
function buildUpdateDebugSql(payload) {
|
|
3821
|
+
const set = payload.set ?? payload.data ?? {};
|
|
3822
|
+
const assignments = Object.entries(set).map(
|
|
3823
|
+
([column, value]) => `${quoteQualifiedIdentifier(column)} = ${toSqlJsonLiteral(value)}`
|
|
3824
|
+
);
|
|
3825
|
+
const sqlParts = [
|
|
3826
|
+
`UPDATE ${resolveDebugTableIdentifier(payload.table_name)} SET ${assignments.length ? assignments.join(", ") : "/* empty set */"}`
|
|
3827
|
+
];
|
|
3828
|
+
if (payload.conditions?.length) {
|
|
3829
|
+
const whereClauses = payload.conditions.map(conditionToDebugSqlClause);
|
|
3830
|
+
sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
|
|
3831
|
+
}
|
|
3832
|
+
const pagination = resolvePagination({
|
|
3833
|
+
currentPage: payload.current_page,
|
|
3834
|
+
pageSize: payload.page_size
|
|
3835
|
+
});
|
|
3836
|
+
appendOrderLimitOffset(sqlParts, payload.sort_by, pagination.limit, pagination.offset);
|
|
3837
|
+
if (payload.columns) {
|
|
3838
|
+
sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
|
|
3839
|
+
}
|
|
3840
|
+
return `${sqlParts.join(" ")};`;
|
|
3841
|
+
}
|
|
3842
|
+
function buildDeleteDebugSql(payload) {
|
|
3843
|
+
const sqlParts = [`DELETE FROM ${quoteQualifiedIdentifier(payload.table_name)}`];
|
|
3844
|
+
const whereClauses = [];
|
|
3845
|
+
if (payload.resource_id) {
|
|
3846
|
+
whereClauses.push(`"resource_id" = ${toSqlLiteral(payload.resource_id)}`);
|
|
3847
|
+
}
|
|
3848
|
+
if (payload.conditions?.length) {
|
|
3849
|
+
whereClauses.push(...payload.conditions.map(conditionToDebugSqlClause));
|
|
3850
|
+
}
|
|
3851
|
+
if (whereClauses.length) {
|
|
3852
|
+
sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
|
|
3853
|
+
}
|
|
3854
|
+
const pagination = resolvePagination({
|
|
3855
|
+
currentPage: payload.current_page,
|
|
3856
|
+
pageSize: payload.page_size
|
|
3857
|
+
});
|
|
3858
|
+
appendOrderLimitOffset(sqlParts, payload.sort_by, pagination.limit, pagination.offset);
|
|
3859
|
+
if (payload.columns) {
|
|
3860
|
+
sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
|
|
3861
|
+
}
|
|
3862
|
+
return `${sqlParts.join(" ")};`;
|
|
3863
|
+
}
|
|
3864
|
+
function rpcFilterToSqlClause(filter) {
|
|
3865
|
+
const column = quoteQualifiedIdentifier(filter.column);
|
|
3866
|
+
const value = filter.value;
|
|
3867
|
+
switch (filter.operator) {
|
|
3868
|
+
case "eq":
|
|
3869
|
+
case "neq":
|
|
3870
|
+
case "gt":
|
|
3871
|
+
case "gte":
|
|
3872
|
+
case "lt":
|
|
3873
|
+
case "lte":
|
|
3874
|
+
case "like":
|
|
3875
|
+
case "ilike": {
|
|
3876
|
+
if (value === void 0 || Array.isArray(value)) {
|
|
3877
|
+
return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
|
|
3878
|
+
}
|
|
3879
|
+
const operatorMap = {
|
|
3880
|
+
eq: "=",
|
|
3881
|
+
neq: "!=",
|
|
3882
|
+
gt: ">",
|
|
3883
|
+
gte: ">=",
|
|
3884
|
+
lt: "<",
|
|
3885
|
+
lte: "<=",
|
|
3886
|
+
like: "LIKE",
|
|
3887
|
+
ilike: "ILIKE"
|
|
3888
|
+
};
|
|
3889
|
+
return `${column} ${operatorMap[filter.operator]} ${toSqlLiteral(value)}`;
|
|
3890
|
+
}
|
|
3891
|
+
case "is":
|
|
3892
|
+
if (value === null) return `${column} IS NULL`;
|
|
3893
|
+
if (value === true) return `${column} IS TRUE`;
|
|
3894
|
+
if (value === false) return `${column} IS FALSE`;
|
|
3895
|
+
return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
|
|
3896
|
+
case "in":
|
|
3897
|
+
if (!Array.isArray(value)) {
|
|
3898
|
+
return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
|
|
3899
|
+
}
|
|
3900
|
+
if (value.length === 0) return "FALSE";
|
|
3901
|
+
return `${column} IN (${value.map((item) => toSqlLiteral(item)).join(", ")})`;
|
|
3902
|
+
default:
|
|
3903
|
+
return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
|
|
3904
|
+
}
|
|
3905
|
+
}
|
|
3906
|
+
function buildRpcDebugSql(payload) {
|
|
3907
|
+
const argsEntries = payload.args ? Object.entries(payload.args) : [];
|
|
3908
|
+
const argsClause = argsEntries.map(([key, value]) => `${quoteQualifiedIdentifier(key)} => ${toSqlJsonLiteral(value)}`).join(", ");
|
|
3909
|
+
const functionRef = payload.schema ? `${quoteQualifiedIdentifier(payload.schema)}.${quoteQualifiedIdentifier(payload.function)}` : quoteQualifiedIdentifier(payload.function);
|
|
3910
|
+
const sqlParts = [
|
|
3911
|
+
`SELECT ${payload.select ? quoteSelectColumnsExpression(payload.select) : "*"} FROM ${functionRef}(${argsClause})`
|
|
3912
|
+
];
|
|
3913
|
+
if (payload.filters?.length) {
|
|
3914
|
+
sqlParts.push(`WHERE ${payload.filters.map(rpcFilterToSqlClause).join(" AND ")}`);
|
|
3915
|
+
}
|
|
3916
|
+
if (payload.order?.column) {
|
|
3917
|
+
const direction = payload.order.ascending === false ? "DESC" : "ASC";
|
|
3918
|
+
sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(payload.order.column)} ${direction}`);
|
|
3919
|
+
}
|
|
3920
|
+
if (payload.limit !== void 0) {
|
|
3921
|
+
sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(payload.limit))}`);
|
|
3922
|
+
}
|
|
3923
|
+
if (payload.offset !== void 0) {
|
|
3924
|
+
sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(payload.offset))}`);
|
|
3925
|
+
}
|
|
3926
|
+
return `${sqlParts.join(" ")};`;
|
|
3927
|
+
}
|
|
2275
3928
|
function createFilterMethods(state, addCondition, self) {
|
|
2276
3929
|
return {
|
|
2277
3930
|
eq(column, value) {
|
|
@@ -2383,7 +4036,7 @@ function createFilterMethods(state, addCondition, self) {
|
|
|
2383
4036
|
not(columnOrExpression, operator, value) {
|
|
2384
4037
|
const expression = String(columnOrExpression);
|
|
2385
4038
|
if (operator != null && value !== void 0) {
|
|
2386
|
-
addCondition("not", void 0, `${expression}.${operator}.${
|
|
4039
|
+
addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue2(value)}`);
|
|
2387
4040
|
} else {
|
|
2388
4041
|
addCondition("not", void 0, expression);
|
|
2389
4042
|
}
|
|
@@ -2446,14 +4099,15 @@ function createRpcFilterMethods(filters, self) {
|
|
|
2446
4099
|
}
|
|
2447
4100
|
};
|
|
2448
4101
|
}
|
|
2449
|
-
function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult) {
|
|
4102
|
+
function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult, tracer, initialCallsite) {
|
|
2450
4103
|
const state = {
|
|
2451
4104
|
filters: []
|
|
2452
4105
|
};
|
|
2453
4106
|
let selectedColumns;
|
|
2454
4107
|
let selectedOptions;
|
|
2455
4108
|
let promise = null;
|
|
2456
|
-
const
|
|
4109
|
+
const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
|
|
4110
|
+
const executeRpc = async (columns, options, callsite) => {
|
|
2457
4111
|
const mergedOptions = mergeOptions(baseOptions, options);
|
|
2458
4112
|
const payload = {
|
|
2459
4113
|
function: functionName,
|
|
@@ -2467,14 +4121,30 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
|
|
|
2467
4121
|
offset: state.offset,
|
|
2468
4122
|
order: state.order
|
|
2469
4123
|
};
|
|
2470
|
-
const
|
|
2471
|
-
|
|
4124
|
+
const endpoint = mergedOptions?.get ? `/rpc/${functionName}` : "/gateway/rpc";
|
|
4125
|
+
const sql = buildRpcDebugSql(payload);
|
|
4126
|
+
return executeWithQueryTrace(
|
|
4127
|
+
tracer,
|
|
4128
|
+
{
|
|
4129
|
+
operation: "rpc",
|
|
4130
|
+
endpoint,
|
|
4131
|
+
functionName,
|
|
4132
|
+
sql,
|
|
4133
|
+
payload,
|
|
4134
|
+
options: mergedOptions
|
|
4135
|
+
},
|
|
4136
|
+
async () => {
|
|
4137
|
+
const response = await client.rpcGateway(payload, mergedOptions);
|
|
4138
|
+
return formatGatewayResult(response, { operation: "rpc" });
|
|
4139
|
+
},
|
|
4140
|
+
callsite
|
|
4141
|
+
);
|
|
2472
4142
|
};
|
|
2473
|
-
const run = (columns, options) => {
|
|
4143
|
+
const run = (columns, options, callsite) => {
|
|
2474
4144
|
const payloadColumns = columns ?? selectedColumns;
|
|
2475
4145
|
const payloadOptions = options ?? selectedOptions;
|
|
2476
4146
|
if (!promise) {
|
|
2477
|
-
promise = executeRpc(payloadColumns, payloadOptions);
|
|
4147
|
+
promise = executeRpc(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
|
|
2478
4148
|
}
|
|
2479
4149
|
return promise;
|
|
2480
4150
|
};
|
|
@@ -2484,10 +4154,10 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
|
|
|
2484
4154
|
select(columns = selectedColumns, options) {
|
|
2485
4155
|
selectedColumns = columns;
|
|
2486
4156
|
selectedOptions = options ?? selectedOptions;
|
|
2487
|
-
return run(columns, options);
|
|
4157
|
+
return run(columns, options, captureTraceCallsite(tracer));
|
|
2488
4158
|
},
|
|
2489
4159
|
async single(columns, options) {
|
|
2490
|
-
const result = await run(columns, options);
|
|
4160
|
+
const result = await run(columns, options, captureTraceCallsite(tracer));
|
|
2491
4161
|
return toSingleResult(result);
|
|
2492
4162
|
},
|
|
2493
4163
|
maybeSingle(columns, options) {
|
|
@@ -2522,7 +4192,7 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
|
|
|
2522
4192
|
});
|
|
2523
4193
|
return builder;
|
|
2524
4194
|
}
|
|
2525
|
-
function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
4195
|
+
function createTableBuilder(tableName, client, formatGatewayResult, tracer, experimental) {
|
|
2526
4196
|
const state = {
|
|
2527
4197
|
conditions: []
|
|
2528
4198
|
};
|
|
@@ -2554,70 +4224,103 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2554
4224
|
}
|
|
2555
4225
|
state.conditions.push(condition);
|
|
2556
4226
|
};
|
|
4227
|
+
const snapshotState = () => ({
|
|
4228
|
+
conditions: state.conditions.map((condition) => ({ ...condition })),
|
|
4229
|
+
limit: state.limit,
|
|
4230
|
+
offset: state.offset,
|
|
4231
|
+
order: state.order ? { ...state.order } : void 0,
|
|
4232
|
+
currentPage: state.currentPage,
|
|
4233
|
+
pageSize: state.pageSize,
|
|
4234
|
+
totalPages: state.totalPages
|
|
4235
|
+
});
|
|
2557
4236
|
const builder = {};
|
|
2558
4237
|
const filterMethods = createFilterMethods(
|
|
2559
4238
|
state,
|
|
2560
4239
|
addCondition,
|
|
2561
4240
|
builder
|
|
2562
4241
|
);
|
|
2563
|
-
const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
|
|
4242
|
+
const runSelect = async (columns = DEFAULT_COLUMNS, options, executionState = snapshotState(), callsite) => {
|
|
2564
4243
|
const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
|
|
2565
|
-
const
|
|
2566
|
-
|
|
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,
|
|
4244
|
+
const plan = createSelectTransportPlan({
|
|
4245
|
+
tableName: resolvedTableName,
|
|
2587
4246
|
columns,
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
4247
|
+
state: executionState,
|
|
4248
|
+
options,
|
|
4249
|
+
buildTypedSelectQuery
|
|
4250
|
+
});
|
|
4251
|
+
if (plan.kind === "query") {
|
|
4252
|
+
return executeWithQueryTrace(
|
|
4253
|
+
tracer,
|
|
4254
|
+
{
|
|
4255
|
+
operation: "select",
|
|
4256
|
+
endpoint: "/gateway/query",
|
|
4257
|
+
table: resolvedTableName,
|
|
4258
|
+
sql: plan.query,
|
|
4259
|
+
payload: plan.payload,
|
|
4260
|
+
options
|
|
4261
|
+
},
|
|
4262
|
+
async () => {
|
|
4263
|
+
const queryResponse = await client.queryGateway(plan.payload, options);
|
|
4264
|
+
return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
|
|
4265
|
+
},
|
|
4266
|
+
callsite
|
|
4267
|
+
);
|
|
4268
|
+
}
|
|
4269
|
+
const sql = buildDebugSelectQuery({
|
|
4270
|
+
tableName: resolvedTableName,
|
|
4271
|
+
...plan.debug
|
|
4272
|
+
});
|
|
4273
|
+
return executeWithQueryTrace(
|
|
4274
|
+
tracer,
|
|
4275
|
+
{
|
|
4276
|
+
operation: "select",
|
|
4277
|
+
endpoint: "/gateway/fetch",
|
|
4278
|
+
table: resolvedTableName,
|
|
4279
|
+
sql,
|
|
4280
|
+
payload: plan.payload,
|
|
4281
|
+
options
|
|
4282
|
+
},
|
|
4283
|
+
async () => {
|
|
4284
|
+
const response = await client.fetchGateway(plan.payload, options);
|
|
4285
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
|
|
4286
|
+
},
|
|
4287
|
+
callsite
|
|
4288
|
+
);
|
|
2601
4289
|
};
|
|
2602
|
-
const createSelectChain = (columns, options) => {
|
|
4290
|
+
const createSelectChain = (columns, options, initialCallsite) => {
|
|
2603
4291
|
const chain = {};
|
|
4292
|
+
const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
|
|
2604
4293
|
const filterMethods2 = createFilterMethods(state, addCondition, chain);
|
|
2605
4294
|
Object.assign(chain, filterMethods2, {
|
|
2606
4295
|
async single(cols, opts) {
|
|
2607
|
-
const r = await runSelect(
|
|
4296
|
+
const r = await runSelect(
|
|
4297
|
+
cols ?? columns,
|
|
4298
|
+
opts ?? options,
|
|
4299
|
+
snapshotState(),
|
|
4300
|
+
callsiteStore.resolve(captureTraceCallsite(tracer))
|
|
4301
|
+
);
|
|
2608
4302
|
return toSingleResult(r);
|
|
2609
4303
|
},
|
|
2610
4304
|
maybeSingle(cols, opts) {
|
|
2611
4305
|
return chain.single(cols, opts);
|
|
2612
4306
|
},
|
|
2613
4307
|
then(onfulfilled, onrejected) {
|
|
2614
|
-
return runSelect(
|
|
4308
|
+
return runSelect(
|
|
4309
|
+
columns,
|
|
4310
|
+
options,
|
|
4311
|
+
snapshotState(),
|
|
4312
|
+
callsiteStore.resolve()
|
|
4313
|
+
).then(onfulfilled, onrejected);
|
|
2615
4314
|
},
|
|
2616
4315
|
catch(onrejected) {
|
|
2617
|
-
return runSelect(columns, options).catch(
|
|
4316
|
+
return runSelect(columns, options, snapshotState(), callsiteStore.resolve()).catch(
|
|
4317
|
+
onrejected
|
|
4318
|
+
);
|
|
2618
4319
|
},
|
|
2619
4320
|
finally(onfinally) {
|
|
2620
|
-
return runSelect(columns, options).finally(
|
|
4321
|
+
return runSelect(columns, options, snapshotState(), callsiteStore.resolve()).finally(
|
|
4322
|
+
onfinally
|
|
4323
|
+
);
|
|
2621
4324
|
}
|
|
2622
4325
|
});
|
|
2623
4326
|
return chain;
|
|
@@ -2634,11 +4337,75 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2634
4337
|
return builder;
|
|
2635
4338
|
},
|
|
2636
4339
|
select(columns = DEFAULT_COLUMNS, options) {
|
|
2637
|
-
return createSelectChain(columns, options);
|
|
4340
|
+
return createSelectChain(columns, options, captureTraceCallsite(tracer));
|
|
4341
|
+
},
|
|
4342
|
+
async findMany(options) {
|
|
4343
|
+
const columns = compileSelectShape(options.select);
|
|
4344
|
+
const baseState = snapshotState();
|
|
4345
|
+
const executionState = snapshotState();
|
|
4346
|
+
const callsite = captureTraceCallsite(tracer);
|
|
4347
|
+
const compiledWhere = compileWhere(options.where);
|
|
4348
|
+
if (compiledWhere?.length) {
|
|
4349
|
+
executionState.conditions.push(...compiledWhere);
|
|
4350
|
+
}
|
|
4351
|
+
if (options.orderBy !== void 0) {
|
|
4352
|
+
executionState.order = compileOrderBy(options.orderBy);
|
|
4353
|
+
}
|
|
4354
|
+
if (options.limit !== void 0) {
|
|
4355
|
+
executionState.limit = options.limit;
|
|
4356
|
+
}
|
|
4357
|
+
if (experimental?.findManyAst && canUseFindManyAstTransport(baseState) && !selectShapeUsesRelationSchema(options.select)) {
|
|
4358
|
+
const resolvedTableName = resolveTableNameForCall(tableName, void 0);
|
|
4359
|
+
const payload = {
|
|
4360
|
+
table_name: resolvedTableName,
|
|
4361
|
+
select: options.select
|
|
4362
|
+
};
|
|
4363
|
+
if (options.where !== void 0) {
|
|
4364
|
+
payload.where = options.where;
|
|
4365
|
+
}
|
|
4366
|
+
const astOrder = toFindManyAstOrder(executionState.order);
|
|
4367
|
+
if (astOrder !== void 0) {
|
|
4368
|
+
payload.orderBy = astOrder;
|
|
4369
|
+
}
|
|
4370
|
+
if (executionState.limit !== void 0) {
|
|
4371
|
+
payload.limit = executionState.limit;
|
|
4372
|
+
}
|
|
4373
|
+
const sql = buildDebugSelectQuery({
|
|
4374
|
+
tableName: resolvedTableName,
|
|
4375
|
+
columns,
|
|
4376
|
+
conditions: executionState.conditions,
|
|
4377
|
+
limit: executionState.limit,
|
|
4378
|
+
order: executionState.order
|
|
4379
|
+
});
|
|
4380
|
+
return executeWithQueryTrace(
|
|
4381
|
+
tracer,
|
|
4382
|
+
{
|
|
4383
|
+
operation: "select",
|
|
4384
|
+
endpoint: "/gateway/fetch",
|
|
4385
|
+
table: resolvedTableName,
|
|
4386
|
+
sql,
|
|
4387
|
+
payload
|
|
4388
|
+
},
|
|
4389
|
+
async () => {
|
|
4390
|
+
const response = await client.fetchGateway(
|
|
4391
|
+
payload
|
|
4392
|
+
);
|
|
4393
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
|
|
4394
|
+
},
|
|
4395
|
+
callsite
|
|
4396
|
+
);
|
|
4397
|
+
}
|
|
4398
|
+
return runSelect(
|
|
4399
|
+
columns,
|
|
4400
|
+
void 0,
|
|
4401
|
+
executionState,
|
|
4402
|
+
callsite
|
|
4403
|
+
);
|
|
2638
4404
|
},
|
|
2639
4405
|
insert(values, options) {
|
|
4406
|
+
const mutationCallsite = captureTraceCallsite(tracer);
|
|
2640
4407
|
if (Array.isArray(values)) {
|
|
2641
|
-
const executeInsertMany = async (columns, selectOptions) => {
|
|
4408
|
+
const executeInsertMany = async (columns, selectOptions, callsite) => {
|
|
2642
4409
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2643
4410
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
2644
4411
|
const payload = {
|
|
@@ -2651,12 +4418,27 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2651
4418
|
if (mergedOptions?.defaultToNull !== void 0) {
|
|
2652
4419
|
payload.default_to_null = mergedOptions.defaultToNull;
|
|
2653
4420
|
}
|
|
2654
|
-
const
|
|
2655
|
-
return
|
|
4421
|
+
const sql = buildInsertDebugSql(payload);
|
|
4422
|
+
return executeWithQueryTrace(
|
|
4423
|
+
tracer,
|
|
4424
|
+
{
|
|
4425
|
+
operation: "insert",
|
|
4426
|
+
endpoint: "/gateway/insert",
|
|
4427
|
+
table: resolvedTableName,
|
|
4428
|
+
sql,
|
|
4429
|
+
payload,
|
|
4430
|
+
options: mergedOptions
|
|
4431
|
+
},
|
|
4432
|
+
async () => {
|
|
4433
|
+
const response = await client.insertGateway(payload, mergedOptions);
|
|
4434
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
4435
|
+
},
|
|
4436
|
+
callsite
|
|
4437
|
+
);
|
|
2656
4438
|
};
|
|
2657
|
-
return createMutationQuery(executeInsertMany);
|
|
4439
|
+
return createMutationQuery(executeInsertMany, DEFAULT_COLUMNS, tracer, mutationCallsite);
|
|
2658
4440
|
}
|
|
2659
|
-
const executeInsertOne = async (columns, selectOptions) => {
|
|
4441
|
+
const executeInsertOne = async (columns, selectOptions, callsite) => {
|
|
2660
4442
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2661
4443
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
2662
4444
|
const payload = {
|
|
@@ -2669,14 +4451,30 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2669
4451
|
if (mergedOptions?.defaultToNull !== void 0) {
|
|
2670
4452
|
payload.default_to_null = mergedOptions.defaultToNull;
|
|
2671
4453
|
}
|
|
2672
|
-
const
|
|
2673
|
-
return
|
|
4454
|
+
const sql = buildInsertDebugSql(payload);
|
|
4455
|
+
return executeWithQueryTrace(
|
|
4456
|
+
tracer,
|
|
4457
|
+
{
|
|
4458
|
+
operation: "insert",
|
|
4459
|
+
endpoint: "/gateway/insert",
|
|
4460
|
+
table: resolvedTableName,
|
|
4461
|
+
sql,
|
|
4462
|
+
payload,
|
|
4463
|
+
options: mergedOptions
|
|
4464
|
+
},
|
|
4465
|
+
async () => {
|
|
4466
|
+
const response = await client.insertGateway(payload, mergedOptions);
|
|
4467
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
4468
|
+
},
|
|
4469
|
+
callsite
|
|
4470
|
+
);
|
|
2674
4471
|
};
|
|
2675
|
-
return createMutationQuery(executeInsertOne);
|
|
4472
|
+
return createMutationQuery(executeInsertOne, DEFAULT_COLUMNS, tracer, mutationCallsite);
|
|
2676
4473
|
},
|
|
2677
4474
|
upsert(values, options) {
|
|
4475
|
+
const mutationCallsite = captureTraceCallsite(tracer);
|
|
2678
4476
|
if (Array.isArray(values)) {
|
|
2679
|
-
const executeUpsertMany = async (columns, selectOptions) => {
|
|
4477
|
+
const executeUpsertMany = async (columns, selectOptions, callsite) => {
|
|
2680
4478
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2681
4479
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
2682
4480
|
const payload = {
|
|
@@ -2691,12 +4489,27 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2691
4489
|
if (mergedOptions?.defaultToNull !== void 0) {
|
|
2692
4490
|
payload.default_to_null = mergedOptions.defaultToNull;
|
|
2693
4491
|
}
|
|
2694
|
-
const
|
|
2695
|
-
return
|
|
4492
|
+
const sql = buildInsertDebugSql(payload);
|
|
4493
|
+
return executeWithQueryTrace(
|
|
4494
|
+
tracer,
|
|
4495
|
+
{
|
|
4496
|
+
operation: "upsert",
|
|
4497
|
+
endpoint: "/gateway/insert",
|
|
4498
|
+
table: resolvedTableName,
|
|
4499
|
+
sql,
|
|
4500
|
+
payload,
|
|
4501
|
+
options: mergedOptions
|
|
4502
|
+
},
|
|
4503
|
+
async () => {
|
|
4504
|
+
const response = await client.insertGateway(payload, mergedOptions);
|
|
4505
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
4506
|
+
},
|
|
4507
|
+
callsite
|
|
4508
|
+
);
|
|
2696
4509
|
};
|
|
2697
|
-
return createMutationQuery(executeUpsertMany);
|
|
4510
|
+
return createMutationQuery(executeUpsertMany, DEFAULT_COLUMNS, tracer, mutationCallsite);
|
|
2698
4511
|
}
|
|
2699
|
-
const executeUpsertOne = async (columns, selectOptions) => {
|
|
4512
|
+
const executeUpsertOne = async (columns, selectOptions, callsite) => {
|
|
2700
4513
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2701
4514
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
2702
4515
|
const payload = {
|
|
@@ -2711,13 +4524,29 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2711
4524
|
if (mergedOptions?.defaultToNull !== void 0) {
|
|
2712
4525
|
payload.default_to_null = mergedOptions.defaultToNull;
|
|
2713
4526
|
}
|
|
2714
|
-
const
|
|
2715
|
-
return
|
|
4527
|
+
const sql = buildInsertDebugSql(payload);
|
|
4528
|
+
return executeWithQueryTrace(
|
|
4529
|
+
tracer,
|
|
4530
|
+
{
|
|
4531
|
+
operation: "upsert",
|
|
4532
|
+
endpoint: "/gateway/insert",
|
|
4533
|
+
table: resolvedTableName,
|
|
4534
|
+
sql,
|
|
4535
|
+
payload,
|
|
4536
|
+
options: mergedOptions
|
|
4537
|
+
},
|
|
4538
|
+
async () => {
|
|
4539
|
+
const response = await client.insertGateway(payload, mergedOptions);
|
|
4540
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
4541
|
+
},
|
|
4542
|
+
callsite
|
|
4543
|
+
);
|
|
2716
4544
|
};
|
|
2717
|
-
return createMutationQuery(executeUpsertOne);
|
|
4545
|
+
return createMutationQuery(executeUpsertOne, DEFAULT_COLUMNS, tracer, mutationCallsite);
|
|
2718
4546
|
},
|
|
2719
4547
|
update(values, options) {
|
|
2720
|
-
const
|
|
4548
|
+
const mutationCallsite = captureTraceCallsite(tracer);
|
|
4549
|
+
const executeUpdate = async (columns, selectOptions, callsite) => {
|
|
2721
4550
|
const filters = state.conditions.length ? [...state.conditions] : void 0;
|
|
2722
4551
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2723
4552
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
@@ -2732,10 +4561,25 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2732
4561
|
if (state.pageSize !== void 0) payload.page_size = state.pageSize;
|
|
2733
4562
|
if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
|
|
2734
4563
|
if (columns) payload.columns = columns;
|
|
2735
|
-
const
|
|
2736
|
-
return
|
|
4564
|
+
const sql = buildUpdateDebugSql(payload);
|
|
4565
|
+
return executeWithQueryTrace(
|
|
4566
|
+
tracer,
|
|
4567
|
+
{
|
|
4568
|
+
operation: "update",
|
|
4569
|
+
endpoint: "/gateway/update",
|
|
4570
|
+
table: resolvedTableName,
|
|
4571
|
+
sql,
|
|
4572
|
+
payload,
|
|
4573
|
+
options: mergedOptions
|
|
4574
|
+
},
|
|
4575
|
+
async () => {
|
|
4576
|
+
const response = await client.updateGateway(payload, mergedOptions);
|
|
4577
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "update" });
|
|
4578
|
+
},
|
|
4579
|
+
callsite
|
|
4580
|
+
);
|
|
2737
4581
|
};
|
|
2738
|
-
const mutation = createMutationQuery(executeUpdate, null);
|
|
4582
|
+
const mutation = createMutationQuery(executeUpdate, null, tracer, mutationCallsite);
|
|
2739
4583
|
const updateChain = {};
|
|
2740
4584
|
const filterMethods2 = createFilterMethods(state, addCondition, updateChain);
|
|
2741
4585
|
Object.assign(updateChain, filterMethods2, mutation);
|
|
@@ -2747,7 +4591,8 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2747
4591
|
if (!resourceId && !filters?.length) {
|
|
2748
4592
|
throw new Error('delete requires a resource_id either via eq("resource_id", ...) or options.resourceId');
|
|
2749
4593
|
}
|
|
2750
|
-
const
|
|
4594
|
+
const mutationCallsite = captureTraceCallsite(tracer);
|
|
4595
|
+
const executeDelete = async (columns, selectOptions, callsite) => {
|
|
2751
4596
|
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2752
4597
|
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
2753
4598
|
const payload = {
|
|
@@ -2760,13 +4605,33 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2760
4605
|
if (state.pageSize !== void 0) payload.page_size = state.pageSize;
|
|
2761
4606
|
if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
|
|
2762
4607
|
if (columns) payload.columns = columns;
|
|
2763
|
-
const
|
|
2764
|
-
return
|
|
4608
|
+
const sql = buildDeleteDebugSql(payload);
|
|
4609
|
+
return executeWithQueryTrace(
|
|
4610
|
+
tracer,
|
|
4611
|
+
{
|
|
4612
|
+
operation: "delete",
|
|
4613
|
+
endpoint: "/gateway/delete",
|
|
4614
|
+
table: resolvedTableName,
|
|
4615
|
+
sql,
|
|
4616
|
+
payload,
|
|
4617
|
+
options: mergedOptions
|
|
4618
|
+
},
|
|
4619
|
+
async () => {
|
|
4620
|
+
const response = await client.deleteGateway(payload, mergedOptions);
|
|
4621
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "delete" });
|
|
4622
|
+
},
|
|
4623
|
+
callsite
|
|
4624
|
+
);
|
|
2765
4625
|
};
|
|
2766
|
-
return createMutationQuery(executeDelete, null);
|
|
4626
|
+
return createMutationQuery(executeDelete, null, tracer, mutationCallsite);
|
|
2767
4627
|
},
|
|
2768
4628
|
async single(columns, options) {
|
|
2769
|
-
const response = await
|
|
4629
|
+
const response = await runSelect(
|
|
4630
|
+
columns ?? DEFAULT_COLUMNS,
|
|
4631
|
+
options,
|
|
4632
|
+
snapshotState(),
|
|
4633
|
+
captureTraceCallsite(tracer)
|
|
4634
|
+
);
|
|
2770
4635
|
return toSingleResult(response);
|
|
2771
4636
|
},
|
|
2772
4637
|
async maybeSingle(columns, options) {
|
|
@@ -2775,14 +4640,29 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
|
2775
4640
|
});
|
|
2776
4641
|
return builder;
|
|
2777
4642
|
}
|
|
2778
|
-
function createQueryBuilder(client, formatGatewayResult) {
|
|
4643
|
+
function createQueryBuilder(client, formatGatewayResult, tracer) {
|
|
2779
4644
|
return async function query(query, options) {
|
|
2780
4645
|
const normalizedQuery = query.trim();
|
|
2781
4646
|
if (!normalizedQuery) {
|
|
2782
4647
|
throw new Error("query requires a non-empty string");
|
|
2783
4648
|
}
|
|
2784
|
-
const
|
|
2785
|
-
|
|
4649
|
+
const payload = { query: normalizedQuery };
|
|
4650
|
+
const callsite = captureTraceCallsite(tracer);
|
|
4651
|
+
return executeWithQueryTrace(
|
|
4652
|
+
tracer,
|
|
4653
|
+
{
|
|
4654
|
+
operation: "query",
|
|
4655
|
+
endpoint: "/gateway/query",
|
|
4656
|
+
sql: normalizedQuery,
|
|
4657
|
+
payload,
|
|
4658
|
+
options
|
|
4659
|
+
},
|
|
4660
|
+
async () => {
|
|
4661
|
+
const response = await client.queryGateway(payload, options);
|
|
4662
|
+
return formatGatewayResult(response, { operation: "query" });
|
|
4663
|
+
},
|
|
4664
|
+
callsite
|
|
4665
|
+
);
|
|
2786
4666
|
};
|
|
2787
4667
|
}
|
|
2788
4668
|
function createClientFromConfig(config) {
|
|
@@ -2794,8 +4674,15 @@ function createClientFromConfig(config) {
|
|
|
2794
4674
|
headers: config.headers
|
|
2795
4675
|
});
|
|
2796
4676
|
const formatGatewayResult = createResultFormatter(config.experimental);
|
|
4677
|
+
const queryTracer = createQueryTracer(config.experimental);
|
|
2797
4678
|
const auth = createAuthClient(config.auth);
|
|
2798
|
-
const from = (table) => createTableBuilder(
|
|
4679
|
+
const from = (table, options) => createTableBuilder(
|
|
4680
|
+
resolveTableNameForCall(table, options?.schema),
|
|
4681
|
+
gateway,
|
|
4682
|
+
formatGatewayResult,
|
|
4683
|
+
queryTracer,
|
|
4684
|
+
config.experimental
|
|
4685
|
+
);
|
|
2799
4686
|
const rpc = (fn, args, options) => {
|
|
2800
4687
|
const normalizedFn = fn.trim();
|
|
2801
4688
|
if (!normalizedFn) {
|
|
@@ -2806,16 +4693,19 @@ function createClientFromConfig(config) {
|
|
|
2806
4693
|
args,
|
|
2807
4694
|
options,
|
|
2808
4695
|
gateway,
|
|
2809
|
-
formatGatewayResult
|
|
4696
|
+
formatGatewayResult,
|
|
4697
|
+
queryTracer,
|
|
4698
|
+
captureTraceCallsite(queryTracer)
|
|
2810
4699
|
);
|
|
2811
4700
|
};
|
|
2812
|
-
const query = createQueryBuilder(gateway, formatGatewayResult);
|
|
4701
|
+
const query = createQueryBuilder(gateway, formatGatewayResult, queryTracer);
|
|
2813
4702
|
const db = createDbModule({ from, rpc, query });
|
|
2814
4703
|
return {
|
|
2815
4704
|
from,
|
|
2816
4705
|
db,
|
|
2817
4706
|
rpc,
|
|
2818
4707
|
query,
|
|
4708
|
+
verifyConnection: gateway.verifyConnection,
|
|
2819
4709
|
auth: auth.auth
|
|
2820
4710
|
};
|
|
2821
4711
|
}
|
|
@@ -2824,12 +4714,40 @@ function toBackendConfig(b) {
|
|
|
2824
4714
|
if (!b) return DEFAULT_BACKEND;
|
|
2825
4715
|
return typeof b === "string" ? { type: b } : b;
|
|
2826
4716
|
}
|
|
4717
|
+
function mergeAuthClientConfig(current, next) {
|
|
4718
|
+
const merged = {
|
|
4719
|
+
...current ?? {},
|
|
4720
|
+
...next
|
|
4721
|
+
};
|
|
4722
|
+
if (current?.headers || next.headers) {
|
|
4723
|
+
merged.headers = {
|
|
4724
|
+
...current?.headers ?? {},
|
|
4725
|
+
...next.headers ?? {}
|
|
4726
|
+
};
|
|
4727
|
+
}
|
|
4728
|
+
return merged;
|
|
4729
|
+
}
|
|
4730
|
+
function mergeExperimentalOptions(current, next) {
|
|
4731
|
+
const merged = {
|
|
4732
|
+
...current ?? {},
|
|
4733
|
+
...next
|
|
4734
|
+
};
|
|
4735
|
+
if (current?.traceQueries && typeof current.traceQueries === "object" && next.traceQueries && typeof next.traceQueries === "object") {
|
|
4736
|
+
merged.traceQueries = {
|
|
4737
|
+
...current.traceQueries,
|
|
4738
|
+
...next.traceQueries
|
|
4739
|
+
};
|
|
4740
|
+
}
|
|
4741
|
+
return merged;
|
|
4742
|
+
}
|
|
2827
4743
|
var AthenaClientBuilderImpl = class {
|
|
2828
4744
|
baseUrl;
|
|
2829
4745
|
apiKey;
|
|
2830
4746
|
backendConfig = DEFAULT_BACKEND;
|
|
2831
4747
|
clientName;
|
|
2832
4748
|
defaultHeaders;
|
|
4749
|
+
authConfig;
|
|
4750
|
+
experimentalOptions;
|
|
2833
4751
|
isHealthTrackingEnabled = false;
|
|
2834
4752
|
url(url) {
|
|
2835
4753
|
this.baseUrl = url;
|
|
@@ -2851,6 +4769,35 @@ var AthenaClientBuilderImpl = class {
|
|
|
2851
4769
|
this.defaultHeaders = headers;
|
|
2852
4770
|
return this;
|
|
2853
4771
|
}
|
|
4772
|
+
auth(config) {
|
|
4773
|
+
this.authConfig = mergeAuthClientConfig(this.authConfig, config);
|
|
4774
|
+
return this;
|
|
4775
|
+
}
|
|
4776
|
+
experimental(options) {
|
|
4777
|
+
this.experimentalOptions = mergeExperimentalOptions(this.experimentalOptions, options);
|
|
4778
|
+
return this;
|
|
4779
|
+
}
|
|
4780
|
+
options(options) {
|
|
4781
|
+
if (options.client !== void 0) {
|
|
4782
|
+
this.clientName = options.client;
|
|
4783
|
+
}
|
|
4784
|
+
if (options.backend !== void 0) {
|
|
4785
|
+
this.backendConfig = toBackendConfig(options.backend);
|
|
4786
|
+
}
|
|
4787
|
+
if (options.headers !== void 0) {
|
|
4788
|
+
this.defaultHeaders = {
|
|
4789
|
+
...this.defaultHeaders ?? {},
|
|
4790
|
+
...options.headers
|
|
4791
|
+
};
|
|
4792
|
+
}
|
|
4793
|
+
if (options.auth !== void 0) {
|
|
4794
|
+
this.authConfig = mergeAuthClientConfig(this.authConfig, options.auth);
|
|
4795
|
+
}
|
|
4796
|
+
if (options.experimental !== void 0) {
|
|
4797
|
+
this.experimentalOptions = mergeExperimentalOptions(this.experimentalOptions, options.experimental);
|
|
4798
|
+
}
|
|
4799
|
+
return this;
|
|
4800
|
+
}
|
|
2854
4801
|
healthTracking(enabled) {
|
|
2855
4802
|
this.isHealthTrackingEnabled = enabled;
|
|
2856
4803
|
return this;
|
|
@@ -2865,7 +4812,9 @@ var AthenaClientBuilderImpl = class {
|
|
|
2865
4812
|
client: this.clientName,
|
|
2866
4813
|
backend: this.backendConfig,
|
|
2867
4814
|
headers: this.defaultHeaders,
|
|
2868
|
-
healthTracking: this.isHealthTrackingEnabled
|
|
4815
|
+
healthTracking: this.isHealthTrackingEnabled,
|
|
4816
|
+
auth: this.authConfig,
|
|
4817
|
+
experimental: this.experimentalOptions
|
|
2869
4818
|
});
|
|
2870
4819
|
}
|
|
2871
4820
|
};
|
|
@@ -3000,8 +4949,8 @@ var TypedAthenaClientImpl = class _TypedAthenaClientImpl {
|
|
|
3000
4949
|
});
|
|
3001
4950
|
this.db = this.baseClient.db;
|
|
3002
4951
|
}
|
|
3003
|
-
from(table) {
|
|
3004
|
-
return this.baseClient.from(table);
|
|
4952
|
+
from(table, options) {
|
|
4953
|
+
return this.baseClient.from(table, options);
|
|
3005
4954
|
}
|
|
3006
4955
|
rpc(fn, args, options) {
|
|
3007
4956
|
return this.baseClient.rpc(fn, args, options);
|
|
@@ -3009,6 +4958,9 @@ var TypedAthenaClientImpl = class _TypedAthenaClientImpl {
|
|
|
3009
4958
|
query(query, options) {
|
|
3010
4959
|
return this.baseClient.query(query, options);
|
|
3011
4960
|
}
|
|
4961
|
+
verifyConnection(options) {
|
|
4962
|
+
return this.baseClient.verifyConnection(options);
|
|
4963
|
+
}
|
|
3012
4964
|
withTenantContext(context) {
|
|
3013
4965
|
return new _TypedAthenaClientImpl({
|
|
3014
4966
|
registry: this.registry,
|
|
@@ -3480,7 +5432,7 @@ function resolveNullishValue(mode) {
|
|
|
3480
5432
|
if (mode === "null") return null;
|
|
3481
5433
|
return "";
|
|
3482
5434
|
}
|
|
3483
|
-
function
|
|
5435
|
+
function isRecord7(value) {
|
|
3484
5436
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3485
5437
|
}
|
|
3486
5438
|
function isNullableColumn(model, key) {
|
|
@@ -3489,7 +5441,7 @@ function isNullableColumn(model, key) {
|
|
|
3489
5441
|
}
|
|
3490
5442
|
function toModelFormDefaults(model, values, options) {
|
|
3491
5443
|
const source = values;
|
|
3492
|
-
if (!
|
|
5444
|
+
if (!isRecord7(source)) {
|
|
3493
5445
|
return {};
|
|
3494
5446
|
}
|
|
3495
5447
|
const mode = options?.nullishMode ?? "empty-string";
|
|
@@ -3745,7 +5697,7 @@ function normalizeBooleanFlag(rawValue, fallback) {
|
|
|
3745
5697
|
return rawValue;
|
|
3746
5698
|
}
|
|
3747
5699
|
if (typeof rawValue === "string") {
|
|
3748
|
-
return
|
|
5700
|
+
return parseBooleanFlag2(rawValue, fallback);
|
|
3749
5701
|
}
|
|
3750
5702
|
return fallback;
|
|
3751
5703
|
}
|
|
@@ -3920,6 +5872,11 @@ async function loadGeneratorConfig(options = {}) {
|
|
|
3920
5872
|
}
|
|
3921
5873
|
}
|
|
3922
5874
|
|
|
5875
|
+
// src/utils/slugify.ts
|
|
5876
|
+
function slugify(input) {
|
|
5877
|
+
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
5878
|
+
}
|
|
5879
|
+
|
|
3923
5880
|
// src/generator/naming.ts
|
|
3924
5881
|
var IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
3925
5882
|
var RESERVED_IDENTIFIERS = /* @__PURE__ */ new Set([
|
|
@@ -4015,7 +5972,7 @@ function applyNamingStyle(input, style) {
|
|
|
4015
5972
|
case "snake":
|
|
4016
5973
|
return words.map((word) => word.toLowerCase()).join("_");
|
|
4017
5974
|
case "kebab":
|
|
4018
|
-
return words.
|
|
5975
|
+
return slugify(words.join("-"));
|
|
4019
5976
|
default:
|
|
4020
5977
|
return input;
|
|
4021
5978
|
}
|
|
@@ -4533,7 +6490,7 @@ var AthenaGatewayCatalogClient = class {
|
|
|
4533
6490
|
async queryRows(query) {
|
|
4534
6491
|
const result = await this.client.query(query);
|
|
4535
6492
|
if (result.error || result.status < 200 || result.status >= 300) {
|
|
4536
|
-
throw new Error(result.error ?? `Gateway query failed with status ${result.status}`);
|
|
6493
|
+
throw new Error(result.error?.message ?? `Gateway query failed with status ${result.status}`);
|
|
4537
6494
|
}
|
|
4538
6495
|
return result.data ?? [];
|
|
4539
6496
|
}
|
|
@@ -4628,10 +6585,24 @@ function resolveGeneratorProvider(providerConfig, experimentalFlags) {
|
|
|
4628
6585
|
}
|
|
4629
6586
|
throw new Error(`Unsupported generator provider kind: ${providerConfig.kind ?? "unknown"}`);
|
|
4630
6587
|
}
|
|
6588
|
+
function canOverwriteArtifact(file) {
|
|
6589
|
+
return file.kind === "model" || file.kind === "schema";
|
|
6590
|
+
}
|
|
6591
|
+
async function fileExists(path) {
|
|
6592
|
+
try {
|
|
6593
|
+
await stat(path);
|
|
6594
|
+
return true;
|
|
6595
|
+
} catch {
|
|
6596
|
+
return false;
|
|
6597
|
+
}
|
|
6598
|
+
}
|
|
4631
6599
|
async function writeArtifacts(files, cwd) {
|
|
4632
6600
|
const writtenFiles = [];
|
|
4633
6601
|
for (const file of files) {
|
|
4634
6602
|
const absolutePath = resolve(cwd, file.path);
|
|
6603
|
+
if (!canOverwriteArtifact(file) && await fileExists(absolutePath)) {
|
|
6604
|
+
continue;
|
|
6605
|
+
}
|
|
4635
6606
|
await mkdir(dirname(absolutePath), { recursive: true });
|
|
4636
6607
|
await writeFile(absolutePath, file.content, "utf8");
|
|
4637
6608
|
writtenFiles.push(file.path);
|
|
@@ -4658,6 +6629,6 @@ async function runSchemaGenerator(options = {}) {
|
|
|
4658
6629
|
};
|
|
4659
6630
|
}
|
|
4660
6631
|
|
|
4661
|
-
export { AthenaClient, AthenaError, AthenaErrorCategory, AthenaErrorCode, AthenaErrorKind, AthenaGatewayError, Backend, DEFAULT_POSTGRES_SCHEMAS, assertInt, coerceInt, createAuthClient, createClient, createModelFormAdapter, createPostgresIntrospectionProvider, createTypedClient, defineDatabase, defineGeneratorConfig, defineModel, defineRegistry, defineSchema, findGeneratorConfigPath, generateArtifactsFromSnapshot, identifier, isAthenaGatewayError, isOk, loadGeneratorConfig, normalizeAthenaError, normalizeGeneratorConfig, normalizeSchemaSelection, parseBooleanFlag, requireAffected, requireSuccess, resolveGeneratorProvider, resolvePostgresColumnType, resolveProviderSchemas, runSchemaGenerator, toModelFormDefaults, toModelPayload, unwrap, unwrapOne, unwrapRows, withRetry };
|
|
6632
|
+
export { AthenaClient, AthenaError, AthenaErrorCategory, AthenaErrorCode, AthenaErrorKind, AthenaGatewayError, Backend, DEFAULT_POSTGRES_SCHEMAS, assertInt, coerceInt, createAuthClient, createAuthReactEmailInput, createClient, createModelFormAdapter, createPostgresIntrospectionProvider, createTypedClient, defineAuthEmailTemplate, defineDatabase, defineGeneratorConfig, defineModel, defineRegistry, defineSchema, findGeneratorConfigPath, generateArtifactsFromSnapshot, identifier, isAthenaGatewayError, isOk, loadGeneratorConfig, normalizeAthenaError, normalizeAthenaGatewayBaseUrl, normalizeGeneratorConfig, normalizeSchemaSelection, parseBooleanFlag2 as parseBooleanFlag, renderAthenaReactEmail, requireAffected, requireSuccess, resolveGeneratorProvider, resolvePostgresColumnType, resolveProviderSchemas, runSchemaGenerator, toModelFormDefaults, toModelPayload, unwrap, unwrapOne, unwrapRows, verifyAthenaGatewayUrl, withRetry };
|
|
4662
6633
|
//# sourceMappingURL=index.js.map
|
|
4663
6634
|
//# sourceMappingURL=index.js.map
|