@xylex-group/athena 2.1.2 → 2.3.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 +287 -116
- package/dist/browser.cjs +1628 -156
- 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 +1625 -156
- package/dist/browser.js.map +1 -1
- package/dist/cli/index.cjs +1532 -145
- 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 +1533 -146
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +1658 -167
- 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 +1656 -168
- package/dist/index.js.map +1 -1
- package/dist/{model-form-2hqmoOUX.d.ts → model-form-BpDXlbxb.d.ts} +97 -2
- package/dist/{model-form-Cy-zaO0u.d.cts → model-form-hoE2jHIi.d.cts} +97 -2
- package/dist/{pipeline-BOPszLsL.d.ts → pipeline-BNIw8pDQ.d.ts} +1 -1
- package/dist/{pipeline-E3FDbs4W.d.cts → pipeline-DNIpEsN8.d.cts} +1 -1
- package/dist/{client-dpAp-NZK.d.cts → react-email-BvyCZnfW.d.cts} +349 -174
- package/dist/{client-BX0NQqOn.d.ts → react-email-qPA1wjFV.d.ts} +349 -174
- package/dist/react.cjs +30 -9
- 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 +30 -9
- package/dist/react.js.map +1 -1
- package/dist/{types-BaBzjwXr.d.cts → types-A5e97acl.d.cts} +2 -1
- package/dist/{types-BaBzjwXr.d.ts → types-A5e97acl.d.ts} +2 -1
- package/dist/{types-CeBPrnGj.d.ts → types-BnD22-vb.d.ts} +1 -1
- package/dist/{types-CpqL-pZx.d.cts → types-bDlr4u7p.d.cts} +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 +75 -17
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# athena-js
|
|
2
2
|
|
|
3
|
-
current version: `2.
|
|
3
|
+
current version: `2.3.0`
|
|
4
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
|
|
@@ -24,66 +24,144 @@ npm install react # React >=17 required for the hook
|
|
|
24
24
|
```ts
|
|
25
25
|
import { createClient } from "@xylex-group/athena";
|
|
26
26
|
|
|
27
|
-
const athenaClient = createClient(ATHENA_URL, ATHENA_API_KEY, {
|
|
28
|
-
client: "CLIENT_NAME",
|
|
29
|
-
backend: { type: "athena" },
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const { data, error } = await athenaClient.from("characters").select(`
|
|
33
|
-
id,
|
|
34
|
-
name,
|
|
35
|
-
from:sender_id(name),
|
|
36
|
-
to:receiver_id(name)
|
|
37
|
-
`);
|
|
38
|
-
|
|
39
|
-
if (error) {
|
|
40
|
-
console.error("gateway error", error);
|
|
41
|
-
} else {
|
|
42
|
-
console.table(data);
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Auth client (Athena Auth server)
|
|
47
|
-
|
|
48
|
-
If your auth backend is now Athena Auth, you can keep core login/session flows in this SDK:
|
|
49
|
-
|
|
50
|
-
```ts
|
|
51
|
-
import { createClient } from "@xylex-group/athena";
|
|
52
|
-
|
|
53
|
-
const athena = createClient(ATHENA_URL, ATHENA_API_KEY, {
|
|
27
|
+
const athenaClient = createClient(ATHENA_URL, ATHENA_API_KEY, {
|
|
54
28
|
client: "CLIENT_NAME",
|
|
55
|
-
|
|
56
|
-
baseUrl: "http://localhost:3001/api/auth",
|
|
57
|
-
// optional: bearer token if you are not using cookie-based sessions
|
|
58
|
-
bearerToken: process.env.AUTH_BEARER_TOKEN,
|
|
59
|
-
},
|
|
29
|
+
backend: { type: "athena" },
|
|
60
30
|
});
|
|
61
31
|
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
32
|
+
const { data, error } = await athenaClient.from("orchestral_sections").findMany({
|
|
33
|
+
select: {
|
|
34
|
+
name: true,
|
|
35
|
+
instruments: {
|
|
36
|
+
select: {
|
|
37
|
+
name: true,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
66
41
|
});
|
|
67
42
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// or clear all sessions
|
|
74
|
-
await athena.auth.session.revoke([{ token: "session_token_here" }, { token: "session_token_2" }]);
|
|
75
|
-
|
|
76
|
-
await athena.auth.signOut();
|
|
77
|
-
|
|
78
|
-
// additional core flows
|
|
79
|
-
await athena.auth.forgetPassword({ email: "demo@example.com", redirectTo: "https://app/reset-password" });
|
|
80
|
-
await athena.auth.resetPassword({ newPassword: "new-secret", token: "reset_token" });
|
|
81
|
-
await athena.auth.verifyEmail({ token: "verify_token", callbackURL: "https://app/verified" });
|
|
82
|
-
await athena.auth.changePassword({ currentPassword: "old-secret", newPassword: "new-secret" });
|
|
83
|
-
await athena.auth.user.update({ name: "Demo User" });
|
|
43
|
+
if (error) {
|
|
44
|
+
console.error("gateway error", error);
|
|
45
|
+
} else {
|
|
46
|
+
console.table(data);
|
|
47
|
+
}
|
|
84
48
|
```
|
|
85
49
|
|
|
86
|
-
|
|
50
|
+
Example version baseline: SDK `@xylex-group/athena` `2.3.0`, Athena server `3.12.3` verified on 2026-06-04.
|
|
51
|
+
|
|
52
|
+
`.findMany({ select, where, orderBy, limit })` is the clean canonical read surface.
|
|
53
|
+
The existing string-based `.select(...)` chain remains fully supported for compatibility,
|
|
54
|
+
including alias/FK patterns like `from:sender_id(name)`.
|
|
55
|
+
For the full AST model, route contract, error behavior, and Athena server implications,
|
|
56
|
+
see [`docs/findmany-ast-and-server-contract.md`](docs/findmany-ast-and-server-contract.md).
|
|
57
|
+
|
|
58
|
+
### Auth client (Athena Auth server)
|
|
59
|
+
|
|
60
|
+
If your auth backend is now Athena Auth, you can keep core login/session flows in this SDK:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { createClient } from "@xylex-group/athena";
|
|
64
|
+
|
|
65
|
+
const athena = createClient(ATHENA_URL, ATHENA_API_KEY, {
|
|
66
|
+
client: "CLIENT_NAME",
|
|
67
|
+
auth: {
|
|
68
|
+
baseUrl: "http://localhost:3001/api/auth",
|
|
69
|
+
// optional: bearer token if you are not using cookie-based sessions
|
|
70
|
+
bearerToken: process.env.AUTH_BEARER_TOKEN,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const login = await athena.auth.signIn.email({
|
|
75
|
+
email: "demo@example.com",
|
|
76
|
+
password: "super-secret",
|
|
77
|
+
rememberMe: true,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const session = await athena.auth.getSession();
|
|
81
|
+
const sessions = await athena.auth.session.list();
|
|
82
|
+
|
|
83
|
+
// clear one session
|
|
84
|
+
await athena.auth.session.revoke({ token: "session_token_here" });
|
|
85
|
+
// or clear all sessions
|
|
86
|
+
await athena.auth.session.revoke([{ token: "session_token_here" }, { token: "session_token_2" }]);
|
|
87
|
+
|
|
88
|
+
await athena.auth.signOut();
|
|
89
|
+
|
|
90
|
+
// additional core flows
|
|
91
|
+
await athena.auth.forgetPassword({ email: "demo@example.com", redirectTo: "https://app/reset-password" });
|
|
92
|
+
await athena.auth.resetPassword({ newPassword: "new-secret", token: "reset_token" });
|
|
93
|
+
await athena.auth.verifyEmail({ token: "verify_token", callbackURL: "https://app/verified" });
|
|
94
|
+
await athena.auth.changePassword({ currentPassword: "old-secret", newPassword: "new-secret" });
|
|
95
|
+
await athena.auth.user.update({ name: "Demo User" });
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
#### React Email templates for admin HTML routes
|
|
99
|
+
|
|
100
|
+
If you use `@react-email/components`, you can pass component+props payloads directly on admin email/template routes:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { Body, Html, Text } from "@react-email/components";
|
|
104
|
+
|
|
105
|
+
function WelcomeEmail(props: { name: string }) {
|
|
106
|
+
return (
|
|
107
|
+
<Html lang="en">
|
|
108
|
+
<Body>
|
|
109
|
+
<Text>Welcome {props.name}</Text>
|
|
110
|
+
</Body>
|
|
111
|
+
</Html>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
await athena.auth.admin.email.template.create({
|
|
116
|
+
templateKey: "welcome",
|
|
117
|
+
subjectTemplate: "Welcome",
|
|
118
|
+
react: {
|
|
119
|
+
component: WelcomeEmail,
|
|
120
|
+
props: { name: "Ava" },
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
For reusable templates, use `defineAuthEmailTemplate(...)`:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { defineAuthEmailTemplate } from "@xylex-group/athena";
|
|
129
|
+
|
|
130
|
+
const welcomeTemplate = defineAuthEmailTemplate({
|
|
131
|
+
component: WelcomeEmail,
|
|
132
|
+
templateKey: "welcome",
|
|
133
|
+
subjectTemplate: "Welcome",
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
await athena.auth.admin.email.template.create(
|
|
137
|
+
welcomeTemplate.toTemplateCreate({
|
|
138
|
+
props: { name: "Ava" },
|
|
139
|
+
}),
|
|
140
|
+
);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
You can also observe render timing/errors:
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
const athena = createClient(ATHENA_URL, ATHENA_API_KEY, {
|
|
147
|
+
auth: {
|
|
148
|
+
baseUrl: AUTH_BASE_URL,
|
|
149
|
+
reactEmail: {
|
|
150
|
+
observe: (event) => {
|
|
151
|
+
console.log(JSON.stringify(event));
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Install support packages in your app:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
pnpm add @react-email/components @react-email/render
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Auth responses follow the same envelope style: `{ ok, status, data, error, errorDetails, raw }`.
|
|
87
165
|
|
|
88
166
|
### Typed schema registry (model-first)
|
|
89
167
|
|
|
@@ -125,6 +203,8 @@ await typed
|
|
|
125
203
|
|
|
126
204
|
For full details, see [`docs/typed-schema-registry.md`](./docs/typed-schema-registry.md).
|
|
127
205
|
|
|
206
|
+
For exhaustive method-by-method documentation with usage snippets (root client, runtime builders, auth bindings, react runtime, cookies, and utils), see [`docs/complete-method-reference.md`](./docs/complete-method-reference.md).
|
|
207
|
+
|
|
128
208
|
### Typed schema generator
|
|
129
209
|
|
|
130
210
|
Schema generation is additive. Existing `createClient(...).from<T>(...)` usage remains valid while teams migrate to generated registry files.
|
|
@@ -165,9 +245,19 @@ For prompt-ready documentation handoff text, see [`docs/generator-codex-handoff-
|
|
|
165
245
|
- `athena-rs` for Rust backend throughput
|
|
166
246
|
- `athena-js` for app/tooling layers that need TypeScript contracts and frontend-facing ergonomics
|
|
167
247
|
|
|
168
|
-
Every query resolves to `{ data, error, errorDetails?, status, count?, raw }`. `data` is `null` on error; `error` is `null` on success.
|
|
169
|
-
|
|
170
|
-
|
|
248
|
+
Every query resolves to `{ data, error, errorDetails?, status, statusText?, count?, raw }`. `data` is `null` on error; `error` is `null` on success.
|
|
249
|
+
|
|
250
|
+
Failed results now include a structured `error` object with the useful fields inline:
|
|
251
|
+
|
|
252
|
+
- `message`
|
|
253
|
+
- `code`
|
|
254
|
+
- `details`
|
|
255
|
+
- `hint`
|
|
256
|
+
- `status`
|
|
257
|
+
- `statusText`
|
|
258
|
+
- normalized metadata such as `kind`, `table`, `operation`, and `retryable`
|
|
259
|
+
|
|
260
|
+
`errorDetails` is still present as a compatibility alias for low-level gateway metadata (`gatewayCode`, `endpoint`, `method`, `requestId`, etc.).
|
|
171
261
|
|
|
172
262
|
## Reliability helper APIs
|
|
173
263
|
|
|
@@ -206,29 +296,78 @@ requireAffected(inserted, { min: 1 }, { table: "users", operation: "insert" });
|
|
|
206
296
|
|
|
207
297
|
`requireAffected` uses `result.count`; request it on writes with `{ count: "exact" }` when you need enforced postconditions.
|
|
208
298
|
|
|
209
|
-
###
|
|
299
|
+
### Structured errors by default
|
|
210
300
|
|
|
211
301
|
```ts
|
|
212
302
|
import { createClient, normalizeAthenaError } from "@xylex-group/athena";
|
|
213
303
|
|
|
214
|
-
const athena = createClient(ATHENA_URL, ATHENA_API_KEY
|
|
215
|
-
experimental: { enableErrorNormalization: true },
|
|
216
|
-
});
|
|
304
|
+
const athena = createClient(ATHENA_URL, ATHENA_API_KEY);
|
|
217
305
|
|
|
218
|
-
const
|
|
219
|
-
if (
|
|
220
|
-
|
|
221
|
-
|
|
306
|
+
const { data, error, status, statusText } = await athena.from("users").insert({ id: 1 }).select();
|
|
307
|
+
if (error) {
|
|
308
|
+
console.error(error);
|
|
309
|
+
console.error(error.hint ?? error.message, status, statusText);
|
|
310
|
+
if (error.kind === "unique_violation") {
|
|
222
311
|
// deterministic conflict handling
|
|
223
312
|
}
|
|
224
313
|
}
|
|
225
314
|
```
|
|
226
315
|
|
|
227
|
-
|
|
316
|
+
`result.error` already carries normalized `kind` values (`unique_violation`, `validation`, `auth`, `rate_limit`, `transient`, etc.) plus operation metadata.
|
|
228
317
|
|
|
229
|
-
`
|
|
318
|
+
`normalizeAthenaError(result)` still exists when you need the normalized envelope from an arbitrary thrown value or mixed unknown input.
|
|
230
319
|
|
|
231
|
-
###
|
|
320
|
+
### Query tracing (experimental)
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
const athena = createClient(ATHENA_URL, ATHENA_API_KEY, {
|
|
324
|
+
experimental: { traceQueries: true },
|
|
325
|
+
});
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
With `traceQueries: true`, the SDK logs every runtime execution (`select`, `insert`, `upsert`, `update`, `delete`, `rpc`, `query`) and includes:
|
|
329
|
+
|
|
330
|
+
- the gateway endpoint used
|
|
331
|
+
- synthesized SQL (or raw SQL for `query(...)` and SQL fallback reads)
|
|
332
|
+
- payload and call options
|
|
333
|
+
- full outcome (`status`, `error`, `count`, `data`, `raw`)
|
|
334
|
+
- callsite metadata (`filePath`, `fileName`, `line`, `column`)
|
|
335
|
+
|
|
336
|
+
For deferred chains, Athena captures that callsite from the public SDK seam that declared or finalized the operation and reuses it for the eventual network execution. That keeps traces pinned to user code instead of drifting into SDK internals when async stack shapes differ between local runs and CI.
|
|
337
|
+
|
|
338
|
+
Use a custom sink:
|
|
339
|
+
|
|
340
|
+
```ts
|
|
341
|
+
const athena = createClient(ATHENA_URL, ATHENA_API_KEY, {
|
|
342
|
+
experimental: {
|
|
343
|
+
traceQueries: {
|
|
344
|
+
logger(event) {
|
|
345
|
+
// Forward into your logger/observability sink
|
|
346
|
+
console.log(event.operation, event.endpoint, event.sql, event.callsite);
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
});
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### findMany AST transport (experimental)
|
|
354
|
+
|
|
355
|
+
```ts
|
|
356
|
+
const athena = createClient(ATHENA_URL, ATHENA_API_KEY, {
|
|
357
|
+
experimental: {
|
|
358
|
+
findManyAst: true,
|
|
359
|
+
},
|
|
360
|
+
});
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
With `findManyAst: true`, clean `findMany(...)` calls send the original object AST body to `/gateway/fetch` instead of compiling the select tree down to `columns` and `conditions` first.
|
|
364
|
+
|
|
365
|
+
- this is opt-in and meant for gateways that explicitly support direct AST bodies
|
|
366
|
+
- existing compiled `findMany(...)` transport remains the default
|
|
367
|
+
- chained builder filters or pagination state that the AST body cannot represent losslessly yet continue to use the legacy compiled path
|
|
368
|
+
- trace output still includes synthesized SQL so diagnostics stay readable
|
|
369
|
+
|
|
370
|
+
### Numeric coercion
|
|
232
371
|
|
|
233
372
|
```ts
|
|
234
373
|
import { coerceInt, assertInt } from "@xylex-group/athena";
|
|
@@ -239,6 +378,38 @@ if (maybeCaseId == null) throw new Error("Invalid case id");
|
|
|
239
378
|
const caseId = assertInt(req.query.case_id, "case_id", { min: 1 });
|
|
240
379
|
```
|
|
241
380
|
|
|
381
|
+
### Utilities subpath
|
|
382
|
+
|
|
383
|
+
Utilities that are intentionally not exported from the root package are available from `@xylex-group/athena/utils`.
|
|
384
|
+
|
|
385
|
+
```ts
|
|
386
|
+
import {
|
|
387
|
+
slugify,
|
|
388
|
+
trimTrailingSlashes,
|
|
389
|
+
parseBooleanFlag,
|
|
390
|
+
isLocalHostname,
|
|
391
|
+
clearAuthCookies,
|
|
392
|
+
proxyRequestHeaders,
|
|
393
|
+
} from "@xylex-group/athena/utils";
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
Examples:
|
|
397
|
+
|
|
398
|
+
```ts
|
|
399
|
+
const slug = slugify("Customer Success / Q4 Report"); // customer-success-q4-report
|
|
400
|
+
const local = isLocalHostname("api.localhost"); // true
|
|
401
|
+
const normalized = trimTrailingSlashes("https://example.com///"); // https://example.com
|
|
402
|
+
const enabled = parseBooleanFlag(process.env.FEATURE_FLAG, false);
|
|
403
|
+
|
|
404
|
+
// Browser-only helper (safe no-op on server runtimes)
|
|
405
|
+
clearAuthCookies();
|
|
406
|
+
|
|
407
|
+
// Preserve forwarded headers when proxying auth requests
|
|
408
|
+
const upstreamHeaders = proxyRequestHeaders(request);
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
`clearAuthCookies()` clears cookies matching Athena/Better Auth prefixes (`athena-auth`, `__Secure-athena-auth`, `better-auth`, `__Secure-better-auth`) and also attempts parent-domain cleanup for subdomain deployments.
|
|
412
|
+
|
|
242
413
|
### Retry helper
|
|
243
414
|
|
|
244
415
|
```ts
|
|
@@ -257,31 +428,31 @@ const result = await withRetry(
|
|
|
257
428
|
|
|
258
429
|
By default, retries target transient/rate-limit failures; use `shouldRetry` for custom policies.
|
|
259
430
|
|
|
260
|
-
## Query builder
|
|
261
|
-
|
|
262
|
-
### DB module namespace
|
|
263
|
-
|
|
264
|
-
`createClient()` keeps root methods (`from`, `rpc`, `query`) and now also exposes `db` as an additive namespace.
|
|
265
|
-
|
|
266
|
-
```ts
|
|
267
|
-
const athena = createClient(ATHENA_URL, ATHENA_API_KEY);
|
|
268
|
-
|
|
269
|
-
await athena.db.from("users").select("id,name").eq("active", true).limit(20);
|
|
270
|
-
|
|
271
|
-
await athena.db.select("users", "id,name").eq("id", 1).single();
|
|
272
|
-
|
|
273
|
-
await athena.db.insert("users", { id: 1, name: "Alice" }).select("id");
|
|
274
|
-
await athena.db.update("users", { name: "Updated" }).eq("id", 1).select("id,name");
|
|
275
|
-
await athena.db.delete("users", { resourceId: "r-1" }).select("id");
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
`db` mirrors the existing query builder semantics while providing a module seam for future database-surface expansion.
|
|
279
|
-
|
|
280
|
-
### Reading rows
|
|
281
|
-
|
|
282
|
-
```ts
|
|
283
|
-
// select all columns
|
|
284
|
-
const { data } = await athena.from("users").select();
|
|
431
|
+
## Query builder
|
|
432
|
+
|
|
433
|
+
### DB module namespace
|
|
434
|
+
|
|
435
|
+
`createClient()` keeps root methods (`from`, `rpc`, `query`) and now also exposes `db` as an additive namespace.
|
|
436
|
+
|
|
437
|
+
```ts
|
|
438
|
+
const athena = createClient(ATHENA_URL, ATHENA_API_KEY);
|
|
439
|
+
|
|
440
|
+
await athena.db.from("users").select("id,name").eq("active", true).limit(20);
|
|
441
|
+
|
|
442
|
+
await athena.db.select("users", "id,name").eq("id", 1).single();
|
|
443
|
+
|
|
444
|
+
await athena.db.insert("users", { id: 1, name: "Alice" }).select("id");
|
|
445
|
+
await athena.db.update("users", { name: "Updated" }).eq("id", 1).select("id,name");
|
|
446
|
+
await athena.db.delete("users", { resourceId: "r-1" }).select("id");
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
`db` mirrors the existing query builder semantics while providing a module seam for future database-surface expansion.
|
|
450
|
+
|
|
451
|
+
### Reading rows
|
|
452
|
+
|
|
453
|
+
```ts
|
|
454
|
+
// select all columns
|
|
455
|
+
const { data } = await athena.from("users").select();
|
|
285
456
|
|
|
286
457
|
// select specific columns
|
|
287
458
|
const { data } = await athena.from("users").select("id, name, email");
|
|
@@ -408,23 +579,23 @@ const { data: user } = await athena
|
|
|
408
579
|
.single();
|
|
409
580
|
```
|
|
410
581
|
|
|
411
|
-
`maybeSingle` behaves identically — both return the first element of the result set.
|
|
412
|
-
|
|
413
|
-
### Table schema targeting
|
|
414
|
-
|
|
415
|
-
Use `schema` in table call options to qualify unqualified table names:
|
|
416
|
-
|
|
417
|
-
```ts
|
|
418
|
-
const { data } = await athena
|
|
419
|
-
.from("users")
|
|
420
|
-
.select("id,email", { schema: "public" });
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
This resolves the table target to `public.users`.
|
|
424
|
-
|
|
425
|
-
### RPC
|
|
426
|
-
|
|
427
|
-
Use `athena.rpc(...)` for Postgres function calls. By default it calls `POST /gateway/rpc`, and with `{ get: true }` it uses the compatibility route `GET /rpc/{function_name}`.
|
|
582
|
+
`maybeSingle` behaves identically — both return the first element of the result set.
|
|
583
|
+
|
|
584
|
+
### Table schema targeting
|
|
585
|
+
|
|
586
|
+
Use `schema` in table call options to qualify unqualified table names:
|
|
587
|
+
|
|
588
|
+
```ts
|
|
589
|
+
const { data } = await athena
|
|
590
|
+
.from("users")
|
|
591
|
+
.select("id,email", { schema: "public" });
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
This resolves the table target to `public.users`.
|
|
595
|
+
|
|
596
|
+
### RPC
|
|
597
|
+
|
|
598
|
+
Use `athena.rpc(...)` for Postgres function calls. By default it calls `POST /gateway/rpc`, and with `{ get: true }` it uses the compatibility route `GET /rpc/{function_name}`.
|
|
428
599
|
|
|
429
600
|
```ts
|
|
430
601
|
const { data, count } = await athena
|
|
@@ -458,12 +629,12 @@ RPC options: `schema`, `count` (`"exact" | "planned" | "estimated"`), `head`, `g
|
|
|
458
629
|
|
|
459
630
|
Pass options as the second argument to `.select()`:
|
|
460
631
|
|
|
461
|
-
| Option | Type | Description |
|
|
462
|
-
| ------------ | ------------------------------------- | -------------------------------------------- |
|
|
463
|
-
| `schema` | `string` | qualify unqualified table names for table calls |
|
|
464
|
-
| `count` | `"exact" \| "planned" \| "estimated"` | request a row count alongside the data |
|
|
465
|
-
| `head` | `boolean` | return response headers only (no rows) |
|
|
466
|
-
| `stripNulls` | `boolean` | strip null values from rows (default `true`) |
|
|
632
|
+
| Option | Type | Description |
|
|
633
|
+
| ------------ | ------------------------------------- | -------------------------------------------- |
|
|
634
|
+
| `schema` | `string` | qualify unqualified table names for table calls |
|
|
635
|
+
| `count` | `"exact" \| "planned" \| "estimated"` | request a row count alongside the data |
|
|
636
|
+
| `head` | `boolean` | return response headers only (no rows) |
|
|
637
|
+
| `stripNulls` | `boolean` | strip null values from rows (default `true`) |
|
|
467
638
|
|
|
468
639
|
```ts
|
|
469
640
|
const { data } = await athena
|