bun-sqlite-for-rxdb 1.3.1 → 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/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;
@@ -12254,6 +12283,13 @@ function getColumnInfo(path2, schema) {
12254
12283
  if (path2 === schema.primaryKey) {
12255
12284
  return { column: "id", type: "string" };
12256
12285
  }
12286
+ const properties = schema.properties;
12287
+ const fieldSchema = properties?.[path2];
12288
+ if (fieldSchema && typeof fieldSchema === "object" && "type" in fieldSchema) {
12289
+ if (fieldSchema.type === "array") {
12290
+ return { jsonPath: `$.${path2}`, type: "array" };
12291
+ }
12292
+ }
12257
12293
  return { jsonPath: `$.${path2}`, type: "unknown" };
12258
12294
  }
12259
12295
 
@@ -12295,6 +12331,14 @@ function hasExpressionIndex(fieldName, schema) {
12295
12331
  INDEX_CACHE.set(cacheKey, hasLowerIndex);
12296
12332
  return hasLowerIndex;
12297
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
+ }
12298
12342
  function isComplexRegex(pattern) {
12299
12343
  return /[*+?()[\]{}|]/.test(pattern.replace(/\\\./g, ""));
12300
12344
  }
@@ -12304,6 +12348,9 @@ function escapeForLike(str) {
12304
12348
  function smartRegexToLike(field, pattern, options, schema, fieldName) {
12305
12349
  if (typeof pattern !== "string")
12306
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
+ }
12307
12354
  const caseInsensitive = options?.includes("i") ?? false;
12308
12355
  const hasLowerIndex = hasExpressionIndex(fieldName, schema);
12309
12356
  const startsWithAnchor = pattern.startsWith("^");
@@ -12342,67 +12389,161 @@ function smartRegexToLike(field, pattern, options, schema, fieldName) {
12342
12389
  }
12343
12390
 
12344
12391
  // src/query/operators.ts
12345
- function translateEq(field, value) {
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
+ }
12404
+ function translateEq(field, value, schema, actualFieldName) {
12346
12405
  if (value === null) {
12347
12406
  return { sql: `${field} IS NULL`, args: [] };
12348
12407
  }
12349
- return { sql: `${field} = ?`, args: [value] };
12408
+ if (schema && actualFieldName) {
12409
+ const columnInfo = getColumnInfo(actualFieldName, schema);
12410
+ if (field !== "value" && columnInfo.type === "array") {
12411
+ return {
12412
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value = ?)`,
12413
+ args: [normalizeValueForSQLite(value)]
12414
+ };
12415
+ }
12416
+ }
12417
+ return { sql: `${field} = ?`, args: [normalizeValueForSQLite(value)] };
12350
12418
  }
12351
- function translateNe(field, value) {
12419
+ function translateNe(field, value, schema, actualFieldName) {
12352
12420
  if (value === null) {
12353
12421
  return { sql: `${field} IS NOT NULL`, args: [] };
12354
12422
  }
12355
- return { sql: `${field} <> ?`, args: [value] };
12423
+ if (schema && actualFieldName) {
12424
+ const columnInfo = getColumnInfo(actualFieldName, schema);
12425
+ if (field !== "value" && columnInfo.type === "array") {
12426
+ return {
12427
+ sql: `NOT EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value = ?)`,
12428
+ args: [normalizeValueForSQLite(value)]
12429
+ };
12430
+ }
12431
+ }
12432
+ return { sql: `(${field} <> ? OR ${field} IS NULL)`, args: [normalizeValueForSQLite(value)] };
12356
12433
  }
12357
- function translateGt(field, value) {
12358
- return { sql: `${field} > ?`, args: [value] };
12434
+ function translateGt(field, value, schema, actualFieldName) {
12435
+ if (schema && actualFieldName) {
12436
+ const columnInfo = getColumnInfo(actualFieldName, schema);
12437
+ if (field !== "value" && columnInfo.type === "array") {
12438
+ return {
12439
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value > ?)`,
12440
+ args: [normalizeValueForSQLite(value)]
12441
+ };
12442
+ }
12443
+ }
12444
+ return { sql: `${field} > ?`, args: [normalizeValueForSQLite(value)] };
12359
12445
  }
12360
- function translateGte(field, value) {
12361
- return { sql: `${field} >= ?`, args: [value] };
12446
+ function translateGte(field, value, schema, actualFieldName) {
12447
+ if (schema && actualFieldName) {
12448
+ const columnInfo = getColumnInfo(actualFieldName, schema);
12449
+ if (field !== "value" && columnInfo.type === "array") {
12450
+ return {
12451
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value >= ?)`,
12452
+ args: [normalizeValueForSQLite(value)]
12453
+ };
12454
+ }
12455
+ }
12456
+ return { sql: `${field} >= ?`, args: [normalizeValueForSQLite(value)] };
12362
12457
  }
12363
- function translateLt(field, value) {
12364
- return { sql: `${field} < ?`, args: [value] };
12458
+ function translateLt(field, value, schema, actualFieldName) {
12459
+ if (schema && actualFieldName) {
12460
+ const columnInfo = getColumnInfo(actualFieldName, schema);
12461
+ if (field !== "value" && columnInfo.type === "array") {
12462
+ return {
12463
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value < ?)`,
12464
+ args: [normalizeValueForSQLite(value)]
12465
+ };
12466
+ }
12467
+ }
12468
+ return { sql: `${field} < ?`, args: [normalizeValueForSQLite(value)] };
12365
12469
  }
