bun-sqlite-for-rxdb 1.4.0 → 1.5.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
@@ -4,33 +4,29 @@
4
4
 
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
 
7
- ## Features
7
+ RxDB storage adapter that translates Mango queries directly to bun:sqlite (except of $regex), bypassing slow in-memory filtering.
8
8
 
9
- - ✅ Uses Bun's native SQLite
10
- - ✅ **260/260 tests passing** (138 local + 122 official RxDB tests)
11
- - ✅ Full RxDB storage interface implementation
9
+ ## Features
10
+ - ✅ **17 Mango operators** directly using SQL ($eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $or, $and, $exists, $elemMatch, $not, $nor, $type, $size, $mod)
11
+ - ✅ **1 Mango operator optimized in memory** (complex $regex)
12
+ - ✅ **Smart regex** - converts simple patterns to SQL LIKE (uses indexes)
12
13
  - ✅ **Attachments support** (base64 storage with digest validation)
13
- - ✅ **Query builder LRU cache** (5.2-57.9x speedup for repeated queries)
14
- - ✅ **18 Mango operators** ($eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $or, $and, $exists, $regex, $elemMatch, $not, $nor, $type, $size, $mod)
14
+
15
15
  - ✅ **Multi-instance support** with connection pooling
16
- - ✅ **1.06-1.68x faster than better-sqlite3** (with WAL mode)
16
+ - ✅ **Dual LRU caching** - prepared statements + query AST parsing
17
+ - ✅ **Property-based testing** with fast-check (3000+ assertions vs Mingo and Sift.js)
17
18
  - ✅ MIT licensed
18
19
 
19
20
  ## Performance
20
21
 
22
+ ### Database Performance
21
23
  Benchmarked against better-sqlite3 (1M documents, WAL mode + PRAGMA synchronous = 1):
22
24
 
23
25
  | Operation | Bun SQLite | better-sqlite3 | Speedup |
24
26
  |-----------|------------|----------------|---------|
25
27
  | Bulk INSERT (1M docs) | 7.42s | 7.90s | **1.06x faster** |
26
28
  | SELECT by ID (10K lookups) | 170ms | 170ms | Equal |
27
- | Complex WHERE query | 484ms | 814ms | **1.68x faster** |
28
-
29
- **Requirements for optimal performance:**
30
- ```typescript
31
- db.run("PRAGMA journal_mode = WAL");
32
- db.run("PRAGMA synchronous = 1");
33
- ```
29
+ | Complex WHERE query | 484ms | 814ms | **1.68x faster** |
34
30
 
35
31
  ## Installation
36
32
 
@@ -66,14 +62,6 @@ bun test
66
62
  bun run typecheck
67
63
  ```
68
64
 
69
- ## Architecture
70
-
71
- **Key components:**
72
- - `RxStorage` factory
73
- - `RxStorageInstance` implementation (11 required methods)
74
- - Mango query → SQL translator
75
- - Change stream observables
76
-
77
65
  ## License
78
66
 
79
67
  MIT © adam2am
package/dist/index.js CHANGED
@@ -4,25 +4,43 @@ var __getProtoOf = Object.getPrototypeOf;
4
4
  var __defProp = Object.defineProperty;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ function __accessProp(key) {
8
+ return this[key];
9
+ }
10
+ var __toESMCache_node;
11
+ var __toESMCache_esm;
7
12
  var __toESM = (mod, isNodeMode, target) => {
13
+ var canCache = mod != null && typeof mod === "object";
14
+ if (canCache) {
15
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
16
+ var cached = cache.get(mod);
17
+ if (cached)
18
+ return cached;
19
+ }
8
20
  target = mod != null ? __create(__getProtoOf(mod)) : {};
9
21
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
22
  for (let key of __getOwnPropNames(mod))
11
23
  if (!__hasOwnProp.call(to, key))
12
24
  __defProp(to, key, {
13
- get: () => mod[key],
25
+ get: __accessProp.bind(mod, key),
14
26
  enumerable: true
15
27
  });
28
+ if (canCache)
29
+ cache.set(mod, to);
16
30
  return to;
17
31
  };
18
32
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
33
+ var __returnValue = (v) => v;
34
+ function __exportSetter(name, newValue) {
35
+ this[name] = __returnValue.bind(null, newValue);
36
+ }
19
37
  var __export = (target, all) => {
20
38
  for (var name in all)
21
39
  __defProp(target, name, {
22
40
  get: all[name],
23
41
  enumerable: true,
24
42
  configurable: true,
25
- set: (newValue) => all[name] = () => newValue
43
+ set: __exportSetter.bind(all, name)
26
44
  });
27
45
  };
28
46
 
@@ -12213,12 +12231,23 @@ var import_rxjs2 = __toESM(require_cjs(), 1);
12213
12231
  // src/query/regex-matcher.ts
12214
12232
  var REGEX_CACHE = new Map;
12215
12233
  var MAX_REGEX_CACHE_SIZE = 100;
12234
+ function isValidRegexOptions(options) {
12235
+ for (let i = 0;i < options.length; i++) {
12236
+ const c = options[i];
12237
+ if (c !== "i" && c !== "m" && c !== "s" && c !== "x" && c !== "u")
12238
+ return false;
12239
+ }
12240
+ return true;
12241
+ }
12216
12242
  function compileRegex(pattern, options) {
12217
12243
  const cacheKey = `${pattern}::${options || ""}`;
12218
12244
  const cached = REGEX_CACHE.get(cacheKey);
12219
12245
  if (cached) {
12220
12246
  return cached.regex;
12221
12247
  }
12248
+ if (options && !isValidRegexOptions(options)) {
12249
+ throw new Error(`Invalid regex options: "${options}". Valid options are: i, m, s, x, u`);
12250
+ }
12222
12251
  const regex = new RegExp(pattern, options);
12223
12252
  if (REGEX_CACHE.size >= MAX_REGEX_CACHE_SIZE) {
12224
12253
  const firstKey = REGEX_CACHE.keys().next().value;
@@ -12302,6 +12331,14 @@ function hasExpressionIndex(fieldName, schema) {
12302
12331
  INDEX_CACHE.set(cacheKey, hasLowerIndex);
12303
12332
  return hasLowerIndex;
12304
12333
  }
12334
+ function isValidRegexOptions2(options) {
12335
+ for (let i = 0;i < options.length; i++) {
12336
+ const c = options[i];
12337
+ if (c !== "i" && c !== "m" && c !== "s" && c !== "x" && c !== "u")
12338
+ return false;
12339
+ }
12340
+ return true;
12341
+ }
12305
12342
  function isComplexRegex(pattern) {
12306
12343
  return /[*+?()[\]{}|]/.test(pattern.replace(/\\\./g, ""));
12307
12344
  }
@@ -12311,6 +12348,9 @@ function escapeForLike(str) {
12311
12348
  function smartRegexToLike(field, pattern, options, schema, fieldName) {
12312
12349
  if (typeof pattern !== "string")
12313
12350
  return null;
12351
+ if (options && !isValidRegexOptions2(options)) {
12352
+ throw new Error(`Invalid regex options: "${options}". Valid options are: i, m, s, x, u`);
12353
+ }
12314
12354
  const caseInsensitive = options?.includes("i") ?? false;
12315
12355
  const hasLowerIndex = hasExpressionIndex(fieldName, schema);
12316
12356
  const startsWithAnchor = pattern.startsWith("^");
@@ -12349,6 +12389,18 @@ function smartRegexToLike(field, pattern, options, schema, fieldName) {
12349
12389
  }
12350
12390
 
12351
12391
  // src/query/operators.ts
12392
+ function normalizeValueForSQLite(value) {
12393
+ if (value instanceof Date) {
12394
+ return value.toISOString();
12395
+ }
12396
+ if (value instanceof RegExp) {
12397
+ return JSON.stringify({ source: value.source, flags: value.flags });
12398
+ }
12399
+ if (value === undefined) {
12400
+ return null;
12401
+ }
12402
+ return value;
12403
+ }
12352
12404
  function translateEq(field, value, schema, actualFieldName) {
12353
12405
  if (value === null) {
12354
12406
  return { sql: `${field} IS NULL`, args: [] };
@@ -12358,11 +12410,11 @@ function translateEq(field, value, schema, actualFieldName) {
12358
12410
  if (field !== "value" && columnInfo.type === "array") {
12359
12411
  return {
12360
12412
  sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value = ?)`,
