@warlock.js/cascade 5.20.0 → 5.21.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.
Files changed (168) hide show
  1. package/CHANGELOG.md +30 -1
  2. package/cjs/index.cjs +2283 -1037
  3. package/cjs/index.cjs.map +1 -1
  4. package/esm/contracts/query-builder.contract.d.mts +30 -3
  5. package/esm/contracts/query-builder.contract.d.mts.map +1 -1
  6. package/esm/data-source/data-source-registry.d.mts +33 -1
  7. package/esm/data-source/data-source-registry.d.mts.map +1 -1
  8. package/esm/data-source/data-source-registry.mjs +75 -5
  9. package/esm/data-source/data-source-registry.mjs.map +1 -1
  10. package/esm/database-dirty-tracker.d.mts +5 -0
  11. package/esm/database-dirty-tracker.d.mts.map +1 -1
  12. package/esm/database-dirty-tracker.mjs +16 -0
  13. package/esm/database-dirty-tracker.mjs.map +1 -1
  14. package/esm/drivers/mongodb/mongodb-driver.d.mts +12 -0
  15. package/esm/drivers/mongodb/mongodb-driver.d.mts.map +1 -1
  16. package/esm/drivers/mongodb/mongodb-driver.mjs +47 -16
  17. package/esm/drivers/mongodb/mongodb-driver.mjs.map +1 -1
  18. package/esm/drivers/mongodb/mongodb-migration-driver.d.mts +1 -1
  19. package/esm/drivers/mongodb/mongodb-migration-driver.d.mts.map +1 -1
  20. package/esm/drivers/mongodb/mongodb-migration-driver.mjs +15 -18
  21. package/esm/drivers/mongodb/mongodb-migration-driver.mjs.map +1 -1
  22. package/esm/drivers/mongodb/mongodb-query-builder.d.mts +13 -3
  23. package/esm/drivers/mongodb/mongodb-query-builder.d.mts.map +1 -1
  24. package/esm/drivers/mongodb/mongodb-query-builder.mjs +72 -19
  25. package/esm/drivers/mongodb/mongodb-query-builder.mjs.map +1 -1
  26. package/esm/drivers/mongodb/mongodb-query-parser.d.mts +6 -0
  27. package/esm/drivers/mongodb/mongodb-query-parser.d.mts.map +1 -1
  28. package/esm/drivers/mongodb/mongodb-query-parser.mjs +128 -30
  29. package/esm/drivers/mongodb/mongodb-query-parser.mjs.map +1 -1
  30. package/esm/drivers/postgres/index.d.mts +2 -3
  31. package/esm/drivers/postgres/index.mjs +1 -2
  32. package/esm/drivers/postgres/postgres-blueprint.mjs +4 -4
  33. package/esm/drivers/postgres/postgres-blueprint.mjs.map +1 -1
  34. package/esm/drivers/postgres/postgres-dialect.d.mts +5 -1
  35. package/esm/drivers/postgres/postgres-dialect.d.mts.map +1 -1
  36. package/esm/drivers/postgres/postgres-dialect.mjs +38 -8
  37. package/esm/drivers/postgres/postgres-dialect.mjs.map +1 -1
  38. package/esm/drivers/postgres/postgres-driver.d.mts +52 -29
  39. package/esm/drivers/postgres/postgres-driver.d.mts.map +1 -1
  40. package/esm/drivers/postgres/postgres-driver.mjs +190 -57
  41. package/esm/drivers/postgres/postgres-driver.mjs.map +1 -1
  42. package/esm/drivers/postgres/postgres-migration-driver.d.mts +2 -1
  43. package/esm/drivers/postgres/postgres-migration-driver.d.mts.map +1 -1
  44. package/esm/drivers/postgres/postgres-migration-driver.mjs +8 -6
  45. package/esm/drivers/postgres/postgres-migration-driver.mjs.map +1 -1
  46. package/esm/drivers/postgres/postgres-query-builder.d.mts +18 -7
  47. package/esm/drivers/postgres/postgres-query-builder.d.mts.map +1 -1
  48. package/esm/drivers/postgres/postgres-query-builder.mjs +146 -31
  49. package/esm/drivers/postgres/postgres-query-builder.mjs.map +1 -1
  50. package/esm/drivers/postgres/postgres-query-parser.d.mts +23 -1
  51. package/esm/drivers/postgres/postgres-query-parser.d.mts.map +1 -1
  52. package/esm/drivers/postgres/postgres-query-parser.mjs +160 -43
  53. package/esm/drivers/postgres/postgres-query-parser.mjs.map +1 -1
  54. package/esm/drivers/postgres/postgres-sql-serializer.mjs +3 -2
  55. package/esm/drivers/postgres/postgres-sql-serializer.mjs.map +1 -1
  56. package/esm/drivers/postgres/postgres-type-converters.mjs +57 -0
  57. package/esm/drivers/postgres/postgres-type-converters.mjs.map +1 -0
  58. package/esm/events/model-events.d.mts +1 -1
  59. package/esm/events/model-events.d.mts.map +1 -1
  60. package/esm/events/model-events.mjs.map +1 -1
  61. package/esm/index.d.mts +5 -6
  62. package/esm/index.mjs +4 -5
  63. package/esm/migration/column-builder.d.mts.map +1 -1
  64. package/esm/migration/column-builder.mjs +2 -2
  65. package/esm/migration/column-builder.mjs.map +1 -1
  66. package/esm/migration/index.d.mts +2 -2
  67. package/esm/migration/index.mjs +1 -1
  68. package/esm/migration/migration-order.mjs +5 -2
  69. package/esm/migration/migration-order.mjs.map +1 -1
  70. package/esm/migration/migration-runner.d.mts +50 -5
  71. package/esm/migration/migration-runner.d.mts.map +1 -1
  72. package/esm/migration/migration-runner.mjs +369 -146
  73. package/esm/migration/migration-runner.mjs.map +1 -1
  74. package/esm/migration/migration.d.mts +36 -3
  75. package/esm/migration/migration.d.mts.map +1 -1
  76. package/esm/migration/migration.mjs +62 -5
  77. package/esm/migration/migration.mjs.map +1 -1
  78. package/esm/model/methods/accessor-methods.mjs +1 -3
  79. package/esm/model/methods/accessor-methods.mjs.map +1 -1
  80. package/esm/model/methods/delete-methods.mjs +6 -2
  81. package/esm/model/methods/delete-methods.mjs.map +1 -1
  82. package/esm/model/methods/hydration-methods.mjs +16 -2
  83. package/esm/model/methods/hydration-methods.mjs.map +1 -1
  84. package/esm/model/methods/instance-event-methods.mjs +2 -1
  85. package/esm/model/methods/instance-event-methods.mjs.map +1 -1
  86. package/esm/model/methods/meta-methods.mjs +53 -16
  87. package/esm/model/methods/meta-methods.mjs.map +1 -1
  88. package/esm/model/methods/query-methods.mjs +86 -15
  89. package/esm/model/methods/query-methods.mjs.map +1 -1
  90. package/esm/model/methods/static-event-methods.mjs +16 -1
  91. package/esm/model/methods/static-event-methods.mjs.map +1 -1
  92. package/esm/model/methods/write-methods.d.mts.map +1 -1
  93. package/esm/model/methods/write-methods.mjs +50 -50
  94. package/esm/model/methods/write-methods.mjs.map +1 -1
  95. package/esm/model/model.d.mts +16 -1
  96. package/esm/model/model.d.mts.map +1 -1
  97. package/esm/model/model.mjs +39 -5
  98. package/esm/model/model.mjs.map +1 -1
  99. package/esm/model/register-model.d.mts +6 -1
  100. package/esm/model/register-model.d.mts.map +1 -1
  101. package/esm/model/register-model.mjs +16 -1
  102. package/esm/model/register-model.mjs.map +1 -1
  103. package/esm/query-builder/query-builder.d.mts +21 -2
  104. package/esm/query-builder/query-builder.d.mts.map +1 -1
  105. package/esm/query-builder/query-builder.mjs +97 -20
  106. package/esm/query-builder/query-builder.mjs.map +1 -1
  107. package/esm/relations/key-conventions.mjs +13 -3
  108. package/esm/relations/key-conventions.mjs.map +1 -1
  109. package/esm/relations/pivot-operations.mjs +1 -1
  110. package/esm/relations/relation-loader.d.mts +15 -5
  111. package/esm/relations/relation-loader.d.mts.map +1 -1
  112. package/esm/relations/relation-loader.mjs +51 -16
  113. package/esm/relations/relation-loader.mjs.map +1 -1
  114. package/esm/remover/database-remover.d.mts.map +1 -1
  115. package/esm/remover/database-remover.mjs +21 -7
  116. package/esm/remover/database-remover.mjs.map +1 -1
  117. package/esm/restorer/database-restorer.d.mts +12 -2
  118. package/esm/restorer/database-restorer.d.mts.map +1 -1
  119. package/esm/restorer/database-restorer.mjs +43 -13
  120. package/esm/restorer/database-restorer.mjs.map +1 -1
  121. package/esm/sync/model-events.mjs +63 -3
  122. package/esm/sync/model-events.mjs.map +1 -1
  123. package/esm/sync/model-sync-operation.d.mts.map +1 -1
  124. package/esm/sync/model-sync-operation.mjs +3 -2
  125. package/esm/sync/model-sync-operation.mjs.map +1 -1
  126. package/esm/sync/sync-manager.d.mts +3 -42
  127. package/esm/sync/sync-manager.d.mts.map +1 -1
  128. package/esm/sync/sync-manager.mjs +37 -126
  129. package/esm/sync/sync-manager.mjs.map +1 -1
  130. package/esm/utils/connect-to-database.d.mts.map +1 -1
  131. package/esm/utils/connect-to-database.mjs +4 -4
  132. package/esm/utils/connect-to-database.mjs.map +1 -1
  133. package/esm/utils/database-writer.utils.d.mts +1 -1
  134. package/esm/utils/database-writer.utils.d.mts.map +1 -1
  135. package/esm/utils/database-writer.utils.mjs +1 -0
  136. package/esm/utils/database-writer.utils.mjs.map +1 -1
  137. package/esm/utils/define-model.d.mts.map +1 -1
  138. package/esm/utils/define-model.mjs +2 -10
  139. package/esm/utils/define-model.mjs.map +1 -1
  140. package/esm/utils/is-valid-date-value.mjs +3 -2
  141. package/esm/utils/is-valid-date-value.mjs.map +1 -1
  142. package/esm/utils/once-connected.d.mts.map +1 -1
  143. package/esm/utils/once-connected.mjs +12 -2
  144. package/esm/utils/once-connected.mjs.map +1 -1
  145. package/esm/validation/mutators/embed-mutator.mjs +19 -11
  146. package/esm/validation/mutators/embed-mutator.mjs.map +1 -1
  147. package/esm/validation/plugins/embed-validator-plugin.d.mts +2 -2
  148. package/esm/validation/plugins/embed-validator-plugin.d.mts.map +1 -1
  149. package/esm/validation/plugins/embed-validator-plugin.mjs +8 -2
  150. package/esm/validation/plugins/embed-validator-plugin.mjs.map +1 -1
  151. package/esm/validation/rules/database-model-rule.mjs +6 -5
  152. package/esm/validation/rules/database-model-rule.mjs.map +1 -1
  153. package/esm/validation/rules/exists-rule.mjs +6 -4
  154. package/esm/validation/rules/exists-rule.mjs.map +1 -1
  155. package/esm/validation/rules/unique-rule.mjs +5 -2
  156. package/esm/validation/rules/unique-rule.mjs.map +1 -1
  157. package/esm/validation/validators/embed-validator.d.mts.map +1 -1
  158. package/esm/validation/validators/embed-validator.mjs +1 -1
  159. package/esm/validation/validators/embed-validator.mjs.map +1 -1
  160. package/esm/writer/database-writer.d.mts +27 -0
  161. package/esm/writer/database-writer.d.mts.map +1 -1
  162. package/esm/writer/database-writer.mjs +84 -17
  163. package/esm/writer/database-writer.mjs.map +1 -1
  164. package/package.json +4 -4
  165. package/esm/drivers/postgres/postgres-sync-adapter.d.mts +0 -79
  166. package/esm/drivers/postgres/postgres-sync-adapter.d.mts.map +0 -1
  167. package/esm/drivers/postgres/postgres-sync-adapter.mjs +0 -162
  168. package/esm/drivers/postgres/postgres-sync-adapter.mjs.map +0 -1
