@xylex-group/athena 1.4.0 → 1.5.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 +101 -8
- package/dist/{errors-CB-eJQ7x.d.cts → errors-C4GJaFI_.d.cts} +16 -1
- package/dist/{errors-CB-eJQ7x.d.ts → errors-C4GJaFI_.d.ts} +16 -1
- package/dist/index.cjs +173 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +173 -4
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +965 -0
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +234 -3
- package/dist/react.d.ts +234 -3
- package/dist/react.js +960 -2
- package/dist/react.js.map +1 -1
- package/package.json +11 -7
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { A as AthenaGatewayCallOptions, a as AthenaConditionValue, b as AthenaConditionCastType, c as AthenaConditionArrayValue, d as AthenaConditionOperator, e as AthenaGatewayErrorDetails, f as AthenaRpcCallOptions, B as BackendConfig, g as BackendType } from './errors-C4GJaFI_.cjs';
|
|
2
|
+
export { i as AthenaGatewayError, o as AthenaGatewayErrorCode, k as AthenaRpcFilter, l as AthenaRpcFilterOperator, m as AthenaRpcOrder, n as AthenaRpcPayload, h as Backend, j as isAthenaGatewayError } from './errors-C4GJaFI_.cjs';
|
|
3
3
|
|
|
4
4
|
interface AthenaResult<T> {
|
|
5
5
|
data: T | null;
|
|
@@ -25,6 +25,8 @@ interface OrderOptions {
|
|
|
25
25
|
/** Shared filter chain - supports eq, limit, etc. in any order relative to select/update */
|
|
26
26
|
interface FilterChain<Self> {
|
|
27
27
|
eq(column: string, value: AthenaConditionValue): Self;
|
|
28
|
+
eqCast(column: string, value: AthenaConditionValue, cast: AthenaConditionCastType): Self;
|
|
29
|
+
eqUuid(column: string, value: string): Self;
|
|
28
30
|
match(filters: Record<string, AthenaConditionValue>): Self;
|
|
29
31
|
range(from: number, to: number): Self;
|
|
30
32
|
limit(count: number): Self;
|
|
@@ -244,4 +246,4 @@ declare function assertInt(value: unknown, label?: string, options?: IntCoercion
|
|
|
244
246
|
*/
|
|
245
247
|
declare function withRetry<T>(config: RetryConfig, fn: () => Promise<T>): Promise<T>;
|
|
246
248
|
|
|
247
|
-
export { AthenaClient, type AthenaErrorKind, AthenaGatewayCallOptions, AthenaGatewayErrorDetails, type AthenaOperationContext, type AthenaResult, AthenaRpcCallOptions, type AthenaSdkClient, BackendConfig, BackendType, type IntCoercionOptions, type NormalizedAthenaError, type RequireAffectedOptions, type RetryBackoffStrategy, type RetryConfig, type RpcOrderOptions, type RpcQueryBuilder, type TableQueryBuilder, type UnwrapOneOptions, type UnwrapOptions, assertInt, coerceInt, createClient, isOk, normalizeAthenaError, requireAffected, requireSuccess, unwrap, unwrapOne, unwrapRows, withRetry };
|
|
249
|
+
export { AthenaClient, AthenaConditionCastType, type AthenaErrorKind, AthenaGatewayCallOptions, AthenaGatewayErrorDetails, type AthenaOperationContext, type AthenaResult, AthenaRpcCallOptions, type AthenaSdkClient, BackendConfig, BackendType, type IntCoercionOptions, type NormalizedAthenaError, type RequireAffectedOptions, type RetryBackoffStrategy, type RetryConfig, type RpcOrderOptions, type RpcQueryBuilder, type TableQueryBuilder, type UnwrapOneOptions, type UnwrapOptions, assertInt, coerceInt, createClient, isOk, normalizeAthenaError, requireAffected, requireSuccess, unwrap, unwrapOne, unwrapRows, withRetry };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { A as AthenaGatewayCallOptions, a as AthenaConditionValue, b as AthenaConditionCastType, c as AthenaConditionArrayValue, d as AthenaConditionOperator, e as AthenaGatewayErrorDetails, f as AthenaRpcCallOptions, B as BackendConfig, g as BackendType } from './errors-C4GJaFI_.js';
|
|
2
|
+
export { i as AthenaGatewayError, o as AthenaGatewayErrorCode, k as AthenaRpcFilter, l as AthenaRpcFilterOperator, m as AthenaRpcOrder, n as AthenaRpcPayload, h as Backend, j as isAthenaGatewayError } from './errors-C4GJaFI_.js';
|
|
3
3
|
|
|
4
4
|
interface AthenaResult<T> {
|
|
5
5
|
data: T | null;
|
|
@@ -25,6 +25,8 @@ interface OrderOptions {
|
|
|
25
25
|
/** Shared filter chain - supports eq, limit, etc. in any order relative to select/update */
|
|
26
26
|
interface FilterChain<Self> {
|
|
27
27
|
eq(column: string, value: AthenaConditionValue): Self;
|
|
28
|
+
eqCast(column: string, value: AthenaConditionValue, cast: AthenaConditionCastType): Self;
|
|
29
|
+
eqUuid(column: string, value: string): Self;
|
|
28
30
|
match(filters: Record<string, AthenaConditionValue>): Self;
|
|
29
31
|
range(from: number, to: number): Self;
|
|
30
32
|
limit(count: number): Self;
|
|
@@ -244,4 +246,4 @@ declare function assertInt(value: unknown, label?: string, options?: IntCoercion
|
|
|
244
246
|
*/
|
|
245
247
|
declare function withRetry<T>(config: RetryConfig, fn: () => Promise<T>): Promise<T>;
|
|
246
248
|
|
|
247
|
-
export { AthenaClient, type AthenaErrorKind, AthenaGatewayCallOptions, AthenaGatewayErrorDetails, type AthenaOperationContext, type AthenaResult, AthenaRpcCallOptions, type AthenaSdkClient, BackendConfig, BackendType, type IntCoercionOptions, type NormalizedAthenaError, type RequireAffectedOptions, type RetryBackoffStrategy, type RetryConfig, type RpcOrderOptions, type RpcQueryBuilder, type TableQueryBuilder, type UnwrapOneOptions, type UnwrapOptions, assertInt, coerceInt, createClient, isOk, normalizeAthenaError, requireAffected, requireSuccess, unwrap, unwrapOne, unwrapRows, withRetry };
|
|
249
|
+
export { AthenaClient, AthenaConditionCastType, type AthenaErrorKind, AthenaGatewayCallOptions, AthenaGatewayErrorDetails, type AthenaOperationContext, type AthenaResult, AthenaRpcCallOptions, type AthenaSdkClient, BackendConfig, BackendType, type IntCoercionOptions, type NormalizedAthenaError, type RequireAffectedOptions, type RetryBackoffStrategy, type RetryConfig, type RpcOrderOptions, type RpcQueryBuilder, type TableQueryBuilder, type UnwrapOneOptions, type UnwrapOptions, assertInt, coerceInt, createClient, isOk, normalizeAthenaError, requireAffected, requireSuccess, unwrap, unwrapOne, unwrapRows, withRetry };
|
package/dist/index.js
CHANGED
|
@@ -366,6 +366,8 @@ function createAthenaGatewayClient(config = {}) {
|
|
|
366
366
|
|
|
367
367
|
// src/client.ts
|
|
368
368
|
var DEFAULT_COLUMNS = "*";
|
|
369
|
+
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;
|
|
370
|
+
var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
|
|
369
371
|
function formatResult(response) {
|
|
370
372
|
const result = {
|
|
371
373
|
data: response.data ?? null,
|
|
@@ -446,14 +448,149 @@ function stringifyFilterValue(value) {
|
|
|
446
448
|
}
|
|
447
449
|
return String(value);
|
|
448
450
|
}
|
|
451
|
+
function isUuidString(value) {
|
|
452
|
+
return UUID_PATTERN.test(value.trim());
|
|
453
|
+
}
|
|
454
|
+
function isUuidIdentifierColumn(column) {
|
|
455
|
+
return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
|
|
456
|
+
}
|
|
457
|
+
function shouldUseUuidTextComparison(column, value) {
|
|
458
|
+
return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
|
|
459
|
+
}
|
|
460
|
+
function normalizeCast(cast) {
|
|
461
|
+
const normalized = cast.trim().toLowerCase();
|
|
462
|
+
if (!SAFE_CAST_PATTERN.test(normalized)) {
|
|
463
|
+
throw new Error(`Invalid cast type "${cast}"`);
|
|
464
|
+
}
|
|
465
|
+
return normalized;
|
|
466
|
+
}
|
|
467
|
+
function escapeSqlStringLiteral(value) {
|
|
468
|
+
return value.replace(/'/g, "''");
|
|
469
|
+
}
|
|
470
|
+
function quoteIdentifier(identifier) {
|
|
471
|
+
return `"${identifier.replace(/"/g, '""')}"`;
|
|
472
|
+
}
|
|
473
|
+
function quoteQualifiedIdentifier(identifier) {
|
|
474
|
+
return identifier.split(".").map((segment) => quoteIdentifier(segment)).join(".");
|
|
475
|
+
}
|
|
476
|
+
function toSqlLiteral(value) {
|
|
477
|
+
if (value === null) return "NULL";
|
|
478
|
+
if (typeof value === "number") return Number.isFinite(value) ? String(value) : "NULL";
|
|
479
|
+
if (typeof value === "boolean") return value ? "TRUE" : "FALSE";
|
|
480
|
+
return `'${escapeSqlStringLiteral(value)}'`;
|
|
481
|
+
}
|
|
482
|
+
function withCast(expression, cast) {
|
|
483
|
+
if (!cast) return expression;
|
|
484
|
+
return `${expression}::${normalizeCast(cast)}`;
|
|
485
|
+
}
|
|
486
|
+
function buildSelectColumnsClause(columns) {
|
|
487
|
+
if (Array.isArray(columns)) {
|
|
488
|
+
return columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
|
|
489
|
+
}
|
|
490
|
+
return columns;
|
|
491
|
+
}
|
|
492
|
+
function conditionToSqlClause(condition) {
|
|
493
|
+
if (!condition.column) return null;
|
|
494
|
+
const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
|
|
495
|
+
const value = condition.value;
|
|
496
|
+
const sqlOperator = {
|
|
497
|
+
eq: "=",
|
|
498
|
+
neq: "!=",
|
|
499
|
+
gt: ">",
|
|
500
|
+
gte: ">=",
|
|
501
|
+
lt: "<",
|
|
502
|
+
lte: "<=",
|
|
503
|
+
like: "LIKE",
|
|
504
|
+
ilike: "ILIKE"
|
|
505
|
+
};
|
|
506
|
+
switch (condition.operator) {
|
|
507
|
+
case "eq":
|
|
508
|
+
case "neq":
|
|
509
|
+
case "gt":
|
|
510
|
+
case "gte":
|
|
511
|
+
case "lt":
|
|
512
|
+
case "lte":
|
|
513
|
+
case "like":
|
|
514
|
+
case "ilike": {
|
|
515
|
+
if (Array.isArray(value) || value === void 0) return null;
|
|
516
|
+
const rhs = withCast(toSqlLiteral(value), condition.value_cast);
|
|
517
|
+
return `${column} ${sqlOperator[condition.operator]} ${rhs}`;
|
|
518
|
+
}
|
|
519
|
+
case "is": {
|
|
520
|
+
if (value === null) return `${column} IS NULL`;
|
|
521
|
+
if (value === true) return `${column} IS TRUE`;
|
|
522
|
+
if (value === false) return `${column} IS FALSE`;
|
|
523
|
+
return null;
|
|
524
|
+
}
|
|
525
|
+
case "in": {
|
|
526
|
+
if (!Array.isArray(value)) return null;
|
|
527
|
+
if (value.length === 0) return "FALSE";
|
|
528
|
+
const values = value.map((item) => withCast(toSqlLiteral(item), condition.value_cast));
|
|
529
|
+
return `${column} IN (${values.join(", ")})`;
|
|
530
|
+
}
|
|
531
|
+
default:
|
|
532
|
+
return null;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
function buildTypedSelectQuery(input) {
|
|
536
|
+
const whereClauses = [];
|
|
537
|
+
for (const condition of input.conditions) {
|
|
538
|
+
const clause = conditionToSqlClause(condition);
|
|
539
|
+
if (!clause) return null;
|
|
540
|
+
whereClauses.push(clause);
|
|
541
|
+
}
|
|
542
|
+
let limit = input.limit;
|
|
543
|
+
let offset = input.offset;
|
|
544
|
+
if (limit === void 0 && input.pageSize !== void 0) {
|
|
545
|
+
limit = input.pageSize;
|
|
546
|
+
}
|
|
547
|
+
if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
|
|
548
|
+
offset = (input.currentPage - 1) * input.pageSize;
|
|
549
|
+
}
|
|
550
|
+
const sqlParts = [
|
|
551
|
+
`SELECT ${buildSelectColumnsClause(input.columns)} FROM ${quoteQualifiedIdentifier(input.tableName)}`
|
|
552
|
+
];
|
|
553
|
+
if (whereClauses.length > 0) {
|
|
554
|
+
sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
|
|
555
|
+
}
|
|
556
|
+
if (input.order?.field) {
|
|
557
|
+
const direction = input.order.direction === "descending" ? "DESC" : "ASC";
|
|
558
|
+
sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(input.order.field)} ${direction}`);
|
|
559
|
+
}
|
|
560
|
+
if (limit !== void 0) {
|
|
561
|
+
sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(limit))}`);
|
|
562
|
+
}
|
|
563
|
+
if (offset !== void 0) {
|
|
564
|
+
sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
|
|
565
|
+
}
|
|
566
|
+
return `${sqlParts.join(" ")};`;
|
|
567
|
+
}
|
|
449
568
|
function createFilterMethods(state, addCondition, self) {
|
|
450
569
|
return {
|
|
451
570
|
eq(column, value) {
|
|
452
|
-
|
|
571
|
+
if (shouldUseUuidTextComparison(column, value)) {
|
|
572
|
+
addCondition("eq", column, value, { columnCast: "text" });
|
|
573
|
+
} else {
|
|
574
|
+
addCondition("eq", column, value);
|
|
575
|
+
}
|
|
576
|
+
return self;
|
|
577
|
+
},
|
|
578
|
+
eqCast(column, value, cast) {
|
|
579
|
+
addCondition("eq", column, value, { valueCast: cast });
|
|
580
|
+
return self;
|
|
581
|
+
},
|
|
582
|
+
eqUuid(column, value) {
|
|
583
|
+
addCondition("eq", column, value, { valueCast: "uuid" });
|
|
453
584
|
return self;
|
|
454
585
|
},
|
|
455
586
|
match(filters) {
|
|
456
|
-
Object.entries(filters).forEach(([column, value]) =>
|
|
587
|
+
Object.entries(filters).forEach(([column, value]) => {
|
|
588
|
+
if (shouldUseUuidTextComparison(column, value)) {
|
|
589
|
+
addCondition("eq", column, value, { columnCast: "text" });
|
|
590
|
+
} else {
|
|
591
|
+
addCondition("eq", column, value);
|
|
592
|
+
}
|
|
593
|
+
});
|
|
457
594
|
return self;
|
|
458
595
|
},
|
|
459
596
|
range(from, to) {
|
|
@@ -677,7 +814,7 @@ function createTableBuilder(tableName, client) {
|
|
|
677
814
|
const state = {
|
|
678
815
|
conditions: []
|
|
679
816
|
};
|
|
680
|
-
const addCondition = (operator, column, value) => {
|
|
817
|
+
const addCondition = (operator, column, value, hints) => {
|
|
681
818
|
const condition = { operator };
|
|
682
819
|
if (column) {
|
|
683
820
|
condition.column = column;
|
|
@@ -691,15 +828,47 @@ function createTableBuilder(tableName, client) {
|
|
|
691
828
|
condition.eq_value = value;
|
|
692
829
|
}
|
|
693
830
|
}
|
|
831
|
+
if (hints?.valueCast) {
|
|
832
|
+
condition.value_cast = hints.valueCast;
|
|
833
|
+
if (operator === "eq") {
|
|
834
|
+
condition.eq_value_cast = hints.valueCast;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
if (hints?.columnCast) {
|
|
838
|
+
condition.column_cast = hints.columnCast;
|
|
839
|
+
if (operator === "eq") {
|
|
840
|
+
condition.eq_column_cast = hints.columnCast;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
694
843
|
state.conditions.push(condition);
|
|
695
844
|
};
|
|
696
845
|
const builder = {};
|
|
697
846
|
const filterMethods = createFilterMethods(state, addCondition, builder);
|
|
698
847
|
const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
|
|
848
|
+
const conditions = state.conditions.length ? state.conditions.map((condition) => ({ ...condition })) : void 0;
|
|
849
|
+
const hasTypedEqualityComparison = conditions?.some(
|
|
850
|
+
(condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
|
|
851
|
+
) ?? false;
|
|
852
|
+
if (hasTypedEqualityComparison && !options?.head && !options?.count && conditions) {
|
|
853
|
+
const query = buildTypedSelectQuery({
|
|
854
|
+
tableName,
|
|
855
|
+
columns,
|
|
856
|
+
conditions,
|
|
857
|
+
limit: state.limit,
|
|
858
|
+
offset: state.offset,
|
|
859
|
+
currentPage: state.currentPage,
|
|
860
|
+
pageSize: state.pageSize,
|
|
861
|
+
order: state.order
|
|
862
|
+
});
|
|
863
|
+
if (query) {
|
|
864
|
+
const queryResponse = await client.queryGateway({ query }, options);
|
|
865
|
+
return formatResult(queryResponse);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
699
868
|
const payload = {
|
|
700
869
|
table_name: tableName,
|
|
701
870
|
columns,
|
|
702
|
-
conditions
|
|
871
|
+
conditions,
|
|
703
872
|
limit: state.limit,
|
|
704
873
|
offset: state.offset,
|
|
705
874
|
current_page: state.currentPage,
|