12361
- args: [value]
12413
+ args: [normalizeValueForSQLite(value)]
12362
12414
  };
12363
12415
  }
12364
12416
  }
12365
- return { sql: `${field} = ?`, args: [value] };
12417
+ return { sql: `${field} = ?`, args: [normalizeValueForSQLite(value)] };
12366
12418
  }
12367
12419
  function translateNe(field, value, schema, actualFieldName) {
12368
12420
  if (value === null) {
@@ -12373,11 +12425,11 @@ function translateNe(field, value, schema, actualFieldName) {
12373
12425
  if (field !== "value" && columnInfo.type === "array") {
12374
12426
  return {
12375
12427
  sql: `NOT EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value = ?)`,
12376
- args: [value]
12428
+ args: [normalizeValueForSQLite(value)]
12377
12429
  };
12378
12430
  }
12379
12431
  }
12380
- return { sql: `(${field} <> ? OR ${field} IS NULL)`, args: [value] };
12432
+ return { sql: `(${field} <> ? OR ${field} IS NULL)`, args: [normalizeValueForSQLite(value)] };
12381
12433
  }
12382
12434
  function translateGt(field, value, schema, actualFieldName) {
12383
12435
  if (schema && actualFieldName) {
@@ -12385,11 +12437,11 @@ function translateGt(field, value, schema, actualFieldName) {
12385
12437
  if (field !== "value" && columnInfo.type === "array") {
12386
12438
  return {
12387
12439
  sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value > ?)`,
12388
- args: [value]
12440
+ args: [normalizeValueForSQLite(value)]
12389
12441
  };
12390
12442
  }
12391
12443
  }
12392
- return { sql: `${field} > ?`, args: [value] };
12444
+ return { sql: `${field} > ?`, args: [normalizeValueForSQLite(value)] };
12393
12445
  }
12394
12446
  function translateGte(field, value, schema, actualFieldName) {
12395
12447
  if (schema && actualFieldName) {
@@ -12397,11 +12449,11 @@ function translateGte(field, value, schema, actualFieldName) {
12397
12449
  if (field !== "value" && columnInfo.type === "array") {
12398
12450
  return {
12399
12451
  sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value >= ?)`,
12400
- args: [value]
12452
+ args: [normalizeValueForSQLite(value)]
12401
12453
  };
12402
12454
  }
12403
12455
  }
12404
- return { sql: `${field} >= ?`, args: [value] };
12456
+ return { sql: `${field} >= ?`, args: [normalizeValueForSQLite(value)] };
12405
12457
  }
12406
12458
  function translateLt(field, value, schema, actualFieldName) {
12407
12459
  if (schema && actualFieldName) {
@@ -12409,11 +12461,11 @@ function translateLt(field, value, schema, actualFieldName) {
12409
12461
  if (field !== "value" && columnInfo.type === "array") {
12410
12462
  return {
12411
12463
  sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value < ?)`,
12412
- args: [value]
12464
+ args: [normalizeValueForSQLite(value)]
12413
12465
  };
12414
12466
  }
12415
12467
  }
12416
- return { sql: `${field} < ?`, args: [value] };
12468
+ return { sql: `${field} < ?`, args: [normalizeValueForSQLite(value)] };
12417
12469
  }
12418
12470
  function translateLte(field, value, schema, actualFieldName) {
12419
12471
  if (schema && actualFieldName) {
@@ -12421,18 +12473,18 @@ function translateLte(field, value, schema, actualFieldName) {
12421
12473
  if (field !== "value" && columnInfo.type === "array") {
12422
12474
  return {
12423
12475
  sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value <= ?)`,
12424
- args: [value]
12476
+ args: [normalizeValueForSQLite(value)]
12425
12477
  };
12426
12478
  }
12427
12479
  }
12428
- return { sql: `${field} <= ?`, args: [value] };
12480
+ return { sql: `${field} <= ?`, args: [normalizeValueForSQLite(value)] };
12429
12481
  }
12430
12482
  function translateIn(field, values, schema, actualFieldName) {
12431
12483
  if (!Array.isArray(values) || values.length === 0) {
12432
12484
  return { sql: "1=0", args: [] };
12433
12485
  }
12434
12486
  const hasNull = values.includes(null);
12435
- const nonNullValues = values.filter((v) => v !== null);
12487
+ const nonNullValues = values.filter((v) => v !== null).map((v) => normalizeValueForSQLite(v));
12436
12488
  if (nonNullValues.length === 0) {
12437
12489
  return { sql: `${field} IS NULL`, args: [] };
12438
12490
  }
@@ -12465,7 +12517,7 @@ function translateNin(field, values, schema, actualFieldName) {
12465
12517
  return { sql: "1=1", args: [] };
12466
12518
  }
12467
12519
  const hasNull = values.includes(null);
12468
- const nonNullValues = values.filter((v) => v !== null);
12520
+ const nonNullValues = values.filter((v) => v !== null).map((v) => normalizeValueForSQLite(v));
12469
12521
  if (nonNullValues.length === 0) {
12470
12522
  return { sql: `${field} IS NOT NULL`, args: [] };
12471
12523
  }
@@ -12480,7 +12532,7 @@ function translateNin(field, values, schema, actualFieldName) {
12480
12532
  args: args2
12481
12533
  };
12482
12534
  }
12483
- return { sql: ninClause2, args: args2 };
12535
+ return { sql: `(${field} IS NULL OR ${ninClause2})`, args: args2 };
12484
12536
  }
