@xylex-group/athena 2.0.0 → 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 -95
- package/dist/browser.cjs +4791 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.cts +25 -0
- package/dist/browser.d.ts +25 -0
- package/dist/browser.js +4745 -0
- package/dist/browser.js.map +1 -0
- package/dist/cli/index.cjs +2087 -220
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +3 -2
- package/dist/cli/index.d.ts +3 -2
- package/dist/cli/index.js +2089 -222
- package/dist/cli/index.js.map +1 -1
- package/dist/cookies.cjs +890 -0
- package/dist/cookies.cjs.map +1 -0
- package/dist/cookies.d.cts +174 -0
- package/dist/cookies.d.ts +174 -0
- package/dist/cookies.js +869 -0
- package/dist/cookies.js.map +1 -0
- package/dist/index.cjs +3046 -1200
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -408
- package/dist/index.d.ts +8 -408
- package/dist/index.js +3045 -1202
- package/dist/index.js.map +1 -1
- package/dist/{model-form-CVOtC8jq.d.ts → model-form-BpDXlbxb.d.ts} +97 -2
- package/dist/{model-form-hXkvHS_3.d.cts → model-form-hoE2jHIi.d.cts} +97 -2
- package/dist/pipeline-BNIw8pDQ.d.ts +8 -0
- package/dist/pipeline-DNIpEsN8.d.cts +8 -0
- package/dist/react-email-BvyCZnfW.d.cts +610 -0
- package/dist/react-email-qPA1wjFV.d.ts +610 -0
- 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-BnzoaNRC.d.cts → types-A5e97acl.d.cts} +2 -1
- package/dist/{types-BnzoaNRC.d.ts → types-A5e97acl.d.ts} +2 -1
- package/dist/{pipeline-CQgV-Yfo.d.ts → types-BnD22-vb.d.ts} +2 -7
- package/dist/{pipeline-C-cN0ACi.d.cts → types-bDlr4u7p.d.cts} +2 -7
- 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 +87 -9
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,26 +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
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
import { createClient, normalizeAthenaError } from "@xylex-group/athena";
|
|
303
|
+
|
|
304
|
+
const athena = createClient(ATHENA_URL, ATHENA_API_KEY);
|
|
305
|
+
|
|
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") {
|
|
311
|
+
// deterministic conflict handling
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
`result.error` already carries normalized `kind` values (`unique_violation`, `validation`, `auth`, `rate_limit`, `transient`, etc.) plus operation metadata.
|
|
317
|
+
|
|
318
|
+
`normalizeAthenaError(result)` still exists when you need the normalized envelope from an arbitrary thrown value or mixed unknown input.
|
|
210
319
|
|
|
211
|
-
|
|
212
|
-
import { normalizeAthenaError } from "@xylex-group/athena";
|
|
320
|
+
### Query tracing (experimental)
|
|
213
321
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
operation: "insert",
|
|
219
|
-
});
|
|
220
|
-
if (err.kind === "unique_violation") {
|
|
221
|
-
// deterministic conflict handling
|
|
222
|
-
}
|
|
223
|
-
}
|
|
322
|
+
```ts
|
|
323
|
+
const athena = createClient(ATHENA_URL, ATHENA_API_KEY, {
|
|
324
|
+
experimental: { traceQueries: true },
|
|
325
|
+
});
|
|
224
326
|
```
|
|
225
327
|
|
|
226
|
-
|
|
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:
|
|
227
339
|
|
|
228
|
-
|
|
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
|
|
229
371
|
|
|
230
372
|
```ts
|
|
231
373
|
import { coerceInt, assertInt } from "@xylex-group/athena";
|
|
@@ -236,6 +378,38 @@ if (maybeCaseId == null) throw new Error("Invalid case id");
|
|
|
236
378
|
const caseId = assertInt(req.query.case_id, "case_id", { min: 1 });
|
|
237
379
|
```
|
|
238
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
|
+
|
|
239
413
|
### Retry helper
|
|
240
414
|
|
|
241
415
|
```ts
|
|
@@ -256,6 +430,24 @@ By default, retries target transient/rate-limit failures; use `shouldRetry` for
|
|
|
256
430
|
|
|
257
431
|
## Query builder
|
|
258
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
|
+
|
|
259
451
|
### Reading rows
|
|
260
452
|
|
|
261
453
|
```ts
|
|
@@ -387,23 +579,23 @@ const { data: user } = await athena
|
|
|
387
579
|
.single();
|
|
388
580
|
```
|
|
389
581
|
|
|
390
|
-
`maybeSingle` behaves identically — both return the first element of the result set.
|
|
391
|
-
|
|
392
|
-
### Table schema targeting
|
|
393
|
-
|
|
394
|
-
Use `schema` in table call options to qualify unqualified table names:
|
|
395
|
-
|
|
396
|
-
```ts
|
|
397
|
-
const { data } = await athena
|
|
398
|
-
.from("users")
|
|
399
|
-
.select("id,email", { schema: "public" });
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
This resolves the table target to `public.users`.
|
|
403
|
-
|
|
404
|
-
### RPC
|
|
405
|
-
|
|
406
|
-
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}`.
|
|
407
599
|
|
|
408
600
|
```ts
|
|
409
601
|
const { data, count } = await athena
|
|
@@ -437,12 +629,12 @@ RPC options: `schema`, `count` (`"exact" | "planned" | "estimated"`), `head`, `g
|
|
|
437
629
|
|
|
438
630
|
Pass options as the second argument to `.select()`:
|
|
439
631
|
|
|
440
|
-
| Option | Type | Description |
|
|
441
|
-
| ------------ | ------------------------------------- | -------------------------------------------- |
|
|
442
|
-
| `schema` | `string` | qualify unqualified table names for table calls |
|
|
443
|
-
| `count` | `"exact" \| "planned" \| "estimated"` | request a row count alongside the data |
|
|
444
|
-
| `head` | `boolean` | return response headers only (no rows) |
|
|
445
|
-
| `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`) |
|
|
446
638
|
|
|
447
639
|
```ts
|
|
448
640
|
const { data } = await athena
|