@xylex-group/athena 1.3.0 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # athena-js
2
2
 
3
- current version: `1.3.0`
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
@@ -183,14 +183,73 @@ const { data } = await athena
183
183
 
184
184
  ### Pagination
185
185
 
186
+ Two styles, pick whichever matches your UI / backend. Both live on the shared `FilterChain`, so they work before or after `.select()`.
187
+
186
188
  ```ts
187
- // explicit limit and offset
189
+ // 1. offset / limit contiguous windows
188
190
  const { data } = await athena.from("users").select().limit(25).offset(50);
189
191
 
190
- // range shorthand equivalent to offset(from).limit(to - from + 1)
191
- 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);
209
+ ```
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();
192
249
  ```
193
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
+
194
253
  ### Single row
195
254
 
196
255
  ```ts
@@ -417,6 +476,10 @@ const athena = createClient(
417
476
 
418
477
  Per-call headers are merged with the client-level headers, with per-call values winning on conflict.
419
478
 
479
+ The SDK also sends a standard identification header on every request:
480
+
481
+ - `X-Athena-Sdk: xylex-group/athena <version>`
482
+
420
483
  ## TypeScript
421
484
 
422
485
  The package is written in TypeScript and ships declaration files. Pass a row type to `.from()` for fully-typed builder methods and results:
@@ -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>;
package/dist/index.cjs CHANGED
@@ -63,6 +63,10 @@ function isAthenaGatewayError(error) {
63
63
  // src/gateway/client.ts
64
64
  var DEFAULT_BASE_URL = "https://athena-db.com";
65
65
  var DEFAULT_CLIENT = "railway_direct";
66
+ var FALLBACK_SDK_VERSION = "1.3.0";
67
+ var SDK_NAME = "xylex-group/athena";
68
+ var SDK_VERSION = typeof process !== "undefined" && process?.env?.npm_package_version ? process.env.npm_package_version : FALLBACK_SDK_VERSION;
69
+ var SDK_HEADER_VALUE = `${SDK_NAME} ${SDK_VERSION}`;
66
70
  function parseResponseBody(rawText, contentType) {
67
71
  if (!rawText) {
68
72
  return { parsed: null, parseFailed: false };
@@ -201,7 +205,8 @@ function buildHeaders(config, options) {
201
205
  const finalApiKey = options?.apiKey ?? config.apiKey;
202
206
  const finalPublishEvent = options?.publishEvent ?? config.publishEvent;
203
207
  const headers = {
204
- "Content-Type": "application/json"
208
+ "Content-Type": "application/json",
209
+ "X-Athena-Sdk": SDK_HEADER_VALUE
205
210
  };
206
211
  if (options?.userId ?? config.userId) {
207
212
  headers["X-User-Id"] = options?.userId ?? config.userId ?? "";
@@ -466,6 +471,25 @@ function createFilterMethods(state, addCondition, self) {
466
471
  state.offset = count;
467
472
  return self;
468
473
  },
474
+ currentPage(value) {
475
+ state.currentPage = value;
476
+ return self;
477
+ },
478
+ pageSize(value) {
479
+ state.pageSize = value;
480
+ return self;
481
+ },
482
+ totalPages(value) {
483
+ state.totalPages = value;
484
+ return self;
485
+ },
486
+ order(column, options) {
487
+ state.order = {
488
+ field: column,
489
+ direction: options?.ascending === false ? "descending" : "ascending"
490
+ };
491
+ return self;
492
+ },
469
493
  gt(column, value) {
470
494
  addCondition("gt", column, value);
471
495
  return self;
@@ -680,6 +704,10 @@ function createTableBuilder(tableName, client) {
680
704
  conditions: state.conditions.length ? [...state.conditions] : void 0,
681
705
  limit: state.limit,
682
706
  offset: state.offset,
707
+ current_page: state.currentPage,
708
+ page_size: state.pageSize,
709
+ total_pages: state.totalPages,
710
+ sort_by: state.order,
683
711
  strip_nulls: options?.stripNulls ?? true,
684
712
  count: options?.count,
685
713
  head: options?.head
@@ -715,6 +743,10 @@ function createTableBuilder(tableName, client) {
715
743
  state.conditions = [];
716
744
  state.limit = void 0;
717
745
  state.offset = void 0;
746
+ state.order = void 0;
747
+ state.currentPage = void 0;
748
+ state.pageSize = void 0;
749
+ state.totalPages = void 0;
718
750
  return builder;
719
751
  },
720
752
  select(columns = DEFAULT_COLUMNS, options) {
@@ -806,6 +838,10 @@ function createTableBuilder(tableName, client) {
806
838
  conditions: filters,
807
839
  strip_nulls: mergedOptions?.stripNulls ?? true
808
840
  };
841
+ if (state.order) payload.sort_by = state.order;
842
+ if (state.currentPage !== void 0) payload.current_page = state.currentPage;
843
+ if (state.pageSize !== void 0) payload.page_size = state.pageSize;
844
+ if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
809
845
  if (columns) payload.columns = columns;
810
846
  const response = await client.updateGateway(payload, mergedOptions);
811
847
  return formatResult(response);
@@ -829,6 +865,10 @@ function createTableBuilder(tableName, client) {
829
865
  resource_id: resourceId,
830
866
  conditions: filters
831
867
  };
868
+ if (state.order) payload.sort_by = state.order;
869
+ if (state.currentPage !== void 0) payload.current_page = state.currentPage;
870
+ if (state.pageSize !== void 0) payload.page_size = state.pageSize;
871
+ if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
832
872
  if (columns) payload.columns = columns;
833
873
  const response = await client.deleteGateway(payload, mergedOptions);
834
874
  return formatResult(response);