@objectstack/driver-memory 3.2.0 → 3.2.2
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/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +24 -0
- package/dist/index.d.mts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +102 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +102 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/memory-driver.test.ts +128 -0
- package/src/memory-driver.ts +127 -2
- package/src/memory-matcher.ts +9 -6
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @objectstack/driver-memory@3.2.
|
|
2
|
+
> @objectstack/driver-memory@3.2.2 build /home/runner/work/spec/spec/packages/plugins/driver-memory
|
|
3
3
|
> tsup --config ../../../tsup.config.ts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
[34mCLI[39m Cleaning output folder
|
|
11
11
|
[34mESM[39m Build start
|
|
12
12
|
[34mCJS[39m Build start
|
|
13
|
-
[
|
|
14
|
-
[
|
|
15
|
-
[
|
|
16
|
-
[
|
|
17
|
-
[
|
|
18
|
-
[
|
|
13
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m52.62 KB[39m
|
|
14
|
+
[32mESM[39m [1mdist/index.mjs.map [22m[32m104.48 KB[39m
|
|
15
|
+
[32mESM[39m ⚡️ Build success in 129ms
|
|
16
|
+
[32mCJS[39m [1mdist/index.js [22m[32m54.30 KB[39m
|
|
17
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m104.53 KB[39m
|
|
18
|
+
[32mCJS[39m ⚡️ Build success in 143ms
|
|
19
19
|
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in
|
|
21
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[
|
|
22
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 17127ms
|
|
21
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m14.27 KB[39m
|
|
22
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m14.27 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @objectstack/driver-memory
|
|
2
2
|
|
|
3
|
+
## 3.2.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 46defbb: Fix filter operators (contains, notContains, startsWith, endsWith, between, null) broken across spec and memory driver
|
|
8
|
+
|
|
9
|
+
- Add `$notContains` to `StringOperatorSchema`, `FieldOperatorsSchema`, `FILTER_OPERATORS`, and `Filter` type
|
|
10
|
+
- Add `notcontains` / `not_contains` to `VALID_AST_OPERATORS` and `AST_OPERATOR_MAP`
|
|
11
|
+
- Fix memory driver `convertToMongoQuery()` passthrough to normalize non-standard operators to Mingo-compatible format
|
|
12
|
+
- Add `$notContains` and `$null` operators to memory matcher
|
|
13
|
+
- Fix undefined value guard in memory matcher to exclude `$exists`, `$ne`, and `$null`
|
|
14
|
+
|
|
15
|
+
- Updated dependencies [46defbb]
|
|
16
|
+
- @objectstack/spec@3.2.2
|
|
17
|
+
- @objectstack/core@3.2.2
|
|
18
|
+
|
|
19
|
+
## 3.2.1
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Updated dependencies [850b546]
|
|
24
|
+
- @objectstack/spec@3.2.1
|
|
25
|
+
- @objectstack/core@3.2.1
|
|
26
|
+
|
|
3
27
|
## 3.2.0
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -181,6 +181,18 @@ declare class InMemoryDriver implements DriverInterface {
|
|
|
181
181
|
* Convert a single ObjectQL condition to MongoDB operator format.
|
|
182
182
|
*/
|
|
183
183
|
private convertConditionToMongo;
|
|
184
|
+
/**
|
|
185
|
+
* Normalize a FilterCondition object by converting non-standard $-prefixed
|
|
186
|
+
* operators ($contains, $notContains, $startsWith, $endsWith, $between, $null)
|
|
187
|
+
* to Mingo-compatible equivalents ($regex, $gte/$lte, null checks).
|
|
188
|
+
*/
|
|
189
|
+
private normalizeFilterCondition;
|
|
190
|
+
/**
|
|
191
|
+
* Convert non-standard field operators to Mingo-compatible format.
|
|
192
|
+
* When multiple regex-producing operators appear on the same field
|
|
193
|
+
* (e.g. $startsWith + $endsWith), they are combined via $and.
|
|
194
|
+
*/
|
|
195
|
+
private normalizeFieldOperators;
|
|
184
196
|
/**
|
|
185
197
|
* Escape special regex characters for safe literal matching.
|
|
186
198
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -181,6 +181,18 @@ declare class InMemoryDriver implements DriverInterface {
|
|
|
181
181
|
* Convert a single ObjectQL condition to MongoDB operator format.
|
|
182
182
|
*/
|
|
183
183
|
private convertConditionToMongo;
|
|
184
|
+
/**
|
|
185
|
+
* Normalize a FilterCondition object by converting non-standard $-prefixed
|
|
186
|
+
* operators ($contains, $notContains, $startsWith, $endsWith, $between, $null)
|
|
187
|
+
* to Mingo-compatible equivalents ($regex, $gte/$lte, null checks).
|
|
188
|
+
*/
|
|
189
|
+
private normalizeFilterCondition;
|
|
190
|
+
/**
|
|
191
|
+
* Convert non-standard field operators to Mingo-compatible format.
|
|
192
|
+
* When multiple regex-producing operators appear on the same field
|
|
193
|
+
* (e.g. $startsWith + $endsWith), they are combined via $and.
|
|
194
|
+
*/
|
|
195
|
+
private normalizeFieldOperators;
|
|
184
196
|
/**
|
|
185
197
|
* Escape special regex characters for safe literal matching.
|
|
186
198
|
*/
|
package/dist/index.js
CHANGED
|
@@ -194,9 +194,6 @@ var import_mingo = require("mingo");
|
|
|
194
194
|
|
|
195
195
|
// src/memory-matcher.ts
|
|
196
196
|
function getValueByPath(obj, path2) {
|
|
197
|
-
if (path2 === "_id" && obj._id === void 0 && obj.id !== void 0) {
|
|
198
|
-
return obj.id;
|
|
199
|
-
}
|
|
200
197
|
if (!path2.includes(".")) return obj[path2];
|
|
201
198
|
return path2.split(".").reduce((o, i) => o ? o[i] : void 0, obj);
|
|
202
199
|
}
|
|
@@ -666,7 +663,7 @@ var _InMemoryDriver = class _InMemoryDriver {
|
|
|
666
663
|
const op = filters.operator === "or" ? "$or" : "$and";
|
|
667
664
|
return { [op]: conditions };
|
|
668
665
|
}
|
|
669
|
-
return filters;
|
|
666
|
+
return this.normalizeFilterCondition(filters);
|
|
670
667
|
}
|
|
671
668
|
if (!Array.isArray(filters) || filters.length === 0) return {};
|
|
672
669
|
const logicGroups = [
|
|
@@ -727,6 +724,9 @@ var _InMemoryDriver = class _InMemoryDriver {
|
|
|
727
724
|
case "contains":
|
|
728
725
|
case "like":
|
|
729
726
|
return { [field]: { $regex: new RegExp(this.escapeRegex(value), "i") } };
|
|
727
|
+
case "notcontains":
|
|
728
|
+
case "not_contains":
|
|
729
|
+
return { [field]: { $not: { $regex: new RegExp(this.escapeRegex(value), "i") } } };
|
|
730
730
|
case "startswith":
|
|
731
731
|
case "starts_with":
|
|
732
732
|
return { [field]: { $regex: new RegExp(`^${this.escapeRegex(value)}`, "i") } };
|
|
@@ -742,6 +742,104 @@ var _InMemoryDriver = class _InMemoryDriver {
|
|
|
742
742
|
return null;
|
|
743
743
|
}
|
|
744
744
|
}
|
|
745
|
+
/**
|
|
746
|
+
* Normalize a FilterCondition object by converting non-standard $-prefixed
|
|
747
|
+
* operators ($contains, $notContains, $startsWith, $endsWith, $between, $null)
|
|
748
|
+
* to Mingo-compatible equivalents ($regex, $gte/$lte, null checks).
|
|
749
|
+
*/
|
|
750
|
+
normalizeFilterCondition(filter) {
|
|
751
|
+
const result = {};
|
|
752
|
+
const extraAndConditions = [];
|
|
753
|
+
for (const key of Object.keys(filter)) {
|
|
754
|
+
const value = filter[key];
|
|
755
|
+
if (key === "$and" || key === "$or") {
|
|
756
|
+
result[key] = Array.isArray(value) ? value.map((child) => this.normalizeFilterCondition(child)) : value;
|
|
757
|
+
continue;
|
|
758
|
+
}
|
|
759
|
+
if (key === "$not") {
|
|
760
|
+
result[key] = value && typeof value === "object" ? this.normalizeFilterCondition(value) : value;
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
if (key.startsWith("$")) {
|
|
764
|
+
result[key] = value;
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
if (value && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof RegExp)) {
|
|
768
|
+
const normalized = this.normalizeFieldOperators(value);
|
|
769
|
+
if (normalized._multiRegex) {
|
|
770
|
+
const regexConditions = normalized._multiRegex;
|
|
771
|
+
delete normalized._multiRegex;
|
|
772
|
+
for (const rc of regexConditions) {
|
|
773
|
+
extraAndConditions.push({ [key]: { ...normalized, ...rc } });
|
|
774
|
+
}
|
|
775
|
+
} else {
|
|
776
|
+
result[key] = normalized;
|
|
777
|
+
}
|
|
778
|
+
} else {
|
|
779
|
+
result[key] = value;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
if (extraAndConditions.length > 0) {
|
|
783
|
+
const existing = result.$and;
|
|
784
|
+
const andArray = Array.isArray(existing) ? existing : [];
|
|
785
|
+
if (Object.keys(result).filter((k) => k !== "$and").length > 0) {
|
|
786
|
+
const rest = { ...result };
|
|
787
|
+
delete rest.$and;
|
|
788
|
+
andArray.push(rest);
|
|
789
|
+
}
|
|
790
|
+
andArray.push(...extraAndConditions);
|
|
791
|
+
return { $and: andArray };
|
|
792
|
+
}
|
|
793
|
+
return result;
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Convert non-standard field operators to Mingo-compatible format.
|
|
797
|
+
* When multiple regex-producing operators appear on the same field
|
|
798
|
+
* (e.g. $startsWith + $endsWith), they are combined via $and.
|
|
799
|
+
*/
|
|
800
|
+
normalizeFieldOperators(ops) {
|
|
801
|
+
const result = {};
|
|
802
|
+
const regexConditions = [];
|
|
803
|
+
for (const op of Object.keys(ops)) {
|
|
804
|
+
const val = ops[op];
|
|
805
|
+
switch (op) {
|
|
806
|
+
case "$contains":
|
|
807
|
+
regexConditions.push({ $regex: new RegExp(this.escapeRegex(val), "i") });
|
|
808
|
+
break;
|
|
809
|
+
case "$notContains":
|
|
810
|
+
result.$not = { $regex: new RegExp(this.escapeRegex(val), "i") };
|
|
811
|
+
break;
|
|
812
|
+
case "$startsWith":
|
|
813
|
+
regexConditions.push({ $regex: new RegExp(`^${this.escapeRegex(val)}`, "i") });
|
|
814
|
+
break;
|
|
815
|
+
case "$endsWith":
|
|
816
|
+
regexConditions.push({ $regex: new RegExp(`${this.escapeRegex(val)}$`, "i") });
|
|
817
|
+
break;
|
|
818
|
+
case "$between":
|
|
819
|
+
if (Array.isArray(val) && val.length === 2) {
|
|
820
|
+
result.$gte = val[0];
|
|
821
|
+
result.$lte = val[1];
|
|
822
|
+
}
|
|
823
|
+
break;
|
|
824
|
+
case "$null":
|
|
825
|
+
if (val === true) {
|
|
826
|
+
result.$eq = null;
|
|
827
|
+
} else {
|
|
828
|
+
result.$ne = null;
|
|
829
|
+
}
|
|
830
|
+
break;
|
|
831
|
+
default:
|
|
832
|
+
result[op] = val;
|
|
833
|
+
break;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
if (regexConditions.length === 1) {
|
|
837
|
+
Object.assign(result, regexConditions[0]);
|
|
838
|
+
} else if (regexConditions.length > 1) {
|
|
839
|
+
result._multiRegex = regexConditions;
|
|
840
|
+
}
|
|
841
|
+
return result;
|
|
842
|
+
}
|
|
745
843
|
/**
|
|
746
844
|
* Escape special regex characters for safe literal matching.
|
|
747
845
|
*/
|