@xylex-group/athena 1.2.1 → 1.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 +254 -88
- package/dist/{errors-DHmpYG46.d.cts → errors-CB-eJQ7x.d.cts} +10 -0
- package/dist/{errors-DHmpYG46.d.ts → errors-CB-eJQ7x.d.ts} +10 -0
- package/dist/index.cjs +365 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +124 -3
- package/dist/index.d.ts +124 -3
- package/dist/index.js +356 -2
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +6 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +6 -1
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# athena-js
|
|
2
2
|
|
|
3
|
-
current version: `1.
|
|
3
|
+
current version: `1.4.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 and a React hook for client-side use.
|
|
5
5
|
|
|
6
6
|
## Install
|
|
@@ -43,9 +43,94 @@ if (error) {
|
|
|
43
43
|
}
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
Every query resolves to `{ data, error, errorDetails?, status, count?, raw }`. `data` is `null` on error; `error` is `null` on success.
|
|
47
|
-
|
|
48
|
-
For richer handling, inspect `errorDetails` (`code`, `status`, `endpoint`, `method`, `requestId`, etc.) or use `AthenaGatewayError` / `isAthenaGatewayError` from the package exports.
|
|
46
|
+
Every query resolves to `{ data, error, errorDetails?, status, count?, raw }`. `data` is `null` on error; `error` is `null` on success.
|
|
47
|
+
|
|
48
|
+
For richer handling, inspect `errorDetails` (`code`, `status`, `endpoint`, `method`, `requestId`, etc.) or use `AthenaGatewayError` / `isAthenaGatewayError` from the package exports.
|
|
49
|
+
|
|
50
|
+
## Reliability helper APIs
|
|
51
|
+
|
|
52
|
+
The SDK exports composable helpers to reduce repetitive route-handler logic.
|
|
53
|
+
|
|
54
|
+
### Result unwrapping and success guards
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import {
|
|
58
|
+
isOk,
|
|
59
|
+
unwrap,
|
|
60
|
+
unwrapRows,
|
|
61
|
+
unwrapOne,
|
|
62
|
+
requireSuccess,
|
|
63
|
+
requireAffected,
|
|
64
|
+
} from "@xylex-group/athena";
|
|
65
|
+
|
|
66
|
+
const result = await athena.from("users").select("id,name");
|
|
67
|
+
|
|
68
|
+
if (isOk(result)) {
|
|
69
|
+
const rows = unwrapRows(result); // typed User[]
|
|
70
|
+
console.log(rows.length);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const one = await athena.from("users").eq("id", 1).single("id,name");
|
|
74
|
+
const user = unwrapOne(one, { allowNull: true });
|
|
75
|
+
|
|
76
|
+
const inserted = await athena
|
|
77
|
+
.from("users")
|
|
78
|
+
.insert({ name: "Alice" })
|
|
79
|
+
.select("id", { count: "exact" });
|
|
80
|
+
|
|
81
|
+
requireSuccess(inserted, { table: "users", operation: "insert" });
|
|
82
|
+
requireAffected(inserted, { min: 1 }, { table: "users", operation: "insert" });
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`requireAffected` uses `result.count`; request it on writes with `{ count: "exact" }` when you need enforced postconditions.
|
|
86
|
+
|
|
87
|
+
### Error normalization
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import { normalizeAthenaError } from "@xylex-group/athena";
|
|
91
|
+
|
|
92
|
+
const result = await athena.from("users").insert({ id: 1 }).select();
|
|
93
|
+
if (result.error) {
|
|
94
|
+
const err = normalizeAthenaError(result, {
|
|
95
|
+
table: "users",
|
|
96
|
+
operation: "insert",
|
|
97
|
+
});
|
|
98
|
+
if (err.kind === "unique_violation") {
|
|
99
|
+
// deterministic conflict handling
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Normalized errors expose stable `kind` values (`unique_violation`, `validation`, `auth`, `rate_limit`, `transient`, etc.) plus operation metadata.
|
|
105
|
+
|
|
106
|
+
### Numeric coercion
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { coerceInt, assertInt } from "@xylex-group/athena";
|
|
110
|
+
|
|
111
|
+
const maybeCaseId = coerceInt(req.query.case_id, { min: 1 });
|
|
112
|
+
if (maybeCaseId == null) throw new Error("Invalid case id");
|
|
113
|
+
|
|
114
|
+
const caseId = assertInt(req.query.case_id, "case_id", { min: 1 });
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Retry helper
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { withRetry } from "@xylex-group/athena";
|
|
121
|
+
|
|
122
|
+
const result = await withRetry(
|
|
123
|
+
{
|
|
124
|
+
retries: 3,
|
|
125
|
+
backoff: "exponential",
|
|
126
|
+
baseDelayMs: 100,
|
|
127
|
+
jitter: true,
|
|
128
|
+
},
|
|
129
|
+
() => athena.from("users").select("id,name"),
|
|
130
|
+
);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
By default, retries target transient/rate-limit failures; use `shouldRetry` for custom policies.
|
|
49
134
|
|
|
50
135
|
## Query builder
|
|
51
136
|
|
|
@@ -64,48 +149,107 @@ const { data } = await athena.from<User>("users").select("id, name");
|
|
|
64
149
|
|
|
65
150
|
### Filters
|
|
66
151
|
|
|
67
|
-
Filters accumulate on the builder and are sent together when the query executes.
|
|
68
|
-
|
|
69
|
-
```ts
|
|
70
|
-
const { data } = await athena
|
|
152
|
+
Filters accumulate on the builder and are sent together when the query executes.
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
const { data } = await athena
|
|
71
156
|
.from("characters")
|
|
72
157
|
.select("id, name")
|
|
73
|
-
.eq("active", true)
|
|
74
|
-
.neq("role", "guest")
|
|
75
|
-
.gt("level", 5)
|
|
76
|
-
.gte("score", 100)
|
|
77
|
-
.lt("age", 30)
|
|
158
|
+
.eq("active", true) // column = value
|
|
159
|
+
.neq("role", "guest") // column != value
|
|
160
|
+
.gt("level", 5) // column > value
|
|
161
|
+
.gte("score", 100) // column >= value
|
|
162
|
+
.lt("age", 30) // column < value
|
|
78
163
|
.lte("created_at", "2024-01-01") // column <= value
|
|
79
|
-
.like("name", "Ali%")
|
|
164
|
+
.like("name", "Ali%") // SQL LIKE (case-sensitive)
|
|
80
165
|
.ilike("email", "%@example%") // SQL ILIKE (case-insensitive)
|
|
81
|
-
.is("deleted_at", null)
|
|
82
|
-
.in("status", ["active", "pending"])
|
|
83
|
-
.contains("tags", ["hero"])
|
|
166
|
+
.is("deleted_at", null) // IS NULL / IS TRUE etc.
|
|
167
|
+
.in("status", ["active", "pending"]) // IN (…)
|
|
168
|
+
.contains("tags", ["hero"]) // array contains value
|
|
84
169
|
.containedBy("tags", ["hero", "villain"]) // array is subset of value
|
|
85
170
|
.match({ role: "admin", active: true }) // multiple eq filters at once
|
|
86
|
-
.not("role", "eq", "banned")
|
|
87
|
-
.or("status.eq.active,status.eq.pending"); // OR expression
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
Canonical style for reads is to call `.select(...)` first, then apply filters:
|
|
91
|
-
|
|
92
|
-
```ts
|
|
93
|
-
const { data } = await athena
|
|
94
|
-
.from("instruments")
|
|
95
|
-
.select("name, section_id")
|
|
96
|
-
.eq("name", "violin");
|
|
97
|
-
```
|
|
171
|
+
.not("role", "eq", "banned") // NOT col op val
|
|
172
|
+
.or("status.eq.active,status.eq.pending"); // OR expression
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Canonical style for reads is to call `.select(...)` first, then apply filters:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
const { data } = await athena
|
|
179
|
+
.from("instruments")
|
|
180
|
+
.select("name, section_id")
|
|
181
|
+
.eq("name", "violin");
|
|
182
|
+
```
|
|
98
183
|
|
|
99
184
|
### Pagination
|
|
100
185
|
|
|
186
|
+
Two styles, pick whichever matches your UI / backend. Both live on the shared `FilterChain`, so they work before or after `.select()`.
|
|
187
|
+
|
|
101
188
|
```ts
|
|
102
|
-
//
|
|
189
|
+
// 1. offset / limit — contiguous windows
|
|
103
190
|
const { data } = await athena.from("users").select().limit(25).offset(50);
|
|
104
191
|
|
|
105
|
-
// range shorthand
|
|
106
|
-
const { data } = await athena.from("users").select().range(0, 24);
|
|
192
|
+
// range shorthand: offset = from, limit = to - from + 1
|
|
193
|
+
const { data: firstTwentyFive } = await athena.from("users").select().range(0, 24);
|
|
194
|
+
|
|
195
|
+
// 2. page based — maps to current_page / page_size / total_pages
|
|
196
|
+
const { data: page2 } = await athena
|
|
197
|
+
.from("orders")
|
|
198
|
+
.select("id, total")
|
|
199
|
+
.currentPage(2)
|
|
200
|
+
.pageSize(25);
|
|
201
|
+
|
|
202
|
+
// .totalPages() is an optional hint some backends use in the response envelope
|
|
203
|
+
const { data: hinted } = await athena
|
|
204
|
+
.from("orders")
|
|
205
|
+
.select("id, total")
|
|
206
|
+
.currentPage(1)
|
|
207
|
+
.pageSize(25)
|
|
208
|
+
.totalPages(10);
|
|
107
209
|
```
|
|
108
210
|
|
|
211
|
+
| Method | Body field |
|
|
212
|
+
|--------|------------|
|
|
213
|
+
| `.limit(n)` | `limit` |
|
|
214
|
+
| `.offset(n)` | `offset` |
|
|
215
|
+
| `.range(from, to)` | `offset` + `limit` |
|
|
216
|
+
| `.currentPage(n)` | `current_page` |
|
|
217
|
+
| `.pageSize(n)` | `page_size` |
|
|
218
|
+
| `.totalPages(n)` | `total_pages` |
|
|
219
|
+
|
|
220
|
+
### Ordering
|
|
221
|
+
|
|
222
|
+
`.order(column, { ascending? })` is available on the table builder, select chain, update chain, and delete — before or after the operation terminator. It serializes to `sort_by: { field, direction }` on the gateway payload and defaults to ascending.
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
// descending + limit
|
|
226
|
+
// SELECT * FROM rsf_messages WHERE room_id = $1 ORDER BY created_at DESC LIMIT 100
|
|
227
|
+
const { data } = await athena
|
|
228
|
+
.from("rsf_messages")
|
|
229
|
+
.eq("room_id", roomId)
|
|
230
|
+
.select("*", { stripNulls: false })
|
|
231
|
+
.order("created_at", { ascending: false })
|
|
232
|
+
.limit(100);
|
|
233
|
+
|
|
234
|
+
// ascending (default) + page-based pagination
|
|
235
|
+
const { data: page } = await athena
|
|
236
|
+
.from("orders")
|
|
237
|
+
.select("id, total, created_at")
|
|
238
|
+
.order("created_at")
|
|
239
|
+
.currentPage(1)
|
|
240
|
+
.pageSize(25);
|
|
241
|
+
|
|
242
|
+
// combine with .single() to grab the newest / oldest row
|
|
243
|
+
const { data: latest } = await athena
|
|
244
|
+
.from("messages")
|
|
245
|
+
.eq("room_id", roomId)
|
|
246
|
+
.select("*")
|
|
247
|
+
.order("created_at", { ascending: false })
|
|
248
|
+
.single();
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Only the last `.order()` wins — the SDK does not support multi-column ordering on the table builder. Use `.rpc()` or `.query()` for that.
|
|
252
|
+
|
|
109
253
|
### Single row
|
|
110
254
|
|
|
111
255
|
```ts
|
|
@@ -119,40 +263,47 @@ const { data: user } = await athena
|
|
|
119
263
|
|
|
120
264
|
`maybeSingle` behaves identically — both return the first element of the result set.
|
|
121
265
|
|
|
122
|
-
### RPC
|
|
123
|
-
|
|
124
|
-
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}`.
|
|
125
|
-
|
|
126
|
-
```ts
|
|
127
|
-
const { data, count } = await athena
|
|
128
|
-
.rpc("list_users", { role: "admin" }, { count: "exact", schema: "public" })
|
|
129
|
-
.eq("active", true)
|
|
130
|
-
.order("created_at", { ascending: false })
|
|
131
|
-
.range(0, 24)
|
|
132
|
-
.select(["id", "email"]);
|
|
133
|
-
|
|
134
|
-
const { data: firstUser } = await athena
|
|
135
|
-
.rpc<{ id: number; email: string }>("list_users", { role: "admin" })
|
|
136
|
-
.single("id,email");
|
|
137
|
-
|
|
138
|
-
const { data: readOnlyUser } = await athena
|
|
139
|
-
.rpc<{
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
266
|
+
### RPC
|
|
267
|
+
|
|
268
|
+
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}`.
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
const { data, count } = await athena
|
|
272
|
+
.rpc("list_users", { role: "admin" }, { count: "exact", schema: "public" })
|
|
273
|
+
.eq("active", true)
|
|
274
|
+
.order("created_at", { ascending: false })
|
|
275
|
+
.range(0, 24)
|
|
276
|
+
.select(["id", "email"]);
|
|
277
|
+
|
|
278
|
+
const { data: firstUser } = await athena
|
|
279
|
+
.rpc<{ id: number; email: string }>("list_users", { role: "admin" })
|
|
280
|
+
.single("id,email");
|
|
281
|
+
|
|
282
|
+
const { data: readOnlyUser } = await athena
|
|
283
|
+
.rpc<{
|
|
284
|
+
id: number;
|
|
285
|
+
email: string;
|
|
286
|
+
}>(
|
|
287
|
+
"list_users",
|
|
288
|
+
{ role: "admin" },
|
|
289
|
+
{ get: true, count: "planned", head: true },
|
|
290
|
+
)
|
|
291
|
+
.eq("id", 1)
|
|
292
|
+
.single("id,email");
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
RPC chain methods: `.eq()`, `.neq()`, `.gt()`, `.gte()`, `.lt()`, `.lte()`, `.like()`, `.ilike()`, `.is()`, `.in()`, `.order()`, `.limit()`, `.offset()`, `.range()`, `.select()`, `.single()`, `.maybeSingle()`.
|
|
296
|
+
RPC options: `schema`, `count` (`"exact" | "planned" | "estimated"`), `head`, `get`.
|
|
297
|
+
|
|
298
|
+
### Options
|
|
148
299
|
|
|
149
300
|
Pass options as the second argument to `.select()`:
|
|
150
301
|
|
|
151
|
-
| Option
|
|
152
|
-
|
|
153
|
-
| `count`
|
|
154
|
-
| `head`
|
|
155
|
-
| `stripNulls` | `boolean`
|
|
302
|
+
| Option | Type | Description |
|
|
303
|
+
| ------------ | ------------------------------------- | -------------------------------------------- |
|
|
304
|
+
| `count` | `"exact" \| "planned" \| "estimated"` | request a row count alongside the data |
|
|
305
|
+
| `head` | `boolean` | return response headers only (no rows) |
|
|
306
|
+
| `stripNulls` | `boolean` | strip null values from rows (default `true`) |
|
|
156
307
|
|
|
157
308
|
```ts
|
|
158
309
|
const { data } = await athena
|
|
@@ -178,9 +329,9 @@ const { data } = await athena
|
|
|
178
329
|
.insert([{ name: "Frodo" }, { name: "Sam" }])
|
|
179
330
|
.select();
|
|
180
331
|
|
|
181
|
-
// Type inference differs by payload shape:
|
|
182
|
-
// - insert(one) => AthenaResult<Row>
|
|
183
|
-
// - insert(many) => AthenaResult<Row[]>
|
|
332
|
+
// Type inference differs by payload shape:
|
|
333
|
+
// - insert(one) => AthenaResult<Row>
|
|
334
|
+
// - insert(many) => AthenaResult<Row[]>
|
|
184
335
|
```
|
|
185
336
|
|
|
186
337
|
### Update
|
|
@@ -206,18 +357,18 @@ const { data } = await athena
|
|
|
206
357
|
)
|
|
207
358
|
.select();
|
|
208
359
|
|
|
209
|
-
// Type inference differs by payload shape:
|
|
210
|
-
// - upsert(one) => AthenaResult<Row>
|
|
211
|
-
// - upsert(many) => AthenaResult<Row[]>
|
|
360
|
+
// Type inference differs by payload shape:
|
|
361
|
+
// - upsert(one) => AthenaResult<Row>
|
|
362
|
+
// - upsert(many) => AthenaResult<Row[]>
|
|
212
363
|
```
|
|
213
364
|
|
|
214
|
-
| Option
|
|
215
|
-
|
|
216
|
-
| `onConflict`
|
|
217
|
-
| `updateBody`
|
|
218
|
-
| `defaultToNull` | `boolean`
|
|
219
|
-
| `count`
|
|
220
|
-
| `head`
|
|
365
|
+
| Option | Type | Description |
|
|
366
|
+
| --------------- | ------------------------------------- | ---------------------------------------- |
|
|
367
|
+
| `onConflict` | `string \| string[]` | column(s) that determine a conflict |
|
|
368
|
+
| `updateBody` | `object` | fields to apply when a conflict occurs |
|
|
369
|
+
| `defaultToNull` | `boolean` | write explicit `null` for missing fields |
|
|
370
|
+
| `count` | `"exact" \| "planned" \| "estimated"` | request a row count |
|
|
371
|
+
| `head` | `boolean` | return headers only |
|
|
221
372
|
|
|
222
373
|
### Delete
|
|
223
374
|
|
|
@@ -286,7 +437,7 @@ export function UsersPanel() {
|
|
|
286
437
|
}
|
|
287
438
|
```
|
|
288
439
|
|
|
289
|
-
The hook returns `fetchGateway`, `insertGateway`, `updateGateway`, `deleteGateway`, `rpcGateway`, `isLoading`, `error`, `lastRequest`, `lastResponse`, and `baseUrl`.
|
|
440
|
+
The hook returns `fetchGateway`, `insertGateway`, `updateGateway`, `deleteGateway`, `rpcGateway`, `isLoading`, `error`, `lastRequest`, `lastResponse`, and `baseUrl`.
|
|
290
441
|
|
|
291
442
|
Hook config options mirror the client options: `baseUrl`, `apiKey`, `headers`, `userId`, `organizationId`, `publishEvent`.
|
|
292
443
|
|
|
@@ -295,28 +446,40 @@ Hook config options mirror the client options: `baseUrl`, `apiKey`, `headers`, `
|
|
|
295
446
|
Pass user and tenant context to every request without repeating it on each call:
|
|
296
447
|
|
|
297
448
|
```ts
|
|
298
|
-
const athena = createClient(
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
449
|
+
const athena = createClient(
|
|
450
|
+
"https://athena-db.com",
|
|
451
|
+
process.env.ATHENA_API_KEY,
|
|
452
|
+
{
|
|
453
|
+
headers: {
|
|
454
|
+
"X-User-Id": currentUser.id,
|
|
455
|
+
"X-Organization-Id": currentUser.organizationId ?? "",
|
|
456
|
+
},
|
|
302
457
|
},
|
|
303
|
-
|
|
458
|
+
);
|
|
304
459
|
```
|
|
305
460
|
|
|
306
|
-
Or pass per-call via options. The Athena server interprets `url` and `key` based on the configured backend type.
|
|
461
|
+
Or pass per-call via options. The Athena server interprets `url` and `key` based on the configured backend type.
|
|
307
462
|
|
|
308
463
|
## Custom headers
|
|
309
464
|
|
|
310
465
|
```ts
|
|
311
|
-
const athena = createClient(
|
|
312
|
-
|
|
313
|
-
|
|
466
|
+
const athena = createClient(
|
|
467
|
+
"https://athena-db.com",
|
|
468
|
+
process.env.ATHENA_API_KEY,
|
|
469
|
+
{
|
|
470
|
+
headers: {
|
|
471
|
+
"X-Custom-Header": "value",
|
|
472
|
+
},
|
|
314
473
|
},
|
|
315
|
-
|
|
474
|
+
);
|
|
316
475
|
```
|
|
317
476
|
|
|
318
477
|
Per-call headers are merged with the client-level headers, with per-call values winning on conflict.
|
|
319
478
|
|
|
479
|
+
The SDK also sends a standard identification header on every request:
|
|
480
|
+
|
|
481
|
+
- `X-Athena-Sdk: xylex-group/athena <version>`
|
|
482
|
+
|
|
320
483
|
## TypeScript
|
|
321
484
|
|
|
322
485
|
The package is written in TypeScript and ships declaration files. Pass a row type to `.from()` for fully-typed builder methods and results:
|
|
@@ -329,7 +492,10 @@ interface User {
|
|
|
329
492
|
active: boolean;
|
|
330
493
|
}
|
|
331
494
|
|
|
332
|
-
const { data } = await athena
|
|
495
|
+
const { data } = await athena
|
|
496
|
+
.from<User>("users")
|
|
497
|
+
.select("id, name")
|
|
498
|
+
.eq("active", true);
|
|
333
499
|
// data is User[] | null
|
|
334
500
|
```
|
|
335
501
|
|
|
@@ -17,6 +17,11 @@ interface AthenaGatewayCondition {
|
|
|
17
17
|
eq_column?: string;
|
|
18
18
|
eq_value?: AthenaConditionValue | AthenaConditionArrayValue | string;
|
|
19
19
|
}
|
|
20
|
+
type AthenaSortDirection = 'ascending' | 'descending';
|
|
21
|
+
interface AthenaSortBy {
|
|
22
|
+
field: string;
|
|
23
|
+
direction: AthenaSortDirection;
|
|
24
|
+
}
|
|
20
25
|
interface AthenaFetchPayload {
|
|
21
26
|
view_name?: string;
|
|
22
27
|
table_name?: string;
|
|
@@ -33,6 +38,7 @@ interface AthenaFetchPayload {
|
|
|
33
38
|
aggregation_column?: string;
|
|
34
39
|
aggregation_strategy?: 'cumulative_sum';
|
|
35
40
|
aggregation_dedup?: boolean;
|
|
41
|
+
sort_by?: AthenaSortBy;
|
|
36
42
|
}
|
|
37
43
|
interface AthenaInsertPayload {
|
|
38
44
|
table_name: string;
|
|
@@ -49,6 +55,10 @@ interface AthenaDeletePayload {
|
|
|
49
55
|
resource_id?: string;
|
|
50
56
|
columns?: string[] | string;
|
|
51
57
|
conditions?: AthenaGatewayCondition[];
|
|
58
|
+
sort_by?: AthenaSortBy;
|
|
59
|
+
current_page?: number;
|
|
60
|
+
page_size?: number;
|
|
61
|
+
total_pages?: number;
|
|
52
62
|
}
|
|
53
63
|
interface AthenaUpdatePayload extends AthenaFetchPayload {
|
|
54
64
|
set?: Record<string, unknown>;
|
|
@@ -17,6 +17,11 @@ interface AthenaGatewayCondition {
|
|
|
17
17
|
eq_column?: string;
|
|
18
18
|
eq_value?: AthenaConditionValue | AthenaConditionArrayValue | string;
|
|
19
19
|
}
|
|
20
|
+
type AthenaSortDirection = 'ascending' | 'descending';
|
|
21
|
+
interface AthenaSortBy {
|
|
22
|
+
field: string;
|
|
23
|
+
direction: AthenaSortDirection;
|
|
24
|
+
}
|
|
20
25
|
interface AthenaFetchPayload {
|
|
21
26
|
view_name?: string;
|
|
22
27
|
table_name?: string;
|
|
@@ -33,6 +38,7 @@ interface AthenaFetchPayload {
|
|
|
33
38
|
aggregation_column?: string;
|
|
34
39
|
aggregation_strategy?: 'cumulative_sum';
|
|
35
40
|
aggregation_dedup?: boolean;
|
|
41
|
+
sort_by?: AthenaSortBy;
|
|
36
42
|
}
|
|
37
43
|
interface AthenaInsertPayload {
|
|
38
44
|
table_name: string;
|
|
@@ -49,6 +55,10 @@ interface AthenaDeletePayload {
|
|
|
49
55
|
resource_id?: string;
|
|
50
56
|
columns?: string[] | string;
|
|
51
57
|
conditions?: AthenaGatewayCondition[];
|
|
58
|
+
sort_by?: AthenaSortBy;
|
|
59
|
+
current_page?: number;
|
|
60
|
+
page_size?: number;
|
|
61
|
+
total_pages?: number;
|
|
52
62
|
}
|
|
53
63
|
interface AthenaUpdatePayload extends AthenaFetchPayload {
|
|
54
64
|
set?: Record<string, unknown>;
|