@xylex-group/athena 1.7.0 → 1.9.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.7.0`
3
+ current version: `1.9.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
@@ -390,11 +390,23 @@ const { data: user } = await athena
390
390
  .single();
391
391
  ```
392
392
 
393
- `maybeSingle` behaves identically — both return the first element of the result set.
394
-
395
- ### RPC
396
-
397
- 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}`.
393
+ `maybeSingle` behaves identically — both return the first element of the result set.
394
+
395
+ ### Table schema targeting
396
+
397
+ Use `schema` in table call options to qualify unqualified table names:
398
+
399
+ ```ts
400
+ const { data } = await athena
401
+ .from("users")
402
+ .select("id,email", { schema: "public" });
403
+ ```
404
+
405
+ This resolves the table target to `public.users`.
406
+
407
+ ### RPC
408
+
409
+ 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}`.
398
410
 
399
411
  ```ts
400
412
  const { data, count } = await athena
@@ -428,11 +440,12 @@ RPC options: `schema`, `count` (`"exact" | "planned" | "estimated"`), `head`, `g
428
440
 
429
441
  Pass options as the second argument to `.select()`:
430
442
 
431
- | Option | Type | Description |
432
- | ------------ | ------------------------------------- | -------------------------------------------- |
433
- | `count` | `"exact" \| "planned" \| "estimated"` | request a row count alongside the data |
434
- | `head` | `boolean` | return response headers only (no rows) |
435
- | `stripNulls` | `boolean` | strip null values from rows (default `true`) |
443
+ | Option | Type | Description |
444
+ | ------------ | ------------------------------------- | -------------------------------------------- |
445
+ | `schema` | `string` | qualify unqualified table names for table calls |
446
+ | `count` | `"exact" \| "planned" \| "estimated"` | request a row count alongside the data |
447
+ | `head` | `boolean` | return response headers only (no rows) |
448
+ | `stripNulls` | `boolean` | strip null values from rows (default `true`) |
436
449
 
437
450
  ```ts
438
451
  const { data } = await athena
package/bin/athena-js.js CHANGED
File without changes
@@ -1231,6 +1231,12 @@ function mergeOptions(...options) {
1231
1231
  return { ...acc, ...next };
1232
1232
  }, void 0);
1233
1233
  }
1234
+ function asAthenaJsonObject(value) {
1235
+ return value;
1236
+ }
1237
+ function asAthenaJsonObjectArray(values) {
1238
+ return values;
1239
+ }
1234
1240
  function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
1235
1241
  let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
1236
1242
  let selectedOptions;
@@ -1319,6 +1325,22 @@ function buildSelectColumnsClause(columns) {
1319
1325
  }
1320
1326
  return quoteSelectColumnsExpression(columns);
1321
1327
  }
