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