12366
- function translateLte(field, value) {
12367
- return { sql: `${field} <= ?`, args: [value] };
12470
+ function translateLte(field, value, schema, actualFieldName) {
12471
+ if (schema && actualFieldName) {
12472
+ const columnInfo = getColumnInfo(actualFieldName, schema);
12473
+ if (field !== "value" && columnInfo.type === "array") {
12474
+ return {
12475
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value <= ?)`,
12476
+ args: [normalizeValueForSQLite(value)]
12477
+ };
12478
+ }
12479
+ }
12480
+ return { sql: `${field} <= ?`, args: [normalizeValueForSQLite(value)] };
12368
12481
  }
12369
- function translateIn(field, values) {
12482
+ function translateIn(field, values, schema, actualFieldName) {
12370
12483
  if (!Array.isArray(values) || values.length === 0) {
12371
12484
  return { sql: "1=0", args: [] };
12372
12485
  }
12373
12486
  const hasNull = values.includes(null);
12374
- const nonNullValues = values.filter((v) => v !== null);
12487
+ const nonNullValues = values.filter((v) => v !== null).map((v) => normalizeValueForSQLite(v));
12375
12488
  if (nonNullValues.length === 0) {
12376
12489
  return { sql: `${field} IS NULL`, args: [] };
12377
12490
  }
12378
- const placeholders = nonNullValues.map(() => "?").join(", ");
12379
- const inClause = `${field} IN (${placeholders})`;
12491
+ if (schema && actualFieldName) {
12492
+ const columnInfo = getColumnInfo(actualFieldName, schema);
12493
+ if (field !== "value" && columnInfo.type === "array") {
12494
+ const inClause2 = `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value IN (SELECT value FROM json_each(?)))`;
12495
+ const args2 = [JSON.stringify(nonNullValues)];
12496
+ if (hasNull) {
12497
+ return {
12498
+ sql: `(${inClause2} OR ${field} IS NULL)`,
12499
+ args: args2
12500
+ };
12501
+ }
12502
+ return { sql: inClause2, args: args2 };
12503
+ }
12504
+ }
12505
+ const inClause = `${field} IN (SELECT value FROM json_each(?))`;
12506
+ const args = [JSON.stringify(nonNullValues)];
12380
12507
  if (hasNull) {
12381
12508
  return {
12382
12509
  sql: `(${inClause} OR ${field} IS NULL)`,
12383
- args: nonNullValues
12510
+ args
12384
12511
  };
12385
12512
  }
12386
- return { sql: inClause, args: nonNullValues };
12513
+ return { sql: inClause, args };
12387
12514
  }
12388
- function translateNin(field, values) {
12515
+ function translateNin(field, values, schema, actualFieldName) {
12389
12516
  if (!Array.isArray(values) || values.length === 0) {
12390
12517
  return { sql: "1=1", args: [] };
12391
12518
  }
12392
12519
  const hasNull = values.includes(null);
12393
- const nonNullValues = values.filter((v) => v !== null);
12520
+ const nonNullValues = values.filter((v) => v !== null).map((v) => normalizeValueForSQLite(v));
12394
12521
  if (nonNullValues.length === 0) {
12395
12522
  return { sql: `${field} IS NOT NULL`, args: [] };
12396
12523
  }
12397
- const placeholders = nonNullValues.map(() => "?").join(", ");
12398
- const ninClause = `${field} NOT IN (${placeholders})`;
12524
+ if (schema && actualFieldName) {
12525
+ const columnInfo = getColumnInfo(actualFieldName, schema);
12526
+ if (field !== "value" && columnInfo.type === "array") {
12527
+ const ninClause2 = `NOT EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value IN (SELECT value FROM json_each(?)))`;
12528
+ const args2 = [JSON.stringify(nonNullValues)];
12529
+ if (hasNull) {
12530
+ return {
12531
+ sql: `(${ninClause2} AND ${field} IS NOT NULL)`,
12532
+ args: args2
12533
+ };
12534
+ }
12535
+ return { sql: `(${field} IS NULL OR ${ninClause2})`, args: args2 };
12536
+ }
12537
+ }
12538
+ const ninClause = `${field} NOT IN (SELECT value FROM json_each(?))`;
12539
+ const args = [JSON.stringify(nonNullValues)];
12399
12540
  if (hasNull) {
12400
12541
  return {
12401
12542
  sql: `(${ninClause} AND ${field} IS NOT NULL)`,
12402
- args: nonNullValues
12543
+ args
12403
12544
  };
12404
12545
  }
12405
- return { sql: ninClause, args: nonNullValues };
12546
+ return { sql: `(${field} IS NULL OR ${ninClause})`, args };
12406
12547
  }
12407
12548
  function translateExists(field, exists) {
12408
12549
  return {
@@ -12416,142 +12557,259 @@ function translateRegex(field, pattern, options, schema, fieldName) {
12416
12557
  return smartResult;
12417
12558
  return null;
12418
12559
  }
12419
- function buildElemMatchConditions(criteria) {
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
+ }
12645
+ function buildElemMatchConditions(criteria, schema, baseFieldName) {
12420
12646
  const conditions = [];
12421
12647
  const args = [];
12422
12648
  for (const [key, value] of Object.entries(criteria)) {
12423
- if (key.startsWith("$")) {
12424
- const fragment = processOperatorValue("json_each.value", { [key]: value });
12425
- conditions.push(fragment.sql);
12426
- 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);
12427
12654
  } else {
12428
- const propertyField = `json_extract(json_each.value, '$.${key}')`;
12429
- const fragment = processOperatorValue(propertyField, value);
12430
- conditions.push(fragment.sql);
12431
- args.push(...fragment.args);
12655
+ fragment = handleFieldCondition(key, value, schema, baseFieldName);
12432
12656
  }
12657
+ if (!fragment)
12658
+ return null;
12659
+ conditions.push(fragment.sql);
12660
+ args.push(...fragment.args);
12433
12661
  }
12434
12662
  return {
12435
12663
  sql: conditions.length > 0 ? conditions.join(" AND ") : "1=1",
12436
12664
  args
12437
12665
  };
12438
12666
  }
12439
- function translateElemMatch(field, criteria) {
12667
+ function translateElemMatch(field, criteria, schema, actualFieldName) {
12668
+ if (typeof criteria === "object" && criteria !== null && !Array.isArray(criteria) && Object.keys(criteria).length === 0) {
12669
+ return { sql: "1=0", args: [] };
12670
+ }
12440
12671
  if (typeof criteria !== "object" || criteria === null) {
12441
12672
  return {
12442
- sql: `EXISTS (SELECT 1 FROM json_each(${field}) WHERE json_each.value = ?)`,
12673
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value = ?)`,
12443
12674
  args: [criteria]
12444
12675
  };
12445
12676
  }
