@xylex-group/athena 1.4.1 → 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 +107 -18
- package/dist/{errors-DQerAaXC.d.cts → errors-C4GJaFI_.d.cts} +1 -1
- package/dist/{errors-DQerAaXC.d.ts → errors-C4GJaFI_.d.ts} +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- 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/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# athena-js
|
|
2
2
|
|
|
3
|
-
current version: `1.
|
|
4
|
-
`@xylex-group/athena` is a database driver and API gateway SDK that lets you interact with SQL backends over HTTP through a fluent builder API. It ships a typed query builder for Node.js / server environments
|
|
3
|
+
current version: `1.5.0`
|
|
4
|
+
`@xylex-group/athena` is a database driver and API gateway SDK that lets you interact with SQL backends over HTTP through a fluent builder API. It ships a typed query builder for Node.js / server environments plus Athena-native React hooks for client-side use.
|
|
5
5
|
|
|
6
6
|
## Install
|
|
7
7
|
|
|
@@ -13,7 +13,7 @@ pnpm add @xylex-group/athena
|
|
|
13
13
|
yarn add @xylex-group/athena
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
React peer dependency is optional — only needed if you use `
|
|
16
|
+
React peer dependency is optional — only needed if you use `@xylex-group/athena/react` hooks.
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
19
|
npm install react # React >=17 required for the hook
|
|
@@ -153,12 +153,12 @@ Filters accumulate on the builder and are sent together when the query executes.
|
|
|
153
153
|
|
|
154
154
|
```ts
|
|
155
155
|
const { data } = await athena
|
|
156
|
-
.from("characters")
|
|
157
|
-
.select("id, name")
|
|
158
|
-
.eq("active", true) // column = value
|
|
159
|
-
.eqUuid("session_id", "550e8400-e29b-41d4-a716-446655440000") // explicit UUID cast
|
|
160
|
-
.eqCast("session_id", "550e8400-e29b-41d4-a716-446655440000", "uuid") // explicit cast type
|
|
161
|
-
.neq("role", "guest") // column != value
|
|
156
|
+
.from("characters")
|
|
157
|
+
.select("id, name")
|
|
158
|
+
.eq("active", true) // column = value
|
|
159
|
+
.eqUuid("session_id", "550e8400-e29b-41d4-a716-446655440000") // explicit UUID cast
|
|
160
|
+
.eqCast("session_id", "550e8400-e29b-41d4-a716-446655440000", "uuid") // explicit cast type
|
|
161
|
+
.neq("role", "guest") // column != value
|
|
162
162
|
.gt("level", 5) // column > value
|
|
163
163
|
.gte("score", 100) // column >= value
|
|
164
164
|
.lt("age", 30) // column < value
|
|
@@ -171,10 +171,10 @@ const { data } = await athena
|
|
|
171
171
|
.containedBy("tags", ["hero", "villain"]) // array is subset of value
|
|
172
172
|
.match({ role: "admin", active: true }) // multiple eq filters at once
|
|
173
173
|
.not("role", "eq", "banned") // NOT col op val
|
|
174
|
-
.or("status.eq.active,status.eq.pending"); // OR expression
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
`eq()` now auto-detects UUID-like values on identifier columns (for example `id`, `*_id`, `*uuid*`) and uses a safe typed comparison path so UUID columns no longer require app-side manual `::uuid` / `::text` casts.
|
|
174
|
+
.or("status.eq.active,status.eq.pending"); // OR expression
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
`eq()` now auto-detects UUID-like values on identifier columns (for example `id`, `*_id`, `*uuid*`) and uses a safe typed comparison path so UUID columns no longer require app-side manual `::uuid` / `::text` casts.
|
|
178
178
|
|
|
179
179
|
Canonical style for reads is to call `.select(...)` first, then apply filters:
|
|
180
180
|
|
|
@@ -412,11 +412,102 @@ mutation.finally(() => …);
|
|
|
412
412
|
|
|
413
413
|
The request fires only once regardless of how many times you call `.then()` or await the object.
|
|
414
414
|
|
|
415
|
-
## React
|
|
415
|
+
## React hooks
|
|
416
416
|
|
|
417
417
|
```tsx
|
|
418
418
|
"use client";
|
|
419
419
|
|
|
420
|
+
import {
|
|
421
|
+
AthenaQueryClientProvider,
|
|
422
|
+
createAthenaQueryClient,
|
|
423
|
+
useAthenaGateway,
|
|
424
|
+
useMutation,
|
|
425
|
+
useQuery,
|
|
426
|
+
} from "@xylex-group/athena/react";
|
|
427
|
+
import { createClient } from "@xylex-group/athena";
|
|
428
|
+
|
|
429
|
+
const queryClient = createAthenaQueryClient({
|
|
430
|
+
cache: { mode: "none" }, // default: no persistent data cache, inflight dedupe only
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
const athena = createClient(
|
|
434
|
+
process.env.NEXT_PUBLIC_ATHENA_URL!,
|
|
435
|
+
process.env.NEXT_PUBLIC_ATHENA_API_KEY!,
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
type Product = {
|
|
439
|
+
id: string;
|
|
440
|
+
name: string;
|
|
441
|
+
price: number;
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
type CreateProductInput = {
|
|
445
|
+
name: string;
|
|
446
|
+
price: number;
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
function ProductsInner() {
|
|
450
|
+
const products = useQuery<Product[]>({
|
|
451
|
+
queryKey: ["products"],
|
|
452
|
+
queryFn: () =>
|
|
453
|
+
athena.from("products").select("id,name,price").limit(50),
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
const createProduct = useMutation<CreateProductInput, Product>({
|
|
457
|
+
mutationFn: (input) =>
|
|
458
|
+
athena.from("products").insert(input).select("id,name,price").single(),
|
|
459
|
+
onSuccess: () => {
|
|
460
|
+
void products.refetch();
|
|
461
|
+
},
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
if (products.isLoading) return <div>Loading...</div>;
|
|
465
|
+
if (products.error) return <div>{products.error.message}</div>;
|
|
466
|
+
|
|
467
|
+
return (
|
|
468
|
+
<div>
|
|
469
|
+
<button
|
|
470
|
+
onClick={() => {
|
|
471
|
+
createProduct.mutate({ name: "New product", price: 99 });
|
|
472
|
+
}}
|
|
473
|
+
>
|
|
474
|
+
Add Product
|
|
475
|
+
</button>
|
|
476
|
+
{products.data?.map((product) => (
|
|
477
|
+
<div key={product.id}>
|
|
478
|
+
{product.name} - {product.price}
|
|
479
|
+
</div>
|
|
480
|
+
))}
|
|
481
|
+
</div>
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
export function Products() {
|
|
486
|
+
return (
|
|
487
|
+
<AthenaQueryClientProvider client={queryClient}>
|
|
488
|
+
<ProductsInner />
|
|
489
|
+
</AthenaQueryClientProvider>
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
Available React APIs:
|
|
495
|
+
|
|
496
|
+
- `useAthenaGateway`: low-level gateway hook (`fetchGateway`, `insertGateway`, `updateGateway`, `deleteGateway`, `rpcGateway`) with request/response logging.
|
|
497
|
+
- `createAthenaQueryClient` + `AthenaQueryClientProvider`: Athena query runtime boundary for scoped state and subscriptions.
|
|
498
|
+
- `useQuery`: lightweight read lifecycle hook (`status`, `isFetching`, `refetch`, `reset`) with normalized Athena error/result handling.
|
|
499
|
+
- `useMutation`: lightweight write lifecycle hook (`mutate`, `mutateAsync`, `reset`) with manual refetch/invalidation flow.
|
|
500
|
+
|
|
501
|
+
By design this is not a cache-heavy React Query clone:
|
|
502
|
+
|
|
503
|
+
- No TanStack/React Query dependency.
|
|
504
|
+
- No persistent data cache by default (`cache.mode = "none"`).
|
|
505
|
+
- Inflight dedupe for identical query keys is enabled.
|
|
506
|
+
- Manual `refetch()` after mutations is the default invalidation strategy.
|
|
507
|
+
|
|
508
|
+
`useAthenaGateway` example:
|
|
509
|
+
|
|
510
|
+
```tsx
|
|
420
511
|
import { useAthenaGateway } from "@xylex-group/athena/react";
|
|
421
512
|
import { useEffect } from "react";
|
|
422
513
|
|
|
@@ -427,7 +518,7 @@ export function UsersPanel() {
|
|
|
427
518
|
});
|
|
428
519
|
|
|
429
520
|
useEffect(() => {
|
|
430
|
-
fetchGateway({
|
|
521
|
+
void fetchGateway({
|
|
431
522
|
table_name: "users",
|
|
432
523
|
columns: ["id", "email"],
|
|
433
524
|
limit: 25,
|
|
@@ -441,9 +532,7 @@ export function UsersPanel() {
|
|
|
441
532
|
}
|
|
442
533
|
```
|
|
443
534
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
Hook config options mirror the client options: `baseUrl`, `apiKey`, `headers`, `userId`, `organizationId`, `publishEvent`.
|
|
535
|
+
`useAthenaGateway` config options mirror the client options: `baseUrl`, `apiKey`, `headers`, `userId`, `organizationId`, `publishEvent`.
|
|
447
536
|
|
|
448
537
|
## User context headers
|
|
449
538
|
|
|
@@ -220,4 +220,4 @@ declare class AthenaGatewayError extends Error {
|
|
|
220
220
|
}
|
|
221
221
|
declare function isAthenaGatewayError(error: unknown): error is AthenaGatewayError;
|
|
222
222
|
|
|
223
|
-
export { type
|
|
223
|
+
export { type AthenaGatewayCallOptions as A, type BackendConfig as B, type AthenaConditionValue as a, type AthenaConditionCastType as b, type AthenaConditionArrayValue as c, type AthenaConditionOperator as d, type AthenaGatewayErrorDetails as e, type AthenaRpcCallOptions as f, type BackendType as g, Backend as h, AthenaGatewayError as i, isAthenaGatewayError as j, type AthenaRpcFilter as k, type AthenaRpcFilterOperator as l, type AthenaRpcOrder as m, type AthenaRpcPayload as n, type AthenaGatewayErrorCode as o, type AthenaGatewayHookConfig as p, type AthenaGatewayHookResult as q, type AthenaFetchPayload as r, type AthenaInsertPayload as s, type AthenaUpdatePayload as t, type AthenaDeletePayload as u, type AthenaGatewayResponse as v };
|
|
@@ -220,4 +220,4 @@ declare class AthenaGatewayError extends Error {
|
|
|
220
220
|
}
|
|
221
221
|
declare function isAthenaGatewayError(error: unknown): error is AthenaGatewayError;
|
|
222
222
|
|
|
223
|
-
export { type
|
|
223
|
+
export { type AthenaGatewayCallOptions as A, type BackendConfig as B, type AthenaConditionValue as a, type AthenaConditionCastType as b, type AthenaConditionArrayValue as c, type AthenaConditionOperator as d, type AthenaGatewayErrorDetails as e, type AthenaRpcCallOptions as f, type BackendType as g, Backend as h, AthenaGatewayError as i, isAthenaGatewayError as j, type AthenaRpcFilter as k, type AthenaRpcFilterOperator as l, type AthenaRpcOrder as m, type AthenaRpcPayload as n, type AthenaGatewayErrorCode as o, type AthenaGatewayHookConfig as p, type AthenaGatewayHookResult as q, type AthenaFetchPayload as r, type AthenaInsertPayload as s, type AthenaUpdatePayload as t, type AthenaDeletePayload as u, type AthenaGatewayResponse as v };
|
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;
|
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;
|