bun-sqlite-for-rxdb 1.5.8 → 1.6.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.
Files changed (2) hide show
  1. package/dist/index.js +455 -122
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -12581,22 +12581,69 @@ function normalizeValueForSQLite(value) {
12581
12581
  if (value === undefined) {
12582
12582
  return null;
12583
12583
  }
12584
+ if (Array.isArray(value)) {
12585
+ return JSON.stringify(value);
12586
+ }
12587
+ if (typeof value === "object" && value !== null) {
12588
+ return JSON.stringify(value);
12589
+ }
12584
12590
  return value;
12585
12591
  }
12586
12592
  function translateEq(field, value, schema, actualFieldName) {
12587
12593
  if (value === null) {
12588
12594
  return { sql: `${field} IS NULL`, args: [] };
12589
12595
  }
12596
+ if (Array.isArray(value) || typeof value === "object" && value !== null && !(value instanceof Date) && !(value instanceof RegExp)) {
12597
+ try {
12598
+ return {
12599
+ sql: `${field} = json(?)`,
12600
+ args: [JSON.stringify(value)]
12601
+ };
12602
+ } catch (e) {
12603
+ return { sql: "1=0", args: [] };
12604
+ }
12605
+ }
12590
12606
  if (schema && actualFieldName) {
12591
12607
  const columnInfo = getColumnInfo(actualFieldName, schema);
12592
12608
  if (field !== "value" && columnInfo.type === "array") {
12609
+ const comparison2 = "value = ?";
12610
+ const guardedSql = addTypeGuard("value", value, comparison2);
12593
12611
  return {
12594
- sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value = ?)`,
12612
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(data, '${buildJsonPath(actualFieldName)}') WHERE ${guardedSql})`,
12595
12613
  args: [normalizeValueForSQLite(value)]
12596
12614
  };
12597
12615
  }
12598
12616
  }
12599
- return { sql: `${field} = ?`, args: [normalizeValueForSQLite(value)] };
12617
+ const comparison = `${field} = ?`;
12618
+ return {
12619
+ sql: addTypeGuard(field, value, comparison),
12620
+ args: [normalizeValueForSQLite(value)]
12621
+ };
12622
+ }
12623
+ function addTypeGuard(field, value, comparisonSql) {
12624
+ let typeExpr = "";
12625
+ if (field === "value") {
12626
+ typeExpr = "type";
12627
+ } else if (field.includes("json_extract")) {
12628
+ const match = field.match(/json_extract\(([^,]+),\s*'([^']+)'\)/);
12629
+ if (match) {
12630
+ const [, jsonColumn, jsonPath] = match;
12631
+ typeExpr = `json_type(${jsonColumn}, '${jsonPath}')`;
12632
+ }
12633
+ }
12634
+ if (!typeExpr)
12635
+ return comparisonSql;
12636
+ const valueType = typeof value;
12637
+ if (valueType === "number") {
12638
+ return `(${typeExpr} IN ('integer', 'real') AND ${comparisonSql})`;
12639
+ }
12640
+ if (valueType === "string") {
12641
+ return `(${typeExpr} = 'text' AND ${comparisonSql})`;
12642
+ }
12643
+ if (valueType === "boolean") {
12644
+ return `(${typeExpr} IN ('true', 'false') AND ${comparisonSql})`;
12645
+ }
12646
+ return comparisonSql;
12600
12647
  }
