bun-sqlite-for-rxdb 1.5.4 → 1.5.7

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.js CHANGED
@@ -12463,9 +12463,19 @@ function getColumnInfo(path2, schema) {
12463
12463
  const properties = schema.properties;
12464
12464
  const fieldSchema = properties?.[path2];
12465
12465
  if (fieldSchema && typeof fieldSchema === "object" && "type" in fieldSchema) {
12466
- if (fieldSchema.type === "array") {
12466
+ const schemaType = fieldSchema.type;
12467
+ if (schemaType === "array") {
12467
12468
  return { jsonPath: `$.${path2}`, type: "array" };
12468
12469
  }
12470
+ if (schemaType === "string") {
12471
+ return { jsonPath: `$.${path2}`, type: "string" };
12472
+ }
12473
+ if (schemaType === "number") {
12474
+ return { jsonPath: `$.${path2}`, type: "number" };
12475
+ }
12476
+ if (schemaType === "boolean") {
12477
+ return { jsonPath: `$.${path2}`, type: "boolean" };
12478
+ }
12469
12479
  }
12470
12480
  return { jsonPath: `$.${path2}`, type: "unknown" };
12471
12481
  }
@@ -12526,32 +12536,41 @@ function smartRegexToLike(field, pattern, options, schema, fieldName) {
12526
12536
  const escaped = escapeForLike(unescaped);
12527
12537
  if (startsWithAnchor && endsWithAnchor) {
12528
12538
  if (caseInsensitive) {
12529
- return hasLowerIndex ? { sql: `LOWER(${field}) = ?`, args: [unescaped.toLowerCase()] } : { sql: `${field} = ? COLLATE NOCASE`, args: [unescaped] };
12539
+ return { sql: `LOWER(${field}) = LOWER(?)`, args: [unescaped] };
12530
12540
  }
12531
12541
  return { sql: `${field} = ?`, args: [unescaped] };
12532
12542
  }
12533
12543
  if (startsWithAnchor) {
12534
- const suffix = caseInsensitive ? escaped.toLowerCase() : escaped;
12535
- if (caseInsensitive && hasLowerIndex) {
12536
- return { sql: `LOWER(${field}) LIKE ? ESCAPE '\\'`, args: [suffix + "%"] };
12544
+ if (caseInsensitive) {
12545
+ return { sql: `LOWER(${field}) LIKE LOWER(?) ESCAPE '\\'`, args: [escaped + "%"] };
12537
12546
  }
12538
- return { sql: `${field} LIKE ?${caseInsensitive ? " COLLATE NOCASE" : ""} ESCAPE '\\'`, args: [suffix + "%"] };
12547
+ return { sql: `${field} LIKE ? ESCAPE '\\'`, args: [escaped + "%"] };
12539
12548
  }
12540
12549
  if (endsWithAnchor) {
12541
- const prefix = caseInsensitive ? escaped.toLowerCase() : escaped;
12542
- if (caseInsensitive && hasLowerIndex) {
12543
- return { sql: `LOWER(${field}) LIKE ? ESCAPE '\\'`, args: ["%" + prefix] };
12550
+ if (caseInsensitive) {
12551
+ return { sql: `LOWER(${field}) LIKE LOWER(?) ESCAPE '\\'`, args: ["%" + escaped] };
12544
12552
  }
12545
- return { sql: `${field} LIKE ?${caseInsensitive ? " COLLATE NOCASE" : ""} ESCAPE '\\'`, args: ["%" + prefix] };
12553
+ return { sql: `${field} LIKE ? ESCAPE '\\'`, args: ["%" + escaped] };
12546
12554
  }
12547
- const middle = caseInsensitive ? escaped.toLowerCase() : escaped;
12548
- if (caseInsensitive && hasLowerIndex) {
12549
- return { sql: `LOWER(${field}) LIKE ? ESCAPE '\\'`, args: ["%" + middle + "%"] };
12555
+ if (caseInsensitive) {
12556
+ return { sql: `LOWER(${field}) LIKE LOWER(?) ESCAPE '\\'`, args: ["%" + escaped + "%"] };
12550
12557
  }
12551
- return { sql: `${field} LIKE ?${caseInsensitive ? " COLLATE NOCASE" : ""} ESCAPE '\\'`, args: ["%" + middle + "%"] };
12558
+ return { sql: `${field} LIKE ? ESCAPE '\\'`, args: ["%" + escaped + "%"] };
12552
12559
  }
12553
12560
 
12554
12561
  // src/query/operators.ts
12562
+ function buildJsonPath(fieldName) {
12563
+ const segments = fieldName.split(".");
12564
+ let path2 = "$";
12565
+ for (const segment of segments) {
12566
+ if (/^\d+$/.test(segment)) {
12567
+ path2 += `[${segment}]`;
12568
+ } else {
12569
+ path2 += `.${segment}`;
12570
+ }
12571
+ }
12572
+ return path2;
12573
+ }
12555
12574
  function normalizeValueForSQLite(value) {
12556
12575
  if (value instanceof Date) {
12557
12576
  return value.toISOString();
@@ -12715,6 +12734,18 @@ function translateExists(field, exists) {
12715
12734
  };
12716
12735
  }
12717
12736
  function translateRegex(field, pattern, options, schema, fieldName) {
12737
+ const columnInfo = getColumnInfo(fieldName, schema);
12738
+ const isArray = field !== "value" && columnInfo.type === "array";
12739
+ if (isArray) {
12740
+ const smartResult2 = smartRegexToLike("value", pattern, options, schema, fieldName);
12741
+ if (smartResult2) {
12742
+ return {
12743
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE ${smartResult2.sql})`,
12744
+ args: smartResult2.args
12745
+ };
12746
+ }
12747
+ return null;
12748
+ }
12718
12749
  const smartResult = smartRegexToLike(field, pattern, options, schema, fieldName);
12719
12750
  if (smartResult)
12720
12751
  return smartResult;
@@ -12757,7 +12788,7 @@ function handleLogicalOperator(operator, value, schema, baseFieldName) {
12757
12788
  };
12758
12789
  }
12759
12790
  function handleFieldCondition(fieldName, value, schema, baseFieldName) {
12760
- const propertyField = `json_extract(value, '$.${fieldName}')`;
12791
+ const propertyField = `json_extract(value, '${buildJsonPath(fieldName)}')`;
12761
12792
  const nestedFieldName = `${baseFieldName}.${fieldName}`;
12762
12793
  if (typeof value === "object" && value !== null && !Array.isArray(value)) {
12763
12794
  if (value instanceof RegExp) {
@@ -12831,17 +12862,14 @@ function translateElemMatch(field, criteria, schema, actualFieldName) {
12831
12862
  if (typeof criteria === "object" && criteria !== null && !Array.isArray(criteria) && Object.keys(criteria).length === 0) {
12832
12863
  return { sql: "1=0", args: [] };
12833
12864
  }
12834
- if (typeof criteria !== "object" || criteria === null) {
12835
- return {
12836
- sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value = ?)`,
12837
- args: [criteria]
12838
- };
12865
+ if (typeof criteria !== "object" || criteria === null || Array.isArray(criteria)) {
12866
+ return null;
12839
12867
  }
12840
12868
  if (criteria.$and && Array.isArray(criteria.$and)) {
12841
12869
  const fragments = criteria.$and.map((cond) => buildElemMatchConditions(cond, schema, actualFieldName));
12842
12870
  if (fragments.some((f) => f === null))
12843
12871
  return null;
12844
- const sql = fragments.map((f) => f.sql).join(" AND ");
12872
+ const sql = fragments.map((f) => `COALESCE((${f.sql}), 0)`).join(" AND ");
12845
12873
  const args = fragments.flatMap((f) => f.args);
12846
12874
  return {
12847
12875
  sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE ${sql})`,
@@ -12852,7 +12880,7 @@ function translateElemMatch(field, criteria, schema, actualFieldName) {
12852
12880
  const fragments = criteria.$or.map((cond) => buildElemMatchConditions(cond, schema, actualFieldName));
12853
12881
  if (fragments.some((f) => f === null))
12854
12882
  return null;
12855
- const sql = fragments.map((f) => f.sql).join(" OR ");
12883
+ const sql = fragments.map((f) => `COALESCE((${f.sql}), 0)`).join(" OR ");
12856
12884
  const args = fragments.flatMap((f) => f.args);
12857
12885
  return {
12858
12886
  sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE ${sql})`,
@@ -12863,7 +12891,7 @@ function translateElemMatch(field, criteria, schema, actualFieldName) {
12863
12891
  const fragments = criteria.$nor.map((cond) => buildElemMatchConditions(cond, schema, actualFieldName));
12864
12892
  if (fragments.some((f) => f === null))
12865
12893
  return null;
12866
- const sql = fragments.map((f) => f.sql).join(" OR ");
12894
+ const sql = fragments.map((f) => `COALESCE((${f.sql}), 0)`).join(" OR ");
12867
12895
  const args = fragments.flatMap((f) => f.args);
12868
12896
  return {
12869
12897
  sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE NOT (${sql}))`,
@@ -12874,7 +12902,7 @@ function translateElemMatch(field, criteria, schema, actualFieldName) {
12874
12902
  if (!fragment)
12875
12903
  return null;
12876
12904
  return {
12877
- sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE ${fragment.sql})`,
12905
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE ${asBoolean(fragment.sql)})`,
12878
12906
  args: fragment.args
12879
12907
  };
12880
12908
  }
@@ -12898,8 +12926,21 @@ function translateLeafOperator(op, field, value, schema, actualFieldName) {
12898
12926
  return translateNin(field, value, schema, actualFieldName);
12899
12927
  case "$exists":
12900
12928
  return translateExists(field, value);
12901
- case "$size":
12902
- return translateSize(field, value);
12929
+ case "$size": {
12930
+ const columnInfo = getColumnInfo(actualFieldName, schema);
12931
+ if (columnInfo.type !== "array" && columnInfo.type !== "unknown") {
12932
+ return { sql: "1=0", args: [] };
12933
+ }
12934
+ let jsonColumn = "data";
12935
+ let jsonPath = actualFieldName;
12936
+ let isDirectPath = false;
12937
+ if (field === "value") {
12938
+ jsonColumn = "value";
12939
+ jsonPath = "";
12940
+ isDirectPath = true;
12941
+ }
12942
+ return translateSize(jsonColumn, jsonPath, value, isDirectPath);
12943
+ }
12903
12944
  case "$mod": {
12904
12945
  const result = translateMod(field, value);
12905
12946
  if (!result)
@@ -12965,9 +13006,12 @@ function translateLeafOperator(op, field, value, schema, actualFieldName) {
12965
13006
  return translateEq(field, value, schema, actualFieldName);
12966
13007
  }
12967
13008
  }
13009
+ function asBoolean(sql) {
13010
+ return `COALESCE((${sql}), 0)`;
13011
+ }
12968
13012
  function wrapWithNot(innerFragment) {
12969
13013
  return {
12970
- sql: `NOT (${innerFragment.sql})`,
13014
+ sql: `NOT (${asBoolean(innerFragment.sql)})`,
12971
13015
  args: innerFragment.args
12972
13016
  };
12973
13017
  }
@@ -12977,22 +13021,28 @@ function translateType(jsonColumn, fieldName, type6, isDirectPath = false) {
12977
13021
  case "null":
12978
13022
  return { sql: `json_type(${jsonColumn}, '${jsonPath}') = 'null'`, args: [] };
12979
13023
  case "boolean":
13024
+ case "bool":
12980
13025
  return { sql: `json_type(${jsonColumn}, '${jsonPath}') IN ('true', 'false')`, args: [] };
12981
13026
  case "number":
13027
+ case "int":
13028
+ case "long":
13029
+ case "double":
13030
+ case "decimal":
12982
13031
  return { sql: `json_type(${jsonColumn}, '${jsonPath}') IN ('integer', 'real')`, args: [] };
12983
13032
  case "string":
12984
- return { sql: `json_type(${jsonColumn}, '${jsonPath}') = 'text'`, args: [] };
13033
+ return { sql: `COALESCE(json_type(${jsonColumn}, '${jsonPath}') = 'text', 0)`, args: [] };
12985
13034
  case "array":
12986
13035
  return { sql: `json_type(${jsonColumn}, '${jsonPath}') = 'array'`, args: [] };
12987
13036
  case "object":
12988
13037
  return { sql: `json_type(${jsonColumn}, '${jsonPath}') = 'object'`, args: [] };
12989
13038
  default:
12990
- return { sql: "1=0", args: [] };
13039
+ return null;
12991
13040
  }
12992
13041
  }
12993
- function translateSize(field, size) {
13042
+ function translateSize(jsonColumn, jsonPath, size, isDirectPath = false) {
13043
+ const path2 = isDirectPath ? jsonPath : `$.${jsonPath}`;
12994
13044
  return {
12995
- sql: `json_array_length(${field}) = ?`,
13045
+ sql: `json_array_length(${jsonColumn}, '${path2}') = ?`,
12996
13046
  args: [size]
12997
13047
  };
12998
13048
  }
@@ -13116,7 +13166,7 @@ function buildWhereClause(selector, schema, collectionName, cache) {
13116
13166
  if (!selector || typeof selector !== "object")
13117
13167
  return null;
13118
13168
  const actualCache = cache ?? getGlobalCache();
13119
- const cacheKey = `v${schema.version}_${stableStringify(selector)}`;
13169
+ const cacheKey = `v3_${schema.version}_${stableStringify(selector)}`;
13120
13170
  const cached = actualCache.get(cacheKey);
13121
13171
  if (cached !== undefined) {
13122
13172
  return cached;
@@ -13153,6 +13203,9 @@ function splitSelector(selector, schema) {
13153
13203
  const jsSelector = jsConditions.length > 0 ? jsConditions.length === 1 ? jsConditions[0] : { $and: jsConditions } : null;
13154
13204
  return { sqlWhere, jsSelector };
13155
13205
  }
13206
+ function coerceToBoolean(sql) {
13207
+ return `COALESCE((${sql}), 0)`;
13208
+ }
13156
13209
  function buildLogicalOperator(operator, conditions, schema, logicalDepth) {
13157
13210
  if (conditions.length === 0) {
13158
13211
  return { sql: operator === "or" ? "1=0" : "1=1", args: [] };
@@ -13160,9 +13213,12 @@ function buildLogicalOperator(operator, conditions, schema, logicalDepth) {
13160
13213
  const fragments = conditions.map((subSelector) => processSelector(subSelector, schema, logicalDepth + 1));
13161
13214
  if (fragments.some((f) => f === null))
13162
13215
  return null;
13163
- const sql = fragments.map((f) => `(${f.sql})`).join(" OR ");
13216
+ const sql = fragments.map((f) => f.sql).join(operator === "and" ? " AND " : " OR ");
13164
13217
  const args = fragments.flatMap((f) => f.args);
13165
- return operator === "nor" ? { sql: `NOT(${sql})`, args } : { sql, args };
13218
+ if (operator === "nor") {
13219
+ return { sql: `NOT(${coerceToBoolean(sql)})`, args };
13220
+ }
13221
+ return { sql, args };
13166
13222
  }
13167
13223
  function processSelector(selector, schema, logicalDepth) {
13168
13224
  if (!selector || typeof selector !== "object")
@@ -13206,7 +13262,7 @@ function processSelector(selector, schema, logicalDepth) {
13206
13262
  continue;
13207
13263
  }
13208
13264
  const columnInfo = getColumnInfo(field, schema);
13209
- const fieldName = columnInfo.column || `json_extract(data, '${columnInfo.jsonPath}')`;
13265
+ const fieldName = columnInfo.column || `json_extract(data, '${buildJsonPath(field)}')`;
13210
13266
  const actualFieldName = columnInfo.jsonPath?.replace(/^\$\./, "") || columnInfo.column || field;
13211
13267
  if (typeof value === "object" && value !== null && !Array.isArray(value)) {
13212
13268
  if (Object.keys(value).length === 0) {
@@ -13217,15 +13273,15 @@ function processSelector(selector, schema, logicalDepth) {
13217
13273
  let fragment;
13218
13274
  if (op === "$not") {
13219
13275
  if (typeof opValue !== "object" || opValue === null || Array.isArray(opValue)) {
13220
- const eqFrag = translateLeafOperator("$eq", fieldName, opValue, schema, actualFieldName);
13221
- if (!eqFrag)
13276
+ const neFrag = translateLeafOperator("$ne", fieldName, opValue, schema, actualFieldName);
13277
+ if (!neFrag)
13222
13278
  return null;
13223
- fragment = wrapWithNot(eqFrag);
13279
+ fragment = neFrag;
13224
13280
  } else if (opValue instanceof Date) {
13225
- const eqFrag = translateLeafOperator("$eq", fieldName, opValue, schema, actualFieldName);
13226
- if (!eqFrag)
13281
+ const neFrag = translateLeafOperator("$ne", fieldName, opValue, schema, actualFieldName);
13282
+ if (!neFrag)
13227
13283
  return null;
13228
- fragment = wrapWithNot(eqFrag);
13284
+ fragment = neFrag;
13229
13285
  } else if (opValue instanceof RegExp) {
13230
13286
  const regexFrag = translateLeafOperator("$regex", fieldName, opValue, schema, actualFieldName);
13231
13287
  if (!regexFrag)
@@ -13266,16 +13322,23 @@ function processSelector(selector, schema, logicalDepth) {
13266
13322
  } else {
13267
13323
  const hasOperators = innerKeys.some((k) => k.startsWith("$"));
13268
13324
  if (!hasOperators) {
13269
- const eqFrag = translateLeafOperator("$eq", fieldName, opValueObj, schema, actualFieldName);
13270
- if (!eqFrag)
13325
+ const neFrag = translateLeafOperator("$ne", fieldName, opValueObj, schema, actualFieldName);
13326
+ if (!neFrag)
13271
13327
  return null;
13272
- fragment = wrapWithNot(eqFrag);
13328
+ fragment = neFrag;
13273
13329
  } else {
13274
13330
  const [[innerOp, innerVal]] = Object.entries(opValueObj);
13275
- const innerFrag = translateLeafOperator(innerOp, fieldName, innerVal, schema, actualFieldName);
13276
- if (!innerFrag)
13277
- return null;
13278
- fragment = wrapWithNot(innerFrag);
13331
+ if (innerOp === "$eq") {
13332
+ const neFrag = translateLeafOperator("$ne", fieldName, innerVal, schema, actualFieldName);
13333
+ if (!neFrag)
13334
+ return null;
13335
+ fragment = neFrag;
13336
+ } else {
13337
+ const innerFrag = translateLeafOperator(innerOp, fieldName, innerVal, schema, actualFieldName);
13338
+ if (!innerFrag)
13339
+ return null;
13340
+ fragment = wrapWithNot(innerFrag);
13341
+ }
13279
13342
  }
13280
13343
  }
13281
13344
  }
@@ -13300,7 +13363,7 @@ function processSelector(selector, schema, logicalDepth) {
13300
13363
  } else if (op === "$options") {
13301
13364
  continue;
13302
13365
  } else if (!op.startsWith("$")) {
13303
- const jsonPath = `json_extract(${fieldName}, '$.${op}')`;
13366
+ const jsonPath = `json_extract(${fieldName}, '${buildJsonPath(op)}')`;
13304
13367
  const nestedFieldName = `${actualFieldName}.${op}`;
13305
13368
  const leafFrag = translateLeafOperator("$eq", jsonPath, opValue, schema, nestedFieldName);
13306
13369
  if (!leafFrag)
@@ -13811,6 +13874,7 @@ class BunSQLiteStorageInstance {
13811
13874
  this.initTable(filename);
13812
13875
  }
13813
13876
  initTable(filename) {
13877
+ this.db.run("PRAGMA case_sensitive_like = ON");
13814
13878
  if (filename !== ":memory:") {
13815
13879
  this.db.run("PRAGMA journal_mode = WAL");
13816
13880
  this.db.run("PRAGMA synchronous = NORMAL");
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=debug-array-index.d.ts.map
@@ -8,6 +8,7 @@ type OperatorExpression = {
8
8
  [key: string]: unknown;
9
9
  };
10
10
  export type ElemMatchCriteria = QueryValue | OperatorExpression;
11
+ export declare function buildJsonPath(fieldName: string): string;
11
12
  export declare function translateEq<RxDocType>(field: string, value: unknown, schema?: RxJsonSchema<RxDocumentData<RxDocType>>, actualFieldName?: string): SqlFragment;
12
13
  export declare function translateNe<RxDocType>(field: string, value: unknown, schema?: RxJsonSchema<RxDocumentData<RxDocType>>, actualFieldName?: string): SqlFragment;
13
14
  export declare function translateGt<RxDocType>(field: string, value: unknown, schema?: RxJsonSchema<RxDocumentData<RxDocType>>, actualFieldName?: string): SqlFragment;
@@ -22,7 +23,7 @@ export declare function translateElemMatch<RxDocType>(field: string, criteria: E
22
23
  export declare function translateLeafOperator<RxDocType>(op: string, field: string, value: unknown, schema: RxJsonSchema<RxDocumentData<RxDocType>>, actualFieldName: string): SqlFragment | null;
23
24
  export declare function wrapWithNot(innerFragment: SqlFragment): SqlFragment;
24
25
  export declare function translateType(jsonColumn: string, fieldName: string, type: string, isDirectPath?: boolean): SqlFragment | null;
25
- export declare function translateSize(field: string, size: number): SqlFragment;
26
+ export declare function translateSize(jsonColumn: string, jsonPath: string, size: number, isDirectPath?: boolean): SqlFragment;
26
27
  export declare function translateMod(field: string, value: unknown): SqlFragment | null;
27
28
  export {};
28
29
  //# sourceMappingURL=operators.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bun-sqlite-for-rxdb",
3
- "version": "1.5.4",
3
+ "version": "1.5.7",
4
4
  "author": "adam2am",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,6 +14,7 @@
14
14
  "main": "dist/index.js",
15
15
  "dependencies": {},
16
16
  "devDependencies": {
17
+ "@msgpack/msgpack": "^3.1.3",
17
18
  "@types/better-sqlite3": "^7.6.13",
18
19
  "@types/bun": "latest",
19
20
  "better-sqlite3": "^12.6.2",