1328
+ function resolveTableNameForCall(tableName, schema) {
1329
+ if (!schema) return tableName;
1330
+ const normalizedSchema = schema.trim();
1331
+ if (!normalizedSchema) {
1332
+ throw new Error("schema option must be a non-empty string");
1333
+ }
1334
+ if (tableName.includes(".")) {
1335
+ if (tableName.startsWith(`${normalizedSchema}.`)) {
1336
+ return tableName;
1337
+ }
1338
+ throw new Error(
1339
+ `schema option "${normalizedSchema}" conflicts with schema-qualified table "${tableName}"`
1340
+ );
1341
+ }
1342
+ return `${normalizedSchema}.${tableName}`;
1343
+ }
1322
1344
  function conditionToSqlClause(condition) {
1323
1345
  if (!condition.column) return null;
1324
1346
  const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
@@ -1398,23 +1420,27 @@ function buildTypedSelectQuery(input) {
1398
1420
  function createFilterMethods(state, addCondition, self) {
1399
1421
  return {
1400
1422
  eq(column, value) {
1401
- if (shouldUseUuidTextComparison(column, value)) {
1402
- addCondition("eq", column, value, { columnCast: "text" });
1423
+ const columnName = String(column);
1424
+ if (shouldUseUuidTextComparison(columnName, value)) {
1425
+ addCondition("eq", columnName, value, { columnCast: "text" });
1403
1426
  } else {
1404
- addCondition("eq", column, value);
1427
+ addCondition("eq", columnName, value);
1405
1428
  }
1406
1429
  return self;
1407
1430
  },
1408
1431
  eqCast(column, value, cast) {
1409
- addCondition("eq", column, value, { valueCast: cast });
1432
+ addCondition("eq", String(column), value, { valueCast: cast });
1410
1433
  return self;
1411
1434
  },
1412
1435
  eqUuid(column, value) {
1413
- addCondition("eq", column, value, { valueCast: "uuid" });
1436
+ addCondition("eq", String(column), value, { valueCast: "uuid" });
1414
1437
  return self;
1415
1438
  },
1416
1439
  match(filters) {
1417
1440
  Object.entries(filters).forEach(([column, value]) => {
1441
+ if (value === void 0) {
1442
+ return;
1443
+ }
1418
1444
  if (shouldUseUuidTextComparison(column, value)) {
1419
1445
  addCondition("eq", column, value, { columnCast: "text" });
1420
1446
  } else {
@@ -1450,60 +1476,61 @@ function createFilterMethods(state, addCondition, self) {
1450
1476
  },
1451
1477
  order(column, options) {
1452
1478
  state.order = {
1453
- field: column,
1479
+ field: String(column),
1454
1480
  direction: options?.ascending === false ? "descending" : "ascending"
1455
1481
  };
1456
1482
  return self;
1457
1483
  },
1458
1484
  gt(column, value) {
1459
- addCondition("gt", column, value);
1485
+ addCondition("gt", String(column), value);
1460
1486
  return self;
1461
1487
  },
1462
1488
  gte(column, value) {
1463
- addCondition("gte", column, value);
1489
+ addCondition("gte", String(column), value);
1464
1490
  return self;
1465
1491
  },
1466
1492
  lt(column, value) {
1467
- addCondition("lt", column, value);
1493
+ addCondition("lt", String(column), value);
1468
1494
  return self;
1469
1495
  },
1470
1496
  lte(column, value) {
1471
- addCondition("lte", column, value);
1497
+ addCondition("lte", String(column), value);
1472
1498
  return self;
1473
1499
  },
1474
1500
  neq(column, value) {
1475
- addCondition("neq", column, value);
1501
+ addCondition("neq", String(column), value);
1476
1502
  return self;
1477
1503
  },
1478
1504
  like(column, value) {
1479
- addCondition("like", column, value);
1505
+ addCondition("like", String(column), value);
1480
1506
  return self;
1481
1507
  },
1482
1508
  ilike(column, value) {
1483
- addCondition("ilike", column, value);
1509
+ addCondition("ilike", String(column), value);
1484
1510
  return self;
1485
1511
  },
1486
1512
  is(column, value) {
1487
- addCondition("is", column, value);
1513
+ addCondition("is", String(column), value);
1488
1514
  return self;
1489
1515
  },
1490
1516
  in(column, values) {
1491
- addCondition("in", column, values);
1517
+ addCondition("in", String(column), values);
1492
1518
  return self;
1493
1519
  },
1494
1520
  contains(column, values) {
1495
- addCondition("contains", column, values);
1521
+ addCondition("contains", String(column), values);
1496
1522
  return self;
1497
1523
  },
1498
1524
  containedBy(column, values) {
1499
- addCondition("containedBy", column, values);
1525
+ addCondition("containedBy", String(column), values);
1500
1526
  return self;
1501
1527
  },
1502
1528
  not(columnOrExpression, operator, value) {
1529
+ const expression = String(columnOrExpression);
1503
1530
  if (operator != null && value !== void 0) {
1504
- addCondition("not", void 0, `${columnOrExpression}.${operator}.${stringifyFilterValue(value)}`);
1531
+ addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue(value)}`);
1505
1532
  } else {
1506
- addCondition("not", void 0, columnOrExpression);
1533
+ addCondition("not", void 0, expression);
1507
1534
  }
1508
1535
  return self;
1509
1536
  },
@@ -1673,15 +1700,20 @@ function createTableBuilder(tableName, client) {
1673
1700
  state.conditions.push(condition);
1674
1701
  };
1675
1702
  const builder = {};
1676
- const filterMethods = createFilterMethods(state, addCondition, builder);
1703
+ const filterMethods = createFilterMethods(
1704
+ state,
1705
+ addCondition,
1706
+ builder
1707
+ );
1677
1708
  const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
1709
+ const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
1678
1710
  const conditions = state.conditions.length ? state.conditions.map((condition) => ({ ...condition })) : void 0;
1679
1711
  const hasTypedEqualityComparison = conditions?.some(
1680
1712
  (condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
1681
1713
  ) ?? false;
1682
1714
  if (hasTypedEqualityComparison && !options?.head && !options?.count && conditions) {
1683
1715
  const query = buildTypedSelectQuery({
1684
- tableName,
1716
+ tableName: resolvedTableName,
1685
1717
  columns,
1686
1718
  conditions,
1687
1719
  limit: state.limit,
@@ -1696,7 +1728,7 @@ function createTableBuilder(tableName, client) {
1696
1728
  }
1697
1729
  }
1698
1730
  const payload = {
1699
- table_name: tableName,
1731
+ table_name: resolvedTableName,
1700
1732
  columns,
1701
1733
  conditions,
1702
1734
  limit: state.limit,
@@ -1753,9 +1785,10 @@ function createTableBuilder(tableName, client) {
1753
1785
  if (Array.isArray(values)) {
1754
1786
  const executeInsertMany = async (columns, selectOptions) => {
1755
1787
  const mergedOptions = mergeOptions(options, selectOptions);
1788
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1756
1789
  const payload = {
1757
- table_name: tableName,
1758
- insert_body: values
1790
+ table_name: resolvedTableName,
1791
+ insert_body: asAthenaJsonObjectArray(values)
1759
1792
  };
1760
1793
  if (columns) payload.columns = columns;
1761
1794
  if (mergedOptions?.count) payload.count = mergedOptions.count;
@@ -1770,9 +1803,10 @@ function createTableBuilder(tableName, client) {
1770
1803
  }
1771
1804
  const executeInsertOne = async (columns, selectOptions) => {
1772
1805
  const mergedOptions = mergeOptions(options, selectOptions);
1806
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1773
1807
  const payload = {
1774
- table_name: tableName,
1775
- insert_body: values
1808
+ table_name: resolvedTableName,
1809
+ insert_body: asAthenaJsonObject(values)
1776
1810
  };
1777
1811
  if (columns) payload.columns = columns;
1778
1812
  if (mergedOptions?.count) payload.count = mergedOptions.count;
@@ -1789,10 +1823,11 @@ function createTableBuilder(tableName, client) {
1789
1823
  if (Array.isArray(values)) {
1790
1824
  const executeUpsertMany = async (columns, selectOptions) => {
1791
1825
  const mergedOptions = mergeOptions(options, selectOptions);
1826
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1792
1827
  const payload = {
1793
- table_name: tableName,
1794
- insert_body: values,
1795
- update_body: options?.updateBody ? options.updateBody : void 0
1828
+ table_name: resolvedTableName,
1829
+ insert_body: asAthenaJsonObjectArray(values),
1830
+ update_body: options?.updateBody ? asAthenaJsonObject(options.updateBody) : void 0
1796
1831
  };
1797
1832
  if (columns) payload.columns = columns;
1798
1833
  if (options?.onConflict) payload.on_conflict = options.onConflict;
@@ -1808,10 +1843,11 @@ function createTableBuilder(tableName, client) {
1808
1843
  }
1809
1844
  const executeUpsertOne = async (columns, selectOptions) => {
1810
1845
  const mergedOptions = mergeOptions(options, selectOptions);
1846
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1811
1847
  const payload = {
1812
- table_name: tableName,
1813
- insert_body: values,
1814
- update_body: options?.updateBody ? options.updateBody : void 0
1848
+ table_name: resolvedTableName,
1849
+ insert_body: asAthenaJsonObject(values),
1850
+ update_body: options?.updateBody ? asAthenaJsonObject(options.updateBody) : void 0
1815
1851
  };
1816
1852
  if (columns) payload.columns = columns;
1817
1853
  if (options?.onConflict) payload.on_conflict = options.onConflict;
@@ -1829,9 +1865,10 @@ function createTableBuilder(tableName, client) {
1829
1865
  const executeUpdate = async (columns, selectOptions) => {
1830
1866
  const filters = state.conditions.length ? [...state.conditions] : void 0;
1831
1867
  const mergedOptions = mergeOptions(options, selectOptions);
1868
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1832
1869
  const payload = {
1833
- table_name: tableName,
1834
- set: values,
1870
+ table_name: resolvedTableName,
1871
+ set: asAthenaJsonObject(values),
1835
1872
  conditions: filters,
1836
1873
  strip_nulls: mergedOptions?.stripNulls ?? true
1837
1874
  };
@@ -1857,8 +1894,9 @@ function createTableBuilder(tableName, client) {
1857
1894
  }
1858
1895
  const executeDelete = async (columns, selectOptions) => {
1859
1896
  const mergedOptions = mergeOptions(options, selectOptions);
1897
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1860
1898
  const payload = {
1861
- table_name: tableName,
1899
+ table_name: resolvedTableName,
1862
1900
  resource_id: resourceId,
1863
1901
  conditions: filters
1864
1902
  };