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