@@ -71,6 +71,11 @@ declare class MongoQueryParser {
71
71
  * ```
72
72
  */
73
73
  parse(): any[];
74
+ /**
75
+ * Atlas requires `$vectorSearch` as the first stage. Any `$match` emitted
76
+ * before it (where clauses, scopes) moves into its `filter` instead.
77
+ */
78
+ private hoistVectorSearch;
74
79
  /**
75
80
  * Apply a raw escape-hatch operation to the pipeline built so far.
76
81
  *
@@ -224,6 +229,7 @@ declare class MongoQueryParser {
224
229
  * @returns The MongoDB filter condition
225
230
  */
226
231
  private buildOperatorCondition;
232
+ private assertArrayOperand;
227
233
  /**
228
234
  * Get MongoDB operator from comparison operator.
229
235
  *
@@ -1 +1 @@
1
- {"version":3,"file":"mongodb-query-parser.d.mts","names":[],"sources":["../../../../../../../../cascade/src/drivers/mongodb/mongodb-query-parser.ts"],"mappings":";;;;;;;AAkBA;KAAY,uBAAA;6CAEV,UAAA,EAAY,UAAA,EAEA;EAAZ,UAAA,EAAY,SAAA,IAE6B;EAAzC,gBAAA,QAAwB,iBAAA;AAAA;;;;;;;AAAiB;AAW3C;cAAa,gBAAA;;;;mBAIM,UAAA;EAUA;;;EAAA,iBALA,UAAA;EA0BW;;;EAAA,iBArBX,gBAAA;EA4KT;;;;EAAA,iBAtKS,eAAA;EAsXV;;;;;;EAAA,iBA9WU,oBAAA;EAg/BT;;;;;cAz+BW,OAAA,EAAS,uBAAuB;EA2lC3C;;;;;;;;;;;;;;;;;;;;EAjkCD,KAAA;EAqxCC;;;;;;;;;;EAAA,QA3rCA,iBAAA;EAm2CA;;;;;;;;;;;;AA6dgB;EA7dhB,QAh0CA,yBAAA;;;;;;;;;;;;;;;;;;UAuDA,WAAA;;;;UAkCA,oBAAA;;;;;;UAkCA,yBAAA;;;;;;;;;;UAyBA,qBAAA;;;;;;;;;;;;;;;;;;;;;;;;EA4DD,cAAA;;;;;;;;UAmCC,eAAA;;;;;;;;UAoDA,UAAA;;;;;;;;;;;UAyEA,eAAA;EAAA,QA8KA,iBAAA;;;;;;;;;UAkBA,sBAAA;;;;;;;UA8EA,mBAAA;;;;;;;;;;;;;UAoNA,oBAAA;;;;;;;;;UAgBA,sBAAA;;;;;;;UAyBA,gBAAA;EAAA,QAYA,oBAAA;;;;;;;;UA2BA,4BAAA;EAAA,QAsBA,aAAA;EAAA,QAYA,qBAAA;EAAA,QASA,4BAAA;EAAA,QAWA,UAAA;EAAA,QAIA,0BAAA;EAAA,QAOA,wBAAA;EAAA,QAKA,uBAAA;EAAA,QAKA,kBAAA;EAAA,QAgBA,sBAAA;EAAA,QAiBA,0BAAA;EAAA,QAQA,+BAAA;EAAA,QAMA,6BAAA;EAAA,QAMA,wBAAA;EAAA,QASA,sBAAA;EAAA,QAQA,yBAAA;EAAA,QASA,kBAAA;EAAA,QAWA,UAAA;EAAA,QAMA,QAAA;EAAA,QAMA,aAAA;EAAA,QAIA,qBAAA;;;;;;UAeA,qBAAA;EAAA,QAmCA,kBAAA;EAAA,QAeA,2BAAA;EAAA,QA0BA,uBAAA;EAAA,QAoBA,wBAAA;EAAA,QAwBA,qBAAA;EAAA,QAMA,wBAAA;EAAA,QAMA,mBAAA;EAAA,QAeA,mBAAA;;;;;UAkBA,0BAAA;EAAA,QAaA,cAAA;EAAA,QAYA,qBAAA;EAAA,QAMA,uBAAA;;;;;;;UAsBA,iBAAA;;;;;;;UAgHA,cAAA;;;;;;;UA2BA,eAAA;EAAA,QA6DA,iBAAA;;;;;;;;UAgBA,+BAAA;;;;;;;;;;UAoCA,qBAAA;;;;;;;UA0BA,sBAAA;;;;;;;UA4BA,4BAAA;;;;;;;;;;;;;UAuFA,uBAAA;EAAA,QAoCA,YAAA;;;;;;;UAgDA,gBAAA;AAAA"}
1
+ {"version":3,"file":"mongodb-query-parser.d.mts","names":[],"sources":["../../../../../../../../cascade/src/drivers/mongodb/mongodb-query-parser.ts"],"mappings":";;;;;;;AAyDA;KAAY,uBAAA;6CAEV,UAAA,EAAY,UAAA,EAEA;EAAZ,UAAA,EAAY,SAAA,IAE6B;EAAzC,gBAAA,QAAwB,iBAAA;AAAA;AAuB1B;;;;;;;;AAAA,cAAa,gBAAA;;;;mBAIM,UAAA;EAkJT;;;EAAA,iBA7IS,UAAA;EAwTT;;;EAAA,iBAnTS,gBAAA;EA6cT;;;;EAAA,iBAvcS,eAAA;EA20BT;;;;;;EAAA,iBAn0BS,oBAAA;EAyqCT;;;;;cAlqCW,OAAA,EAAS,uBAAuB;EAktC3C;;;;;;;;;;;;;;;;;;;;EAxrCD,KAAA;EA07CC;;;;EAAA,QAj2CA,iBAAA;EAi6CA;;;;;;;;;;EAAA,QAl3CA,iBAAA;EAo2DA;;AAAgB;;;;;;;;;;;EAAhB,QAj0DA,yBAAA;;;;;;;;;;;;;;;;;;UAuDA,WAAA;;;;UAkCA,oBAAA;;;;;;UAkCA,yBAAA;;;;;;;;;;UAyBA,qBAAA;;;;;;;;;;;;;;;;;;;;;;;;EA4DD,cAAA;;;;;;;;UAmCC,eAAA;;;;;;;;UAoDA,UAAA;;;;;;;;;;;UAyEA,eAAA;EAAA,QAqKA,iBAAA;;;;;;;;;UAkBA,sBAAA;;;;;;;UAgFA,mBAAA;;;;;;;;;;;;;UAyNA,oBAAA;;;;;;;;;UAgBA,sBAAA;EAAA,QAkDA,kBAAA;;;;;;;UAcA,gBAAA;EAAA,QAYA,oBAAA;;;;;;;;UA2BA,4BAAA;EAAA,QAsBA,aAAA;EAAA,QAYA,qBAAA;EAAA,QASA,4BAAA;EAAA,QAWA,UAAA;EAAA,QAIA,0BAAA;EAAA,QAOA,wBAAA;EAAA,QAKA,uBAAA;EAAA,QAKA,kBAAA;EAAA,QAgBA,sBAAA;EAAA,QAiBA,0BAAA;EAAA,QAQA,+BAAA;EAAA,QAMA,6BAAA;EAAA,QAMA,wBAAA;EAAA,QASA,sBAAA;EAAA,QAQA,yBAAA;EAAA,QASA,kBAAA;EAAA,QAWA,UAAA;EAAA,QAMA,QAAA;EAAA,QAMA,aAAA;EAAA,QAIA,qBAAA;;;;;;UAeA,qBAAA;EAAA,QAmCA,kBAAA;EAAA,QAeA,2BAAA;EAAA,QA0BA,uBAAA;EAAA,QAoBA,wBAAA;EAAA,QAwBA,qBAAA;EAAA,QAMA,wBAAA;EAAA,QAMA,mBAAA;EAAA,QAeA,mBAAA;;;;;UAkBA,0BAAA;EAAA,QAaA,cAAA;EAAA,QAYA,qBAAA;EAAA,QAMA,uBAAA;;;;;;;UAsBA,iBAAA;;;;;;;UAgHA,cAAA;;;;;;;UA0BA,eAAA;EAAA,QA6DA,iBAAA;;;;;;;;UAgBA,+BAAA;;;;;;;;;;UAoCA,qBAAA;;;;;;;UA0BA,sBAAA;;;;;;;UA4BA,4BAAA;;;;;;;;;;;;;UAuFA,uBAAA;EAAA,QAoCA,YAAA;;;;;;;UAgDA,gBAAA;AAAA"}
@@ -1,11 +1,48 @@
1
1
  import { UnsafeRawExpressionError } from "../../errors/unsafe-raw-expression.error.mjs";
2
2
  import { UnsupportedQueryOperationError } from "../../errors/unsupported-query-operation.error.mjs";
3
3
  import { isAggregateExpression } from "../../expressions/aggregate-expressions.mjs";
4
- import { escapeRegex, resolveLikePattern } from "../../utils/escape-regex.mjs";
4
+ import { escapeRegex } from "../../utils/escape-regex.mjs";
5
5
  import { isPipelineStageObject } from "./pipeline-stage-object.mjs";
6
6
  import { colors } from "@mongez/copper";
7
7
 
8
8
  //#region ../cascade/src/drivers/mongodb/mongodb-query-parser.ts
9
+ const isPlainObject = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
10
+ /**
11
+ * AND one `key: value` condition into `target`. Operators on the same field
12
+ * with distinct keys are merged (`{ age: { $gt, $lt } }`); any other collision
13
+ * (same operator, `$expr`, `$nor`, ...) is pushed into `$and` so neither
14
+ * side is overwritten.
15
+ */
16
+ const mergeConditionEntry = (target, key, value) => {
17
+ if (!(key in target)) {
18
+ target[key] = value;
19
+ return;
20
+ }
21
+ if (key === "$and" && Array.isArray(target.$and) && Array.isArray(value)) {
22
+ target.$and.push(...value);
23
+ return;
24
+ }
25
+ const existing = target[key];
26
+ if (!key.startsWith("$") && isPlainObject(existing) && isPlainObject(value) && !Object.keys(value).some((operator) => operator in existing)) {
27
+ target[key] = {
28
+ ...existing,
29
+ ...value
30
+ };
31
+ return;
32
+ }
33
+ if (!Array.isArray(target.$and)) target.$and = [];
34
+ target.$and.push({ [key]: value });
35
+ };
36
+ /**
37
+ * Compile a LIKE argument to regex source with the same wildcards as SQL/pg:
38
+ * `%` matches any run of characters and `_` exactly one. Every other regex
39
+ * metacharacter in a string is escaped, so `a.b*` matches literally. An explicit
40
+ * `RegExp` is developer-authored and used verbatim.
41
+ */
42
+ function resolveMongoLikePattern(pattern) {
43
+ if (pattern instanceof RegExp) return pattern.source;
44
+ return escapeRegex(pattern).replace(/%+/g, ".*").replace(/_/g, ".");
45
+ }
9
46
  /**
10
47
  * Parses query builder operations into MongoDB aggregation pipeline.
11
48
  *
@@ -96,6 +133,7 @@ var MongoQueryParser = class {
96
133
  this.trackGroupFieldNames(stage, operations, stageIndex);
97
134
  const renameStage = this.buildGroupRenameStage(builtStage, stageIndex);
98
135
  if (renameStage) pipeline.push(renameStage);
136
+ if (stage === "$lookup" && builtStage.$lookup && operations[0]?.data?.type === "inner") pipeline.push({ $match: { [builtStage.$lookup.as]: { $ne: [] } } });
99
137
  };
100
138
  for (const op of this.orderStages(this.operations)) {
101
139
  if (op.mergeable && op.stage === currentStage) {
@@ -115,7 +153,23 @@ var MongoQueryParser = class {
115
153
  }
116
154
  }
117
155
  if (currentBuffer.length > 0) emit(currentStage, currentBuffer);
118
- return pipeline;
156
+ return this.hoistVectorSearch(pipeline);
157
+ }
158
+ /**
159
+ * Atlas requires `$vectorSearch` as the first stage. Any `$match` emitted
160
+ * before it (where clauses, scopes) moves into its `filter` instead.
161
+ */
162
+ hoistVectorSearch(pipeline) {
163
+ const index = pipeline.findIndex((stage) => stage.$vectorSearch);
164
+ if (index <= 0) return pipeline;
165
+ const before = pipeline.slice(0, index).filter((stage) => !stage.$limit);
166
+ if (!before.every((stage) => stage.$match)) throw new UnsupportedQueryOperationError("similarTo", "mongodb", "$vectorSearch must be the first pipeline stage; only where() filters can precede similarTo().");
167
+ const vectorStage = pipeline[index].$vectorSearch;
168
+ const filters = [...before.map((stage) => stage.$match), ...vectorStage.filter ? [vectorStage.filter] : []];
169
+ return [{ $vectorSearch: {
170
+ ...vectorStage,
171
+ ...filters.length === 0 ? {} : { filter: filters.length === 1 ? filters[0] : { $and: filters } }
172
+ } }, ...pipeline.slice(index + 1)];
119
173
  }
120
174
  /**
121
175
  * Apply a raw escape-hatch operation to the pipeline built so far.
@@ -411,11 +465,7 @@ var MongoQueryParser = class {
411
465
  pushOr(value);
412
466
  return;
413
467
  }
414
- if (value && typeof value === "object" && !Array.isArray(value) && andFilter[key] && typeof andFilter[key] === "object" && !Array.isArray(andFilter[key])) andFilter[key] = {
415
- ...andFilter[key],
416
- ...value
417
- };
418
- else andFilter[key] = value;
468
+ mergeConditionEntry(andFilter, key, value);
419
469
  });
420
470
  };
421
471
  const queueSimpleWhere = (condition) => {
@@ -426,10 +476,9 @@ var MongoQueryParser = class {
426
476
  const enterTopLevelOrMode = () => {
427
477
  if (topLevelOrMode) return;
428
478
  topLevelOrMode = true;
429
- while (pendingSimpleWhere.length > 0) {
430
- const condition = pendingSimpleWhere.shift();
431
- if (condition) pushOr(condition);
432
- }
479
+ const pending = pendingSimpleWhere.splice(0).filter(Boolean);
480
+ if (pending.length === 1) pushOr(pending[0]);
481
+ else if (pending.length > 1) pushOr({ $and: pending });
433
482
  };
434
483
  const flushPendingSimpleWhere = () => {
435
484
  if (pendingSimpleWhere.length === 0) return;
@@ -528,14 +577,13 @@ var MongoQueryParser = class {
528
577
  }
529
578
  return orClauses.length > 0 ? { $or: orClauses } : null;
530
579
  }
531
- for (const op of matchOps) if (op.type === "where:callback") {
532
- const nestedCondition = this.buildCallbackCondition(op.data);
533
- if (nestedCondition) Object.assign(andFilter, nestedCondition);
534
- } else if (op.type === "where:object") Object.assign(andFilter, op.data);
535
- else {
536
- const condition = this.buildWhereCondition(op);
537
- if (condition) Object.assign(andFilter, condition);
538
- }
580
+ const mergeInto = (condition) => {
581
+ if (!condition) return;
582
+ Object.entries(condition).forEach(([key, value]) => mergeConditionEntry(andFilter, key, value));
583
+ };
584
+ for (const op of matchOps) if (op.type === "where:callback") mergeInto(this.buildCallbackCondition(op.data));
585
+ else if (op.type === "where:object") mergeInto(op.data);
586
+ else mergeInto(this.buildWhereCondition(op));
539
587
  return Object.keys(andFilter).length > 0 ? andFilter : null;
540
588
  }
541
589
  /**
@@ -549,11 +597,16 @@ var MongoQueryParser = class {
549
597
  switch (op.type) {
550
598
  case "where":
551
599
  case "orWhere": return this.buildOperatorCondition(field, operator, value);
552
- case "whereIn": return { [field]: { $in: value || op.data.values } };
553
- case "whereNotIn": return { [field]: { $nin: value || op.data.values } };
554
- case "whereNull": return { [field]: null };
555
- case "whereNotNull": return { [field]: { $ne: null } };
556
- case "whereBetween": return { [field]: {
600
+ case "whereIn":
601
+ case "orWhereIn": return { [field]: { $in: value || op.data.values } };
602
+ case "whereNotIn":
603
+ case "orWhereNotIn": return { [field]: { $nin: value || op.data.values } };
604
+ case "whereNull":
605
+ case "orWhereNull": return { [field]: null };
606
+ case "whereNotNull":
607
+ case "orWhereNotNull": return { [field]: { $ne: null } };
608
+ case "whereBetween":
609
+ case "orWhereBetween": return { [field]: {
557
610
  $gte: op.data.range[0],
558
611
  $lte: op.data.range[1]
559
612
  } };
@@ -648,7 +701,7 @@ var MongoQueryParser = class {
648
701
  */
649
702
  buildLikeRegexSource(data) {
650
703
  if (data.isRegExp === true && typeof data.pattern === "string") return data.pattern;
651
- return resolveLikePattern(data.pattern);
704
+ return resolveMongoLikePattern(data.pattern);
652
705
  }
653
706
  /**
654
707
  * Build a condition based on the operator.
@@ -661,14 +714,59 @@ var MongoQueryParser = class {
661
714
  buildOperatorCondition(field, operator, value) {
662
715
  switch (operator) {
663
716
  case "=": return { [field]: value };
664
- case "!=": return { [field]: { $ne: value } };
717
+ case "!=":
718
+ case "<>": return { [field]: { $ne: value } };
719
+ case "in": return { [field]: { $in: this.assertArrayOperand(operator, value) } };
720
+ case "notIn":
721
+ case "not in": return { [field]: { $nin: this.assertArrayOperand(operator, value) } };
722
+ case "between":
723
+ case "notBetween":
724
+ case "not between": {
725
+ const range = this.assertArrayOperand(operator, value);
726
+ if (range.length !== 2) throw new Error(`Operator "${operator}" requires a [min, max] pair.`);
727
+ const bounds = {
728
+ $gte: range[0],
729
+ $lte: range[1]
730
+ };
731
+ return { [field]: operator === "between" ? bounds : { $not: bounds } };
732
+ }
733
+ case "like": return { [field]: {
734
+ $regex: resolveMongoLikePattern(value),
735
+ $options: "i"
736
+ } };
737
+ case "notLike":
738
+ case "not like": return { [field]: { $not: {
739
+ $regex: resolveMongoLikePattern(value),
740
+ $options: "i"
741
+ } } };
742
+ case "startsWith": return { [field]: {
743
+ $regex: `^${escapeRegex(String(value))}`,
744
+ $options: "i"
745
+ } };
746
+ case "notStartsWith": return { [field]: { $not: {
747
+ $regex: `^${escapeRegex(String(value))}`,
748
+ $options: "i"
749
+ } } };
750
+ case "endsWith": return { [field]: {
751
+ $regex: `${escapeRegex(String(value))}$`,
752
+ $options: "i"
753
+ } };
754
+ case "notEndsWith": return { [field]: { $not: {
755
+ $regex: `${escapeRegex(String(value))}$`,
756
+ $options: "i"
757
+ } } };
758
+ case "exists": return { [field]: { $exists: value !== false } };
665
759
  case ">": return { [field]: { $gt: value } };
666
760
  case ">=": return { [field]: { $gte: value } };
667
761
  case "<": return { [field]: { $lt: value } };
668
762
  case "<=": return { [field]: { $lte: value } };
669
- default: return { [field]: value };
763
+ default: throw new Error(`Unsupported where operator "${operator}" on the MongoDB driver.`);
670
764
  }
671
765
  }
766
+ assertArrayOperand(operator, value) {
767
+ if (!Array.isArray(value)) throw new Error(`Operator "${operator}" requires an array operand.`);
768
+ return value;
769
+ }
672
770
  /**
673
771
  * Get MongoDB operator from comparison operator.
674
772
  *
@@ -784,12 +882,12 @@ var MongoQueryParser = class {
784
882
  }
785
883
  startOfDay(date) {
786
884
  const copy = new Date(date);
787
- copy.setHours(0, 0, 0, 0);
885
+ copy.setUTCHours(0, 0, 0, 0);
788
886
  return copy;
789
887
  }
790
888
  endOfDay(date) {
791
889
  const copy = new Date(date);
792
- copy.setHours(23, 59, 59, 999);
890
+ copy.setUTCHours(23, 59, 59, 999);
793
891
  return copy;
794
892
  }
795
893
  normalizePath(path) {
@@ -989,7 +1087,7 @@ var MongoQueryParser = class {
989
1087
  sort[op.data.field] = op.data.direction === "asc" ? 1 : -1;
990
1088
  break;
991
1089
  case "orderByRandom": return { $sample: { size: op.data.limit } };
992
- case "orderByRaw": break;
1090
+ case "orderByRaw": throw new Error("orderByRaw() is not supported by the MongoDB driver; use orderBy() instead.");
993
1091
  }
994
1092
  return Object.keys(sort).length > 0 ? { $sort: sort } : null;
995
1093
  }