12601
12648
  function translateNe(field, value, schema, actualFieldName) {
12602
12649
  if (value === null) {
@@ -12605,8 +12652,10 @@ function translateNe(field, value, schema, actualFieldName) {
12605
12652
  if (schema && actualFieldName) {
12606
12653
  const columnInfo = getColumnInfo(actualFieldName, schema);
12607
12654
  if (field !== "value" && columnInfo.type === "array") {
12655
+ const comparison = "value = ?";
12656
+ const guardedSql = addTypeGuard("value", value, comparison);
12608
12657
  return {
12609
- sql: `NOT EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value = ?)`,
12658
+ sql: `NOT EXISTS (SELECT 1 FROM jsonb_each(data, '${buildJsonPath(actualFieldName)}') WHERE ${guardedSql})`,
12610
12659
  args: [normalizeValueForSQLite(value)]
12611
12660
  };
12612
12661
  }
@@ -12617,49 +12666,73 @@ function translateGt(field, value, schema, actualFieldName) {
12617
12666
  if (schema && actualFieldName) {
12618
12667
  const columnInfo = getColumnInfo(actualFieldName, schema);
12619
12668
  if (field !== "value" && columnInfo.type === "array") {
12669
+ const comparison2 = "value > ?";
12670
+ const guardedSql = addTypeGuard("value", value, comparison2);
12620
12671
  return {
12621
- sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value > ?)`,
12672
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(data, '${buildJsonPath(actualFieldName)}') WHERE ${guardedSql})`,
12622
12673
  args: [normalizeValueForSQLite(value)]
12623
12674
  };
12624
12675
  }
12625
12676
  }
12626
- return { sql: `${field} > ?`, args: [normalizeValueForSQLite(value)] };
12677
+ const comparison = `${field} > ?`;
12678
+ return {
12679
+ sql: addTypeGuard(field, value, comparison),
12680
+ args: [normalizeValueForSQLite(value)]
12681
+ };
12627
12682
  }
12628
12683
  function translateGte(field, value, schema, actualFieldName) {
12629
12684
  if (schema && actualFieldName) {
12630
12685
  const columnInfo = getColumnInfo(actualFieldName, schema);
12631
12686
  if (field !== "value" && columnInfo.type === "array") {
12687
+ const comparison2 = "value >= ?";
12688
+ const guardedSql = addTypeGuard("value", value, comparison2);
12632
12689
  return {
12633
- sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value >= ?)`,
12690
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(data, '${buildJsonPath(actualFieldName)}') WHERE ${guardedSql})`,
12634
12691
  args: [normalizeValueForSQLite(value)]
12635
12692
  };
12636
12693
  }
12637
12694
  }
12638
- return { sql: `${field} >= ?`, args: [normalizeValueForSQLite(value)] };
12695
+ const comparison = `${field} >= ?`;
12696
+ return {
12697
+ sql: addTypeGuard(field, value, comparison),
12698
+ args: [normalizeValueForSQLite(value)]
12699
+ };
12639
12700
  }
12640
12701
  function translateLt(field, value, schema, actualFieldName) {
12641
12702
  if (schema && actualFieldName) {
12642
12703
  const columnInfo = getColumnInfo(actualFieldName, schema);
12643
12704
  if (field !== "value" && columnInfo.type === "array") {
12705
+ const comparison2 = "value < ?";
12706
+ const guardedSql = addTypeGuard("value", value, comparison2);
12644
12707
  return {
12645
- sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value < ?)`,
12708
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(data, '${buildJsonPath(actualFieldName)}') WHERE ${guardedSql})`,
12646
12709
  args: [normalizeValueForSQLite(value)]
12647
12710
  };
12648
12711
  }
12649
12712
  }
12650
- return { sql: `${field} < ?`, args: [normalizeValueForSQLite(value)] };
12713
+ const comparison = `${field} < ?`;
12714
+ return {
12715
+ sql: addTypeGuard(field, value, comparison),
12716
+ args: [normalizeValueForSQLite(value)]
12717
+ };
12651
12718
  }
12652
12719
  function translateLte(field, value, schema, actualFieldName) {
12653
12720
  if (schema && actualFieldName) {
12654
12721
  const columnInfo = getColumnInfo(actualFieldName, schema);
12655
12722
  if (field !== "value" && columnInfo.type === "array") {
12723
+ const comparison2 = "value <= ?";
12724
+ const guardedSql = addTypeGuard("value", value, comparison2);
12656
12725
  return {
12657
- sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value <= ?)`,
12726
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(data, '${buildJsonPath(actualFieldName)}') WHERE ${guardedSql})`,
12658
12727
  args: [normalizeValueForSQLite(value)]
12659
12728
  };
12660
12729
  }
12661
12730
  }
12662
- return { sql: `${field} <= ?`, args: [normalizeValueForSQLite(value)] };
12731
+ const comparison = `${field} <= ?`;
12732
+ return {
12733
+ sql: addTypeGuard(field, value, comparison),
12734
+ args: [normalizeValueForSQLite(value)]
12735
+ };
12663
12736
  }