12446
12677
  if (criteria.$and && Array.isArray(criteria.$and)) {
12447
- const fragments = criteria.$and.map((cond) => buildElemMatchConditions(cond));
12678
+ const fragments = criteria.$and.map((cond) => buildElemMatchConditions(cond, schema, actualFieldName));
12679
+ if (fragments.some((f) => f === null))
12680
+ return null;
12448
12681
  const sql = fragments.map((f) => f.sql).join(" AND ");
12449
12682
  const args = fragments.flatMap((f) => f.args);
12450
12683
  return {
12451
- sql: `EXISTS (SELECT 1 FROM json_each(${field}) WHERE ${sql})`,
12684
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE ${sql})`,
12452
12685
  args
12453
12686
  };
12454
12687
  }
12455
12688
  if (criteria.$or && Array.isArray(criteria.$or)) {
12456
- const fragments = criteria.$or.map((cond) => buildElemMatchConditions(cond));
12689
+ const fragments = criteria.$or.map((cond) => buildElemMatchConditions(cond, schema, actualFieldName));
12690
+ if (fragments.some((f) => f === null))
12691
+ return null;
12457
12692
  const sql = fragments.map((f) => f.sql).join(" OR ");
12458
12693
  const args = fragments.flatMap((f) => f.args);
12459
12694
  return {
12460
- sql: `EXISTS (SELECT 1 FROM json_each(${field}) WHERE ${sql})`,
12695
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE ${sql})`,
12461
12696
  args
12462
12697
  };
12463
12698
  }
12464
12699
  if (criteria.$nor && Array.isArray(criteria.$nor)) {
12465
- const fragments = criteria.$nor.map((cond) => buildElemMatchConditions(cond));
12700
+ const fragments = criteria.$nor.map((cond) => buildElemMatchConditions(cond, schema, actualFieldName));
12701
+ if (fragments.some((f) => f === null))
12702
+ return null;
12466
12703
  const sql = fragments.map((f) => f.sql).join(" OR ");
12467
12704
  const args = fragments.flatMap((f) => f.args);
12468
12705
  return {
12469
- sql: `EXISTS (SELECT 1 FROM json_each(${field}) WHERE NOT (${sql}))`,
12706
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE NOT (${sql}))`,
12470
12707
  args
12471
12708
  };
12472
12709
  }
12473
- const fragment = buildElemMatchConditions(criteria);
12474
- if (fragment.sql === "1=1") {
12710
+ const fragment = buildElemMatchConditions(criteria, schema, actualFieldName);
12711
+ if (!fragment)
12475
12712
  return null;
12476
- }
12477
12713
  return {
12478
- sql: `EXISTS (SELECT 1 FROM json_each(${field}) WHERE ${fragment.sql})`,
12714
+ sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE ${fragment.sql})`,
12479
12715
  args: fragment.args
12480
12716
  };