12485
12537
  }
12486
12538
  const ninClause = `${field} NOT IN (SELECT value FROM json_each(?))`;
@@ -12491,7 +12543,7 @@ function translateNin(field, values, schema, actualFieldName) {
12491
12543
  args
12492
12544
  };
12493
12545
  }
12494
- return { sql: ninClause, args };
12546
+ return { sql: `(${field} IS NULL OR ${ninClause})`, args };
12495
12547
  }
12496
12548
  function translateExists(field, exists) {
12497
12549
  return {
@@ -12505,21 +12557,107 @@ function translateRegex(field, pattern, options, schema, fieldName) {
12505
12557
  return smartResult;
12506
12558
  return null;
12507
12559
  }
12560
+ var LOGICAL_OPERATORS = new Set(["$and", "$or", "$nor", "$not"]);
12561
+ var LEAF_OPERATORS = new Set(["$eq", "$ne", "$gt", "$gte", "$lt", "$lte", "$in", "$nin", "$exists", "$regex", "$type", "$size", "$mod", "$elemMatch"]);
12562
+ function isLogicalOperator(key) {
12563
+ return LOGICAL_OPERATORS.has(key);
12564
+ }
12565
+ function isOperatorObject(obj) {
12566
+ let hasKeys = false;
12567
+ for (const k in obj) {
12568
+ hasKeys = true;
12569
+ if (!k.startsWith("$"))
12570
+ return false;
12571
+ }
12572
+ return hasKeys;
12573
+ }
12574
+ function handleLogicalOperator(operator, value, schema, baseFieldName) {
12575
+ if (operator === "$not") {
12576
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
12577
+ const innerFragment = buildElemMatchConditions(value, schema, baseFieldName);
12578
+ if (!innerFragment)
12579
+ return null;
12580
+ return { sql: `NOT (${innerFragment.sql})`, args: innerFragment.args };
12581
+ }
12582
+ return { sql: "1=1", args: [] };
12583
+ }
12584
+ if (!Array.isArray(value))
12585
+ return { sql: "1=0", args: [] };
12586
+ const nestedConditions = value.map((cond) => buildElemMatchConditions(cond, schema, baseFieldName));
12587
+ if (nestedConditions.some((f) => f === null))
12588
+ return null;
12589
+ const joiner = operator === "$and" ? " AND " : operator === "$or" ? " OR " : " AND NOT ";
12590
+ const sql = nestedConditions.map((f) => `(${f.sql})`).join(joiner);
12591
+ return {
12592
+ sql: `(${sql})`,
12593
+ args: nestedConditions.flatMap((f) => f.args)
12594
+ };
12595
+ }
12596
+ function handleFieldCondition(fieldName, value, schema, baseFieldName) {
12597
+ const propertyField = `json_extract(value, '$.${fieldName}')`;
12598
+ const nestedFieldName = `${baseFieldName}.${fieldName}`;
12599
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
12600
+ if (value instanceof RegExp) {
12601
+ return translateLeafOperator("$regex", propertyField, value, schema, nestedFieldName);
12602
+ }
12603
+ if (value instanceof Date) {
12604
+ return translateLeafOperator("$eq", propertyField, value, schema, nestedFieldName);
12605
+ }
12606
+ const valueObj = value;
12607
+ if (Object.keys(valueObj).length === 0) {
12608
+ return { sql: "1=0", args: [] };
12609
+ }
12610
+ if (isOperatorObject(valueObj)) {
12611
+ const fragments2 = [];
12612
+ for (const [op, opValue] of Object.entries(valueObj)) {
12613
+ if (op === "$not") {
12614
+ const innerFragment = handleFieldCondition(fieldName, opValue, schema, baseFieldName);
12615
+ if (!innerFragment)
12616
+ return null;
12617
+ fragments2.push({ sql: `NOT (${innerFragment.sql})`, args: innerFragment.args });
12618
+ } else {
12619
+ const frag = translateLeafOperator(op, propertyField, opValue, schema, nestedFieldName);
12620
+ if (!frag)
12621
+ return null;
12622
+ fragments2.push(frag);
12623
+ }
12624
+ }
12625
+ if (fragments2.some((f) => f === null))
12626
+ return null;
12627
+ return {
12628
+ sql: fragments2.map((f) => f.sql).join(" AND "),
12629
+ args: fragments2.flatMap((f) => f.args)
12630
+ };
12631
+ }
12632
+ const fragments = Object.entries(valueObj).map(([nestedKey, nestedValue]) => {
12633
+ const nestedField = `json_extract(value, '$.${fieldName}.${nestedKey}')`;
12634
+ return translateLeafOperator("$eq", nestedField, nestedValue, schema, `${nestedFieldName}.${nestedKey}`);
12635
+ });
12636
+ if (fragments.some((f) => f === null))
12637
+ return null;
12638
+ return {
12639
+ sql: fragments.map((f) => f.sql).join(" AND "),
12640
+ args: fragments.flatMap((f) => f.args)
12641
+ };
12642
+ }
12643
+ return translateLeafOperator("$eq", propertyField, value, schema, nestedFieldName);
12644
+ }
12508
12645
  function buildElemMatchConditions(criteria, schema, baseFieldName) {
12509
12646
  const conditions = [];
12510
12647
  const args = [];
12511
12648
  for (const [key, value] of Object.entries(criteria)) {
12512
- if (key.startsWith("$")) {
12513
- const fragment = processOperatorValue("value", { [key]: value }, schema, baseFieldName);
12514
- conditions.push(fragment.sql);
12515
- args.push(...fragment.args);
12649
+ let fragment;
12650
+ if (isLogicalOperator(key)) {
12651
+ fragment = handleLogicalOperator(key, value, schema, baseFieldName);
12652
+ } else if (key.startsWith("$")) {
12653
+ fragment = translateLeafOperator(key, "value", value, schema, baseFieldName);
12516
12654
  } else {
12517
- const propertyField = `json_extract(value, '$.${key}')`;
12518
- const nestedFieldName = `${baseFieldName}.${key}`;
12519
- const fragment = processOperatorValue(propertyField, value, schema, nestedFieldName);
12520
- conditions.push(fragment.sql);
12521
- args.push(...fragment.args);
12655
+ fragment = handleFieldCondition(key, value, schema, baseFieldName);
12522
12656
  }
12657
+ if (!fragment)
12658
+ return null;
12659
+ conditions.push(fragment.sql);
12660
+ args.push(...fragment.args);
12523
12661
  }
12524
12662
  return {
12525
12663
  sql: conditions.length > 0 ? conditions.join(" AND ") : "1=1",
@@ -12538,6 +12676,8 @@ function translateElemMatch(field, criteria, schema, actualFieldName) {
12538
12676
  }
12539
12677
  if (criteria.$and && Array.isArray(criteria.$and)) {
12540
12678
  const fragments = criteria.$and.map((cond) => buildElemMatchConditions(cond, schema, actualFieldName));
12679
+ if (fragments.some((f) => f === null))
12680
+ return null;
12541
12681
  const sql = fragments.map((f) => f.sql).join(" AND ");
12542
12682
  const args = fragments.flatMap((f) => f.args);
12543
12683
  return {
@@ -12547,6 +12687,8 @@ function translateElemMatch(field, criteria, schema, actualFieldName) {
12547
12687
  }
12548
12688
  if (criteria.$or && Array.isArray(criteria.$or)) {
12549
12689
  const fragments = criteria.$or.map((cond) => buildElemMatchConditions(cond, schema, actualFieldName));
12690
+ if (fragments.some((f) => f === null))
12691
+ return null;
12550
12692
  const sql = fragments.map((f) => f.sql).join(" OR ");
12551
12693
  const args = fragments.flatMap((f) => f.args);
12552
12694
  return {
@@ -12556,6 +12698,8 @@ function translateElemMatch(field, criteria, schema, actualFieldName) {
12556
12698
  }
12557
12699
  if (criteria.$nor && Array.isArray(criteria.$nor)) {
12558
12700
  const fragments = criteria.$nor.map((cond) => buildElemMatchConditions(cond, schema, actualFieldName));
12701
+ if (fragments.some((f) => f === null))
12702
+ return null;
12559
12703
  const sql = fragments.map((f) => f.sql).join(" OR ");
12560
12704
  const args = fragments.flatMap((f) => f.args);
12561
12705
  return {
@@ -12564,129 +12708,104 @@ function translateElemMatch(field, criteria, schema, actualFieldName) {
12564
12708
  };
12565
12709
  }
12566
12710
  const fragment = buildElemMatchConditions(criteria, schema, actualFieldName);
12711
+ if (!fragment)
12712
+ return null;
12567
12713
  return {
12568
12714
  sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE ${fragment.sql})`,
12569
12715
  args: fragment.args
12570
12716
  };
12571
12717
  }
12572
- function processOperatorValue(field, value, schema, actualFieldName) {
12573
- if (typeof value === "object" && value !== null && !Array.isArray(value)) {
12574
- const [[op, opValue]] = Object.entries(value);
12575
- if (!op.startsWith("$")) {
12576
- const jsonPath = `json_extract(${field}, '$.${op}')`;
12577
- const nestedFieldName = `${actualFieldName}.${op}`;
12578
- return translateEq(jsonPath, opValue, schema, nestedFieldName);
12579
- }
12580
- switch (op) {
12581
- case "$eq":
12582
- return translateEq(field, opValue, schema, actualFieldName);
12583
- case "$ne":
12584
- return translateNe(field, opValue, schema, actualFieldName);
12585
- case "$gt":
12586
- return translateGt(field, opValue, schema, actualFieldName);
12587
- case "$gte":
12588
- return translateGte(field, opValue, schema, actualFieldName);
12589
- case "$lt":
12590
- return translateLt(field, opValue, schema, actualFieldName);
12591
- case "$lte":
12592
- return translateLte(field, opValue, schema, actualFieldName);
12593
- case "$in":
12594
- return translateIn(field, opValue, schema, actualFieldName);
12595
- case "$nin":
12596
- return translateNin(field, opValue, schema, actualFieldName);
12597
- case "$exists":
12598
- return translateExists(field, opValue);
12599
- case "$size":
12600
- return translateSize(field, opValue);
12601
- case "$mod": {
12602
- const result = translateMod(field, opValue);
12603
- if (!result)
12604
- return translateEq(field, opValue, schema, actualFieldName);
12605
- return result;
12718
+ function translateLeafOperator(op, field, value, schema, actualFieldName) {
12719
+ switch (op) {
12720
+ case "$eq":
12721
+ return translateEq(field, value, schema, actualFieldName);
12722
+ case "$ne":
12723
+ return translateNe(field, value, schema, actualFieldName);
12724
+ case "$gt":
12725
+ return translateGt(field, value, schema, actualFieldName);
12726
+ case "$gte":
12727
+ return translateGte(field, value, schema, actualFieldName);
12728
+ case "$lt":
12729
+ return translateLt(field, value, schema, actualFieldName);
12730
+ case "$lte":
12731
+ return translateLte(field, value, schema, actualFieldName);
12732
+ case "$in":
12733
+ return translateIn(field, value, schema, actualFieldName);
12734
+ case "$nin":
12735
+ return translateNin(field, value, schema, actualFieldName);
12736
+ case "$exists":
12737
+ return translateExists(field, value);
12738
+ case "$size":
12739
+ return translateSize(field, value);
12740
+ case "$mod": {
12741
+ const result = translateMod(field, value);
12742
+ if (!result)
12743
+ return translateEq(field, value, schema, actualFieldName);
12744
+ return result;
12745
+ }
12746
+ case "$regex": {
12747
+ let pattern;
12748
+ let options;
12749
+ if (value instanceof RegExp) {
12750
+ pattern = value.source;
12751
+ options = value.flags;
12752
+ } else if (typeof value === "string") {
12753
+ pattern = value;
12754
+ } else if (typeof value === "object" && value !== null) {
12755
+ const regexObj = value;
12756
+ pattern = regexObj.pattern || regexObj.$regex;
12757
+ options = regexObj.$options;
12758
+ } else {
12759
+ return null;
12606
12760
  }
12607
- case "$regex": {
12608
- const options = value.$options;
12609
- const regexFragment = translateRegex(field, opValue, options, schema, actualFieldName);
12610
- return regexFragment || { sql: "1=0", args: [] };
12611
- }
12612
- case "$type": {
12613
- let jsonCol = "data";
12614
- let path2 = `$.${actualFieldName}`;
12615
- let useDirectType = false;
12616
- if (field === "value") {
12617
- jsonCol = "value";
12618
- path2 = "";
12619
- useDirectType = true;
12620
- } else if (field.startsWith("json_extract(")) {
12621
- const match = field.match(/json_extract\(([^,]+),\s*'([^']+)'\)/);
12622
- if (match) {
12623
- jsonCol = match[1];
12624
- path2 = match[2];
12625
- }
12761
+ return translateRegex(field, pattern, options, schema, actualFieldName);
12762
+ }
12763
+ case "$type": {
12764
+ let jsonCol = "data";
12765
+ let path2 = `$.${actualFieldName}`;
12766
+ let useDirectType = false;
12767
+ if (field === "value") {
12768
+ jsonCol = "value";
12769
+ path2 = "";
12770
+ useDirectType = true;
12771
+ } else if (field.startsWith("json_extract(")) {
12772
+ const match = field.match(/json_extract\(([^,]+),\s*'([^']+)'\)/);
12773
+ if (match && match[1] && match[2]) {
12774
+ jsonCol = match[1];
12775
+ path2 = match[2];
12776
+ }
12777
+ }
12778
+ if (useDirectType) {
12779
+ const typeMap = {
12780
+ null: "null",
12781
+ boolean: "true",
12782
+ number: "integer",
12783
+ string: "text",
12784
+ array: "array",
12785
+ object: "object"
12786
+ };
12787
+ const sqlType = typeMap[value];
12788
+ if (!sqlType)
12789
+ return { sql: "1=0", args: [] };
12790
+ if (value === "boolean") {
12791
+ return { sql: `(type IN ('true', 'false'))`, args: [] };
12626
12792
  }
12627
- if (useDirectType) {
12628
- const typeMap = {
12629
- null: "null",
12630
- boolean: "true",
12631
- number: "integer",
12632
- string: "text",
12633
- array: "array",
12634
- object: "object"
12635
- };
12636
- const sqlType = typeMap[opValue];
12637
- if (!sqlType)
12638
- return { sql: "1=0", args: [] };
12639
- if (opValue === "boolean") {
12640
- return { sql: `(type IN ('true', 'false'))`, args: [] };
12641
- }
12642
- if (opValue === "number") {
12643
- return { sql: `(type IN ('integer', 'real'))`, args: [] };
12644
- }
12645
- return { sql: `type = '${sqlType}'`, args: [] };
12793
+ if (value === "number") {
12794
+ return { sql: `(type IN ('integer', 'real'))`, args: [] };
12646
12795
  }
12647
- const typeFragment = translateType(jsonCol, path2, opValue, true);
12648
- return typeFragment || { sql: "1=0", args: [] };
12649
- }
12650
- case "$elemMatch": {
12651
- const elemMatchFragment = translateElemMatch(field, opValue, schema, actualFieldName);
12652
- return elemMatchFragment || { sql: "1=0", args: [] };
12653
- }
12654
- case "$not": {
12655
- const result = translateNot(field, opValue, schema, actualFieldName);
12656
- if (!result)
12657
- return translateEq(field, opValue, schema, actualFieldName);
12658
- return result;
12796
+ return { sql: `type = '${sqlType}'`, args: [] };
12659
12797
  }
12660
- case "$and": {
12661
- if (!Array.isArray(opValue))
12662
- return translateEq(field, opValue, schema, actualFieldName);
12663
- const fragments = opValue.map((v) => processOperatorValue(field, v, schema, actualFieldName));
12664
- const sql = fragments.map((f) => f.sql).join(" AND ");
12665
- const args = fragments.flatMap((f) => f.args);
12666
- return { sql: `(${sql})`, args };
12667
- }
12668
- case "$or": {
12669
- if (!Array.isArray(opValue))
12670
- return translateEq(field, opValue, schema, actualFieldName);
12671
- const fragments = opValue.map((v) => processOperatorValue(field, v, schema, actualFieldName));
12672
- const sql = fragments.map((f) => f.sql).join(" OR ");
12673
- const args = fragments.flatMap((f) => f.args);
12674
- return { sql: `(${sql})`, args };
12675
- }
12676
- default:
12677
- return translateEq(field, opValue, schema, actualFieldName);
12798
+ const typeFragment = translateType(jsonCol, path2, value, true);
12799
+ return typeFragment || { sql: "1=0", args: [] };
12678
12800
  }
12801
+ default:
12802
+ return translateEq(field, value, schema, actualFieldName);
12679
12803
  }
12680
- return translateEq(field, value, schema, actualFieldName);
12681
12804
  }
12682
- function translateNot(field, criteria, schema, actualFieldName) {
12683
- if (criteria === undefined || criteria === null || typeof criteria !== "object" || Array.isArray(criteria) || Object.keys(criteria).length === 0) {
12684
- return { sql: "1=0", args: [] };
12685
- }
12686
- const inner = processOperatorValue(field, criteria, schema, actualFieldName);
12805
+ function wrapWithNot(innerFragment) {
12687
12806
  return {
12688
- sql: `NOT (${inner.sql})`,
12689
- args: inner.args
12807
+ sql: `NOT (${innerFragment.sql})`,
12808
+ args: innerFragment.args
12690
12809
  };
12691
12810
  }
12692
12811
  function translateType(jsonColumn, fieldName, type6, isDirectPath = false) {
@@ -12800,6 +12919,14 @@ function _stringify(value, stack) {
12800
12919
  }
12801
12920
  const objType = Object.prototype.toString.call(obj);
12802
12921
  if (objType !== "[object Object]") {
12922
+ if (obj instanceof RegExp) {
12923
+ stack.pop();
12924
+ return `{"$regex":${strEscape(obj.source)},"$options":${strEscape(obj.flags)}}`;
12925
+ }
12926
+ if (obj instanceof Date) {
12927
+ stack.pop();
12928
+ return strEscape(obj.toISOString());
12929
+ }
12803
12930
  const result = JSON.stringify(obj);
12804
12931
  stack.pop();
12805
12932
  return result;
@@ -12822,27 +12949,27 @@ function _stringify(value, stack) {
12822
12949
  }
12823
12950
 
12824
12951
  // src/query/builder.ts
12825
- var QUERY_CACHE = new Map;
12826
12952
  var MAX_CACHE_SIZE = 1000;
12827
- function buildWhereClause(selector, schema, collectionName) {
12953
+ var GLOBAL_CACHE = new Map;
12954
+ function buildWhereClause(selector, schema, collectionName, cache = GLOBAL_CACHE) {
12828
12955
  if (!selector || typeof selector !== "object")
12829
12956
  return null;
12830
12957
  const cacheKey = `v${schema.version}_${collectionName}_${stableStringify(selector)}`;
12831
- const cached = QUERY_CACHE.get(cacheKey);
12832
- if (cached) {
12833
- QUERY_CACHE.delete(cacheKey);
12834
- QUERY_CACHE.set(cacheKey, cached);
12958
+ const cached = cache.get(cacheKey);
12959
+ if (cached !== undefined) {
12960
+ cache.delete(cacheKey);
12961
+ cache.set(cacheKey, cached);
12835
12962
  return cached;
12836
12963
  }
12837
12964
  const result = processSelector(selector, schema, 0);
12838
12965
  if (!result)
12839
12966
  return null;
12840
- if (QUERY_CACHE.size >= MAX_CACHE_SIZE) {
12841
- const firstKey = QUERY_CACHE.keys().next().value;
12967
+ if (cache.size >= MAX_CACHE_SIZE) {
12968
+ const firstKey = cache.keys().next().value;
12842
12969
  if (firstKey)
12843
- QUERY_CACHE.delete(firstKey);
12970
+ cache.delete(firstKey);
12844
12971
  }
12845
- QUERY_CACHE.set(cacheKey, result);
12972
+ cache.set(cacheKey, result);
12846
12973
  return result;
12847
12974
  }
12848
12975
  function buildLogicalOperator(operator, conditions, schema, logicalDepth) {
@@ -12896,80 +13023,124 @@ function processSelector(selector, schema, logicalDepth) {
12896
13023
  if (Object.keys(value).length === 0) {
12897
13024
  return { sql: "1=0", args: [] };
12898
13025
  }
13026
+ const fieldFragments = [];
12899
13027
  for (const [op, opValue] of Object.entries(value)) {
12900
13028
  let fragment;
12901
- switch (op) {
12902
- case "$eq":
12903
- fragment = translateEq(fieldName, opValue, schema, actualFieldName);
12904
- break;
12905
- case "$ne":
12906
- fragment = translateNe(fieldName, opValue, schema, actualFieldName);
12907
- break;
12908
- case "$gt":
12909
- fragment = translateGt(fieldName, opValue, schema, actualFieldName);
12910
- break;
12911
- case "$gte":
12912
- fragment = translateGte(fieldName, opValue, schema, actualFieldName);
12913
- break;
12914
- case "$lt":
12915
- fragment = translateLt(fieldName, opValue, schema, actualFieldName);
12916
- break;
12917
- case "$lte":
12918
- fragment = translateLte(fieldName, opValue, schema, actualFieldName);
12919
- break;
12920
- case "$in":
12921
- fragment = translateIn(fieldName, opValue, schema, actualFieldName);
12922
- break;
12923
- case "$nin":
12924
- fragment = translateNin(fieldName, opValue, schema, actualFieldName);
12925
- break;
12926
- case "$exists":
12927
- fragment = translateExists(fieldName, opValue);
12928
- break;
12929
- case "$regex":
12930
- const options = value.$options;
12931
- const regexFragment = translateRegex(fieldName, opValue, options, schema, actualFieldName);
12932
- if (!regexFragment)
13029
+ if (op === "$not") {
13030
+ if (typeof opValue !== "object" || opValue === null || Array.isArray(opValue)) {
13031
+ const eqFrag = translateLeafOperator("$eq", fieldName, opValue, schema, actualFieldName);
13032
+ if (!eqFrag)
12933
13033
  return null;
12934
- fragment = regexFragment;
12935
- break;
12936
- case "$elemMatch":
12937
- const elemMatchFragment = translateElemMatch(fieldName, opValue, schema, actualFieldName);
12938
- if (!elemMatchFragment)
13034
+ fragment = wrapWithNot(eqFrag);
13035
+ } else if (opValue instanceof Date) {
13036
+ const eqFrag = translateLeafOperator("$eq", fieldName, opValue, schema, actualFieldName);
13037
+ if (!eqFrag)
12939
13038
  return null;
12940
- fragment = elemMatchFragment;
12941
- break;
12942
- case "$not": {
12943
- const notResult = translateNot(fieldName, opValue, schema, actualFieldName);
12944
- if (!notResult)
13039
+ fragment = wrapWithNot(eqFrag);
13040
+ } else if (opValue instanceof RegExp) {
13041
+ const regexFrag = translateLeafOperator("$regex", fieldName, opValue, schema, actualFieldName);
13042
+ if (!regexFrag)
12945
13043
  return null;
12946
- fragment = notResult;
12947
- break;
13044
+ fragment = wrapWithNot(regexFrag);
13045
+ } else {
13046
+ const opValueObj = opValue;
13047
+ const innerKeys = Object.keys(opValueObj);
13048
+ if (innerKeys.length === 0) {
13049
+ fragment = { sql: "1=0", args: [] };
13050
+ } else if (innerKeys.some((k) => k === "$and" || k === "$or" || k === "$nor")) {
13051
+ let recursivelyWrapLeafOperators = function(items2, field2) {
13052
+ return items2.map((item) => {
13053
+ const keys = Object.keys(item);
13054
+ if (keys.some((k) => !k.startsWith("$")))
13055
+ return item;
13056
+ if (keys.length === 1 && LOGICAL_OPS.has(keys[0])) {
13057
+ const logicalOp2 = keys[0];
13058
+ return { [logicalOp2]: recursivelyWrapLeafOperators(item[logicalOp2], field2) };
13059
+ }
13060
+ return { [field2]: item };
13061
+ });
13062
+ };
13063
+ const logicalOp = innerKeys[0];
13064
+ const nestedSelector = opValueObj;
13065
+ const items = nestedSelector[logicalOp];
13066
+ const LOGICAL_OPS = new Set(["$and", "$or", "$nor"]);
13067
+ const wrappedItems = recursivelyWrapLeafOperators(items, field);
13068
+ const innerFragment = processSelector({ [logicalOp]: wrappedItems }, schema, logicalDepth + 1);
13069
+ if (!innerFragment)
13070
+ return null;
13071
+ fragment = wrapWithNot(innerFragment);
13072
+ } else if (innerKeys.length === 1 && innerKeys[0] === "$elemMatch") {
13073
+ const elemMatchFragment = translateElemMatch(fieldName, opValueObj.$elemMatch, schema, actualFieldName);
13074
+ if (!elemMatchFragment)
13075
+ return null;
13076
+ fragment = wrapWithNot(elemMatchFragment);
13077
+ } else {
13078
+ const hasOperators = innerKeys.some((k) => k.startsWith("$"));
13079
+ if (!hasOperators) {
13080
+ const eqFrag = translateLeafOperator("$eq", fieldName, opValueObj, schema, actualFieldName);
13081
+ if (!eqFrag)
13082
+ return null;
13083
+ fragment = wrapWithNot(eqFrag);
13084
+ } else {
13085
+ const [[innerOp, innerVal]] = Object.entries(opValueObj);
13086
+ const innerFrag = translateLeafOperator(innerOp, fieldName, innerVal, schema, actualFieldName);
13087
+ if (!innerFrag)
13088
+ return null;
13089
+ fragment = wrapWithNot(innerFrag);
13090
+ }
13091
+ }
12948
13092
  }
12949
- case "$type":
12950
- const typeFragment = translateType("data", actualFieldName, opValue);
12951
- if (!typeFragment)
12952
- return null;
12953
- fragment = typeFragment;
12954
- break;
12955
- case "$size":
12956
- fragment = translateSize(fieldName, opValue);
12957
- break;
12958
- case "$mod": {
12959
- const modResult = translateMod(fieldName, opValue);
12960
- if (!modResult)
12961
- return null;
12962
- fragment = modResult;
12963
- break;
13093
+ } else if (op === "$elemMatch") {
13094
+ const elemMatchFragment = translateElemMatch(fieldName, opValue, schema, actualFieldName);
13095
+ if (!elemMatchFragment)
13096
+ return null;
13097
+ fragment = elemMatchFragment;
13098
+ } else if (op === "$regex") {
13099
+ const regexValue = opValue;
13100
+ const optionsValue = value.$options;
13101
+ let combinedValue;
13102
+ if (typeof regexValue === "string" && optionsValue) {
13103
+ combinedValue = { $regex: regexValue, $options: optionsValue };
13104
+ } else {
13105
+ combinedValue = regexValue;
12964
13106
  }
12965
- default:
12966
- continue;
13107
+ const leafFrag = translateLeafOperator("$regex", fieldName, combinedValue, schema, actualFieldName);
13108
+ if (!leafFrag)
13109
+ return null;
13110
+ fragment = leafFrag;
13111
+ } else if (op === "$options") {
13112
+ continue;
13113
+ } else if (!op.startsWith("$")) {
13114
+ const jsonPath = `json_extract(${fieldName}, '$.${op}')`;
13115
+ const nestedFieldName = `${actualFieldName}.${op}`;
13116
+ const leafFrag = translateLeafOperator("$eq", jsonPath, opValue, schema, nestedFieldName);
13117
+ if (!leafFrag)
13118
+ return null;
13119
+ fragment = leafFrag;
13120
+ } else {
13121
+ const leafFrag = translateLeafOperator(op, fieldName, opValue, schema, actualFieldName);
13122
+ if (!leafFrag)
13123
+ return null;
13124
+ fragment = leafFrag;
13125
+ }
13126
+ if (fieldFragments.length > 0) {
13127
+ const prev = fieldFragments.pop();
13128
+ fieldFragments.push({
13129
+ sql: `(${prev.sql} AND ${fragment.sql})`,
13130
+ args: [...prev.args, ...fragment.args]
13131
+ });
13132
+ } else {
13133
+ fieldFragments.push(fragment);
12967
13134
  }
12968
- conditions.push(fragment.sql);
12969
- args.push(...fragment.args);
12970
13135
  }
13136
+ fieldFragments.forEach((f) => {
13137
+ conditions.push(f.sql);
13138
+ args.push(...f.args);
13139
+ });
12971
13140
  } else {
12972
- const fragment = translateEq(fieldName, value, schema, actualFieldName);
13141
+ const fragment = translateLeafOperator("$eq", fieldName, value, schema, actualFieldName);
13142
+ if (!fragment)
13143
+ return null;
12973
13144
  conditions.push(fragment.sql);
12974
13145
  args.push(...fragment.args);
12975
13146
  }
@@ -13423,6 +13594,7 @@ class BunSQLiteStorageInstance {
13423
13594
  db;
13424
13595
  stmtManager;
13425
13596
  changeStream$ = new import_rxjs2.Subject;
13597
+ queryCache = new Map;
13426
13598
  databaseName;
13427
13599
  collectionName;
13428
13600
  schema;
@@ -13590,7 +13762,7 @@ class BunSQLiteStorageInstance {
13590
13762
  return rows.map((row) => JSON.parse(row.data));
13591
13763
  }
13592
13764
  async query(preparedQuery) {
13593
- const whereResult = buildWhereClause(preparedQuery.query.selector, this.schema, this.collectionName);
13765
+ const whereResult = buildWhereClause(preparedQuery.query.selector, this.schema, this.collectionName, this.queryCache);
13594
13766
  if (!whereResult) {
13595
13767
  return this.queryWithOurMemory(preparedQuery);
13596
13768
  }
@@ -13645,7 +13817,7 @@ class BunSQLiteStorageInstance {
13645
13817
  return path2.split(".").reduce((current, key) => current?.[key], obj);
13646
13818
  }
13647
13819
  async count(preparedQuery) {
13648
- const whereResult = buildWhereClause(preparedQuery.query.selector, this.schema, this.collectionName);
13820
+ const whereResult = buildWhereClause(preparedQuery.query.selector, this.schema, this.collectionName, this.queryCache);
13649
13821
  if (!whereResult) {
13650
13822
  const allDocs = await this.queryWithOurMemory(preparedQuery);
13651
13823
  return {
@@ -13680,12 +13852,16 @@ class BunSQLiteStorageInstance {
13680
13852
  if (this.closed)
13681
13853
  return this.closed;
13682
13854
  this.closed = (async () => {
13855
+ this.queryCache.clear();
13683
13856
  this.changeStream$.complete();
13684
13857
  this.stmtManager.close();
13685
13858
  releaseDatabase(this.databaseName);
13686
13859
  })();
13687
13860
  return this.closed;
13688
13861
  }
13862
+ getCacheSize() {
13863
+ return this.queryCache.size;
13864
+ }
13689
13865
  async remove() {
13690
13866
  if (this.closed)
13691
13867
  throw new Error("already closed");
@@ -5,6 +5,7 @@ export declare class BunSQLiteStorageInstance<RxDocType> implements RxStorageIns
5
5
  private db;
6
6
  private stmtManager;
7
7
  private changeStream$;
8
+ private queryCache;
8
9
  readonly databaseName: string;
9
10
  readonly collectionName: string;
10
11
  readonly schema: Readonly<RxJsonSchema<RxDocumentData<RxDocType>>>;
@@ -24,6 +25,7 @@ export declare class BunSQLiteStorageInstance<RxDocType> implements RxStorageIns
24
25
  changeStream(): Observable<EventBulk<RxStorageChangeEvent<RxDocumentData<RxDocType>>, RxStorageDefaultCheckpoint>>;
25
26
  cleanup(minimumDeletedTime: number): Promise<boolean>;
26
27
  close(): Promise<void>;
28
+ getCacheSize(): number;
27
29
  remove(): Promise<void>;
28
30
  private attachmentMapKey;
29
31
  getAttachmentData(documentId: string, attachmentId: string, digest: string): Promise<string>;
@@ -2,6 +2,6 @@ import type { RxJsonSchema, MangoQuerySelector, RxDocumentData } from 'rxdb';
2
2
  import type { SqlFragment } from './operators';
3
3
  export declare function getCacheSize(): number;
4
4
  export declare function clearCache(): void;
5
- export declare function buildWhereClause<RxDocType>(selector: MangoQuerySelector<RxDocumentData<RxDocType>>, schema: RxJsonSchema<RxDocumentData<RxDocType>>, collectionName: string): SqlFragment | null;
5
+ export declare function buildWhereClause<RxDocType>(selector: MangoQuerySelector<RxDocumentData<RxDocType>>, schema: RxJsonSchema<RxDocumentData<RxDocType>>, collectionName: string, cache?: Map<string, SqlFragment | null>): SqlFragment | null;
6
6
  export declare function buildLogicalOperator<RxDocType>(operator: 'or' | 'nor' | 'and', conditions: MangoQuerySelector<RxDocumentData<RxDocType>>[], schema: RxJsonSchema<RxDocumentData<RxDocType>>, logicalDepth: number): SqlFragment | null;
7
7
  //# sourceMappingURL=builder.d.ts.map
@@ -19,7 +19,8 @@ export declare function translateNin<RxDocType>(field: string, values: unknown[]
19
19
  export declare function translateExists(field: string, exists: boolean): SqlFragment;
20
20
  export declare function translateRegex<RxDocType>(field: string, pattern: string, options: string | undefined, schema: RxJsonSchema<RxDocumentData<RxDocType>>, fieldName: string): SqlFragment | null;
21
21
  export declare function translateElemMatch<RxDocType>(field: string, criteria: ElemMatchCriteria, schema: RxJsonSchema<RxDocumentData<RxDocType>>, actualFieldName: string): SqlFragment | null;
22
- export declare function translateNot<RxDocType>(field: string, criteria: unknown, schema: RxJsonSchema<RxDocumentData<RxDocType>>, actualFieldName: string): SqlFragment | null;
22
+ export declare function translateLeafOperator<RxDocType>(op: string, field: string, value: unknown, schema: RxJsonSchema<RxDocumentData<RxDocType>>, actualFieldName: string): SqlFragment | null;
23
+ export declare function wrapWithNot(innerFragment: SqlFragment): SqlFragment;
23
24
  export declare function translateType(jsonColumn: string, fieldName: string, type: string, isDirectPath?: boolean): SqlFragment | null;
24
25
  export declare function translateSize(field: string, size: number): SqlFragment;
25
26
  export declare function translateMod(field: string, value: unknown): SqlFragment | null;
@@ -3,5 +3,6 @@ export interface SqlFragment {
3
3
  sql: string;
4
4
  args: (string | number | boolean)[];
5
5
  }
6
+ export declare function clearRegexCache(): void;
6
7
  export declare function smartRegexToLike<RxDocType>(field: string, pattern: string, options: string | undefined, schema: RxJsonSchema<RxDocumentData<RxDocType>>, fieldName: string): SqlFragment | null;
7
8
  //# sourceMappingURL=smart-regex.d.ts.map
package/package.json CHANGED
@@ -1,11 +1,16 @@
1
1
  {
2
2
  "name": "bun-sqlite-for-rxdb",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "author": "adam2am",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/adam2am/bun-sqlite-for-rxdb.git"
8
8
  },
9
+ "scripts": {
10
+ "build": "bun build src/index.ts --outdir dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
11
+ "test": "bun test test/",
12
+ "typecheck": "tsc --noEmit"
13
+ },
9
14
  "main": "dist/index.js",
10
15
  "dependencies": {},
11
16
  "devDependencies": {
@@ -45,11 +50,6 @@
45
50
  "README.md",
46
51
  "LICENSE"
47
52
  ],
48
- "scripts": {
49
- "build": "bun build src/index.ts --outdir dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
50
- "test": "bun test src/",
51
- "typecheck": "tsc --noEmit"
52
- },
53
53
  "type": "module",
54
54
  "types": "dist/index.d.ts"
55
55
  }