12664
12737
  function translateIn(field, values, schema, actualFieldName) {
12665
12738
  if (!Array.isArray(values) || values.length === 0) {
@@ -12673,26 +12746,34 @@ function translateIn(field, values, schema, actualFieldName) {
12673
12746
  if (schema && actualFieldName) {
12674
12747
  const columnInfo = getColumnInfo(actualFieldName, schema);
12675
12748
  if (field !== "value" && columnInfo.type === "array") {
12676
- const inClause2 = `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value IN (SELECT value FROM json_each(?)))`;
12677
- const args2 = [JSON.stringify(nonNullValues)];
12678
- if (hasNull) {
12679
- return {
12680
- sql: `(${inClause2} OR ${field} IS NULL)`,
12681
- args: args2
12682
- };
12749
+ try {
12750
+ const inClause = `EXISTS (SELECT 1 FROM jsonb_each(data, '${buildJsonPath(actualFieldName)}') WHERE value IN (SELECT value FROM json_each(?)))`;
12751
+ const args = [JSON.stringify(nonNullValues)];
12752
+ if (hasNull) {
12753
+ return {
12754
+ sql: `(${inClause} OR ${field} IS NULL)`,
12755
+ args
12756
+ };
12757
+ }
12758
+ return { sql: inClause, args };
12759
+ } catch (e) {
12760
+ return { sql: "1=0", args: [] };
12683
12761
  }
12684
- return { sql: inClause2, args: args2 };
12685
12762
  }
12686
12763
  }
12687
- const inClause = `${field} IN (SELECT value FROM json_each(?))`;
12688
- const args = [JSON.stringify(nonNullValues)];
12689
- if (hasNull) {
12690
- return {
12691
- sql: `(${inClause} OR ${field} IS NULL)`,
12692
- args
12693
- };
12764
+ try {
12765
+ const inClause = `${field} IN (SELECT value FROM json_each(?))`;
12766
+ const args = [JSON.stringify(nonNullValues)];
12767
+ if (hasNull) {
12768
+ return {
12769
+ sql: `(${inClause} OR ${field} IS NULL)`,
12770
+ args
12771
+ };
12772
+ }
12773
+ return { sql: inClause, args };
12774
+ } catch (e) {
12775
+ return { sql: "1=0", args: [] };
12694
12776
  }
12695
- return { sql: inClause, args };
12696
12777
  }
12697
12778
  function translateNin(field, values, schema, actualFieldName) {
12698
12779
  if (!Array.isArray(values) || values.length === 0) {
@@ -12706,30 +12787,54 @@ function translateNin(field, values, schema, actualFieldName) {
12706
12787
  if (schema && actualFieldName) {
12707
12788
  const columnInfo = getColumnInfo(actualFieldName, schema);
12708
12789
  if (field !== "value" && columnInfo.type === "array") {
12709
- const ninClause2 = `NOT EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value IN (SELECT value FROM json_each(?)))`;
12710
- const args2 = [JSON.stringify(nonNullValues)];
12711
- if (hasNull) {
12712
- return {
12713
- sql: `(${ninClause2} AND ${field} IS NOT NULL)`,
12714
- args: args2
12715
- };
12790
+ try {
12791
+ const ninClause = `NOT EXISTS (SELECT 1 FROM jsonb_each(data, '${buildJsonPath(actualFieldName)}') WHERE value IN (SELECT value FROM json_each(?)))`;
12792
+ const args = [JSON.stringify(nonNullValues)];
12793
+ if (hasNull) {
12794
+ return {
12795
+ sql: `(${ninClause} AND ${field} IS NOT NULL)`,
12796
+ args
12797
+ };
12798
+ }
12799
+ return { sql: `(${field} IS NULL OR ${ninClause})`, args };
12800
+ } catch (e) {
12801
+ return { sql: "1=1", args: [] };
12716
12802
  }
12717
- return { sql: `(${field} IS NULL OR ${ninClause2})`, args: args2 };
12718
12803
  }
12719
12804
  }
12720
- const ninClause = `${field} NOT IN (SELECT value FROM json_each(?))`;
12721
- const args = [JSON.stringify(nonNullValues)];
12722
- if (hasNull) {
12723
- return {
12724
- sql: `(${ninClause} AND ${field} IS NOT NULL)`,
12725
- args
12726
- };
12805
+ try {
12806
+ const ninClause = `${field} NOT IN (SELECT value FROM json_each(?))`;
12807
+ const args = [JSON.stringify(nonNullValues)];
12808
+ if (hasNull) {
12809
+ return {
12810
+ sql: `(${ninClause} AND ${field} IS NOT NULL)`,
12811
+ args
12812
+ };
12813
+ }
12814
+ return { sql: `(${field} IS NULL OR ${ninClause})`, args };
12815
+ } catch (e) {
12816
+ return { sql: "1=1", args: [] };
12727
12817
  }
12728
- return { sql: `(${field} IS NULL OR ${ninClause})`, args };
12729
12818
  }
12730
12819
  function translateExists(field, exists) {
12820
+ let typeExpr = "";
12821
+ if (field === "value") {
12822
+ typeExpr = "type";
12823
+ } else if (field.includes("json_extract")) {
12824
+ const match = field.match(/json_extract\(([^,]+),\s*'([^']+)'\)/);
12825
+ if (match) {
12826
+ const [, jsonColumn, jsonPath] = match;
12827
+ typeExpr = `json_type(${jsonColumn}, '${jsonPath}')`;
12828
+ }
12829
+ }
12830
+ if (!typeExpr) {
12831
+ return {
12832
+ sql: exists ? `${field} IS NOT NULL` : `${field} IS NULL`,
12833
+ args: []
12834
+ };
12835
+ }
12731
12836
  return {
12732
- sql: exists ? `${field} IS NOT NULL` : `${field} IS NULL`,
12837
+ sql: exists ? `${typeExpr} IS NOT NULL` : `${typeExpr} IS NULL`,
12733
12838
  args: []
12734
12839
  };
12735
12840
  }
@@ -12740,7 +12845,7 @@ function translateRegex(field, pattern, options, schema, fieldName) {
12740
12845
  const smartResult2 = smartRegexToLike("value", pattern, options, schema, fieldName);
12741
12846
  if (smartResult2) {
12742
12847
  return {
12743
- sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE ${smartResult2.sql})`,
12848
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(data, '${buildJsonPath(fieldName)}') WHERE ${smartResult2.sql})`,
12744
12849
  args: smartResult2.args
12745
12850
  };
12746
12851
  }
@@ -12752,7 +12857,7 @@ function translateRegex(field, pattern, options, schema, fieldName) {
12752
12857
  return null;
12753
12858
  }
12754
12859
  var LOGICAL_OPERATORS = new Set(["$and", "$or", "$nor", "$not"]);
12755
- var LEAF_OPERATORS = new Set(["$eq", "$ne", "$gt", "$gte", "$lt", "$lte", "$in", "$nin", "$exists", "$regex", "$type", "$size", "$mod", "$elemMatch"]);
12860
+ var LEAF_OPERATORS = new Set(["$eq", "$ne", "$gt", "$gte", "$lt", "$lte", "$in", "$nin", "$exists", "$regex", "$type", "$size", "$mod", "$elemMatch", "$all"]);
12756
12861
  function isLogicalOperator(key) {
12757
12862
  return LOGICAL_OPERATORS.has(key);
12758
12863
  }
@@ -12872,7 +12977,7 @@ function translateElemMatch(field, criteria, schema, actualFieldName) {
12872
12977
  const sql = fragments.map((f) => `COALESCE((${f.sql}), 0)`).join(" AND ");
12873
12978
  const args = fragments.flatMap((f) => f.args);
12874
12979
  return {
12875
- sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE ${sql})`,
12980
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(data, '${buildJsonPath(actualFieldName)}') WHERE ${sql})`,
12876
12981
  args
12877
12982
  };
12878
12983
  }
@@ -12883,7 +12988,7 @@ function translateElemMatch(field, criteria, schema, actualFieldName) {
12883
12988
  const sql = fragments.map((f) => `COALESCE((${f.sql}), 0)`).join(" OR ");
12884
12989
  const args = fragments.flatMap((f) => f.args);
12885
12990
  return {
12886
- sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE ${sql})`,
12991
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(data, '${buildJsonPath(actualFieldName)}') WHERE ${sql})`,
12887
12992
  args
12888
12993
  };
12889
12994
  }
@@ -12894,7 +12999,7 @@ function translateElemMatch(field, criteria, schema, actualFieldName) {
12894
12999
  const sql = fragments.map((f) => `COALESCE((${f.sql}), 0)`).join(" OR ");
12895
13000
  const args = fragments.flatMap((f) => f.args);
12896
13001
  return {
12897
- sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE NOT (${sql}))`,
13002
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(data, '${buildJsonPath(actualFieldName)}') WHERE NOT (${sql}))`,
12898
13003
  args
12899
13004
  };
12900
13005
  }
@@ -12902,7 +13007,7 @@ function translateElemMatch(field, criteria, schema, actualFieldName) {
12902
13007
  if (!fragment)
12903
13008
  return null;
12904
13009
  return {
12905
- sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE ${asBoolean(fragment.sql)})`,
13010
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(data, '${buildJsonPath(actualFieldName)}') WHERE ${asBoolean(fragment.sql)})`,
12906
13011
  args: fragment.args
12907
13012
  };
12908
13013
  }
@@ -12979,6 +13084,42 @@ function translateLeafOperator(op, field, value, schema, actualFieldName) {
12979
13084
  path2 = match[2];
12980
13085
  }
12981
13086
  }
13087
+ if (Array.isArray(value)) {
13088
+ const types = value;
13089
+ if (types.length === 0)
13090
+ return { sql: "1=0", args: [] };
13091
+ if (useDirectType) {
13092
+ const typeMap = {
13093
+ null: "null",
13094
+ boolean: "true",
13095
+ number: "integer",
13096
+ string: "text",
13097
+ array: "array",
13098
+ object: "object"
13099
+ };
13100
+ const conditions = [];
13101
+ for (const t of types) {
13102
+ const sqlType = typeMap[t];
13103
+ if (!sqlType)
13104
+ continue;
13105
+ if (t === "boolean")
13106
+ conditions.push(`(type IN ('true', 'false'))`);
13107
+ else if (t === "number")
13108
+ conditions.push(`(type IN ('integer', 'real'))`);
13109
+ else
13110
+ conditions.push(`type = '${sqlType}'`);
13111
+ }
13112
+ if (conditions.length === 0)
13113
+ return { sql: "1=0", args: [] };
13114
+ return { sql: `(${conditions.join(" OR ")})`, args: [] };
13115
+ } else {
13116
+ const fragments = types.map((t) => translateType(jsonCol, path2, t, true)).filter((f) => f !== null);
13117
+ if (fragments.length === 0)
13118
+ return { sql: "1=0", args: [] };
13119
+ const sql = fragments.map((f) => f.sql).join(" OR ");
13120
+ return { sql: `(${sql})`, args: [] };
13121
+ }
13122
+ }
12982
13123
  if (useDirectType) {
12983
13124
  const typeMap = {
12984
13125
  null: "null",
@@ -13002,6 +13143,33 @@ function translateLeafOperator(op, field, value, schema, actualFieldName) {
13002
13143
  const typeFragment = translateType(jsonCol, path2, value, true);
13003
13144
  return typeFragment || { sql: "1=0", args: [] };
13004
13145
  }
13146
+ case "$all": {
13147
+ if (!Array.isArray(value) || value.length === 0)
13148
+ return { sql: "1=0", args: [] };
13149
+ const fragments = [];
13150
+ for (const val of value) {
13151
+ if (val instanceof RegExp) {
13152
+ const frag = translateLeafOperator("$regex", field, val, schema, actualFieldName);
13153
+ if (!frag)
13154
+ return null;
13155
+ fragments.push(frag);
13156
+ } else if (typeof val === "object" && val !== null && !Array.isArray(val) && "$elemMatch" in val) {
13157
+ const frag = translateElemMatch(actualFieldName, val.$elemMatch, schema, actualFieldName);
13158
+ if (!frag)
13159
+ return null;
13160
+ fragments.push(frag);
13161
+ } else {
13162
+ const frag = translateLeafOperator("$eq", field, val, schema, actualFieldName);
13163
+ if (!frag)
13164
+ return null;
13165
+ fragments.push(frag);
13166
+ }
13167
+ }
13168
+ return {
13169
+ sql: `(${fragments.map((f) => f.sql).join(" AND ")})`,
13170
+ args: fragments.flatMap((f) => f.args)
13171
+ };
13172
+ }
13005
13173
  default:
13006
13174
  return translateEq(field, value, schema, actualFieldName);
13007
13175
  }
@@ -13162,11 +13330,21 @@ function _stringify(value, stack) {
13162
13330
  }
13163
13331
 
13164
13332
  // src/query/builder.ts
13333
+ function isOperatorObject2(value) {
13334
+ if (typeof value !== "object" || value === null || Array.isArray(value))
13335
+ return false;
13336
+ if (value instanceof Date || value instanceof RegExp)
13337
+ return false;
13338
+ const keys = Object.keys(value);
13339
+ if (keys.length === 0)
13340
+ return false;
13341
+ return keys.every((k) => k.startsWith("$"));
13342
+ }
13165
13343
  function buildWhereClause(selector, schema, collectionName, cache) {
13166
13344
  if (!selector || typeof selector !== "object")
13167
13345
  return null;
13168
13346
  const actualCache = cache ?? getGlobalCache();
13169
- const cacheKey = `v3_${schema.version}_${stableStringify(selector)}`;
13347
+ const cacheKey = `v4_${schema.version}_${stableStringify(selector)}`;
13170
13348
  const cached = actualCache.get(cacheKey);
13171
13349
  if (cached !== undefined) {
13172
13350
  return cached;
@@ -13226,6 +13404,17 @@ function processSelector(selector, schema, logicalDepth) {
13226
13404
  const conditions = [];
13227
13405
  const args = [];
13228
13406
  for (const [field, value] of Object.entries(selector)) {
13407
+ if (field.includes(".") && !field.startsWith("$")) {
13408
+ const parts = field.split(".");
13409
+ let currentPath = "";
13410
+ for (const part of parts) {
13411
+ currentPath = currentPath ? `${currentPath}.${part}` : part;
13412
+ const columnInfo2 = getColumnInfo(currentPath, schema);
13413
+ if (columnInfo2.type === "array") {
13414
+ return null;
13415
+ }
13416
+ }
13417
+ }
13229
13418
  if (field === "$and" && Array.isArray(value)) {
13230
13419
  const andFragments = value.map((subSelector) => processSelector(subSelector, schema, logicalDepth + 1));
13231
13420
  if (andFragments.some((f) => f === null))
@@ -13265,9 +13454,26 @@ function processSelector(selector, schema, logicalDepth) {
13265
13454
  const fieldName = columnInfo.column || `json_extract(data, '${buildJsonPath(field)}')`;
13266
13455
  const actualFieldName = columnInfo.jsonPath?.replace(/^\$\./, "") || columnInfo.column || field;
13267
13456
  if (typeof value === "object" && value !== null && !Array.isArray(value)) {
13457
+ const valueUnknown = value;
13458
+ if (valueUnknown instanceof Date || valueUnknown instanceof RegExp) {
13459
+ const fragment = translateLeafOperator("$eq", fieldName, value, schema, actualFieldName);
13460
+ if (!fragment)
13461
+ return null;
13462
+ conditions.push(fragment.sql);
13463
+ args.push(...fragment.args);
13464
+ continue;
13465
+ }
13268
13466
  if (Object.keys(value).length === 0) {
13269
13467
  return { sql: "1=0", args: [] };
13270
13468
  }
13469
+ if (!isOperatorObject2(value)) {
13470
+ const fragment = translateLeafOperator("$eq", fieldName, value, schema, actualFieldName);
13471
+ if (!fragment)
13472
+ return null;
13473
+ conditions.push(fragment.sql);
13474
+ args.push(...fragment.args);
13475
+ continue;
13476
+ }
13271
13477
  const fieldFragments = [];
13272
13478
  for (const [op, opValue] of Object.entries(value)) {
13273
13479
  let fragment;
@@ -13402,98 +13608,225 @@ function processSelector(selector, schema, logicalDepth) {
13402
13608
  }
13403
13609
 
13404
13610
  // src/query/lightweight-matcher.ts
13611
+ function isOperatorObject3(obj) {
13612
+ if (typeof obj !== "object" || obj === null || Array.isArray(obj))
13613
+ return false;
13614
+ const keys = Object.keys(obj);
13615
+ if (keys.length === 0)
13616
+ return false;
13617
+ return keys.every((k) => k.startsWith("$"));
13618
+ }
13619
+ function isSameBsonType(a, b) {
13620
+ if (a === null || b === null)
13621
+ return a === b;
13622
+ return typeof a === typeof b;
13623
+ }
13624
+ function getNestedValue(obj, path2) {
13625
+ const segments = path2.split(".");
13626
+ let value = obj;
13627
+ for (let i = 0;i < segments.length; i++) {
13628
+ const field = segments[i];
13629
+ if (Array.isArray(value) && !/^\d+$/.test(field)) {
13630
+ const remainingPath = segments.slice(i).join(".");
13631
+ const results = [];
13632
+ for (const item of value) {
13633
+ const res = getNestedValue(item, remainingPath);
13634
+ if (res !== undefined) {
13635
+ if (Array.isArray(res))
13636
+ results.push(...res);
13637
+ else
13638
+ results.push(res);
13639
+ }
13640
+ }
13641
+ return results.length > 0 ? results : undefined;
13642
+ }
13643
+ value = value?.[field];
13644
+ if (value === undefined)
13645
+ return;
13646
+ }
13647
+ return value;
13648
+ }
13405
13649
  var operators = {
13406
- $eq: (a, b) => a === b,
13407
- $ne: (a, b) => a !== b,
13408
- $gt: (a, b) => a > b,
13409
- $gte: (a, b) => a >= b,
13410
- $lt: (a, b) => a < b,
13411
- $lte: (a, b) => a <= b,
13412
- $in: (a, b) => Array.isArray(b) && b.some((v) => v === a),
13413
- $nin: (a, b) => Array.isArray(b) && !b.some((v) => v === a),
13650
+ $eq: (a, b) => {
13651
+ if (typeof a === "object" && typeof b === "object" && a !== null && b !== null) {
13652
+ return stableStringify(a) === stableStringify(b);
13653
+ }
13654
+ return a === b;
13655
+ },
13656
+ $ne: (a, b) => {
13657
+ if (typeof a === "object" && typeof b === "object" && a !== null && b !== null) {
13658
+ return stableStringify(a) !== stableStringify(b);
13659
+ }
13660
+ return a !== b;
13661
+ },
13662
+ $gt: (a, b) => isSameBsonType(a, b) && a > b,
13663
+ $gte: (a, b) => isSameBsonType(a, b) && a >= b,
13664
+ $lt: (a, b) => isSameBsonType(a, b) && a < b,
13665
+ $lte: (a, b) => isSameBsonType(a, b) && a <= b,
13666
+ $in: (a, b) => {
13667
+ if (!Array.isArray(b))
13668
+ return false;
13669
+ const aStr = typeof a === "object" && a !== null ? stableStringify(a) : undefined;
13670
+ return b.some((v) => {
13671
+ if (aStr !== undefined && typeof v === "object" && v !== null) {
13672
+ return aStr === stableStringify(v);
13673
+ }
13674
+ return v === a;
13675
+ });
13676
+ },
13677
+ $nin: (a, b) => {
13678
+ if (!Array.isArray(b))
13679
+ return false;
13680
+ const aStr = typeof a === "object" && a !== null ? stableStringify(a) : undefined;
13681
+ return !b.some((v) => {
13682
+ if (aStr !== undefined && typeof v === "object" && v !== null) {
13683
+ return aStr === stableStringify(v);
13684
+ }
13685
+ return v === a;
13686
+ });
13687
+ },
13414
13688
  $exists: (a, b) => a !== undefined === b,
13689
+ $mod: (a, b) => Array.isArray(b) && b.length === 2 && typeof a === "number" && a % b[0] === b[1],
13690
+ $size: (a, b) => Array.isArray(a) && a.length === b,
13691
+ $regex: (a, b) => {
13692
+ const pattern = typeof b === "string" ? b : b.pattern;
13693
+ const flags = typeof b === "string" ? undefined : b.options;
13694
+ return matchesRegex(a, pattern, flags);
13695
+ },
13415
13696
  $type: (a, b) => {
13416
- const type6 = Array.isArray(a) ? "array" : typeof a;
13417
- return type6 === b;
13697
+ let type6;
13698
+ if (a === null)
13699
+ type6 = "null";
13700
+ else if (Array.isArray(a))
13701
+ type6 = "array";
13702
+ else
13703
+ type6 = typeof a;
13704
+ const matchType = (t) => {
13705
+ if (t === "int" || t === "long" || t === "decimal" || t === "double")
13706
+ return type6 === "number";
13707
+ if (t === "bool")
13708
+ return type6 === "boolean";
13709
+ return type6 === t;
13710
+ };
13711
+ return Array.isArray(b) ? b.some(matchType) : matchType(b);
13712
+ },
13713
+ $not: (a, b, matcher) => {
13714
+ if (isOperatorObject3(b)) {
13715
+ return !matchesOperators(a, b, matcher);
13716
+ }
13717
+ return operators.$ne(a, b, matcher);
13418
13718
  },
13419
- $mod: (a, b) => {
13420
- if (!Array.isArray(b) || b.length !== 2)
13719
+ $elemMatch: (val, query, matcher) => {
13720
+ if (!Array.isArray(val))
13421
13721
  return false;
13422
- const [divisor, remainder] = b;
13423
- return typeof a === "number" && a % divisor === remainder;
13722
+ const isOpObj = isOperatorObject3(query) && !["$and", "$or", "$nor"].some((k) => (k in query));
13723
+ return val.some((item) => {
13724
+ if (isOpObj)
13725
+ return matchesOperators(item, query, matcher);
13726
+ return matcher(item, query);
13727
+ });
13424
13728
  },
13425
- $size: (a, b) => Array.isArray(a) && a.length === b
13729
+ $all: (a, b, matcher) => {
13730
+ if (!Array.isArray(b))
13731
+ return false;
13732
+ if (!Array.isArray(a)) {
13733
+ return b.length === 1 && operators.$eq(a, b[0], matcher);
13734
+ }
13735
+ return b.every((req) => {
13736
+ if (typeof req === "object" && req !== null && !Array.isArray(req) && !(req instanceof Date) && !(req instanceof RegExp)) {
13737
+ if (req.$elemMatch) {
13738
+ return operators.$elemMatch(a, req.$elemMatch, matcher);
13739
+ }
13740
+ }
13741
+ if (req instanceof RegExp) {
13742
+ return a.some((item) => matchesRegex(item, req.source, req.flags));
13743
+ }
13744
+ const reqStr = typeof req === "object" && req !== null ? stableStringify(req) : undefined;
13745
+ return a.some((item) => {
13746
+ if (reqStr !== undefined && typeof item === "object" && item !== null) {
13747
+ return reqStr === stableStringify(item);
13748
+ }
13749
+ return item === req;
13750
+ });
13751
+ });
13752
+ }
13426
13753
  };
13427
- function getNestedValue(obj, path2) {
13428
- return path2.split(".").reduce((current, key) => current?.[key], obj);
13754
+ function matchesOperators(value, condition, matcher) {
13755
+ for (const [op, arg] of Object.entries(condition)) {
13756
+ if (op === "$options")
13757
+ continue;
13758
+ const fn = operators[op];
13759
+ if (fn) {
13760
+ let operatorArg = arg;
13761
+ if (op === "$regex" && typeof arg === "string" && condition.$options) {
13762
+ operatorArg = { pattern: arg, options: condition.$options };
13763
+ }
13764
+ const isNegative = op === "$ne" || op === "$nin";
13765
+ const isStructural = op === "$size" || op === "$type" || op === "$elemMatch" || op === "$all";
13766
+ const argIsArrayOrObject = typeof arg === "object" && arg !== null;
13767
+ const skipTraversal = argIsArrayOrObject && (op === "$eq" || op === "$ne");
13768
+ if (Array.isArray(value) && !isStructural && !skipTraversal) {
13769
+ const predicate = (v) => fn(v, operatorArg, matcher);
13770
+ if (isNegative ? !value.every(predicate) : !value.some(predicate))
13771
+ return false;
13772
+ } else {
13773
+ if (!fn(value, operatorArg, matcher))
13774
+ return false;
13775
+ }
13776
+ }
13777
+ }
13778
+ return true;
13429
13779
  }
13430
13780
  function matchesSelector(doc, selector) {
13431
13781
  if (!selector || typeof selector !== "object")
13432
13782
  return true;
13433
- if (selector.$and) {
13434
- return Array.isArray(selector.$and) && selector.$and.every((s) => matchesSelector(doc, s));
13435
- }
13436
- if (selector.$or) {
13437
- return Array.isArray(selector.$or) && selector.$or.some((s) => matchesSelector(doc, s));
13438
- }
13439
- if (selector.$nor) {
13440
- return Array.isArray(selector.$nor) && !selector.$nor.some((s) => matchesSelector(doc, s));
13441
- }
13783
+ if (Array.isArray(selector.$and) && !selector.$and.every((s) => matchesSelector(doc, s)))
13784
+ return false;
13785
+ if (Array.isArray(selector.$or) && !selector.$or.some((s) => matchesSelector(doc, s)))
13786
+ return false;
13787
+ if (Array.isArray(selector.$nor) && selector.$nor.some((s) => matchesSelector(doc, s)))
13788
+ return false;
13442
13789
  for (const [field, condition] of Object.entries(selector)) {
13443
- const value = getNestedValue(doc, field);
13444
- if (typeof condition !== "object" || condition === null || Array.isArray(condition)) {
13445
- if (value !== condition)
13446
- return false;
13790
+ if (field.startsWith("$"))
13447
13791
  continue;
13448
- }
13449
- for (const [op, opValue] of Object.entries(condition)) {
13450
- if (op === "$regex") {
13451
- const options = condition.$options;
13452
- if (!matchesRegex(value, opValue, options))
13453
- return false;
13454
- continue;
13455
- }
13456
- if (op === "$not") {
13457
- if (matchesOperator(value, opValue))
13792
+ const value = getNestedValue(doc, field);
13793
+ if (typeof condition === "object" && condition !== null && !Array.isArray(condition)) {
13794
+ const conditionUnknown = condition;
13795
+ if (conditionUnknown instanceof Date || conditionUnknown instanceof RegExp) {
13796
+ const eq = operators.$eq;
13797
+ if (Array.isArray(value)) {
13798
+ if (!value.some((v) => eq(v, condition, matchesSelector)))
13799
+ return false;
13800
+ } else {
13801
+ if (!eq(value, condition, matchesSelector))
13802
+ return false;
13803
+ }
13804
+ } else if (isOperatorObject3(condition)) {
13805
+ if (!matchesOperators(value, condition, matchesSelector))
13458
13806
  return false;
13459
- continue;
13807
+ } else {
13808
+ const eq = operators.$eq;
13809
+ if (Array.isArray(value)) {
13810
+ if (!value.some((v) => eq(v, condition, matchesSelector)))
13811
+ return false;
13812
+ } else {
13813
+ if (!eq(value, condition, matchesSelector))
13814
+ return false;
13815
+ }
13460
13816
  }
13461
- if (op === "$elemMatch") {
13462
- if (!Array.isArray(value))
13817
+ } else {
13818
+ const eq = operators.$eq;
13819
+ if (Array.isArray(value)) {
13820
+ if (!value.some((v) => eq(v, condition, matchesSelector)))
13463
13821
  return false;
13464
- const hasMatch = value.some((item) => matchesSelector(item, opValue));
13465
- if (!hasMatch)
13822
+ } else {
13823
+ if (!eq(value, condition, matchesSelector))
13466
13824
  return false;
13467
- continue;
13468
13825
  }
13469
- if (op === "$options")
13470
- continue;
13471
- const operator = operators[op];
13472
- if (!operator)
13473
- return false;
13474
- if (!operator(value, opValue))
13475
- return false;
13476
13826
  }
13477
13827
  }
13478
13828
  return true;
13479
13829
  }
13480
- function matchesOperator(value, operator) {
13481
- if (typeof operator !== "object" || operator === null) {
13482
- return value === operator;
13483
- }
13484
- for (const [op, opValue] of Object.entries(operator)) {
13485
- if (op === "$regex") {
13486
- const options = operator.$options;
13487
- return matchesRegex(value, opValue, options);
13488
- }
13489
- const operatorFn = operators[op];
13490
- if (!operatorFn)
13491
- return false;
13492
- if (operatorFn(value, opValue))
13493
- return true;
13494
- }
13495
- return false;
13496
- }
13497
13830
 
13498
13831
  // src/rxdb-helpers.ts
13499
13832
  function randomToken2(length) {
@@ -14101,7 +14434,7 @@ class BunSQLiteStorageInstance {
14101
14434
  const stmt = this.db.prepare(sql);
14102
14435
  const documents = [];
14103
14436
  let skipped = 0;
14104
- for (const row of stmt.all(...queryArgs)) {
14437
+ for (const row of stmt.iterate(...queryArgs)) {
14105
14438
  const doc = JSON.parse(row.data);
14106
14439
  if (matchesSelector(doc, jsSelector)) {
14107
14440
  if (skip > 0 && skipped < skip) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bun-sqlite-for-rxdb",
3
- "version": "1.5.8",
3
+ "version": "1.6.0",
4
4
  "author": "adam2am",
5
5
  "repository": {
6
6
  "type": "git",