12481
12717
  }
12482
- function processOperatorValue(field, value) {
12483
- if (typeof value === "object" && value !== null && !Array.isArray(value)) {
12484
- const [[op, opValue]] = Object.entries(value);
12485
- if (!op.startsWith("$")) {
12486
- const jsonPath = `json_extract(${field}, '$.${op}')`;
12487
- return translateEq(jsonPath, opValue);
12488
- }
12489
- switch (op) {
12490
- case "$eq":
12491
- return translateEq(field, opValue);
12492
- case "$ne":
12493
- return translateNe(field, opValue);
12494
- case "$gt":
12495
- return translateGt(field, opValue);
12496
- case "$gte":
12497
- return translateGte(field, opValue);
12498
- case "$lt":
12499
- return translateLt(field, opValue);
12500
- case "$lte":
12501
- return translateLte(field, opValue);
12502
- case "$in":
12503
- return translateIn(field, opValue);
12504
- case "$nin":
12505
- return translateNin(field, opValue);
12506
- case "$exists":
12507
- return translateExists(field, opValue);
12508
- case "$size":
12509
- return translateSize(field, opValue);
12510
- case "$mod": {
12511
- const result = translateMod(field, opValue);
12512
- if (!result)
12513
- return translateEq(field, opValue);
12514
- return result;
12515
- }
12516
- case "$not": {
12517
- const result = translateNot(field, opValue);
12518
- if (!result)
12519
- return translateEq(field, opValue);
12520
- return result;
12521
- }
12522
- case "$and": {
12523
- if (!Array.isArray(opValue))
12524
- return translateEq(field, opValue);
12525
- const fragments = opValue.map((v) => processOperatorValue(field, v));
12526
- const sql = fragments.map((f) => f.sql).join(" AND ");
12527
- const args = fragments.flatMap((f) => f.args);
12528
- return { sql: `(${sql})`, args };
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;
12529
12760
  }
12530
- case "$or": {
12531
- if (!Array.isArray(opValue))
12532
- return translateEq(field, opValue);
12533
- const fragments = opValue.map((v) => processOperatorValue(field, v));
12534
- const sql = fragments.map((f) => f.sql).join(" OR ");
12535
- const args = fragments.flatMap((f) => f.args);
12536
- return { sql: `(${sql})`, args };
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: [] };
12792
+ }
12793
+ if (value === "number") {
12794
+ return { sql: `(type IN ('integer', 'real'))`, args: [] };
12795
+ }
12796
+ return { sql: `type = '${sqlType}'`, args: [] };
12537
12797
  }
12538
- default:
12539
- return translateEq(field, opValue);
12798
+ const typeFragment = translateType(jsonCol, path2, value, true);
12799
+ return typeFragment || { sql: "1=0", args: [] };
12540
12800
  }
12801
+ default:
12802
+ return translateEq(field, value, schema, actualFieldName);
12541
12803
  }
12542
- return translateEq(field, value);
12543
12804
  }
