@electric-sql/client 1.3.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/dist/index.mjs CHANGED
@@ -467,6 +467,8 @@ var SUBSET_PARAM_LIMIT = `subset__limit`;
467
467
  var SUBSET_PARAM_OFFSET = `subset__offset`;
468
468
  var SUBSET_PARAM_ORDER_BY = `subset__order_by`;
469
469
  var SUBSET_PARAM_WHERE_PARAMS = `subset__params`;
470
+ var SUBSET_PARAM_WHERE_EXPR = `subset__where_expr`;
471
+ var SUBSET_PARAM_ORDER_BY_EXPR = `subset__order_by_expr`;
470
472
  var ELECTRIC_PROTOCOL_QUERY_PARAMS = [
471
473
  LIVE_QUERY_PARAM,
472
474
  LIVE_SSE_QUERY_PARAM,
@@ -479,7 +481,9 @@ var ELECTRIC_PROTOCOL_QUERY_PARAMS = [
479
481
  SUBSET_PARAM_LIMIT,
480
482
  SUBSET_PARAM_OFFSET,
481
483
  SUBSET_PARAM_ORDER_BY,
482
- SUBSET_PARAM_WHERE_PARAMS
484
+ SUBSET_PARAM_WHERE_PARAMS,
485
+ SUBSET_PARAM_WHERE_EXPR,
486
+ SUBSET_PARAM_ORDER_BY_EXPR
483
487
  ];
484
488
 
485
489
  // src/fetch.ts
@@ -766,6 +770,81 @@ function chainAborter(aborter, sourceSignal) {
766
770
  function noop() {
767
771
  }
768
772
 
773
+ // src/expression-compiler.ts
774
+ function compileExpression(expr, columnMapper) {
775
+ switch (expr.type) {
776
+ case `ref`: {
777
+ const mappedColumn = columnMapper ? columnMapper(expr.column) : expr.column;
778
+ return quoteIdentifier(mappedColumn);
779
+ }
780
+ case `val`:
781
+ return `$${expr.paramIndex}`;
782
+ case `func`:
783
+ return compileFunction(expr, columnMapper);
784
+ default: {
785
+ const _exhaustive = expr;
786
+ throw new Error(`Unknown expression type: ${JSON.stringify(_exhaustive)}`);
787
+ }
788
+ }
789
+ }
790
+ function compileFunction(expr, columnMapper) {
791
+ const args = expr.args.map((arg) => compileExpression(arg, columnMapper));
792
+ switch (expr.name) {
793
+ // Binary comparison operators
794
+ case `eq`:
795
+ return `${args[0]} = ${args[1]}`;
796
+ case `gt`:
797
+ return `${args[0]} > ${args[1]}`;
798
+ case `gte`:
799
+ return `${args[0]} >= ${args[1]}`;
800
+ case `lt`:
801
+ return `${args[0]} < ${args[1]}`;
802
+ case `lte`:
803
+ return `${args[0]} <= ${args[1]}`;
804
+ // Logical operators
805
+ case `and`:
806
+ return args.map((a) => `(${a})`).join(` AND `);
807
+ case `or`:
808
+ return args.map((a) => `(${a})`).join(` OR `);
809
+ case `not`:
810
+ return `NOT (${args[0]})`;
811
+ // Special operators
812
+ case `in`:
813
+ return `${args[0]} = ANY(${args[1]})`;
814
+ case `like`:
815
+ return `${args[0]} LIKE ${args[1]}`;
816
+ case `ilike`:
817
+ return `${args[0]} ILIKE ${args[1]}`;
818
+ case `isNull`:
819
+ case `isUndefined`:
820
+ return `${args[0]} IS NULL`;
821
+ // String functions
822
+ case `upper`:
823
+ return `UPPER(${args[0]})`;
824
+ case `lower`:
825
+ return `LOWER(${args[0]})`;
826
+ case `length`:
827
+ return `LENGTH(${args[0]})`;
828
+ case `concat`:
829
+ return `CONCAT(${args.join(`, `)})`;
830
+ // Other functions
831
+ case `coalesce`:
832
+ return `COALESCE(${args.join(`, `)})`;
833
+ default:
834
+ throw new Error(`Unknown function: ${expr.name}`);
835
+ }
836
+ }
837
+ function compileOrderBy(clauses, columnMapper) {
838
+ return clauses.map((clause) => {
839
+ const mappedColumn = columnMapper ? columnMapper(clause.column) : clause.column;
840
+ let sql = quoteIdentifier(mappedColumn);
841
+ if (clause.direction === `desc`) sql += ` DESC`;
842
+ if (clause.nulls === `first`) sql += ` NULLS FIRST`;
843
+ if (clause.nulls === `last`) sql += ` NULLS LAST`;
844
+ return sql;
845
+ }).join(`, `);
846
+ }
847
+
769
848
  // src/client.ts
770
849
  import {
771
850
  fetchEventSource
@@ -1433,7 +1512,7 @@ requestShape_fn = async function() {
1433
1512
  return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
1434
1513
  };
1435
1514
  constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
1436
- var _a, _b, _c, _d;
1515
+ var _a, _b, _c, _d, _e, _f;
1437
1516
  const [requestHeaders, params] = await Promise.all([
1438
1517
  resolveHeaders(this.options.headers),
1439
1518
  this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
@@ -1478,10 +1557,20 @@ constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
1478
1557
  }
1479
1558
  }
1480
1559
  if (subsetParams) {
1481
- if (subsetParams.where && typeof subsetParams.where === `string`) {
1560
+ if (subsetParams.whereExpr) {
1561
+ const compiledWhere = compileExpression(
1562
+ subsetParams.whereExpr,
1563
+ (_c = this.options.columnMapper) == null ? void 0 : _c.encode
1564
+ );
1565
+ setQueryParam(fetchUrl, SUBSET_PARAM_WHERE, compiledWhere);
1566
+ fetchUrl.searchParams.set(
1567
+ SUBSET_PARAM_WHERE_EXPR,
1568
+ JSON.stringify(subsetParams.whereExpr)
1569
+ );
1570
+ } else if (subsetParams.where && typeof subsetParams.where === `string`) {
1482
1571
  const encodedWhere = encodeWhereClause(
1483
1572
  subsetParams.where,
1484
- (_c = this.options.columnMapper) == null ? void 0 : _c.encode
1573
+ (_d = this.options.columnMapper) == null ? void 0 : _d.encode
1485
1574
  );
1486
1575
  setQueryParam(fetchUrl, SUBSET_PARAM_WHERE, encodedWhere);
1487
1576
  }
@@ -1494,10 +1583,20 @@ constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
1494
1583
  setQueryParam(fetchUrl, SUBSET_PARAM_LIMIT, subsetParams.limit);
1495
1584
  if (subsetParams.offset)
1496
1585
  setQueryParam(fetchUrl, SUBSET_PARAM_OFFSET, subsetParams.offset);
1497
- if (subsetParams.orderBy && typeof subsetParams.orderBy === `string`) {
1586
+ if (subsetParams.orderByExpr) {
1587
+ const compiledOrderBy = compileOrderBy(
1588
+ subsetParams.orderByExpr,
1589
+ (_e = this.options.columnMapper) == null ? void 0 : _e.encode
1590
+ );
1591
+ setQueryParam(fetchUrl, SUBSET_PARAM_ORDER_BY, compiledOrderBy);
1592
+ fetchUrl.searchParams.set(
1593
+ SUBSET_PARAM_ORDER_BY_EXPR,
1594
+ JSON.stringify(subsetParams.orderByExpr)
1595
+ );
1596
+ } else if (subsetParams.orderBy && typeof subsetParams.orderBy === `string`) {
1498
1597
  const encodedOrderBy = encodeWhereClause(
1499
1598
  subsetParams.orderBy,
1500
- (_d = this.options.columnMapper) == null ? void 0 : _d.encode
1599
+ (_f = this.options.columnMapper) == null ? void 0 : _f.encode
1501
1600
  );
1502
1601
  setQueryParam(fetchUrl, SUBSET_PARAM_ORDER_BY, encodedOrderBy);
1503
1602
  }
@@ -2078,6 +2177,8 @@ export {
2078
2177
  Shape,
2079
2178
  ShapeStream,
2080
2179
  camelToSnake,
2180
+ compileExpression,
2181
+ compileOrderBy,
2081
2182
  createColumnMapper,
2082
2183
  isChangeMessage,
2083
2184
  isControlMessage,