@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/dist/index.mjs CHANGED
@@ -161,9 +161,6 @@ import { Query, Aggregator } from "mingo";
161
161
 
162
162
  // src/memory-matcher.ts
163
163
  function getValueByPath(obj, path2) {
164
- if (path2 === "_id" && obj._id === void 0 && obj.id !== void 0) {
165
- return obj.id;
166
- }
167
164
  if (!path2.includes(".")) return obj[path2];
168
165
  return path2.split(".").reduce((o, i) => o ? o[i] : void 0, obj);
169
166
  }
@@ -633,7 +630,7 @@ var _InMemoryDriver = class _InMemoryDriver {
633
630
  const op = filters.operator === "or" ? "$or" : "$and";
634
631
  return { [op]: conditions };
635
632
  }
636
- return filters;
633
+ return this.normalizeFilterCondition(filters);
637
634
  }
638
635
  if (!Array.isArray(filters) || filters.length === 0) return {};
639
636
  const logicGroups = [
@@ -694,6 +691,9 @@ var _InMemoryDriver = class _InMemoryDriver {
694
691
  case "contains":
695
692
  case "like":
696
693
  return { [field]: { $regex: new RegExp(this.escapeRegex(value), "i") } };
694
+ case "notcontains":
695
+ case "not_contains":
696
+ return { [field]: { $not: { $regex: new RegExp(this.escapeRegex(value), "i") } } };
697
697
  case "startswith":
698
698
  case "starts_with":
699
699
  return { [field]: { $regex: new RegExp(`^${this.escapeRegex(value)}`, "i") } };
@@ -709,6 +709,104 @@ var _InMemoryDriver = class _InMemoryDriver {
709
709
  return null;
710
710
  }
711
711
  }
712
+ /**
713
+ * Normalize a FilterCondition object by converting non-standard $-prefixed
714
+ * operators ($contains, $notContains, $startsWith, $endsWith, $between, $null)
715
+ * to Mingo-compatible equivalents ($regex, $gte/$lte, null checks).
716
+ */
717
+ normalizeFilterCondition(filter) {
718
+ const result = {};
719
+ const extraAndConditions = [];
720
+ for (const key of Object.keys(filter)) {
721
+ const value = filter[key];
722
+ if (key === "$and" || key === "$or") {
723
+ result[key] = Array.isArray(value) ? value.map((child) => this.normalizeFilterCondition(child)) : value;
724
+ continue;
725
+ }
726
+ if (key === "$not") {
727
+ result[key] = value && typeof value === "object" ? this.normalizeFilterCondition(value) : value;
728
+ continue;
729
+ }
730
+ if (key.startsWith("$")) {
731
+ result[key] = value;
732
+ continue;
733
+ }
734
+ if (value && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof RegExp)) {
735
+ const normalized = this.normalizeFieldOperators(value);
736
+ if (normalized._multiRegex) {
737
+ const regexConditions = normalized._multiRegex;
738
+ delete normalized._multiRegex;
739
+ for (const rc of regexConditions) {
740
+ extraAndConditions.push({ [key]: { ...normalized, ...rc } });
741
+ }
742
+ } else {
743
+ result[key] = normalized;
744
+ }
745
+ } else {
746
+ result[key] = value;
747
+ }
748
+ }
749
+ if (extraAndConditions.length > 0) {
750
+ const existing = result.$and;
751
+ const andArray = Array.isArray(existing) ? existing : [];
752
+ if (Object.keys(result).filter((k) => k !== "$and").length > 0) {
753
+ const rest = { ...result };
754
+ delete rest.$and;
755
+ andArray.push(rest);
756
+ }
757
+ andArray.push(...extraAndConditions);
758
+ return { $and: andArray };
759
+ }
760
+ return result;
761
+ }
762
+ /**
763
+ * Convert non-standard field operators to Mingo-compatible format.
764
+ * When multiple regex-producing operators appear on the same field
765
+ * (e.g. $startsWith + $endsWith), they are combined via $and.
766
+ */
767
+ normalizeFieldOperators(ops) {
768
+ const result = {};
769
+ const regexConditions = [];
770
+ for (const op of Object.keys(ops)) {
771
+ const val = ops[op];
772
+ switch (op) {
773
+ case "$contains":
774
+ regexConditions.push({ $regex: new RegExp(this.escapeRegex(val), "i") });
775
+ break;
776
+ case "$notContains":
777
+ result.$not = { $regex: new RegExp(this.escapeRegex(val), "i") };
778
+ break;
779
+ case "$startsWith":
780
+ regexConditions.push({ $regex: new RegExp(`^${this.escapeRegex(val)}`, "i") });
781
+ break;
782
+ case "$endsWith":
783
+ regexConditions.push({ $regex: new RegExp(`${this.escapeRegex(val)}$`, "i") });
784
+ break;
785
+ case "$between":
786
+ if (Array.isArray(val) && val.length === 2) {
787
+ result.$gte = val[0];
788
+ result.$lte = val[1];
789
+ }
790
+ break;
791
+ case "$null":
792
+ if (val === true) {
793
+ result.$eq = null;
794
+ } else {
795
+ result.$ne = null;
796
+ }
797
+ break;
798
+ default:
799
+ result[op] = val;
800
+ break;
801
+ }
802
+ }
803
+ if (regexConditions.length === 1) {
804
+ Object.assign(result, regexConditions[0]);
805
+ } else if (regexConditions.length > 1) {
806
+ result._multiRegex = regexConditions;
807
+ }
808
+ return result;
809
+ }
712
810
  /**
713
811
  * Escape special regex characters for safe literal matching.
714
812
  */