12544
- function translateNot(field, criteria) {
12545
- if (!criteria || typeof criteria === "object" && Object.keys(criteria).length === 0)
12546
- return null;
12547
- const inner = processOperatorValue(field, criteria);
12805
+ function wrapWithNot(innerFragment) {
12548
12806
  return {
12549
- sql: `NOT(${inner.sql})`,
12550
- args: inner.args
12807
+ sql: `NOT (${innerFragment.sql})`,
12808
+ args: innerFragment.args
12551
12809
  };
12552
12810
  }
12553
- function translateType(jsonColumn, fieldName, type6) {
12554
- const jsonPath = `$.${fieldName}`;
12811
+ function translateType(jsonColumn, fieldName, type6, isDirectPath = false) {
12812
+ const jsonPath = isDirectPath ? fieldName : `$.${fieldName}`;
12555
12813
  switch (type6) {
12556
12814
  case "null":
12557
12815
  return { sql: `json_type(${jsonColumn}, '${jsonPath}') = 'null'`, args: [] };
@@ -12566,7 +12824,7 @@ function translateType(jsonColumn, fieldName, type6) {
12566
12824
  case "object":
12567
12825
  return { sql: `json_type(${jsonColumn}, '${jsonPath}') = 'object'`, args: [] };
12568
12826
  default:
12569
- return null;
12827
+ return { sql: "1=0", args: [] };
12570
12828
  }
12571
12829
  }
12572
12830
  function translateSize(field, size) {
@@ -12577,11 +12835,11 @@ function translateSize(field, size) {
12577
12835
  }
12578
12836
  function translateMod(field, value) {
12579
12837
  if (!Array.isArray(value) || value.length !== 2)
12580
- return null;
12838
+ return { sql: "1=0", args: [] };
12581
12839
  const [divisor, remainder] = value;
12582
12840
  return {
12583
- sql: `${field} % ? = ?`,
12584
- args: [divisor, remainder]
12841
+ sql: `(${field} - (CAST(${field} / ? AS INTEGER) * ?)) = ?`,
12842
+ args: [divisor, divisor, remainder]
12585
12843
  };
12586
12844
  }
12587
12845
 
@@ -12661,6 +12919,14 @@ function _stringify(value, stack) {
12661
12919
  }
12662
12920
  const objType = Object.prototype.toString.call(obj);
12663
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
+ }
12664
12930
  const result = JSON.stringify(obj);
12665
12931
  stack.pop();
12666
12932
  return result;
@@ -12683,37 +12949,37 @@ function _stringify(value, stack) {
12683
12949
  }
12684
12950
 
12685
12951
  // src/query/builder.ts
12686
- var QUERY_CACHE = new Map;
12687
12952
  var MAX_CACHE_SIZE = 1000;
12688
- function buildWhereClause(selector, schema, collectionName) {
12953
+ var GLOBAL_CACHE = new Map;
12954
+ function buildWhereClause(selector, schema, collectionName, cache = GLOBAL_CACHE) {
12689
12955
  if (!selector || typeof selector !== "object")
12690
12956
  return null;
12691
12957
  const cacheKey = `v${schema.version}_${collectionName}_${stableStringify(selector)}`;
12692
- const cached = QUERY_CACHE.get(cacheKey);
12693
- if (cached) {
12694
- QUERY_CACHE.delete(cacheKey);
12695
- QUERY_CACHE.set(cacheKey, cached);
12958
+ const cached = cache.get(cacheKey);
12959
+ if (cached !== undefined) {
12960
+ cache.delete(cacheKey);
12961
+ cache.set(cacheKey, cached);
12696
12962
  return cached;
12697
12963
  }
12698
12964
  const result = processSelector(selector, schema, 0);
12699
12965
  if (!result)
12700
12966
  return null;
12701
- if (QUERY_CACHE.size >= MAX_CACHE_SIZE) {
12702
- const firstKey = QUERY_CACHE.keys().next().value;
12967
+ if (cache.size >= MAX_CACHE_SIZE) {
12968
+ const firstKey = cache.keys().next().value;
12703
12969
  if (firstKey)
12704
- QUERY_CACHE.delete(firstKey);
12970
+ cache.delete(firstKey);
12705
12971
  }
12706
- QUERY_CACHE.set(cacheKey, result);
12972
+ cache.set(cacheKey, result);
12707
12973
  return result;
12708
12974
  }
12709
12975
  function buildLogicalOperator(operator, conditions, schema, logicalDepth) {
12710
12976
  if (conditions.length === 0) {
12711
- return { sql: "1=1", args: [] };
12977
+ return { sql: operator === "or" ? "1=0" : "1=1", args: [] };
12712
12978
  }
12713
12979
  const fragments = conditions.map((subSelector) => processSelector(subSelector, schema, logicalDepth + 1));
12714
12980
  if (fragments.some((f) => f === null))
12715
12981
  return null;
12716
- const sql = fragments.map((f) => f.sql).join(" OR ");
12982
+ const sql = fragments.map((f) => `(${f.sql})`).join(" OR ");
12717
12983
  const args = fragments.flatMap((f) => f.args);
12718
12984
  return operator === "nor" ? { sql: `NOT(${sql})`, args } : { sql, args };
12719
12985
  }
@@ -12738,8 +13004,7 @@ function processSelector(selector, schema, logicalDepth) {
12738
13004
  const orFragment = buildLogicalOperator("or", value, schema, logicalDepth);
12739
13005
  if (!orFragment)
12740
13006
  return null;
12741
- const needsParens = logicalDepth > 0;
12742
- conditions.push(needsParens ? `(${orFragment.sql})` : orFragment.sql);
13007
+ conditions.push(`(${orFragment.sql})`);
12743
13008
  args.push(...orFragment.args);
12744
13009
  continue;
12745
13010
  }
@@ -12755,80 +13020,127 @@ function processSelector(selector, schema, logicalDepth) {
12755
13020
  const fieldName = columnInfo.column || `json_extract(data, '${columnInfo.jsonPath}')`;
12756
13021
  const actualFieldName = columnInfo.jsonPath?.replace(/^\$\./, "") || columnInfo.column || field;
12757
13022
  if (typeof value === "object" && value !== null && !Array.isArray(value)) {
13023
+ if (Object.keys(value).length === 0) {
13024
+ return { sql: "1=0", args: [] };
13025
+ }
13026
+ const fieldFragments = [];
12758
13027
  for (const [op, opValue] of Object.entries(value)) {
12759
13028
  let fragment;
12760
- switch (op) {
12761
- case "$eq":
12762
- fragment = translateEq(fieldName, opValue);
12763
- break;
12764
- case "$ne":
12765
- fragment = translateNe(fieldName, opValue);
12766
- break;
12767
- case "$gt":
12768
- fragment = translateGt(fieldName, opValue);
12769
- break;
12770
- case "$gte":
12771
- fragment = translateGte(fieldName, opValue);
12772
- break;
12773
- case "$lt":
12774
- fragment = translateLt(fieldName, opValue);
12775
- break;
12776
- case "$lte":
12777
- fragment = translateLte(fieldName, opValue);
12778
- break;
12779
- case "$in":
12780
- fragment = translateIn(fieldName, opValue);
12781
- break;
12782
- case "$nin":
12783
- fragment = translateNin(fieldName, opValue);
12784
- break;
12785
- case "$exists":
12786
- fragment = translateExists(fieldName, opValue);
12787
- break;
12788
- case "$regex":
12789
- const options = value.$options;
12790
- const regexFragment = translateRegex(fieldName, opValue, options, schema, actualFieldName);
12791
- 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)
12792
13033
  return null;
12793
- fragment = regexFragment;
12794
- break;
12795
- case "$elemMatch":
12796
- const elemMatchFragment = translateElemMatch(fieldName, opValue);
12797
- if (!elemMatchFragment)
13034
+ fragment = wrapWithNot(eqFrag);
13035
+ } else if (opValue instanceof Date) {
13036
+ const eqFrag = translateLeafOperator("$eq", fieldName, opValue, schema, actualFieldName);
13037
+ if (!eqFrag)
12798
13038
  return null;
12799
- fragment = elemMatchFragment;
12800
- break;
12801
- case "$not": {
12802
- const notResult = translateNot(fieldName, opValue);
12803
- if (!notResult)
13039
+ fragment = wrapWithNot(eqFrag);
13040
+ } else if (opValue instanceof RegExp) {
13041
+ const regexFrag = translateLeafOperator("$regex", fieldName, opValue, schema, actualFieldName);
13042
+ if (!regexFrag)
12804
13043
  return null;
12805
- fragment = notResult;
12806
- 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
+ }
12807
13092
  }
12808
- case "$type":
12809
- const typeFragment = translateType("data", actualFieldName, opValue);
12810
- if (!typeFragment)
12811
- return null;
12812
- fragment = typeFragment;
12813
- break;
12814
- case "$size":
12815
- fragment = translateSize(fieldName, opValue);
12816
- break;
12817
- case "$mod": {
12818
- const modResult = translateMod(fieldName, opValue);
12819
- if (!modResult)
12820
- return null;
12821
- fragment = modResult;
12822
- 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;
12823
13106
  }
12824
- default:
12825
- 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);
12826
13134
  }
12827
- conditions.push(fragment.sql);
12828
- args.push(...fragment.args);
12829
13135
  }
13136
+ fieldFragments.forEach((f) => {
13137
+ conditions.push(f.sql);
13138
+ args.push(...f.args);
13139
+ });
12830
13140
  } else {
12831
- const fragment = translateEq(fieldName, value);
13141
+ const fragment = translateLeafOperator("$eq", fieldName, value, schema, actualFieldName);
13142
+ if (!fragment)
13143
+ return null;
12832
13144
  conditions.push(fragment.sql);
12833
13145
  args.push(...fragment.args);
12834
13146
  }
@@ -12837,6 +13149,100 @@ function processSelector(selector, schema, logicalDepth) {
12837
13149
  return { sql: where, args };
12838
13150
  }
12839
13151
 
13152
+ // src/query/lightweight-matcher.ts
13153
+ var operators = {
13154
+ $eq: (a, b) => a === b,
13155
+ $ne: (a, b) => a !== b,
13156
+ $gt: (a, b) => a > b,
13157
+ $gte: (a, b) => a >= b,
13158
+ $lt: (a, b) => a < b,
13159
+ $lte: (a, b) => a <= b,
13160
+ $in: (a, b) => Array.isArray(b) && b.some((v) => v === a),
13161
+ $nin: (a, b) => Array.isArray(b) && !b.some((v) => v === a),
13162
+ $exists: (a, b) => a !== undefined === b,
13163
+ $type: (a, b) => {
13164
+ const type6 = Array.isArray(a) ? "array" : typeof a;
13165
+ return type6 === b;
13166
+ },
13167
+ $mod: (a, b) => {
13168
+ if (!Array.isArray(b) || b.length !== 2)
13169
+ return false;
13170
+ const [divisor, remainder] = b;
13171
+ return typeof a === "number" && a % divisor === remainder;
13172
+ },
13173
+ $size: (a, b) => Array.isArray(a) && a.length === b
13174
+ };
13175
+ function getNestedValue(obj, path2) {
13176
+ return path2.split(".").reduce((current, key) => current?.[key], obj);
13177
+ }
13178
+ function matchesSelector(doc, selector) {
13179
+ if (!selector || typeof selector !== "object")
13180
+ return true;
13181
+ if (selector.$and) {
13182
+ return Array.isArray(selector.$and) && selector.$and.every((s) => matchesSelector(doc, s));
13183
+ }
13184
+ if (selector.$or) {
13185
+ return Array.isArray(selector.$or) && selector.$or.some((s) => matchesSelector(doc, s));
13186
+ }
13187
+ if (selector.$nor) {
13188
+ return Array.isArray(selector.$nor) && !selector.$nor.some((s) => matchesSelector(doc, s));
13189
+ }
13190
+ for (const [field, condition] of Object.entries(selector)) {
13191
+ const value = getNestedValue(doc, field);
13192
+ if (typeof condition !== "object" || condition === null || Array.isArray(condition)) {
13193
+ if (value !== condition)
13194
+ return false;
13195
+ continue;
13196
+ }
13197
+ for (const [op, opValue] of Object.entries(condition)) {
13198
+ if (op === "$regex") {
13199
+ const options = condition.$options;
13200
+ if (!matchesRegex(value, opValue, options))
13201
+ return false;
13202
+ continue;
13203
+ }
13204
+ if (op === "$not") {
13205
+ if (matchesOperator(value, opValue))
13206
+ return false;
13207
+ continue;
13208
+ }
13209
+ if (op === "$elemMatch") {
13210
+ if (!Array.isArray(value))
13211
+ return false;
13212
+ const hasMatch = value.some((item) => matchesSelector(item, opValue));
13213
+ if (!hasMatch)
13214
+ return false;
13215
+ continue;
13216
+ }
13217
+ if (op === "$options")
13218
+ continue;
13219
+ const operator = operators[op];
13220
+ if (!operator)
13221
+ return false;
13222
+ if (!operator(value, opValue))
13223
+ return false;
13224
+ }
13225
+ }
13226
+ return true;
13227
+ }
13228
+ function matchesOperator(value, operator) {
13229
+ if (typeof operator !== "object" || operator === null) {
13230
+ return value === operator;
13231
+ }
13232
+ for (const [op, opValue] of Object.entries(operator)) {
13233
+ if (op === "$regex") {
13234
+ const options = operator.$options;
13235
+ return matchesRegex(value, opValue, options);
13236
+ }
13237
+ const operatorFn = operators[op];
13238
+ if (!operatorFn)
13239
+ return false;
13240
+ if (operatorFn(value, opValue))
13241
+ return true;
13242
+ }
13243
+ return false;
13244
+ }
13245
+
12840
13246
  // src/rxdb-helpers.ts
12841
13247
  function randomToken2(length) {
12842
13248
  return Math.random().toString(36).substring(2, 2 + length);
@@ -13188,6 +13594,7 @@ class BunSQLiteStorageInstance {
13188
13594
  db;
13189
13595
  stmtManager;
13190
13596
  changeStream$ = new import_rxjs2.Subject;
13597
+ queryCache = new Map;
13191
13598
  databaseName;
13192
13599
  collectionName;
13193
13600
  schema;
@@ -13355,7 +13762,7 @@ class BunSQLiteStorageInstance {
13355
13762
  return rows.map((row) => JSON.parse(row.data));
13356
13763
  }
13357
13764
  async query(preparedQuery) {
13358
- const whereResult = buildWhereClause(preparedQuery.query.selector, this.schema, this.collectionName);
13765
+ const whereResult = buildWhereClause(preparedQuery.query.selector, this.schema, this.collectionName, this.queryCache);
13359
13766
  if (!whereResult) {
13360
13767
  return this.queryWithOurMemory(preparedQuery);
13361
13768
  }
@@ -13375,6 +13782,9 @@ class BunSQLiteStorageInstance {
13375
13782
  queryArgs.push(preparedQuery.query.limit);
13376
13783
  }
13377
13784
  if (preparedQuery.query.skip) {
13785
+ if (!preparedQuery.query.limit) {
13786
+ sql += ` LIMIT -1`;
13787
+ }
13378
13788
  sql += ` OFFSET ?`;
13379
13789
  queryArgs.push(preparedQuery.query.skip);
13380
13790
  }
@@ -13389,31 +13799,6 @@ class BunSQLiteStorageInstance {
13389
13799
  const documents = rows.map((row) => JSON.parse(row.data));
13390
13800
  return { documents };
13391
13801
  }
13392
- matchesSelector(doc, selector) {
13393
- for (const [key, value] of Object.entries(selector)) {
13394
- const docValue = this.getNestedValue(doc, key);
13395
- if (typeof value === "object" && value !== null) {
13396
- for (const [op, opValue] of Object.entries(value)) {
13397
- if (op === "$eq" && docValue !== opValue)
13398
- return false;
13399
- if (op === "$ne" && docValue === opValue)
13400
- return false;
13401
- if (op === "$gt" && !(docValue > opValue))
13402
- return false;
13403
- if (op === "$gte" && !(docValue >= opValue))
13404
- return false;
13405
- if (op === "$lt" && !(docValue < opValue))
13406
- return false;
13407
- if (op === "$lte" && !(docValue <= opValue))
13408
- return false;
13409
- }
13410
- } else {
13411
- if (docValue !== value)
13412
- return false;
13413
- }
13414
- }
13415
- return true;
13416
- }
13417
13802
  sortDocuments(docs, sort) {
13418
13803
  return docs.sort((a, b) => {
13419
13804
  for (const sortField of sort) {
@@ -13432,7 +13817,7 @@ class BunSQLiteStorageInstance {
13432
13817
  return path2.split(".").reduce((current, key) => current?.[key], obj);
13433
13818
  }
13434
13819
  async count(preparedQuery) {
13435
- const whereResult = buildWhereClause(preparedQuery.query.selector, this.schema, this.collectionName);
13820
+ const whereResult = buildWhereClause(preparedQuery.query.selector, this.schema, this.collectionName, this.queryCache);
13436
13821
  if (!whereResult) {
13437
13822
  const allDocs = await this.queryWithOurMemory(preparedQuery);
13438
13823
  return {
@@ -13467,12 +13852,16 @@ class BunSQLiteStorageInstance {
13467
13852
  if (this.closed)
13468
13853
  return this.closed;
13469
13854
  this.closed = (async () => {
13855
+ this.queryCache.clear();
13470
13856
  this.changeStream$.complete();
13471
13857
  this.stmtManager.close();
13472
13858
  releaseDatabase(this.databaseName);
13473
13859
  })();
13474
13860
  return this.closed;
13475
13861
  }
13862
+ getCacheSize() {
13863
+ return this.queryCache.size;
13864
+ }
13476
13865
  async remove() {
13477
13866
  if (this.closed)
13478
13867
  throw new Error("already closed");
@@ -13512,17 +13901,38 @@ class BunSQLiteStorageInstance {
13512
13901
  }
13513
13902
  queryWithOurMemory(preparedQuery) {
13514
13903
  const query = `SELECT json(data) as data FROM "${this.tableName}"`;
13515
- const rows = this.stmtManager.all({ query, params: [] });
13516
- let documents = rows.map((row) => JSON.parse(row.data));
13517
- documents = documents.filter((doc) => this.matchesRegexSelector(doc, preparedQuery.query.selector));
13518
- if (preparedQuery.query.sort && preparedQuery.query.sort.length > 0) {
13519
- documents = this.sortDocuments(documents, preparedQuery.query.sort);
13520
- }
13521
- if (preparedQuery.query.skip) {
13522
- documents = documents.slice(preparedQuery.query.skip);
13523
- }
13524
- if (preparedQuery.query.limit) {
13525
- documents = documents.slice(0, preparedQuery.query.limit);
13904
+ const selector = preparedQuery.query.selector;
13905
+ const hasSort = preparedQuery.query.sort && preparedQuery.query.sort.length > 0;
13906
+ if (hasSort) {
13907
+ const rows = this.stmtManager.all({ query, params: [] });
13908
+ let documents2 = rows.map((row) => JSON.parse(row.data));
13909
+ documents2 = documents2.filter((doc) => matchesSelector(doc, selector));
13910
+ documents2 = this.sortDocuments(documents2, preparedQuery.query.sort);
13911
+ if (preparedQuery.query.skip) {
13912
+ documents2 = documents2.slice(preparedQuery.query.skip);
13913
+ }
13914
+ if (preparedQuery.query.limit) {
13915
+ documents2 = documents2.slice(0, preparedQuery.query.limit);
13916
+ }
13917
+ return { documents: documents2 };
13918
+ }
13919
+ const stmt = this.db.prepare(query);
13920
+ const documents = [];
13921
+ const skip = preparedQuery.query.skip || 0;
13922
+ const limit = preparedQuery.query.limit;
13923
+ let skipped = 0;
13924
+ for (const row of stmt.iterate()) {
13925
+ const doc = JSON.parse(row.data);
13926
+ if (matchesSelector(doc, selector)) {
13927
+ if (skipped < skip) {
13928
+ skipped++;
13929
+ continue;
13930
+ }
13931
+ documents.push(doc);
13932
+ if (limit && documents.length >= limit) {
13933
+ break;
13934
+ }
13935
+ }
13526
13936
  }
13527
13937
  return { documents };
13528
13938
  }