bun-sqlite-for-rxdb 1.3.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +349 -115
- package/dist/src/instance.d.ts +0 -1
- package/dist/src/query/builder.d.ts +1 -0
- package/dist/src/query/lightweight-matcher.d.ts +3 -0
- package/dist/src/query/operators.d.ts +11 -11
- package/dist/src/query/schema-mapper.d.ts +1 -1
- package/package.json +5 -3
- package/CHANGELOG.md +0 -722
package/dist/index.js
CHANGED
|
@@ -12254,6 +12254,13 @@ function getColumnInfo(path2, schema) {
|
|
|
12254
12254
|
if (path2 === schema.primaryKey) {
|
|
12255
12255
|
return { column: "id", type: "string" };
|
|
12256
12256
|
}
|
|
12257
|
+
const properties = schema.properties;
|
|
12258
|
+
const fieldSchema = properties?.[path2];
|
|
12259
|
+
if (fieldSchema && typeof fieldSchema === "object" && "type" in fieldSchema) {
|
|
12260
|
+
if (fieldSchema.type === "array") {
|
|
12261
|
+
return { jsonPath: `$.${path2}`, type: "array" };
|
|
12262
|
+
}
|
|
12263
|
+
}
|
|
12257
12264
|
return { jsonPath: `$.${path2}`, type: "unknown" };
|
|
12258
12265
|
}
|
|
12259
12266
|
|
|
@@ -12342,31 +12349,85 @@ function smartRegexToLike(field, pattern, options, schema, fieldName) {
|
|
|
12342
12349
|
}
|
|
12343
12350
|
|
|
12344
12351
|
// src/query/operators.ts
|
|
12345
|
-
function translateEq(field, value) {
|
|
12352
|
+
function translateEq(field, value, schema, actualFieldName) {
|
|
12346
12353
|
if (value === null) {
|
|
12347
12354
|
return { sql: `${field} IS NULL`, args: [] };
|
|
12348
12355
|
}
|
|
12356
|
+
if (schema && actualFieldName) {
|
|
12357
|
+
const columnInfo = getColumnInfo(actualFieldName, schema);
|
|
12358
|
+
if (field !== "value" && columnInfo.type === "array") {
|
|
12359
|
+
return {
|
|
12360
|
+
sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value = ?)`,
|
|
12361
|
+
args: [value]
|
|
12362
|
+
};
|
|
12363
|
+
}
|
|
12364
|
+
}
|
|
12349
12365
|
return { sql: `${field} = ?`, args: [value] };
|
|
12350
12366
|
}
|
|
12351
|
-
function translateNe(field, value) {
|
|
12367
|
+
function translateNe(field, value, schema, actualFieldName) {
|
|
12352
12368
|
if (value === null) {
|
|
12353
12369
|
return { sql: `${field} IS NOT NULL`, args: [] };
|
|
12354
12370
|
}
|
|
12355
|
-
|
|
12371
|
+
if (schema && actualFieldName) {
|
|
12372
|
+
const columnInfo = getColumnInfo(actualFieldName, schema);
|
|
12373
|
+
if (field !== "value" && columnInfo.type === "array") {
|
|
12374
|
+
return {
|
|
12375
|
+
sql: `NOT EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value = ?)`,
|
|
12376
|
+
args: [value]
|
|
12377
|
+
};
|
|
12378
|
+
}
|
|
12379
|
+
}
|
|
12380
|
+
return { sql: `(${field} <> ? OR ${field} IS NULL)`, args: [value] };
|
|
12356
12381
|
}
|
|
12357
|
-
function translateGt(field, value) {
|
|
12382
|
+
function translateGt(field, value, schema, actualFieldName) {
|
|
12383
|
+
if (schema && actualFieldName) {
|
|
12384
|
+
const columnInfo = getColumnInfo(actualFieldName, schema);
|
|
12385
|
+
if (field !== "value" && columnInfo.type === "array") {
|
|
12386
|
+
return {
|
|
12387
|
+
sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value > ?)`,
|
|
12388
|
+
args: [value]
|
|
12389
|
+
};
|
|
12390
|
+
}
|
|
12391
|
+
}
|
|
12358
12392
|
return { sql: `${field} > ?`, args: [value] };
|
|
12359
12393
|
}
|
|
12360
|
-
function translateGte(field, value) {
|
|
12394
|
+
function translateGte(field, value, schema, actualFieldName) {
|
|
12395
|
+
if (schema && actualFieldName) {
|
|
12396
|
+
const columnInfo = getColumnInfo(actualFieldName, schema);
|
|
12397
|
+
if (field !== "value" && columnInfo.type === "array") {
|
|
12398
|
+
return {
|
|
12399
|
+
sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value >= ?)`,
|
|
12400
|
+
args: [value]
|
|
12401
|
+
};
|
|
12402
|
+
}
|
|
12403
|
+
}
|
|
12361
12404
|
return { sql: `${field} >= ?`, args: [value] };
|
|
12362
12405
|
}
|
|
12363
|
-
function translateLt(field, value) {
|
|
12406
|
+
function translateLt(field, value, schema, actualFieldName) {
|
|
12407
|
+
if (schema && actualFieldName) {
|
|
12408
|
+
const columnInfo = getColumnInfo(actualFieldName, schema);
|
|
12409
|
+
if (field !== "value" && columnInfo.type === "array") {
|
|
12410
|
+
return {
|
|
12411
|
+
sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value < ?)`,
|
|
12412
|
+
args: [value]
|
|
12413
|
+
};
|
|
12414
|
+
}
|
|
12415
|
+
}
|
|
12364
12416
|
return { sql: `${field} < ?`, args: [value] };
|
|
12365
12417
|
}
|
|
12366
|
-
function translateLte(field, value) {
|
|
12418
|
+
function translateLte(field, value, schema, actualFieldName) {
|
|
12419
|
+
if (schema && actualFieldName) {
|
|
12420
|
+
const columnInfo = getColumnInfo(actualFieldName, schema);
|
|
12421
|
+
if (field !== "value" && columnInfo.type === "array") {
|
|
12422
|
+
return {
|
|
12423
|
+
sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value <= ?)`,
|
|
12424
|
+
args: [value]
|
|
12425
|
+
};
|
|
12426
|
+
}
|
|
12427
|
+
}
|
|
12367
12428
|
return { sql: `${field} <= ?`, args: [value] };
|
|
12368
12429
|
}
|
|
12369
|
-
function translateIn(field, values) {
|
|
12430
|
+
function translateIn(field, values, schema, actualFieldName) {
|
|
12370
12431
|
if (!Array.isArray(values) || values.length === 0) {
|
|
12371
12432
|
return { sql: "1=0", args: [] };
|
|
12372
12433
|
}
|
|
@@ -12375,17 +12436,31 @@ function translateIn(field, values) {
|
|
|
12375
12436
|
if (nonNullValues.length === 0) {
|
|
12376
12437
|
return { sql: `${field} IS NULL`, args: [] };
|
|
12377
12438
|
}
|
|
12378
|
-
|
|
12379
|
-
|
|
12439
|
+
if (schema && actualFieldName) {
|
|
12440
|
+
const columnInfo = getColumnInfo(actualFieldName, schema);
|
|
12441
|
+
if (field !== "value" && columnInfo.type === "array") {
|
|
12442
|
+
const inClause2 = `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value IN (SELECT value FROM json_each(?)))`;
|
|
12443
|
+
const args2 = [JSON.stringify(nonNullValues)];
|
|
12444
|
+
if (hasNull) {
|
|
12445
|
+
return {
|
|
12446
|
+
sql: `(${inClause2} OR ${field} IS NULL)`,
|
|
12447
|
+
args: args2
|
|
12448
|
+
};
|
|
12449
|
+
}
|
|
12450
|
+
return { sql: inClause2, args: args2 };
|
|
12451
|
+
}
|
|
12452
|
+
}
|
|
12453
|
+
const inClause = `${field} IN (SELECT value FROM json_each(?))`;
|
|
12454
|
+
const args = [JSON.stringify(nonNullValues)];
|
|
12380
12455
|
if (hasNull) {
|
|
12381
12456
|
return {
|
|
12382
12457
|
sql: `(${inClause} OR ${field} IS NULL)`,
|
|
12383
|
-
args
|
|
12458
|
+
args
|
|
12384
12459
|
};
|
|
12385
12460
|
}
|
|
12386
|
-
return { sql: inClause, args
|
|
12461
|
+
return { sql: inClause, args };
|
|
12387
12462
|
}
|
|
12388
|
-
function translateNin(field, values) {
|
|
12463
|
+
function translateNin(field, values, schema, actualFieldName) {
|
|
12389
12464
|
if (!Array.isArray(values) || values.length === 0) {
|
|
12390
12465
|
return { sql: "1=1", args: [] };
|
|
12391
12466
|
}
|
|
@@ -12394,15 +12469,29 @@ function translateNin(field, values) {
|
|
|
12394
12469
|
if (nonNullValues.length === 0) {
|
|
12395
12470
|
return { sql: `${field} IS NOT NULL`, args: [] };
|
|
12396
12471
|
}
|
|
12397
|
-
|
|
12398
|
-
|
|
12472
|
+
if (schema && actualFieldName) {
|
|
12473
|
+
const columnInfo = getColumnInfo(actualFieldName, schema);
|
|
12474
|
+
if (field !== "value" && columnInfo.type === "array") {
|
|
12475
|
+
const ninClause2 = `NOT EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value IN (SELECT value FROM json_each(?)))`;
|
|
12476
|
+
const args2 = [JSON.stringify(nonNullValues)];
|
|
12477
|
+
if (hasNull) {
|
|
12478
|
+
return {
|
|
12479
|
+
sql: `(${ninClause2} AND ${field} IS NOT NULL)`,
|
|
12480
|
+
args: args2
|
|
12481
|
+
};
|
|
12482
|
+
}
|
|
12483
|
+
return { sql: ninClause2, args: args2 };
|
|
12484
|
+
}
|
|
12485
|
+
}
|
|
12486
|
+
const ninClause = `${field} NOT IN (SELECT value FROM json_each(?))`;
|
|
12487
|
+
const args = [JSON.stringify(nonNullValues)];
|
|
12399
12488
|
if (hasNull) {
|
|
12400
12489
|
return {
|
|
12401
12490
|
sql: `(${ninClause} AND ${field} IS NOT NULL)`,
|
|
12402
|
-
args
|
|
12491
|
+
args
|
|
12403
12492
|
};
|
|
12404
12493
|
}
|
|
12405
|
-
return { sql: ninClause, args
|
|
12494
|
+
return { sql: ninClause, args };
|
|
12406
12495
|
}
|
|
12407
12496
|
function translateExists(field, exists) {
|
|
12408
12497
|
return {
|
|
@@ -12416,17 +12505,18 @@ function translateRegex(field, pattern, options, schema, fieldName) {
|
|
|
12416
12505
|
return smartResult;
|
|
12417
12506
|
return null;
|
|
12418
12507
|
}
|
|
12419
|
-
function buildElemMatchConditions(criteria) {
|
|
12508
|
+
function buildElemMatchConditions(criteria, schema, baseFieldName) {
|
|
12420
12509
|
const conditions = [];
|
|
12421
12510
|
const args = [];
|
|
12422
12511
|
for (const [key, value] of Object.entries(criteria)) {
|
|
12423
12512
|
if (key.startsWith("$")) {
|
|
12424
|
-
const fragment = processOperatorValue("
|
|
12513
|
+
const fragment = processOperatorValue("value", { [key]: value }, schema, baseFieldName);
|
|
12425
12514
|
conditions.push(fragment.sql);
|
|
12426
12515
|
args.push(...fragment.args);
|
|
12427
12516
|
} else {
|
|
12428
|
-
const propertyField = `json_extract(
|
|
12429
|
-
const
|
|
12517
|
+
const propertyField = `json_extract(value, '$.${key}')`;
|
|
12518
|
+
const nestedFieldName = `${baseFieldName}.${key}`;
|
|
12519
|
+
const fragment = processOperatorValue(propertyField, value, schema, nestedFieldName);
|
|
12430
12520
|
conditions.push(fragment.sql);
|
|
12431
12521
|
args.push(...fragment.args);
|
|
12432
12522
|
}
|
|
@@ -12436,73 +12526,74 @@ function buildElemMatchConditions(criteria) {
|
|
|
12436
12526
|
args
|
|
12437
12527
|
};
|
|
12438
12528
|
}
|
|
12439
|
-
function translateElemMatch(field, criteria) {
|
|
12529
|
+
function translateElemMatch(field, criteria, schema, actualFieldName) {
|
|
12530
|
+
if (typeof criteria === "object" && criteria !== null && !Array.isArray(criteria) && Object.keys(criteria).length === 0) {
|
|
12531
|
+
return { sql: "1=0", args: [] };
|
|
12532
|
+
}
|
|
12440
12533
|
if (typeof criteria !== "object" || criteria === null) {
|
|
12441
12534
|
return {
|
|
12442
|
-
sql: `EXISTS (SELECT 1 FROM
|
|
12535
|
+
sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE value = ?)`,
|
|
12443
12536
|
args: [criteria]
|
|
12444
12537
|
};
|
|
12445
12538
|
}
|
|
12446
12539
|
if (criteria.$and && Array.isArray(criteria.$and)) {
|
|
12447
|
-
const fragments = criteria.$and.map((cond) => buildElemMatchConditions(cond));
|
|
12540
|
+
const fragments = criteria.$and.map((cond) => buildElemMatchConditions(cond, schema, actualFieldName));
|
|
12448
12541
|
const sql = fragments.map((f) => f.sql).join(" AND ");
|
|
12449
12542
|
const args = fragments.flatMap((f) => f.args);
|
|
12450
12543
|
return {
|
|
12451
|
-
sql: `EXISTS (SELECT 1 FROM
|
|
12544
|
+
sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE ${sql})`,
|
|
12452
12545
|
args
|
|
12453
12546
|
};
|
|
12454
12547
|
}
|
|
12455
12548
|
if (criteria.$or && Array.isArray(criteria.$or)) {
|
|
12456
|
-
const fragments = criteria.$or.map((cond) => buildElemMatchConditions(cond));
|
|
12549
|
+
const fragments = criteria.$or.map((cond) => buildElemMatchConditions(cond, schema, actualFieldName));
|
|
12457
12550
|
const sql = fragments.map((f) => f.sql).join(" OR ");
|
|
12458
12551
|
const args = fragments.flatMap((f) => f.args);
|
|
12459
12552
|
return {
|
|
12460
|
-
sql: `EXISTS (SELECT 1 FROM
|
|
12553
|
+
sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE ${sql})`,
|
|
12461
12554
|
args
|
|
12462
12555
|
};
|
|
12463
12556
|
}
|
|
12464
12557
|
if (criteria.$nor && Array.isArray(criteria.$nor)) {
|
|
12465
|
-
const fragments = criteria.$nor.map((cond) => buildElemMatchConditions(cond));
|
|
12558
|
+
const fragments = criteria.$nor.map((cond) => buildElemMatchConditions(cond, schema, actualFieldName));
|
|
12466
12559
|
const sql = fragments.map((f) => f.sql).join(" OR ");
|
|
12467
12560
|
const args = fragments.flatMap((f) => f.args);
|
|
12468
12561
|
return {
|
|
12469
|
-
sql: `EXISTS (SELECT 1 FROM
|
|
12562
|
+
sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE NOT (${sql}))`,
|
|
12470
12563
|
args
|
|
12471
12564
|
};
|
|
12472
12565
|
}
|
|
12473
|
-
const fragment = buildElemMatchConditions(criteria);
|
|
12474
|
-
if (fragment.sql === "1=1") {
|
|
12475
|
-
return null;
|
|
12476
|
-
}
|
|
12566
|
+
const fragment = buildElemMatchConditions(criteria, schema, actualFieldName);
|
|
12477
12567
|
return {
|
|
12478
|
-
sql: `EXISTS (SELECT 1 FROM
|
|
12568
|
+
sql: `EXISTS (SELECT 1 FROM jsonb_each(${field}) WHERE ${fragment.sql})`,
|
|
12479
12569
|
args: fragment.args
|
|
12480
12570
|
};
|
|
12481
12571
|
}
|
|
12482
|
-
function processOperatorValue(field, value) {
|
|
12572
|
+
function processOperatorValue(field, value, schema, actualFieldName) {
|
|
12483
12573
|
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
12484
12574
|
const [[op, opValue]] = Object.entries(value);
|
|
12485
12575
|
if (!op.startsWith("$")) {
|
|
12486
12576
|
const jsonPath = `json_extract(${field}, '$.${op}')`;
|
|
12487
|
-
|
|
12577
|
+
const nestedFieldName = `${actualFieldName}.${op}`;
|
|
12578
|
+
return translateEq(jsonPath, opValue, schema, nestedFieldName);
|
|
12488
12579
|
}
|
|
12489
12580
|
switch (op) {
|
|
12490
12581
|
case "$eq":
|
|
12491
|
-
return translateEq(field, opValue);
|
|
12582
|
+
return translateEq(field, opValue, schema, actualFieldName);
|
|
12492
12583
|
case "$ne":
|
|
12493
|
-
return translateNe(field, opValue);
|
|
12584
|
+
return translateNe(field, opValue, schema, actualFieldName);
|
|
12494
12585
|
case "$gt":
|
|
12495
|
-
return translateGt(field, opValue);
|
|
12586
|
+
return translateGt(field, opValue, schema, actualFieldName);
|
|
12496
12587
|
case "$gte":
|
|
12497
|
-
return translateGte(field, opValue);
|
|
12588
|
+
return translateGte(field, opValue, schema, actualFieldName);
|
|
12498
12589
|
case "$lt":
|
|
12499
|
-
return translateLt(field, opValue);
|
|
12590
|
+
return translateLt(field, opValue, schema, actualFieldName);
|
|
12500
12591
|
case "$lte":
|
|
12501
|
-
return translateLte(field, opValue);
|
|
12592
|
+
return translateLte(field, opValue, schema, actualFieldName);
|
|
12502
12593
|
case "$in":
|
|
12503
|
-
return translateIn(field, opValue);
|
|
12594
|
+
return translateIn(field, opValue, schema, actualFieldName);
|
|
12504
12595
|
case "$nin":
|
|
12505
|
-
return translateNin(field, opValue);
|
|
12596
|
+
return translateNin(field, opValue, schema, actualFieldName);
|
|
12506
12597
|
case "$exists":
|
|
12507
12598
|
return translateExists(field, opValue);
|
|
12508
12599
|
case "$size":
|
|
@@ -12510,48 +12601,96 @@ function processOperatorValue(field, value) {
|
|
|
12510
12601
|
case "$mod": {
|
|
12511
12602
|
const result = translateMod(field, opValue);
|
|
12512
12603
|
if (!result)
|
|
12513
|
-
return translateEq(field, opValue);
|
|
12604
|
+
return translateEq(field, opValue, schema, actualFieldName);
|
|
12514
12605
|
return result;
|
|
12515
12606
|
}
|
|
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
|
+
}
|
|
12626
|
+
}
|
|
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: [] };
|
|
12646
|
+
}
|
|
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
|
+
}
|
|
12516
12654
|
case "$not": {
|
|
12517
|
-
const result = translateNot(field, opValue);
|
|
12655
|
+
const result = translateNot(field, opValue, schema, actualFieldName);
|
|
12518
12656
|
if (!result)
|
|
12519
|
-
return translateEq(field, opValue);
|
|
12657
|
+
return translateEq(field, opValue, schema, actualFieldName);
|
|
12520
12658
|
return result;
|
|
12521
12659
|
}
|
|
12522
12660
|
case "$and": {
|
|
12523
12661
|
if (!Array.isArray(opValue))
|
|
12524
|
-
return translateEq(field, opValue);
|
|
12525
|
-
const fragments = opValue.map((v) => processOperatorValue(field, v));
|
|
12662
|
+
return translateEq(field, opValue, schema, actualFieldName);
|
|
12663
|
+
const fragments = opValue.map((v) => processOperatorValue(field, v, schema, actualFieldName));
|
|
12526
12664
|
const sql = fragments.map((f) => f.sql).join(" AND ");
|
|
12527
12665
|
const args = fragments.flatMap((f) => f.args);
|
|
12528
12666
|
return { sql: `(${sql})`, args };
|
|
12529
12667
|
}
|
|
12530
12668
|
case "$or": {
|
|
12531
12669
|
if (!Array.isArray(opValue))
|
|
12532
|
-
return translateEq(field, opValue);
|
|
12533
|
-
const fragments = opValue.map((v) => processOperatorValue(field, v));
|
|
12670
|
+
return translateEq(field, opValue, schema, actualFieldName);
|
|
12671
|
+
const fragments = opValue.map((v) => processOperatorValue(field, v, schema, actualFieldName));
|
|
12534
12672
|
const sql = fragments.map((f) => f.sql).join(" OR ");
|
|
12535
12673
|
const args = fragments.flatMap((f) => f.args);
|
|
12536
12674
|
return { sql: `(${sql})`, args };
|
|
12537
12675
|
}
|
|
12538
12676
|
default:
|
|
12539
|
-
return translateEq(field, opValue);
|
|
12677
|
+
return translateEq(field, opValue, schema, actualFieldName);
|
|
12540
12678
|
}
|
|
12541
12679
|
}
|
|
12542
|
-
return translateEq(field, value);
|
|
12680
|
+
return translateEq(field, value, schema, actualFieldName);
|
|
12543
12681
|
}
|
|
12544
|
-
function translateNot(field, criteria) {
|
|
12545
|
-
if (
|
|
12546
|
-
return
|
|
12547
|
-
|
|
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);
|
|
12548
12687
|
return {
|
|
12549
|
-
sql: `NOT(${inner.sql})`,
|
|
12688
|
+
sql: `NOT (${inner.sql})`,
|
|
12550
12689
|
args: inner.args
|
|
12551
12690
|
};
|
|
12552
12691
|
}
|
|
12553
|
-
function translateType(jsonColumn, fieldName, type6) {
|
|
12554
|
-
const jsonPath = `$.${fieldName}`;
|
|
12692
|
+
function translateType(jsonColumn, fieldName, type6, isDirectPath = false) {
|
|
12693
|
+
const jsonPath = isDirectPath ? fieldName : `$.${fieldName}`;
|
|
12555
12694
|
switch (type6) {
|
|
12556
12695
|
case "null":
|
|
12557
12696
|
return { sql: `json_type(${jsonColumn}, '${jsonPath}') = 'null'`, args: [] };
|
|
@@ -12566,7 +12705,7 @@ function translateType(jsonColumn, fieldName, type6) {
|
|
|
12566
12705
|
case "object":
|
|
12567
12706
|
return { sql: `json_type(${jsonColumn}, '${jsonPath}') = 'object'`, args: [] };
|
|
12568
12707
|
default:
|
|
12569
|
-
return
|
|
12708
|
+
return { sql: "1=0", args: [] };
|
|
12570
12709
|
}
|
|
12571
12710
|
}
|
|
12572
12711
|
function translateSize(field, size) {
|
|
@@ -12577,11 +12716,11 @@ function translateSize(field, size) {
|
|
|
12577
12716
|
}
|
|
12578
12717
|
function translateMod(field, value) {
|
|
12579
12718
|
if (!Array.isArray(value) || value.length !== 2)
|
|
12580
|
-
return
|
|
12719
|
+
return { sql: "1=0", args: [] };
|
|
12581
12720
|
const [divisor, remainder] = value;
|
|
12582
12721
|
return {
|
|
12583
|
-
sql:
|
|
12584
|
-
args: [divisor, remainder]
|
|
12722
|
+
sql: `(${field} - (CAST(${field} / ? AS INTEGER) * ?)) = ?`,
|
|
12723
|
+
args: [divisor, divisor, remainder]
|
|
12585
12724
|
};
|
|
12586
12725
|
}
|
|
12587
12726
|
|
|
@@ -12708,12 +12847,12 @@ function buildWhereClause(selector, schema, collectionName) {
|
|
|
12708
12847
|
}
|
|
12709
12848
|
function buildLogicalOperator(operator, conditions, schema, logicalDepth) {
|
|
12710
12849
|
if (conditions.length === 0) {
|
|
12711
|
-
return { sql: "1=1", args: [] };
|
|
12850
|
+
return { sql: operator === "or" ? "1=0" : "1=1", args: [] };
|
|
12712
12851
|
}
|
|
12713
12852
|
const fragments = conditions.map((subSelector) => processSelector(subSelector, schema, logicalDepth + 1));
|
|
12714
12853
|
if (fragments.some((f) => f === null))
|
|
12715
12854
|
return null;
|
|
12716
|
-
const sql = fragments.map((f) => f.sql).join(" OR ");
|
|
12855
|
+
const sql = fragments.map((f) => `(${f.sql})`).join(" OR ");
|
|
12717
12856
|
const args = fragments.flatMap((f) => f.args);
|
|
12718
12857
|
return operator === "nor" ? { sql: `NOT(${sql})`, args } : { sql, args };
|
|
12719
12858
|
}
|
|
@@ -12738,8 +12877,7 @@ function processSelector(selector, schema, logicalDepth) {
|
|
|
12738
12877
|
const orFragment = buildLogicalOperator("or", value, schema, logicalDepth);
|
|
12739
12878
|
if (!orFragment)
|
|
12740
12879
|
return null;
|
|
12741
|
-
|
|
12742
|
-
conditions.push(needsParens ? `(${orFragment.sql})` : orFragment.sql);
|
|
12880
|
+
conditions.push(`(${orFragment.sql})`);
|
|
12743
12881
|
args.push(...orFragment.args);
|
|
12744
12882
|
continue;
|
|
12745
12883
|
}
|
|
@@ -12755,32 +12893,35 @@ function processSelector(selector, schema, logicalDepth) {
|
|
|
12755
12893
|
const fieldName = columnInfo.column || `json_extract(data, '${columnInfo.jsonPath}')`;
|
|
12756
12894
|
const actualFieldName = columnInfo.jsonPath?.replace(/^\$\./, "") || columnInfo.column || field;
|
|
12757
12895
|
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
12896
|
+
if (Object.keys(value).length === 0) {
|
|
12897
|
+
return { sql: "1=0", args: [] };
|
|
12898
|
+
}
|
|
12758
12899
|
for (const [op, opValue] of Object.entries(value)) {
|
|
12759
12900
|
let fragment;
|
|
12760
12901
|
switch (op) {
|
|
12761
12902
|
case "$eq":
|
|
12762
|
-
fragment = translateEq(fieldName, opValue);
|
|
12903
|
+
fragment = translateEq(fieldName, opValue, schema, actualFieldName);
|
|
12763
12904
|
break;
|
|
12764
12905
|
case "$ne":
|
|
12765
|
-
fragment = translateNe(fieldName, opValue);
|
|
12906
|
+
fragment = translateNe(fieldName, opValue, schema, actualFieldName);
|
|
12766
12907
|
break;
|
|
12767
12908
|
case "$gt":
|
|
12768
|
-
fragment = translateGt(fieldName, opValue);
|
|
12909
|
+
fragment = translateGt(fieldName, opValue, schema, actualFieldName);
|
|
12769
12910
|
break;
|
|
12770
12911
|
case "$gte":
|
|
12771
|
-
fragment = translateGte(fieldName, opValue);
|
|
12912
|
+
fragment = translateGte(fieldName, opValue, schema, actualFieldName);
|
|
12772
12913
|
break;
|
|
12773
12914
|
case "$lt":
|
|
12774
|
-
fragment = translateLt(fieldName, opValue);
|
|
12915
|
+
fragment = translateLt(fieldName, opValue, schema, actualFieldName);
|
|
12775
12916
|
break;
|
|
12776
12917
|
case "$lte":
|
|
12777
|
-
fragment = translateLte(fieldName, opValue);
|
|
12918
|
+
fragment = translateLte(fieldName, opValue, schema, actualFieldName);
|
|
12778
12919
|
break;
|
|
12779
12920
|
case "$in":
|
|
12780
|
-
fragment = translateIn(fieldName, opValue);
|
|
12921
|
+
fragment = translateIn(fieldName, opValue, schema, actualFieldName);
|
|
12781
12922
|
break;
|
|
12782
12923
|
case "$nin":
|
|
12783
|
-
fragment = translateNin(fieldName, opValue);
|
|
12924
|
+
fragment = translateNin(fieldName, opValue, schema, actualFieldName);
|
|
12784
12925
|
break;
|
|
12785
12926
|
case "$exists":
|
|
12786
12927
|
fragment = translateExists(fieldName, opValue);
|
|
@@ -12793,13 +12934,13 @@ function processSelector(selector, schema, logicalDepth) {
|
|
|
12793
12934
|
fragment = regexFragment;
|
|
12794
12935
|
break;
|
|
12795
12936
|
case "$elemMatch":
|
|
12796
|
-
const elemMatchFragment = translateElemMatch(fieldName, opValue);
|
|
12937
|
+
const elemMatchFragment = translateElemMatch(fieldName, opValue, schema, actualFieldName);
|
|
12797
12938
|
if (!elemMatchFragment)
|
|
12798
12939
|
return null;
|
|
12799
12940
|
fragment = elemMatchFragment;
|
|
12800
12941
|
break;
|
|
12801
12942
|
case "$not": {
|
|
12802
|
-
const notResult = translateNot(fieldName, opValue);
|
|
12943
|
+
const notResult = translateNot(fieldName, opValue, schema, actualFieldName);
|
|
12803
12944
|
if (!notResult)
|
|
12804
12945
|
return null;
|
|
12805
12946
|
fragment = notResult;
|
|
@@ -12828,7 +12969,7 @@ function processSelector(selector, schema, logicalDepth) {
|
|
|
12828
12969
|
args.push(...fragment.args);
|
|
12829
12970
|
}
|
|
12830
12971
|
} else {
|
|
12831
|
-
const fragment = translateEq(fieldName, value);
|
|
12972
|
+
const fragment = translateEq(fieldName, value, schema, actualFieldName);
|
|
12832
12973
|
conditions.push(fragment.sql);
|
|
12833
12974
|
args.push(...fragment.args);
|
|
12834
12975
|
}
|
|
@@ -12837,6 +12978,100 @@ function processSelector(selector, schema, logicalDepth) {
|
|
|
12837
12978
|
return { sql: where, args };
|
|
12838
12979
|
}
|
|
12839
12980
|
|
|
12981
|
+
// src/query/lightweight-matcher.ts
|
|
12982
|
+
var operators = {
|
|
12983
|
+
$eq: (a, b) => a === b,
|
|
12984
|
+
$ne: (a, b) => a !== b,
|
|
12985
|
+
$gt: (a, b) => a > b,
|
|
12986
|
+
$gte: (a, b) => a >= b,
|
|
12987
|
+
$lt: (a, b) => a < b,
|
|
12988
|
+
$lte: (a, b) => a <= b,
|
|
12989
|
+
$in: (a, b) => Array.isArray(b) && b.some((v) => v === a),
|
|
12990
|
+
$nin: (a, b) => Array.isArray(b) && !b.some((v) => v === a),
|
|
12991
|
+
$exists: (a, b) => a !== undefined === b,
|
|
12992
|
+
$type: (a, b) => {
|
|
12993
|
+
const type6 = Array.isArray(a) ? "array" : typeof a;
|
|
12994
|
+
return type6 === b;
|
|
12995
|
+
},
|
|
12996
|
+
$mod: (a, b) => {
|
|
12997
|
+
if (!Array.isArray(b) || b.length !== 2)
|
|
12998
|
+
return false;
|
|
12999
|
+
const [divisor, remainder] = b;
|
|
13000
|
+
return typeof a === "number" && a % divisor === remainder;
|
|
13001
|
+
},
|
|
13002
|
+
$size: (a, b) => Array.isArray(a) && a.length === b
|
|
13003
|
+
};
|
|
13004
|
+
function getNestedValue(obj, path2) {
|
|
13005
|
+
return path2.split(".").reduce((current, key) => current?.[key], obj);
|
|
13006
|
+
}
|
|
13007
|
+
function matchesSelector(doc, selector) {
|
|
13008
|
+
if (!selector || typeof selector !== "object")
|
|
13009
|
+
return true;
|
|
13010
|
+
if (selector.$and) {
|
|
13011
|
+
return Array.isArray(selector.$and) && selector.$and.every((s) => matchesSelector(doc, s));
|
|
13012
|
+
}
|
|
13013
|
+
if (selector.$or) {
|
|
13014
|
+
return Array.isArray(selector.$or) && selector.$or.some((s) => matchesSelector(doc, s));
|
|
13015
|
+
}
|
|
13016
|
+
if (selector.$nor) {
|
|
13017
|
+
return Array.isArray(selector.$nor) && !selector.$nor.some((s) => matchesSelector(doc, s));
|
|
13018
|
+
}
|
|
13019
|
+
for (const [field, condition] of Object.entries(selector)) {
|
|
13020
|
+
const value = getNestedValue(doc, field);
|
|
13021
|
+
if (typeof condition !== "object" || condition === null || Array.isArray(condition)) {
|
|
13022
|
+
if (value !== condition)
|
|
13023
|
+
return false;
|
|
13024
|
+
continue;
|
|
13025
|
+
}
|
|
13026
|
+
for (const [op, opValue] of Object.entries(condition)) {
|
|
13027
|
+
if (op === "$regex") {
|
|
13028
|
+
const options = condition.$options;
|
|
13029
|
+
if (!matchesRegex(value, opValue, options))
|
|
13030
|
+
return false;
|
|
13031
|
+
continue;
|
|
13032
|
+
}
|
|
13033
|
+
if (op === "$not") {
|
|
13034
|
+
if (matchesOperator(value, opValue))
|
|
13035
|
+
return false;
|
|
13036
|
+
continue;
|
|
13037
|
+
}
|
|
13038
|
+
if (op === "$elemMatch") {
|
|
13039
|
+
if (!Array.isArray(value))
|
|
13040
|
+
return false;
|
|
13041
|
+
const hasMatch = value.some((item) => matchesSelector(item, opValue));
|
|
13042
|
+
if (!hasMatch)
|
|
13043
|
+
return false;
|
|
13044
|
+
continue;
|
|
13045
|
+
}
|
|
13046
|
+
if (op === "$options")
|
|
13047
|
+
continue;
|
|
13048
|
+
const operator = operators[op];
|
|
13049
|
+
if (!operator)
|
|
13050
|
+
return false;
|
|
13051
|
+
if (!operator(value, opValue))
|
|
13052
|
+
return false;
|
|
13053
|
+
}
|
|
13054
|
+
}
|
|
13055
|
+
return true;
|
|
13056
|
+
}
|
|
13057
|
+
function matchesOperator(value, operator) {
|
|
13058
|
+
if (typeof operator !== "object" || operator === null) {
|
|
13059
|
+
return value === operator;
|
|
13060
|
+
}
|
|
13061
|
+
for (const [op, opValue] of Object.entries(operator)) {
|
|
13062
|
+
if (op === "$regex") {
|
|
13063
|
+
const options = operator.$options;
|
|
13064
|
+
return matchesRegex(value, opValue, options);
|
|
13065
|
+
}
|
|
13066
|
+
const operatorFn = operators[op];
|
|
13067
|
+
if (!operatorFn)
|
|
13068
|
+
return false;
|
|
13069
|
+
if (operatorFn(value, opValue))
|
|
13070
|
+
return true;
|
|
13071
|
+
}
|
|
13072
|
+
return false;
|
|
13073
|
+
}
|
|
13074
|
+
|
|
12840
13075
|
// src/rxdb-helpers.ts
|
|
12841
13076
|
function randomToken2(length) {
|
|
12842
13077
|
return Math.random().toString(36).substring(2, 2 + length);
|
|
@@ -13375,6 +13610,9 @@ class BunSQLiteStorageInstance {
|
|
|
13375
13610
|
queryArgs.push(preparedQuery.query.limit);
|
|
13376
13611
|
}
|
|
13377
13612
|
if (preparedQuery.query.skip) {
|
|
13613
|
+
if (!preparedQuery.query.limit) {
|
|
13614
|
+
sql += ` LIMIT -1`;
|
|
13615
|
+
}
|
|
13378
13616
|
sql += ` OFFSET ?`;
|
|
13379
13617
|
queryArgs.push(preparedQuery.query.skip);
|
|
13380
13618
|
}
|
|
@@ -13389,31 +13627,6 @@ class BunSQLiteStorageInstance {
|
|
|
13389
13627
|
const documents = rows.map((row) => JSON.parse(row.data));
|
|
13390
13628
|
return { documents };
|
|
13391
13629
|
}
|
|
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
13630
|
sortDocuments(docs, sort) {
|
|
13418
13631
|
return docs.sort((a, b) => {
|
|
13419
13632
|
for (const sortField of sort) {
|
|
@@ -13512,17 +13725,38 @@ class BunSQLiteStorageInstance {
|
|
|
13512
13725
|
}
|
|
13513
13726
|
queryWithOurMemory(preparedQuery) {
|
|
13514
13727
|
const query = `SELECT json(data) as data FROM "${this.tableName}"`;
|
|
13515
|
-
const
|
|
13516
|
-
|
|
13517
|
-
|
|
13518
|
-
|
|
13519
|
-
|
|
13520
|
-
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
|
|
13524
|
-
|
|
13525
|
-
|
|
13728
|
+
const selector = preparedQuery.query.selector;
|
|
13729
|
+
const hasSort = preparedQuery.query.sort && preparedQuery.query.sort.length > 0;
|
|
13730
|
+
if (hasSort) {
|
|
13731
|
+
const rows = this.stmtManager.all({ query, params: [] });
|
|
13732
|
+
let documents2 = rows.map((row) => JSON.parse(row.data));
|
|
13733
|
+
documents2 = documents2.filter((doc) => matchesSelector(doc, selector));
|
|
13734
|
+
documents2 = this.sortDocuments(documents2, preparedQuery.query.sort);
|
|
13735
|
+
if (preparedQuery.query.skip) {
|
|
13736
|
+
documents2 = documents2.slice(preparedQuery.query.skip);
|
|
13737
|
+
}
|
|
13738
|
+
if (preparedQuery.query.limit) {
|
|
13739
|
+
documents2 = documents2.slice(0, preparedQuery.query.limit);
|
|
13740
|
+
}
|
|
13741
|
+
return { documents: documents2 };
|
|
13742
|
+
}
|
|
13743
|
+
const stmt = this.db.prepare(query);
|
|
13744
|
+
const documents = [];
|
|
13745
|
+
const skip = preparedQuery.query.skip || 0;
|
|
13746
|
+
const limit = preparedQuery.query.limit;
|
|
13747
|
+
let skipped = 0;
|
|
13748
|
+
for (const row of stmt.iterate()) {
|
|
13749
|
+
const doc = JSON.parse(row.data);
|
|
13750
|
+
if (matchesSelector(doc, selector)) {
|
|
13751
|
+
if (skipped < skip) {
|
|
13752
|
+
skipped++;
|
|
13753
|
+
continue;
|
|
13754
|
+
}
|
|
13755
|
+
documents.push(doc);
|
|
13756
|
+
if (limit && documents.length >= limit) {
|
|
13757
|
+
break;
|
|
13758
|
+
}
|
|
13759
|
+
}
|
|
13526
13760
|
}
|
|
13527
13761
|
return { documents };
|
|
13528
13762
|
}
|