@warlock.js/cascade 4.0.47 → 4.0.58

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 (401) hide show
  1. package/cjs/context/database-data-source-context.d.ts +29 -0
  2. package/cjs/context/database-data-source-context.d.ts.map +1 -0
  3. package/cjs/context/database-data-source-context.js +28 -0
  4. package/cjs/context/database-data-source-context.js.map +1 -0
  5. package/cjs/context/database-transaction-context.d.ts +31 -0
  6. package/cjs/context/database-transaction-context.d.ts.map +1 -0
  7. package/cjs/context/database-transaction-context.js +34 -0
  8. package/cjs/context/database-transaction-context.js.map +1 -0
  9. package/cjs/contracts/database-driver.contract.d.ts +143 -0
  10. package/cjs/contracts/database-driver.contract.d.ts.map +1 -0
  11. package/cjs/contracts/database-id-generator.contract.d.ts +109 -0
  12. package/cjs/contracts/database-id-generator.contract.d.ts.map +1 -0
  13. package/cjs/contracts/database-remover.contract.d.ts +104 -0
  14. package/cjs/contracts/database-remover.contract.d.ts.map +1 -0
  15. package/cjs/contracts/database-restorer.contract.d.ts +143 -0
  16. package/cjs/contracts/database-restorer.contract.d.ts.map +1 -0
  17. package/cjs/contracts/database-writer.contract.d.ts +119 -0
  18. package/cjs/contracts/database-writer.contract.d.ts.map +1 -0
  19. package/cjs/contracts/driver-blueprint.contract.d.ts +45 -0
  20. package/cjs/contracts/driver-blueprint.contract.d.ts.map +1 -0
  21. package/cjs/contracts/index.d.ts +10 -0
  22. package/cjs/contracts/index.d.ts.map +1 -0
  23. package/cjs/contracts/migration-driver.contract.d.ts +365 -0
  24. package/cjs/contracts/migration-driver.contract.d.ts.map +1 -0
  25. package/cjs/contracts/query-builder.contract.d.ts +1128 -0
  26. package/cjs/contracts/query-builder.contract.d.ts.map +1 -0
  27. package/cjs/contracts/sync-adapter.contract.d.ts +58 -0
  28. package/cjs/contracts/sync-adapter.contract.d.ts.map +1 -0
  29. package/cjs/data-source/data-source-registry.d.ts +104 -0
  30. package/cjs/data-source/data-source-registry.d.ts.map +1 -0
  31. package/cjs/data-source/data-source-registry.js +138 -0
  32. package/cjs/data-source/data-source-registry.js.map +1 -0
  33. package/cjs/data-source/data-source.d.ts +106 -0
  34. package/cjs/data-source/data-source.d.ts.map +1 -0
  35. package/cjs/data-source/data-source.js +77 -0
  36. package/cjs/data-source/data-source.js.map +1 -0
  37. package/cjs/database-dirty-tracker.d.ts +253 -0
  38. package/cjs/database-dirty-tracker.d.ts.map +1 -0
  39. package/cjs/database-dirty-tracker.js +389 -0
  40. package/cjs/database-dirty-tracker.js.map +1 -0
  41. package/cjs/drivers/mongo/mongo-id-generator.d.ts +116 -0
  42. package/cjs/drivers/mongo/mongo-id-generator.d.ts.map +1 -0
  43. package/cjs/drivers/mongo/mongo-id-generator.js +149 -0
  44. package/cjs/drivers/mongo/mongo-id-generator.js.map +1 -0
  45. package/cjs/drivers/mongo/mongo-migration-driver.d.ts +228 -0
  46. package/cjs/drivers/mongo/mongo-migration-driver.d.ts.map +1 -0
  47. package/cjs/drivers/mongo/mongo-migration-driver.js +524 -0
  48. package/cjs/drivers/mongo/mongo-migration-driver.js.map +1 -0
  49. package/cjs/drivers/mongo/mongo-query-builder.d.ts +922 -0
  50. package/cjs/drivers/mongo/mongo-query-builder.d.ts.map +1 -0
  51. package/cjs/drivers/mongo/mongo-query-builder.js +1740 -0
  52. package/cjs/drivers/mongo/mongo-query-builder.js.map +1 -0
  53. package/cjs/drivers/mongo/mongo-query-operations.d.ts +226 -0
  54. package/cjs/drivers/mongo/mongo-query-operations.d.ts.map +1 -0
  55. package/cjs/drivers/mongo/mongo-query-operations.js +270 -0
  56. package/cjs/drivers/mongo/mongo-query-operations.js.map +1 -0
  57. package/cjs/drivers/mongo/mongo-query-parser.d.ts +262 -0
  58. package/cjs/drivers/mongo/mongo-query-parser.d.ts.map +1 -0
  59. package/cjs/drivers/mongo/mongo-query-parser.js +1351 -0
  60. package/cjs/drivers/mongo/mongo-query-parser.js.map +1 -0
  61. package/cjs/drivers/mongo/mongo-sync-adapter.d.ts +79 -0
  62. package/cjs/drivers/mongo/mongo-sync-adapter.d.ts.map +1 -0
  63. package/cjs/drivers/mongo/mongo-sync-adapter.js +146 -0
  64. package/cjs/drivers/mongo/mongo-sync-adapter.js.map +1 -0
  65. package/cjs/drivers/mongo/mongodb-blueprint.d.ts +30 -0
  66. package/cjs/drivers/mongo/mongodb-blueprint.d.ts.map +1 -0
  67. package/cjs/drivers/mongo/mongodb-blueprint.js +51 -0
  68. package/cjs/drivers/mongo/mongodb-blueprint.js.map +1 -0
  69. package/cjs/drivers/mongo/mongodb-driver.d.ts +188 -0
  70. package/cjs/drivers/mongo/mongodb-driver.d.ts.map +1 -0
  71. package/cjs/drivers/mongo/mongodb-driver.js +411 -0
  72. package/cjs/drivers/mongo/mongodb-driver.js.map +1 -0
  73. package/cjs/drivers/mongo/types.d.ts +43 -0
  74. package/cjs/drivers/mongo/types.d.ts.map +1 -0
  75. package/cjs/errors/missing-data-source.error.d.ts +22 -0
  76. package/cjs/errors/missing-data-source.error.d.ts.map +1 -0
  77. package/cjs/errors/missing-data-source.error.js +29 -0
  78. package/cjs/errors/missing-data-source.error.js.map +1 -0
  79. package/cjs/events/model-events.d.ts +231 -0
  80. package/cjs/events/model-events.d.ts.map +1 -0
  81. package/cjs/events/model-events.js +259 -0
  82. package/cjs/events/model-events.js.map +1 -0
  83. package/cjs/expressions/aggregate-expressions.d.ts +215 -0
  84. package/cjs/expressions/aggregate-expressions.d.ts.map +1 -0
  85. package/cjs/expressions/aggregate-expressions.js +221 -0
  86. package/cjs/expressions/aggregate-expressions.js.map +1 -0
  87. package/cjs/expressions/index.d.ts +2 -0
  88. package/cjs/expressions/index.d.ts.map +1 -0
  89. package/cjs/index.d.ts +41 -0
  90. package/cjs/index.d.ts.map +1 -0
  91. package/cjs/index.js +1 -267
  92. package/cjs/index.js.map +1 -1
  93. package/cjs/migration/column-builder.d.ts +167 -0
  94. package/cjs/migration/column-builder.d.ts.map +1 -0
  95. package/cjs/migration/column-builder.js +217 -0
  96. package/cjs/migration/column-builder.js.map +1 -0
  97. package/cjs/migration/foreign-key-builder.d.ts +110 -0
  98. package/cjs/migration/foreign-key-builder.d.ts.map +1 -0
  99. package/cjs/migration/foreign-key-builder.js +129 -0
  100. package/cjs/migration/foreign-key-builder.js.map +1 -0
  101. package/cjs/migration/index.d.ts +6 -0
  102. package/cjs/migration/index.d.ts.map +1 -0
  103. package/cjs/migration/migration-runner.d.ts +231 -0
  104. package/cjs/migration/migration-runner.d.ts.map +1 -0
  105. package/cjs/migration/migration-runner.js +443 -0
  106. package/cjs/migration/migration-runner.js.map +1 -0
  107. package/cjs/migration/migration.js +1346 -0
  108. package/cjs/migration/migration.js.map +1 -0
  109. package/cjs/migration/types.d.ts +132 -0
  110. package/cjs/migration/types.d.ts.map +1 -0
  111. package/cjs/model/model.d.ts +1267 -0
  112. package/cjs/model/model.d.ts.map +1 -0
  113. package/cjs/model/model.js +1463 -0
  114. package/cjs/model/model.js.map +1 -0
  115. package/cjs/model/register-model.d.ts +80 -0
  116. package/cjs/model/register-model.d.ts.map +1 -0
  117. package/cjs/model/register-model.js +91 -0
  118. package/cjs/model/register-model.js.map +1 -0
  119. package/cjs/remover/database-remover.d.ts +100 -0
  120. package/cjs/remover/database-remover.d.ts.map +1 -0
  121. package/cjs/remover/database-remover.js +209 -0
  122. package/cjs/remover/database-remover.js.map +1 -0
  123. package/cjs/restorer/database-restorer.d.ts +131 -0
  124. package/cjs/restorer/database-restorer.d.ts.map +1 -0
  125. package/cjs/restorer/database-restorer.js +425 -0
  126. package/cjs/restorer/database-restorer.js.map +1 -0
  127. package/cjs/sync/index.d.ts +12 -0
  128. package/cjs/sync/index.d.ts.map +1 -0
  129. package/cjs/sync/model-events.d.ts +62 -0
  130. package/cjs/sync/model-events.d.ts.map +1 -0
  131. package/cjs/sync/model-events.js +49 -0
  132. package/cjs/sync/model-events.js.map +1 -0
  133. package/cjs/sync/model-sync-operation.d.ts +163 -0
  134. package/cjs/sync/model-sync-operation.d.ts.map +1 -0
  135. package/cjs/sync/model-sync-operation.js +292 -0
  136. package/cjs/sync/model-sync-operation.js.map +1 -0
  137. package/cjs/sync/model-sync.d.ts +130 -0
  138. package/cjs/sync/model-sync.d.ts.map +1 -0
  139. package/cjs/sync/model-sync.js +178 -0
  140. package/cjs/sync/model-sync.js.map +1 -0
  141. package/cjs/sync/sync-context.d.ts +70 -0
  142. package/cjs/sync/sync-context.d.ts.map +1 -0
  143. package/cjs/sync/sync-context.js +101 -0
  144. package/cjs/sync/sync-context.js.map +1 -0
  145. package/cjs/sync/sync-manager.d.ts +213 -0
  146. package/cjs/sync/sync-manager.d.ts.map +1 -0
  147. package/cjs/sync/sync-manager.js +689 -0
  148. package/cjs/sync/sync-manager.js.map +1 -0
  149. package/cjs/sync/types.d.ts +289 -0
  150. package/cjs/sync/types.d.ts.map +1 -0
  151. package/cjs/types.d.ts +45 -0
  152. package/cjs/types.d.ts.map +1 -0
  153. package/cjs/utils/connect-to-database.d.ts +246 -0
  154. package/cjs/utils/connect-to-database.d.ts.map +1 -0
  155. package/cjs/utils/connect-to-database.js +92 -0
  156. package/cjs/utils/connect-to-database.js.map +1 -0
  157. package/cjs/utils/database-writer.utils.d.ts +15 -0
  158. package/cjs/utils/database-writer.utils.d.ts.map +1 -0
  159. package/cjs/utils/database-writer.utils.js +14 -0
  160. package/cjs/utils/database-writer.utils.js.map +1 -0
  161. package/cjs/utils/define-model.js +100 -0
  162. package/cjs/utils/define-model.js.map +1 -0
  163. package/cjs/utils/once-connected.d.ts +146 -0
  164. package/cjs/utils/once-connected.d.ts.map +1 -0
  165. package/cjs/utils/once-connected.js +252 -0
  166. package/cjs/utils/once-connected.js.map +1 -0
  167. package/cjs/validation/database-seal-plugins.d.ts +2 -0
  168. package/cjs/validation/database-seal-plugins.d.ts.map +1 -0
  169. package/cjs/validation/database-seal-plugins.js +4 -0
  170. package/cjs/validation/database-seal-plugins.js.map +1 -0
  171. package/cjs/validation/database-writer-validation-error.d.ts +97 -0
  172. package/cjs/validation/database-writer-validation-error.d.ts.map +1 -0
  173. package/cjs/validation/database-writer-validation-error.js +160 -0
  174. package/cjs/validation/database-writer-validation-error.js.map +1 -0
  175. package/cjs/validation/index.d.ts +3 -0
  176. package/cjs/validation/index.d.ts.map +1 -0
  177. package/cjs/validation/mutators/embed-mutator.d.ts +9 -0
  178. package/cjs/validation/mutators/embed-mutator.d.ts.map +1 -0
  179. package/cjs/validation/mutators/embed-mutator.js +33 -0
  180. package/cjs/validation/mutators/embed-mutator.js.map +1 -0
  181. package/cjs/validation/plugins/embed-validator-plugin.d.ts +24 -0
  182. package/cjs/validation/plugins/embed-validator-plugin.d.ts.map +1 -0
  183. package/cjs/validation/plugins/embed-validator-plugin.js +18 -0
  184. package/cjs/validation/plugins/embed-validator-plugin.js.map +1 -0
  185. package/cjs/validation/rules/database-model-rule.d.ts +7 -0
  186. package/cjs/validation/rules/database-model-rule.d.ts.map +1 -0
  187. package/cjs/validation/rules/database-model-rule.js +27 -0
  188. package/cjs/validation/rules/database-model-rule.js.map +1 -0
  189. package/cjs/validation/transformers/embed-model-transformer.d.ts +3 -0
  190. package/cjs/validation/transformers/embed-model-transformer.d.ts.map +1 -0
  191. package/cjs/validation/transformers/embed-model-transformer.js +18 -0
  192. package/cjs/validation/transformers/embed-model-transformer.js.map +1 -0
  193. package/cjs/validation/validators/embed-validator.d.ts +21 -0
  194. package/cjs/validation/validators/embed-validator.d.ts.map +1 -0
  195. package/cjs/validation/validators/embed-validator.js +42 -0
  196. package/cjs/validation/validators/embed-validator.js.map +1 -0
  197. package/cjs/writer/database-writer.d.ts +181 -0
  198. package/cjs/writer/database-writer.d.ts.map +1 -0
  199. package/cjs/writer/database-writer.js +402 -0
  200. package/cjs/writer/database-writer.js.map +1 -0
  201. package/esm/context/database-data-source-context.d.ts +29 -0
  202. package/esm/context/database-data-source-context.d.ts.map +1 -0
  203. package/esm/context/database-data-source-context.js +28 -0
  204. package/esm/context/database-data-source-context.js.map +1 -0
  205. package/esm/context/database-transaction-context.d.ts +31 -0
  206. package/esm/context/database-transaction-context.d.ts.map +1 -0
  207. package/esm/context/database-transaction-context.js +34 -0
  208. package/esm/context/database-transaction-context.js.map +1 -0
  209. package/esm/contracts/database-driver.contract.d.ts +143 -0
  210. package/esm/contracts/database-driver.contract.d.ts.map +1 -0
  211. package/esm/contracts/database-id-generator.contract.d.ts +109 -0
  212. package/esm/contracts/database-id-generator.contract.d.ts.map +1 -0
  213. package/esm/contracts/database-remover.contract.d.ts +104 -0
  214. package/esm/contracts/database-remover.contract.d.ts.map +1 -0
  215. package/esm/contracts/database-restorer.contract.d.ts +143 -0
  216. package/esm/contracts/database-restorer.contract.d.ts.map +1 -0
  217. package/esm/contracts/database-writer.contract.d.ts +119 -0
  218. package/esm/contracts/database-writer.contract.d.ts.map +1 -0
  219. package/esm/contracts/driver-blueprint.contract.d.ts +45 -0
  220. package/esm/contracts/driver-blueprint.contract.d.ts.map +1 -0
  221. package/esm/contracts/index.d.ts +10 -0
  222. package/esm/contracts/index.d.ts.map +1 -0
  223. package/esm/contracts/migration-driver.contract.d.ts +365 -0
  224. package/esm/contracts/migration-driver.contract.d.ts.map +1 -0
  225. package/esm/contracts/query-builder.contract.d.ts +1128 -0
  226. package/esm/contracts/query-builder.contract.d.ts.map +1 -0
  227. package/esm/contracts/sync-adapter.contract.d.ts +58 -0
  228. package/esm/contracts/sync-adapter.contract.d.ts.map +1 -0
  229. package/esm/data-source/data-source-registry.d.ts +104 -0
  230. package/esm/data-source/data-source-registry.d.ts.map +1 -0
  231. package/esm/data-source/data-source-registry.js +138 -0
  232. package/esm/data-source/data-source-registry.js.map +1 -0
  233. package/esm/data-source/data-source.d.ts +106 -0
  234. package/esm/data-source/data-source.d.ts.map +1 -0
  235. package/esm/data-source/data-source.js +77 -0
  236. package/esm/data-source/data-source.js.map +1 -0
  237. package/esm/database-dirty-tracker.d.ts +253 -0
  238. package/esm/database-dirty-tracker.d.ts.map +1 -0
  239. package/esm/database-dirty-tracker.js +389 -0
  240. package/esm/database-dirty-tracker.js.map +1 -0
  241. package/esm/drivers/mongo/mongo-id-generator.d.ts +116 -0
  242. package/esm/drivers/mongo/mongo-id-generator.d.ts.map +1 -0
  243. package/esm/drivers/mongo/mongo-id-generator.js +149 -0
  244. package/esm/drivers/mongo/mongo-id-generator.js.map +1 -0
  245. package/esm/drivers/mongo/mongo-migration-driver.d.ts +228 -0
  246. package/esm/drivers/mongo/mongo-migration-driver.d.ts.map +1 -0
  247. package/esm/drivers/mongo/mongo-migration-driver.js +524 -0
  248. package/esm/drivers/mongo/mongo-migration-driver.js.map +1 -0
  249. package/esm/drivers/mongo/mongo-query-builder.d.ts +922 -0
  250. package/esm/drivers/mongo/mongo-query-builder.d.ts.map +1 -0
  251. package/esm/drivers/mongo/mongo-query-builder.js +1740 -0
  252. package/esm/drivers/mongo/mongo-query-builder.js.map +1 -0
  253. package/esm/drivers/mongo/mongo-query-operations.d.ts +226 -0
  254. package/esm/drivers/mongo/mongo-query-operations.d.ts.map +1 -0
  255. package/esm/drivers/mongo/mongo-query-operations.js +270 -0
  256. package/esm/drivers/mongo/mongo-query-operations.js.map +1 -0
  257. package/esm/drivers/mongo/mongo-query-parser.d.ts +262 -0
  258. package/esm/drivers/mongo/mongo-query-parser.d.ts.map +1 -0
  259. package/esm/drivers/mongo/mongo-query-parser.js +1351 -0
  260. package/esm/drivers/mongo/mongo-query-parser.js.map +1 -0
  261. package/esm/drivers/mongo/mongo-sync-adapter.d.ts +79 -0
  262. package/esm/drivers/mongo/mongo-sync-adapter.d.ts.map +1 -0
  263. package/esm/drivers/mongo/mongo-sync-adapter.js +146 -0
  264. package/esm/drivers/mongo/mongo-sync-adapter.js.map +1 -0
  265. package/esm/drivers/mongo/mongodb-blueprint.d.ts +30 -0
  266. package/esm/drivers/mongo/mongodb-blueprint.d.ts.map +1 -0
  267. package/esm/drivers/mongo/mongodb-blueprint.js +51 -0
  268. package/esm/drivers/mongo/mongodb-blueprint.js.map +1 -0
  269. package/esm/drivers/mongo/mongodb-driver.d.ts +188 -0
  270. package/esm/drivers/mongo/mongodb-driver.d.ts.map +1 -0
  271. package/esm/drivers/mongo/mongodb-driver.js +411 -0
  272. package/esm/drivers/mongo/mongodb-driver.js.map +1 -0
  273. package/esm/drivers/mongo/types.d.ts +43 -0
  274. package/esm/drivers/mongo/types.d.ts.map +1 -0
  275. package/esm/errors/missing-data-source.error.d.ts +22 -0
  276. package/esm/errors/missing-data-source.error.d.ts.map +1 -0
  277. package/esm/errors/missing-data-source.error.js +29 -0
  278. package/esm/errors/missing-data-source.error.js.map +1 -0
  279. package/esm/events/model-events.d.ts +231 -0
  280. package/esm/events/model-events.d.ts.map +1 -0
  281. package/esm/events/model-events.js +259 -0
  282. package/esm/events/model-events.js.map +1 -0
  283. package/esm/expressions/aggregate-expressions.d.ts +215 -0
  284. package/esm/expressions/aggregate-expressions.d.ts.map +1 -0
  285. package/esm/expressions/aggregate-expressions.js +221 -0
  286. package/esm/expressions/aggregate-expressions.js.map +1 -0
  287. package/esm/expressions/index.d.ts +2 -0
  288. package/esm/expressions/index.d.ts.map +1 -0
  289. package/esm/index.d.ts +41 -0
  290. package/esm/index.d.ts.map +1 -0
  291. package/esm/index.js +1 -40
  292. package/esm/index.js.map +1 -1
  293. package/esm/migration/column-builder.d.ts +167 -0
  294. package/esm/migration/column-builder.d.ts.map +1 -0
  295. package/esm/migration/column-builder.js +217 -0
  296. package/esm/migration/column-builder.js.map +1 -0
  297. package/esm/migration/foreign-key-builder.d.ts +110 -0
  298. package/esm/migration/foreign-key-builder.d.ts.map +1 -0
  299. package/esm/migration/foreign-key-builder.js +129 -0
  300. package/esm/migration/foreign-key-builder.js.map +1 -0
  301. package/esm/migration/index.d.ts +6 -0
  302. package/esm/migration/index.d.ts.map +1 -0
  303. package/esm/migration/migration-runner.d.ts +231 -0
  304. package/esm/migration/migration-runner.d.ts.map +1 -0
  305. package/esm/migration/migration-runner.js +443 -0
  306. package/esm/migration/migration-runner.js.map +1 -0
  307. package/esm/migration/migration.js +1346 -0
  308. package/esm/migration/migration.js.map +1 -0
  309. package/esm/migration/types.d.ts +132 -0
  310. package/esm/migration/types.d.ts.map +1 -0
  311. package/esm/model/model.d.ts +1267 -0
  312. package/esm/model/model.d.ts.map +1 -0
  313. package/esm/model/model.js +1463 -0
  314. package/esm/model/model.js.map +1 -0
  315. package/esm/model/register-model.d.ts +80 -0
  316. package/esm/model/register-model.d.ts.map +1 -0
  317. package/esm/model/register-model.js +91 -0
  318. package/esm/model/register-model.js.map +1 -0
  319. package/esm/remover/database-remover.d.ts +100 -0
  320. package/esm/remover/database-remover.d.ts.map +1 -0
  321. package/esm/remover/database-remover.js +209 -0
  322. package/esm/remover/database-remover.js.map +1 -0
  323. package/esm/restorer/database-restorer.d.ts +131 -0
  324. package/esm/restorer/database-restorer.d.ts.map +1 -0
  325. package/esm/restorer/database-restorer.js +425 -0
  326. package/esm/restorer/database-restorer.js.map +1 -0
  327. package/esm/sync/index.d.ts +12 -0
  328. package/esm/sync/index.d.ts.map +1 -0
  329. package/esm/sync/model-events.d.ts +62 -0
  330. package/esm/sync/model-events.d.ts.map +1 -0
  331. package/esm/sync/model-events.js +49 -0
  332. package/esm/sync/model-events.js.map +1 -0
  333. package/esm/sync/model-sync-operation.d.ts +163 -0
  334. package/esm/sync/model-sync-operation.d.ts.map +1 -0
  335. package/esm/sync/model-sync-operation.js +292 -0
  336. package/esm/sync/model-sync-operation.js.map +1 -0
  337. package/esm/sync/model-sync.d.ts +130 -0
  338. package/esm/sync/model-sync.d.ts.map +1 -0
  339. package/esm/sync/model-sync.js +178 -0
  340. package/esm/sync/model-sync.js.map +1 -0
  341. package/esm/sync/sync-context.d.ts +70 -0
  342. package/esm/sync/sync-context.d.ts.map +1 -0
  343. package/esm/sync/sync-context.js +101 -0
  344. package/esm/sync/sync-context.js.map +1 -0
  345. package/esm/sync/sync-manager.d.ts +213 -0
  346. package/esm/sync/sync-manager.d.ts.map +1 -0
  347. package/esm/sync/sync-manager.js +689 -0
  348. package/esm/sync/sync-manager.js.map +1 -0
  349. package/esm/sync/types.d.ts +289 -0
  350. package/esm/sync/types.d.ts.map +1 -0
  351. package/esm/types.d.ts +45 -0
  352. package/esm/types.d.ts.map +1 -0
  353. package/esm/utils/connect-to-database.d.ts +246 -0
  354. package/esm/utils/connect-to-database.d.ts.map +1 -0
  355. package/esm/utils/connect-to-database.js +92 -0
  356. package/esm/utils/connect-to-database.js.map +1 -0
  357. package/esm/utils/database-writer.utils.d.ts +15 -0
  358. package/esm/utils/database-writer.utils.d.ts.map +1 -0
  359. package/esm/utils/database-writer.utils.js +14 -0
  360. package/esm/utils/database-writer.utils.js.map +1 -0
  361. package/esm/utils/define-model.js +100 -0
  362. package/esm/utils/define-model.js.map +1 -0
  363. package/esm/utils/once-connected.d.ts +146 -0
  364. package/esm/utils/once-connected.d.ts.map +1 -0
  365. package/esm/utils/once-connected.js +252 -0
  366. package/esm/utils/once-connected.js.map +1 -0
  367. package/esm/validation/database-seal-plugins.d.ts +2 -0
  368. package/esm/validation/database-seal-plugins.d.ts.map +1 -0
  369. package/esm/validation/database-seal-plugins.js +4 -0
  370. package/esm/validation/database-seal-plugins.js.map +1 -0
  371. package/esm/validation/database-writer-validation-error.d.ts +97 -0
  372. package/esm/validation/database-writer-validation-error.d.ts.map +1 -0
  373. package/esm/validation/database-writer-validation-error.js +160 -0
  374. package/esm/validation/database-writer-validation-error.js.map +1 -0
  375. package/esm/validation/index.d.ts +3 -0
  376. package/esm/validation/index.d.ts.map +1 -0
  377. package/esm/validation/mutators/embed-mutator.d.ts +9 -0
  378. package/esm/validation/mutators/embed-mutator.d.ts.map +1 -0
  379. package/esm/validation/mutators/embed-mutator.js +33 -0
  380. package/esm/validation/mutators/embed-mutator.js.map +1 -0
  381. package/esm/validation/plugins/embed-validator-plugin.d.ts +24 -0
  382. package/esm/validation/plugins/embed-validator-plugin.d.ts.map +1 -0
  383. package/esm/validation/plugins/embed-validator-plugin.js +18 -0
  384. package/esm/validation/plugins/embed-validator-plugin.js.map +1 -0
  385. package/esm/validation/rules/database-model-rule.d.ts +7 -0
  386. package/esm/validation/rules/database-model-rule.d.ts.map +1 -0
  387. package/esm/validation/rules/database-model-rule.js +27 -0
  388. package/esm/validation/rules/database-model-rule.js.map +1 -0
  389. package/esm/validation/transformers/embed-model-transformer.d.ts +3 -0
  390. package/esm/validation/transformers/embed-model-transformer.d.ts.map +1 -0
  391. package/esm/validation/transformers/embed-model-transformer.js +18 -0
  392. package/esm/validation/transformers/embed-model-transformer.js.map +1 -0
  393. package/esm/validation/validators/embed-validator.d.ts +21 -0
  394. package/esm/validation/validators/embed-validator.d.ts.map +1 -0
  395. package/esm/validation/validators/embed-validator.js +42 -0
  396. package/esm/validation/validators/embed-validator.js.map +1 -0
  397. package/esm/writer/database-writer.d.ts +181 -0
  398. package/esm/writer/database-writer.d.ts.map +1 -0
  399. package/esm/writer/database-writer.js +402 -0
  400. package/esm/writer/database-writer.js.map +1 -0
  401. package/package.json +61 -52
@@ -0,0 +1,1351 @@
1
+ 'use strict';var copper=require('@mongez/copper'),aggregateExpressions=require('../../expressions/aggregate-expressions.js');/**
2
+ * Parses query builder operations into MongoDB aggregation pipeline.
3
+ *
4
+ * This parser is responsible for converting the abstract operations collected
5
+ * by the query builder into a concrete MongoDB aggregation pipeline. It handles
6
+ * intelligent grouping of mergeable operations (like multiple where clauses)
7
+ * into single pipeline stages for optimal performance.
8
+ */
9
+ class MongoQueryParser {
10
+ /**
11
+ * The MongoDB collection being queried.
12
+ */
13
+ collection;
14
+ /**
15
+ * The ordered list of operations to parse.
16
+ */
17
+ operations;
18
+ /**
19
+ * Factory for creating sub-builders (used when resolving callbacks).
20
+ */
21
+ createSubBuilder;
22
+ /**
23
+ * Track group field names for automatic _id renaming.
24
+ * Maps pipeline index to field names.
25
+ */
26
+ groupFieldNames = new Map();
27
+ /**
28
+ * Create a new MongoDB query parser.
29
+ *
30
+ * @param options - Configuration options for the parser
31
+ */
32
+ constructor(options) {
33
+ this.collection = options.collection;
34
+ this.operations = options.operations;
35
+ this.createSubBuilder = options.createSubBuilder;
36
+ }
37
+ /**
38
+ * Parse the operations into a MongoDB aggregation pipeline.
39
+ *
40
+ * This method intelligently groups mergeable operations (e.g., multiple where
41
+ * clauses) into single pipeline stages while maintaining the correct execution
42
+ * order for non-mergeable operations.
43
+ *
44
+ * @returns The MongoDB aggregation pipeline
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * const parser = new MongoQueryParser({ collection, operations });
49
+ * const pipeline = parser.parse();
50
+ * // [
51
+ * // { $match: { status: 'active', age: { $gt: 18 } } },
52
+ * // { $sort: { createdAt: -1 } },
53
+ * // { $limit: 10 }
54
+ * // ]
55
+ * ```
56
+ */
57
+ parse() {
58
+ const pipeline = [];
59
+ let currentStage = null;
60
+ let currentBuffer = [];
61
+ for (const op of this.operations) {
62
+ if (op.mergeable && op.stage === currentStage) {
63
+ // Same mergeable stage, add to buffer
64
+ currentBuffer.push(op);
65
+ }
66
+ else {
67
+ // Different stage or non-mergeable, flush buffer
68
+ if (currentBuffer.length > 0) {
69
+ const builtStage = this.buildStage(currentStage, currentBuffer);
70
+ if (builtStage) {
71
+ const stageIndex = pipeline.length;
72
+ pipeline.push(builtStage);
73
+ // Track field names for group stages with aggregates
74
+ this.trackGroupFieldNames(currentStage, currentBuffer, stageIndex);
75
+ }
76
+ currentBuffer = [];
77
+ }
78
+ if (op.mergeable) {
79
+ // Start new buffer
80
+ currentStage = op.stage;
81
+ currentBuffer.push(op);
82
+ }
83
+ else {
84
+ // Non-mergeable, add directly
85
+ const builtStage = this.buildStage(op.stage, [op]);
86
+ if (builtStage) {
87
+ const stageIndex = pipeline.length;
88
+ pipeline.push(builtStage);
89
+ // Track field names for group stages with aggregates
90
+ this.trackGroupFieldNames(op.stage, [op], stageIndex);
91
+ }
92
+ currentStage = null;
93
+ }
94
+ }
95
+ }
96
+ // Flush remaining buffer
97
+ if (currentBuffer.length > 0) {
98
+ const builtStage = this.buildStage(currentStage, currentBuffer);
99
+ if (builtStage) {
100
+ const stageIndex = pipeline.length;
101
+ pipeline.push(builtStage);
102
+ // Track field names for group stages with aggregates
103
+ this.trackGroupFieldNames(currentStage, currentBuffer, stageIndex);
104
+ }
105
+ }
106
+ // Post-process: Rename _id to actual field names after $group stages with aggregates
107
+ return this.postProcessGroupStages(pipeline);
108
+ }
109
+ /**
110
+ * Track field names for group stages that need _id renaming.
111
+ */
112
+ trackGroupFieldNames(stage, operations, stageIndex) {
113
+ if (stage === "$group") {
114
+ const op = operations[0];
115
+ if (op.type === "groupByWithAggregates" && op.payload.fields) {
116
+ const fieldNames = this.extractGroupFieldNames(op.payload.fields);
117
+ if (fieldNames) {
118
+ this.groupFieldNames.set(stageIndex, fieldNames);
119
+ }
120
+ }
121
+ }
122
+ }
123
+ /**
124
+ * Post-process pipeline to rename _id fields after $group stages.
125
+ *
126
+ * This automatically renames MongoDB's `_id` field to the actual field name(s)
127
+ * used for grouping, making the results more intuitive.
128
+ *
129
+ * @param pipeline - The aggregation pipeline
130
+ * @returns The processed pipeline
131
+ */
132
+ postProcessGroupStages(pipeline) {
133
+ const processed = [];
134
+ for (let i = 0; i < pipeline.length; i++) {
135
+ const stage = pipeline[i];
136
+ // Check if this is a $group stage that needs _id renaming
137
+ if (stage.$group && this.groupFieldNames.has(i)) {
138
+ const fieldNames = this.groupFieldNames.get(i);
139
+ // Add the $group stage
140
+ processed.push(stage);
141
+ // Add a $project stage to rename _id
142
+ const projection = {};
143
+ if (typeof fieldNames === "string") {
144
+ // Single field: rename _id to field name
145
+ projection[fieldNames] = "$_id";
146
+ }
147
+ else if (Array.isArray(fieldNames) && fieldNames.length > 0) {
148
+ // Multiple fields: _id is an object, spread it
149
+ for (const fieldName of fieldNames) {
150
+ projection[fieldName] = `$_id.${fieldName}`;
151
+ }
152
+ }
153
+ // Include all aggregate fields
154
+ const aggregateFields = Object.keys(stage.$group).filter((key) => key !== "_id");
155
+ for (const field of aggregateFields) {
156
+ projection[field] = 1;
157
+ }
158
+ if (Object.keys(projection).length > 0) {
159
+ // now unselect the _id field
160
+ projection._id = 0;
161
+ processed.push({ $project: projection });
162
+ }
163
+ }
164
+ else {
165
+ // Regular stage, add as-is
166
+ processed.push(stage);
167
+ }
168
+ }
169
+ return processed;
170
+ }
171
+ /**
172
+ * Convert the parsed pipeline to a pretty-printed string for debugging.
173
+ *
174
+ * This method formats the MongoDB aggregation pipeline in a human-readable
175
+ * way, making it easier to understand and debug complex queries.
176
+ *
177
+ * @returns A formatted string representation of the pipeline
178
+ *
179
+ * @example
180
+ * ```typescript
181
+ * const parser = new MongoQueryParser({ collection, operations });
182
+ * console.log(parser.toPrettyString());
183
+ * // Output:
184
+ * // MongoDB Aggregation Pipeline:
185
+ * // ════════════════════════════
186
+ * // Stage 1: $match
187
+ * // status: "active"
188
+ * // age: { $gt: 18 }
189
+ * //
190
+ * // Stage 2: $sort
191
+ * // createdAt: -1
192
+ * ```
193
+ */
194
+ toPrettyString() {
195
+ const pipeline = this.parse();
196
+ if (pipeline.length === 0) {
197
+ return "MongoDB Aggregation Pipeline: (empty)";
198
+ }
199
+ let output = "MongoDB Aggregation Pipeline:\n";
200
+ output += "═".repeat(50) + "\n";
201
+ pipeline.forEach((stage, index) => {
202
+ const stageName = Object.keys(stage)[0];
203
+ const stageData = stage[stageName];
204
+ if (index > 0) {
205
+ output += "\n";
206
+ }
207
+ output += `Stage ${index + 1}: ${copper.colors.redBright(stageName)}\n`;
208
+ output += this.formatStageData(stageData, 2);
209
+ });
210
+ return output;
211
+ }
212
+ /**
213
+ * Format stage data with proper indentation.
214
+ *
215
+ * @param data - The stage data to format
216
+ * @param indent - The indentation level
217
+ * @returns Formatted string
218
+ */
219
+ formatStageData(data, indent = 0) {
220
+ const spaces = " ".repeat(indent);
221
+ if (typeof data !== "object" || data === null) {
222
+ return `${spaces}${JSON.stringify(data)}\n`;
223
+ }
224
+ if (Array.isArray(data)) {
225
+ if (data.length === 0)
226
+ return `${spaces}[]`;
227
+ let result = "";
228
+ data.forEach((item, index) => {
229
+ result += `${spaces}[${copper.colors.magenta(index)}]:\n`;
230
+ result += this.formatStageData(item, indent + 2);
231
+ });
232
+ return result;
233
+ }
234
+ let result = "";
235
+ Object.entries(data).forEach(([key, value]) => {
236
+ const isOperator = key.startsWith("$");
237
+ const coloredKey = isOperator ? copper.colors.magentaBright(key) : copper.colors.blue(key);
238
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
239
+ result += `${spaces}${coloredKey}:\n`;
240
+ result += this.formatStageData(value, indent + 2);
241
+ }
242
+ else if (Array.isArray(value)) {
243
+ result += `${spaces}${coloredKey}:\n`;
244
+ result += this.formatStageData(value, indent + 2);
245
+ }
246
+ else {
247
+ const formattedValue = typeof value === "number"
248
+ ? copper.colors.yellowBright(value)
249
+ : typeof value === "boolean"
250
+ ? copper.colors.cyanBright(value.toString())
251
+ : typeof value === "string"
252
+ ? copper.colors.greenBright(JSON.stringify(value))
253
+ : copper.colors.greenBright(String(value));
254
+ result += `${spaces}${coloredKey}: ${formattedValue}\n`;
255
+ }
256
+ });
257
+ return result.endsWith("\n") ? result : `${result}\n`;
258
+ }
259
+ /**
260
+ * Build a single pipeline stage from a group of operations.
261
+ *
262
+ * @param stage - The pipeline stage type
263
+ * @param operations - The operations to build the stage from
264
+ * @returns The built pipeline stage or null if no stage should be added
265
+ */
266
+ buildStage(stage, operations) {
267
+ switch (stage) {
268
+ case "$match":
269
+ return this.buildMatchStage(operations);
270
+ case "$project":
271
+ return this.buildProjectStage(operations);
272
+ case "$sort":
273
+ return this.buildSortStage(operations);
274
+ case "$group":
275
+ return this.buildGroupStage(operations);
276
+ case "$lookup":
277
+ return this.buildLookupStage(operations);
278
+ case "$limit":
279
+ return { $limit: operations[0].payload.value };
280
+ case "$skip":
281
+ return { $skip: operations[0].payload.value };
282
+ case "$setWindowFields":
283
+ return {
284
+ $setWindowFields: operations[0].payload.spec,
285
+ };
286
+ default:
287
+ return null;
288
+ }
289
+ }
290
+ /**
291
+ * Build a $match stage from where operations.
292
+ *
293
+ * Query building strategy:
294
+ * - Top-level where() + orWhere() = Pure OR
295
+ * - Use callbacks for AND + OR grouping
296
+ *
297
+ * @param operations - The where operations
298
+ * @returns The $match stage or null
299
+ */
300
+ buildMatchStage(operations) {
301
+ const andFilter = {};
302
+ const orClauses = [];
303
+ const pendingSimpleWhere = [];
304
+ let topLevelOrMode = false;
305
+ const pushOr = (clause) => {
306
+ if (!clause) {
307
+ return;
308
+ }
309
+ if (this.isPureOrCondition(clause)) {
310
+ orClauses.push(...clause.$or);
311
+ return;
312
+ }
313
+ if (Array.isArray(clause)) {
314
+ orClauses.push(...clause);
315
+ return;
316
+ }
317
+ orClauses.push(clause);
318
+ };
319
+ const mergeAnd = (condition) => {
320
+ if (!condition) {
321
+ return;
322
+ }
323
+ Object.entries(condition).forEach(([key, value]) => {
324
+ if (key === "$or") {
325
+ pushOr(value);
326
+ return;
327
+ }
328
+ if (value &&
329
+ typeof value === "object" &&
330
+ !Array.isArray(value) &&
331
+ andFilter[key] &&
332
+ typeof andFilter[key] === "object" &&
333
+ !Array.isArray(andFilter[key])) {
334
+ andFilter[key] = { ...andFilter[key], ...value };
335
+ }
336
+ else {
337
+ andFilter[key] = value;
338
+ }
339
+ });
340
+ };
341
+ const queueSimpleWhere = (condition) => {
342
+ if (!condition) {
343
+ return;
344
+ }
345
+ if (topLevelOrMode) {
346
+ pushOr(condition);
347
+ }
348
+ else {
349
+ pendingSimpleWhere.push(condition);
350
+ }
351
+ };
352
+ const enterTopLevelOrMode = () => {
353
+ if (topLevelOrMode) {
354
+ return;
355
+ }
356
+ topLevelOrMode = true;
357
+ while (pendingSimpleWhere.length > 0) {
358
+ const condition = pendingSimpleWhere.shift();
359
+ if (condition) {
360
+ pushOr(condition);
361
+ }
362
+ }
363
+ };
364
+ const flushPendingSimpleWhere = () => {
365
+ if (pendingSimpleWhere.length === 0) {
366
+ return;
367
+ }
368
+ if (topLevelOrMode) {
369
+ pendingSimpleWhere.forEach(pushOr);
370
+ }
371
+ else {
372
+ pendingSimpleWhere.forEach(mergeAnd);
373
+ }
374
+ pendingSimpleWhere.length = 0;
375
+ };
376
+ for (const op of operations) {
377
+ if (op.type === "where:callback" || op.type === "orWhere:callback") {
378
+ flushPendingSimpleWhere();
379
+ const callbackCondition = this.buildCallbackCondition(op.payload);
380
+ if (!callbackCondition) {
381
+ continue;
382
+ }
383
+ const treatAsOr = op.type === "orWhere:callback" ||
384
+ (topLevelOrMode && !this.isPureOrCondition(callbackCondition)) ||
385
+ this.isPureOrCondition(callbackCondition);
386
+ if (treatAsOr) {
387
+ if (op.type === "orWhere:callback") {
388
+ enterTopLevelOrMode();
389
+ }
390
+ pushOr(callbackCondition);
391
+ }
392
+ else {
393
+ mergeAnd(callbackCondition);
394
+ }
395
+ continue;
396
+ }
397
+ if (op.type === "where:object") {
398
+ queueSimpleWhere(op.payload);
399
+ continue;
400
+ }
401
+ if (op.type === "where:not" ||
402
+ op.type === "orWhere:not" ||
403
+ op.type === "where:exists" ||
404
+ op.type === "where:notExists") {
405
+ const negated = op.type === "where:not" || op.type === "where:notExists";
406
+ const nested = this.buildCallbackCondition(op.payload.callback);
407
+ if (nested) {
408
+ const condition = negated ? { $nor: [nested] } : nested;
409
+ if (op.type.startsWith("orWhere")) {
410
+ enterTopLevelOrMode();
411
+ pushOr(condition);
412
+ }
413
+ else {
414
+ queueSimpleWhere(condition);
415
+ }
416
+ }
417
+ continue;
418
+ }
419
+ if (op.type === "orWhere:object") {
420
+ enterTopLevelOrMode();
421
+ pushOr(op.payload);
422
+ continue;
423
+ }
424
+ const condition = this.buildWhereCondition(op);
425
+ if (!condition) {
426
+ continue;
427
+ }
428
+ if (op.type.startsWith("orWhere")) {
429
+ enterTopLevelOrMode();
430
+ pushOr(condition);
431
+ }
432
+ else {
433
+ queueSimpleWhere(condition);
434
+ }
435
+ }
436
+ flushPendingSimpleWhere();
437
+ const hasAnd = Object.keys(andFilter).length > 0;
438
+ const hasOr = orClauses.length > 0;
439
+ if (!hasAnd && !hasOr) {
440
+ return null;
441
+ }
442
+ const match = {};
443
+ if (hasAnd) {
444
+ Object.assign(match, andFilter);
445
+ }
446
+ if (hasOr) {
447
+ match.$or = orClauses;
448
+ }
449
+ return { $match: match };
450
+ }
451
+ isPureOrCondition(condition) {
452
+ return (condition &&
453
+ typeof condition === "object" &&
454
+ !Array.isArray(condition) &&
455
+ Object.keys(condition).length === 1 &&
456
+ Array.isArray(condition.$or));
457
+ }
458
+ /**
459
+ * Build a condition from a callback-based where clause.
460
+ * Creates a sub-builder, executes the callback, and extracts the conditions.
461
+ * If callback has orWhere, all conditions become OR.
462
+ *
463
+ * @param callback - The callback function
464
+ * @returns The built condition or null
465
+ */
466
+ buildCallbackCondition(callback) {
467
+ // Create a temporary sub-builder
468
+ const subBuilder = this.createSubBuilder();
469
+ // Execute the callback with the sub-builder
470
+ callback(subBuilder);
471
+ // Extract only match operations from the sub-builder
472
+ const matchOps = subBuilder.operations.filter((op) => op.stage === "$match");
473
+ if (matchOps.length === 0) {
474
+ return null;
475
+ }
476
+ const andFilter = {};
477
+ const orClauses = [];
478
+ const hasInternalOr = matchOps.some((op) => op.type.startsWith("orWhere"));
479
+ const pushOr = (clause) => {
480
+ if (!clause) {
481
+ return;
482
+ }
483
+ if (this.isPureOrCondition(clause)) {
484
+ orClauses.push(...clause.$or);
485
+ return;
486
+ }
487
+ orClauses.push(clause);
488
+ };
489
+ if (hasInternalOr) {
490
+ for (const op of matchOps) {
491
+ if (op.type === "where:callback" || op.type === "orWhere:callback") {
492
+ const nestedCondition = this.buildCallbackCondition(op.payload);
493
+ if (nestedCondition) {
494
+ pushOr(nestedCondition);
495
+ }
496
+ continue;
497
+ }
498
+ if (op.type === "where:object" || op.type === "orWhere:object") {
499
+ pushOr(op.payload);
500
+ continue;
501
+ }
502
+ const condition = this.buildWhereCondition(op);
503
+ if (condition) {
504
+ pushOr(condition);
505
+ }
506
+ }
507
+ return orClauses.length > 0 ? { $or: orClauses } : null;
508
+ }
509
+ for (const op of matchOps) {
510
+ if (op.type === "where:callback") {
511
+ const nestedCondition = this.buildCallbackCondition(op.payload);
512
+ if (nestedCondition) {
513
+ Object.assign(andFilter, nestedCondition);
514
+ }
515
+ }
516
+ else if (op.type === "where:object") {
517
+ Object.assign(andFilter, op.payload);
518
+ }
519
+ else {
520
+ const condition = this.buildWhereCondition(op);
521
+ if (condition) {
522
+ Object.assign(andFilter, condition);
523
+ }
524
+ }
525
+ }
526
+ return Object.keys(andFilter).length > 0 ? andFilter : null;
527
+ }
528
+ /**
529
+ * Build a MongoDB filter condition from a where operation.
530
+ *
531
+ * @param op - The operation to build
532
+ * @returns The MongoDB filter condition
533
+ */
534
+ buildWhereCondition(op) {
535
+ const { field, operator, value } = op.payload;
536
+ switch (op.type) {
537
+ case "where":
538
+ case "orWhere":
539
+ return this.buildOperatorCondition(field, operator, value);
540
+ case "whereIn":
541
+ return { [field]: { $in: value || op.payload.values } };
542
+ case "whereNotIn":
543
+ return { [field]: { $nin: value || op.payload.values } };
544
+ case "whereNull":
545
+ return { [field]: null };
546
+ case "whereNotNull":
547
+ return { [field]: { $ne: null } };
548
+ case "whereBetween":
549
+ return {
550
+ [field]: {
551
+ $gte: op.payload.range[0],
552
+ $lte: op.payload.range[1],
553
+ },
554
+ };
555
+ case "whereNotBetween":
556
+ return {
557
+ [field]: {
558
+ $not: {
559
+ $gte: op.payload.range[0],
560
+ $lte: op.payload.range[1],
561
+ },
562
+ },
563
+ };
564
+ case "whereLike": {
565
+ const pattern = typeof op.payload.pattern === "string" ? op.payload.pattern : op.payload.pattern.source;
566
+ return { [field]: { $regex: pattern, $options: "i" } };
567
+ }
568
+ case "whereNotLike": {
569
+ const notPattern = typeof op.payload.pattern === "string" ? op.payload.pattern : op.payload.pattern.source;
570
+ return { [field]: { $not: { $regex: notPattern, $options: "i" } } };
571
+ }
572
+ case "whereStartsWith":
573
+ return { [field]: { $regex: `^${op.payload.value}`, $options: "i" } };
574
+ case "whereNotStartsWith":
575
+ return {
576
+ [field]: { $not: { $regex: `^${op.payload.value}`, $options: "i" } },
577
+ };
578
+ case "whereEndsWith":
579
+ return { [field]: { $regex: `${op.payload.value}$`, $options: "i" } };
580
+ case "whereNotEndsWith":
581
+ return {
582
+ [field]: { $not: { $regex: `${op.payload.value}$`, $options: "i" } },
583
+ };
584
+ case "whereExists":
585
+ return { [field]: { $exists: true } };
586
+ case "whereNotExists":
587
+ return { [field]: { $exists: false } };
588
+ case "whereSize":
589
+ if (op.payload.operator === "=") {
590
+ return { [field]: { $size: op.payload.size } };
591
+ }
592
+ else {
593
+ const mongoOp = this.getMongoOperator(op.payload.operator);
594
+ return {
595
+ $expr: {
596
+ [mongoOp]: [{ $size: `$${field}` }, op.payload.size],
597
+ },
598
+ };
599
+ }
600
+ case "textSearch":
601
+ return {
602
+ $text: { $search: op.payload.query },
603
+ ...(op.payload.filters || {}),
604
+ };
605
+ case "whereRaw":
606
+ case "orWhereRaw":
607
+ return this.resolveRawExpression(op.payload.expression, op.payload.bindings);
608
+ case "whereColumn":
609
+ case "orWhereColumn":
610
+ return this.buildColumnComparison(op.payload.first, op.payload.operator, op.payload.second);
611
+ case "whereBetweenColumns":
612
+ return this.buildBetweenColumnsCondition(op.payload.field, op.payload.lowerColumn, op.payload.upperColumn);
613
+ case "whereDate":
614
+ case "whereDateEquals":
615
+ return this.buildDateEqualityCondition(op.payload.field, op.payload.value);
616
+ case "whereDateBefore":
617
+ return this.buildDateBeforeCondition(op.payload.field, op.payload.value);
618
+ case "whereDateAfter":
619
+ return this.buildDateAfterCondition(op.payload.field, op.payload.value);
620
+ case "whereTime":
621
+ return this.buildTimeCondition(op.payload.field, op.payload.value);
622
+ case "whereDay":
623
+ return this.buildDatePartCondition(op.payload.field, "$dayOfMonth", op.payload.value);
624
+ case "whereMonth":
625
+ return this.buildDatePartCondition(op.payload.field, "$month", op.payload.value);
626
+ case "whereYear":
627
+ return this.buildDatePartCondition(op.payload.field, "$year", op.payload.value);
628
+ case "whereJsonContains":
629
+ return this.buildJsonContainsCondition(op.payload.path, op.payload.value);
630
+ case "whereJsonDoesntContain":
631
+ return this.buildJsonDoesntContainCondition(op.payload.path, op.payload.value);
632
+ case "whereJsonContainsKey":
633
+ return this.buildJsonContainsKeyCondition(op.payload.path);
634
+ case "whereJsonLength":
635
+ return this.buildJsonLengthCondition(op.payload.path, op.payload.operator, op.payload.value);
636
+ case "whereJsonIsArray":
637
+ return this.buildJsonTypeCondition(op.payload.path, "array");
638
+ case "whereJsonIsObject":
639
+ return this.buildJsonTypeCondition(op.payload.path, "object");
640
+ case "whereArrayLength":
641
+ return this.buildArrayLengthCondition(op.payload.field, op.payload.operator, op.payload.value);
642
+ case "whereFullText":
643
+ case "orWhereFullText":
644
+ return { $text: { $search: op.payload.query } };
645
+ case "whereSearch":
646
+ return {
647
+ [op.payload.field]: {
648
+ $regex: op.payload.query,
649
+ $options: "i",
650
+ },
651
+ };
652
+ case "where:not":
653
+ case "orWhere:not": {
654
+ const nestedNot = this.buildCallbackCondition(op.payload.callback);
655
+ return nestedNot ? { $nor: [nestedNot] } : null;
656
+ }
657
+ case "where:exists":
658
+ return this.buildCallbackCondition(op.payload.callback);
659
+ case "where:notExists": {
660
+ const nestedExists = this.buildCallbackCondition(op.payload.callback);
661
+ return nestedExists ? { $nor: [nestedExists] } : null;
662
+ }
663
+ case "whereArrayContains":
664
+ if (op.payload.key) {
665
+ return {
666
+ [field]: {
667
+ $elemMatch: { [op.payload.key]: op.payload.value },
668
+ },
669
+ };
670
+ }
671
+ else {
672
+ return { [field]: op.payload.value };
673
+ }
674
+ default:
675
+ return null;
676
+ }
677
+ }
678
+ /**
679
+ * Build a condition based on the operator.
680
+ *
681
+ * @param field - The field name
682
+ * @param operator - The comparison operator
683
+ * @param value - The value to compare
684
+ * @returns The MongoDB filter condition
685
+ */
686
+ buildOperatorCondition(field, operator, value) {
687
+ switch (operator) {
688
+ case "=":
689
+ return { [field]: value };
690
+ case "!=":
691
+ return { [field]: { $ne: value } };
692
+ case ">":
693
+ return { [field]: { $gt: value } };
694
+ case ">=":
695
+ return { [field]: { $gte: value } };
696
+ case "<":
697
+ return { [field]: { $lt: value } };
698
+ case "<=":
699
+ return { [field]: { $lte: value } };
700
+ default:
701
+ return { [field]: value };
702
+ }
703
+ }
704
+ /**
705
+ * Get MongoDB operator from comparison operator.
706
+ *
707
+ * @param operator - The comparison operator
708
+ * @returns The MongoDB operator
709
+ */
710
+ getMongoOperator(operator) {
711
+ const map = {
712
+ "=": "$eq",
713
+ "!=": "$ne",
714
+ ">": "$gt",
715
+ ">=": "$gte",
716
+ "<": "$lt",
717
+ "<=": "$lte",
718
+ };
719
+ return map[operator] || "$eq";
720
+ }
721
+ resolveRawExpression(expression, bindings) {
722
+ if (typeof expression === "string") {
723
+ const bound = this.bindRawString(expression, bindings);
724
+ return { $where: bound };
725
+ }
726
+ if (typeof expression === "object" && expression !== null) {
727
+ return expression;
728
+ }
729
+ return null;
730
+ }
731
+ bindRawString(expression, bindings) {
732
+ if (!bindings || bindings.length === 0) {
733
+ return expression;
734
+ }
735
+ let index = 0;
736
+ return expression.replace(/\?/g, () => {
737
+ const value = bindings[index++];
738
+ return value === undefined ? "?" : JSON.stringify(value);
739
+ });
740
+ }
741
+ buildColumnComparison(first, operator, second) {
742
+ const mongoOperator = this.getMongoOperator(operator);
743
+ return {
744
+ $expr: {
745
+ [mongoOperator]: [this.wrapColumn(first), this.wrapColumn(second)],
746
+ },
747
+ };
748
+ }
749
+ buildBetweenColumnsCondition(field, lower, upper) {
750
+ return {
751
+ $expr: {
752
+ $and: [
753
+ { $gte: [this.wrapColumn(field), this.wrapColumn(lower)] },
754
+ { $lte: [this.wrapColumn(field), this.wrapColumn(upper)] },
755
+ ],
756
+ },
757
+ };
758
+ }
759
+ wrapColumn(column) {
760
+ return column.startsWith("$") ? column : `$${column}`;
761
+ }
762
+ buildDateEqualityCondition(field, value) {
763
+ const target = this.normalizeDateInput(value);
764
+ const start = this.startOfDay(target);
765
+ const end = this.endOfDay(target);
766
+ return { [field]: { $gte: start, $lte: end } };
767
+ }
768
+ buildDateBeforeCondition(field, value) {
769
+ const target = this.startOfDay(this.normalizeDateInput(value));
770
+ return { [field]: { $lt: target } };
771
+ }
772
+ buildDateAfterCondition(field, value) {
773
+ const target = this.endOfDay(this.normalizeDateInput(value));
774
+ return { [field]: { $gt: target } };
775
+ }
776
+ buildTimeCondition(field, value) {
777
+ return {
778
+ $expr: {
779
+ $eq: [
780
+ {
781
+ $dateToString: {
782
+ format: "%H:%M",
783
+ date: `$${field}`,
784
+ },
785
+ },
786
+ value,
787
+ ],
788
+ },
789
+ };
790
+ }
791
+ buildDatePartCondition(field, operator, value) {
792
+ return {
793
+ $expr: {
794
+ $eq: [
795
+ {
796
+ [operator]: `$${field}`,
797
+ },
798
+ value,
799
+ ],
800
+ },
801
+ };
802
+ }
803
+ buildJsonContainsCondition(path, value) {
804
+ const fieldPath = this.normalizePath(path);
805
+ if (Array.isArray(value)) {
806
+ return { [fieldPath]: { $all: value } };
807
+ }
808
+ return { [fieldPath]: value };
809
+ }
810
+ buildJsonDoesntContainCondition(path, value) {
811
+ const fieldPath = this.normalizePath(path);
812
+ const values = Array.isArray(value) ? value : [value];
813
+ return { [fieldPath]: { $nin: values } };
814
+ }
815
+ buildJsonContainsKeyCondition(path) {
816
+ return {
817
+ [this.normalizePath(path)]: { $exists: true },
818
+ };
819
+ }
820
+ buildJsonLengthCondition(path, operator, value) {
821
+ const mongoOperator = this.getMongoOperator(operator);
822
+ return {
823
+ $expr: {
824
+ [mongoOperator]: [{ $size: { $ifNull: [`$${this.normalizePath(path)}`, []] } }, value],
825
+ },
826
+ };
827
+ }
828
+ buildJsonTypeCondition(path, type) {
829
+ return {
830
+ $expr: {
831
+ $eq: [{ $type: `$${this.normalizePath(path)}` }, type],
832
+ },
833
+ };
834
+ }
835
+ buildArrayLengthCondition(field, operator, value) {
836
+ const mongoOperator = this.getMongoOperator(operator);
837
+ return {
838
+ $expr: {
839
+ [mongoOperator]: [{ $size: { $ifNull: [`$${field}`, []] } }, value],
840
+ },
841
+ };
842
+ }
843
+ normalizeDateInput(value) {
844
+ if (value instanceof Date) {
845
+ return value;
846
+ }
847
+ const parsed = new Date(value);
848
+ if (Number.isNaN(parsed.getTime())) {
849
+ throw new Error(`Invalid date value: ${value}`);
850
+ }
851
+ return parsed;
852
+ }
853
+ startOfDay(date) {
854
+ const copy = new Date(date);
855
+ copy.setHours(0, 0, 0, 0);
856
+ return copy;
857
+ }
858
+ endOfDay(date) {
859
+ const copy = new Date(date);
860
+ copy.setHours(23, 59, 59, 999);
861
+ return copy;
862
+ }
863
+ normalizePath(path) {
864
+ return path.replace(/->/g, ".");
865
+ }
866
+ applyProjectionFields(projection, fields, value) {
867
+ for (const field of fields) {
868
+ projection[field] = value;
869
+ }
870
+ }
871
+ /**
872
+ * Apply projection object with aliases and inclusion/exclusion.
873
+ * @param projection - The projection object to modify
874
+ * @param projectionObj - The projection specification
875
+ */
876
+ applyProjectionObject(projection, projectionObj) {
877
+ for (const [field, value] of Object.entries(projectionObj)) {
878
+ // Handle boolean values (true = 1, false = 0)
879
+ if (typeof value === "boolean") {
880
+ projection[field] = value ? 1 : 0;
881
+ continue;
882
+ }
883
+ // Handle numeric values (0 or 1)
884
+ if (typeof value === "number") {
885
+ projection[field] = value;
886
+ continue;
887
+ }
888
+ // Handle string values (aliases)
889
+ if (typeof value === "string") {
890
+ // Alias: project the field with a new name
891
+ projection[value] = `$${field}`;
892
+ continue;
893
+ }
894
+ // Handle complex expressions (objects)
895
+ if (typeof value === "object" && value !== null) {
896
+ projection[field] = value;
897
+ continue;
898
+ }
899
+ // Default: include the field
900
+ projection[field] = 1;
901
+ }
902
+ }
903
+ applyRawProjection(projection, expression, bindings) {
904
+ const resolved = this.resolveProjectionExpression(expression, bindings);
905
+ if (!resolved) {
906
+ return;
907
+ }
908
+ if (typeof resolved === "object" && resolved !== null && !Array.isArray(resolved)) {
909
+ Object.assign(projection, resolved);
910
+ }
911
+ }
912
+ resolveProjectionExpression(expression, bindings) {
913
+ if (typeof expression === "string") {
914
+ const source = bindings && expression.includes("?")
915
+ ? this.bindRawString(expression, bindings)
916
+ : expression;
917
+ if (source.startsWith(":")) {
918
+ return source.slice(1);
919
+ }
920
+ return this.normalizeFieldReference(source);
921
+ }
922
+ if (typeof expression === "object" && expression !== null && !(expression instanceof Date)) {
923
+ return expression;
924
+ }
925
+ if (typeof expression === "number" || typeof expression === "boolean") {
926
+ return expression;
927
+ }
928
+ return expression;
929
+ }
930
+ normalizeFieldReference(value) {
931
+ if (typeof value === "string") {
932
+ if (value.startsWith(":")) {
933
+ return value.slice(1);
934
+ }
935
+ // If already a field reference, return as-is
936
+ if (value.startsWith("$")) {
937
+ return value;
938
+ }
939
+ // Check if it's a string literal (contains spaces or special chars)
940
+ // Field paths are typically: alphanumeric, underscore, dot only
941
+ if (!/^[a-zA-Z0-9_.]+$/.test(value)) {
942
+ return value; // Return as literal
943
+ }
944
+ // Otherwise, treat as field reference
945
+ return `$${value}`;
946
+ }
947
+ return value;
948
+ }
949
+ buildAggregateProjection(field, aggregate) {
950
+ if (aggregate === "count") {
951
+ return this.buildArraySizeExpression(field);
952
+ }
953
+ const map = {
954
+ sum: "$sum",
955
+ avg: "$avg",
956
+ min: "$min",
957
+ max: "$max",
958
+ first: "$first",
959
+ last: "$last",
960
+ };
961
+ const operator = map[aggregate];
962
+ if (!operator) {
963
+ return null;
964
+ }
965
+ return {
966
+ [operator]: this.normalizeFieldReference(field),
967
+ };
968
+ }
969
+ buildExistsProjection(field) {
970
+ return {
971
+ $ne: [{ $type: `$${field}` }, "missing"],
972
+ };
973
+ }
974
+ buildArraySizeExpression(field) {
975
+ return {
976
+ $size: { $ifNull: [`$${field}`, []] },
977
+ };
978
+ }
979
+ buildCaseExpression(cases, otherwise) {
980
+ return {
981
+ $switch: {
982
+ branches: cases.map((item) => ({
983
+ case: this.resolveProjectionExpression(item.when),
984
+ then: this.resolveLiteralOrExpression(item.then),
985
+ })),
986
+ default: this.resolveLiteralOrExpression(otherwise),
987
+ },
988
+ };
989
+ }
990
+ buildCondExpression(condition, thenValue, elseValue) {
991
+ return {
992
+ $cond: [
993
+ this.resolveProjectionExpression(condition),
994
+ this.resolveLiteralOrExpression(thenValue),
995
+ this.resolveLiteralOrExpression(elseValue),
996
+ ],
997
+ };
998
+ }
999
+ /**
1000
+ * Resolve a value as a literal (if it's a plain string) or as an expression.
1001
+ * Used for `then`/`default` values in CASE/WHEN expressions.
1002
+ */
1003
+ resolveLiteralOrExpression(value) {
1004
+ // If it's a string that starts with $, treat as field reference
1005
+ if (typeof value === "string" && value.startsWith("$")) {
1006
+ return value;
1007
+ }
1008
+ // If it's a plain string (not starting with $), treat as literal
1009
+ if (typeof value === "string") {
1010
+ return value;
1011
+ }
1012
+ // For objects (expressions), numbers, booleans, etc., use normal resolution
1013
+ return this.resolveProjectionExpression(value);
1014
+ }
1015
+ inferJsonAlias(path) {
1016
+ const normalized = this.normalizePath(path);
1017
+ const segments = normalized.split(".");
1018
+ return segments[segments.length - 1];
1019
+ }
1020
+ buildConcatExpression(values) {
1021
+ return {
1022
+ $concat: values.map((value) => this.normalizeFieldReference(value)),
1023
+ };
1024
+ }
1025
+ buildCoalesceExpression(values) {
1026
+ if (values.length === 0) {
1027
+ return null;
1028
+ }
1029
+ let expression = this.normalizeFieldReference(values[values.length - 1]);
1030
+ for (let index = values.length - 2; index >= 0; index--) {
1031
+ expression = {
1032
+ $ifNull: [this.normalizeFieldReference(values[index]), expression],
1033
+ };
1034
+ }
1035
+ return expression;
1036
+ }
1037
+ /**
1038
+ * Build a $project stage from select operations.
1039
+ *
1040
+ * @param operations - The select operations
1041
+ * @returns The $project stage or null
1042
+ */
1043
+ buildProjectStage(operations) {
1044
+ if (operations.length === 0) {
1045
+ return null;
1046
+ }
1047
+ const projection = {};
1048
+ const driverCallbacks = [];
1049
+ for (const op of operations) {
1050
+ switch (op.type) {
1051
+ case "select":
1052
+ // Handle new projection format with aliases
1053
+ if (op.payload.projection) {
1054
+ this.applyProjectionObject(projection, op.payload.projection);
1055
+ }
1056
+ else if (op.payload.fields) {
1057
+ this.applyProjectionFields(projection, op.payload.fields, 1);
1058
+ }
1059
+ break;
1060
+ case "deselect":
1061
+ this.applyProjectionFields(projection, op.payload.fields, 0);
1062
+ break;
1063
+ case "addSelect":
1064
+ this.applyProjectionFields(projection, op.payload.fields, 1);
1065
+ break;
1066
+ case "selectRaw":
1067
+ this.applyRawProjection(projection, op.payload.expression, op.payload.bindings);
1068
+ break;
1069
+ case "selectSub":
1070
+ case "addSelectSub": {
1071
+ const expr = this.resolveProjectionExpression(op.payload.expression, op.payload.bindings);
1072
+ if (expr !== undefined) {
1073
+ projection[op.payload.alias] = expr;
1074
+ }
1075
+ break;
1076
+ }
1077
+ case "selectAggregate":
1078
+ projection[op.payload.alias] = this.buildAggregateProjection(op.payload.field, op.payload.aggregate);
1079
+ break;
1080
+ case "selectExists":
1081
+ projection[op.payload.alias] = this.buildExistsProjection(op.payload.field);
1082
+ break;
1083
+ case "selectCount":
1084
+ projection[op.payload.alias] = this.buildArraySizeExpression(op.payload.field);
1085
+ break;
1086
+ case "selectCase":
1087
+ projection[op.payload.alias] = this.buildCaseExpression(op.payload.cases, op.payload.otherwise);
1088
+ break;
1089
+ case "selectWhen":
1090
+ projection[op.payload.alias] = this.buildCondExpression(op.payload.condition, op.payload.thenValue, op.payload.elseValue);
1091
+ break;
1092
+ case "selectDriverProjection":
1093
+ driverCallbacks.push(op.payload.callback);
1094
+ break;
1095
+ case "selectJson": {
1096
+ const alias = op.payload.alias ?? this.inferJsonAlias(op.payload.path);
1097
+ projection[alias] = this.normalizeFieldReference(`$${this.normalizePath(op.payload.path)}`);
1098
+ break;
1099
+ }
1100
+ case "selectJsonRaw": {
1101
+ projection[op.payload.alias] = this.resolveProjectionExpression(op.payload.expression);
1102
+ break;
1103
+ }
1104
+ case "deselectJson":
1105
+ projection[this.normalizePath(op.payload.path)] = 0;
1106
+ break;
1107
+ case "selectConcat":
1108
+ projection[op.payload.alias] = this.buildConcatExpression(op.payload.fields);
1109
+ break;
1110
+ case "selectCoalesce":
1111
+ projection[op.payload.alias] = this.buildCoalesceExpression(op.payload.fields);
1112
+ break;
1113
+ }
1114
+ }
1115
+ for (const callback of driverCallbacks) {
1116
+ callback(projection);
1117
+ }
1118
+ return Object.keys(projection).length > 0 ? { $project: projection } : null;
1119
+ }
1120
+ /**
1121
+ * Build a $sort stage from order operations.
1122
+ *
1123
+ * @param operations - The order operations
1124
+ * @returns The $sort stage or null
1125
+ */
1126
+ buildSortStage(operations) {
1127
+ const sort = {};
1128
+ for (const op of operations) {
1129
+ switch (op.type) {
1130
+ case "orderBy":
1131
+ sort[op.payload.field] = op.payload.direction === "asc" ? 1 : -1;
1132
+ break;
1133
+ case "orderByRandom":
1134
+ return { $sample: { size: op.payload.limit } };
1135
+ }
1136
+ }
1137
+ return Object.keys(sort).length > 0 ? { $sort: sort } : null;
1138
+ }
1139
+ /**
1140
+ * Build a $group stage from group operations.
1141
+ *
1142
+ * @param operations - The group operations
1143
+ * @returns The $group stage or null
1144
+ */
1145
+ buildGroupStage(operations) {
1146
+ const op = operations[0];
1147
+ switch (op.type) {
1148
+ case "groupBy": {
1149
+ const stage = this.buildGroupByStage(op.payload.fields);
1150
+ if (stage) {
1151
+ return stage;
1152
+ }
1153
+ break;
1154
+ }
1155
+ case "groupByWithAggregates": {
1156
+ const stage = this.buildGroupByWithAggregatesStage(op.payload.fields, op.payload.aggregates);
1157
+ if (stage) {
1158
+ return stage;
1159
+ }
1160
+ break;
1161
+ }
1162
+ case "groupByRaw": {
1163
+ const expression = op.payload.expression;
1164
+ if (expression && typeof expression === "object") {
1165
+ return { $group: expression };
1166
+ }
1167
+ // If expression is not an object, it might be a string or other type
1168
+ // In that case, we should still return it as a $group stage
1169
+ if (expression) {
1170
+ return { $group: { _id: expression } };
1171
+ }
1172
+ break;
1173
+ }
1174
+ case "distinct": {
1175
+ const stage = this.buildGroupByStage(op.payload.fields);
1176
+ if (stage) {
1177
+ return stage;
1178
+ }
1179
+ break;
1180
+ }
1181
+ }
1182
+ return null;
1183
+ }
1184
+ buildGroupByStage(fields) {
1185
+ const groupId = this.buildGroupId(fields);
1186
+ if (!groupId) {
1187
+ return null;
1188
+ }
1189
+ return { $group: { _id: groupId } };
1190
+ }
1191
+ /**
1192
+ * Build a $group stage with aggregates from group operations.
1193
+ *
1194
+ * @param fields - Fields to group by
1195
+ * @param aggregates - Aggregate operations (abstract or raw)
1196
+ * @returns The $group stage or null
1197
+ */
1198
+ buildGroupByWithAggregatesStage(fields, aggregates) {
1199
+ const groupId = this.buildGroupId(fields);
1200
+ if (!groupId) {
1201
+ return null;
1202
+ }
1203
+ const groupStage = {
1204
+ _id: groupId,
1205
+ };
1206
+ // Translate each aggregate expression
1207
+ for (const [alias, expression] of Object.entries(aggregates)) {
1208
+ if (aggregateExpressions.isAggregateExpression(expression)) {
1209
+ // Translate abstract expression to MongoDB format
1210
+ groupStage[alias] = this.translateAggregateExpression(expression);
1211
+ }
1212
+ else {
1213
+ // Use raw expression as-is (already in MongoDB format)
1214
+ groupStage[alias] = expression;
1215
+ }
1216
+ }
1217
+ return { $group: groupStage };
1218
+ }
1219
+ /**
1220
+ * Extract field names from GroupByInput for renaming _id.
1221
+ *
1222
+ * @param fields - The grouping fields
1223
+ * @returns Field name(s) to use for renaming _id
1224
+ */
1225
+ extractGroupFieldNames(fields) {
1226
+ if (typeof fields === "string") {
1227
+ return fields;
1228
+ }
1229
+ if (Array.isArray(fields)) {
1230
+ const allStrings = fields.every((field) => typeof field === "string");
1231
+ if (allStrings) {
1232
+ return fields;
1233
+ }
1234
+ // For complex arrays, return null (don't rename)
1235
+ return null;
1236
+ }
1237
+ if (typeof fields === "object" && fields !== null) {
1238
+ // For object syntax, use the keys as field names
1239
+ return Object.keys(fields);
1240
+ }
1241
+ return null;
1242
+ }
1243
+ /**
1244
+ * Translate an abstract aggregate expression to MongoDB format.
1245
+ *
1246
+ * @param expr - Abstract aggregate expression
1247
+ * @returns MongoDB aggregation expression
1248
+ */
1249
+ translateAggregateExpression(expr) {
1250
+ switch (expr.__agg) {
1251
+ case "count":
1252
+ return { $sum: 1 };
1253
+ case "sum":
1254
+ if (!expr.__field) {
1255
+ throw new Error("Sum aggregate requires a field name");
1256
+ }
1257
+ return { $sum: `$${expr.__field}` };
1258
+ case "avg":
1259
+ if (!expr.__field) {
1260
+ throw new Error("Average aggregate requires a field name");
1261
+ }
1262
+ return { $avg: `$${expr.__field}` };
1263
+ case "min":
1264
+ if (!expr.__field) {
1265
+ throw new Error("Min aggregate requires a field name");
1266
+ }
1267
+ return { $min: `$${expr.__field}` };
1268
+ case "max":
1269
+ if (!expr.__field) {
1270
+ throw new Error("Max aggregate requires a field name");
1271
+ }
1272
+ return { $max: `$${expr.__field}` };
1273
+ case "first":
1274
+ if (!expr.__field) {
1275
+ throw new Error("First aggregate requires a field name");
1276
+ }
1277
+ return { $first: `$${expr.__field}` };
1278
+ case "last":
1279
+ if (!expr.__field) {
1280
+ throw new Error("Last aggregate requires a field name");
1281
+ }
1282
+ return { $last: `$${expr.__field}` };
1283
+ case "distinct":
1284
+ if (!expr.__field) {
1285
+ throw new Error("Distinct aggregate requires a field name");
1286
+ }
1287
+ return { $distinct: `$${expr.__field}` };
1288
+ case "floor":
1289
+ if (!expr.__field) {
1290
+ throw new Error("Floor aggregate requires a field name");
1291
+ }
1292
+ return { $floor: `$${expr.__field}` };
1293
+ default:
1294
+ throw new Error(`Unknown aggregate function: ${expr.__agg}`);
1295
+ }
1296
+ }
1297
+ buildGroupId(fields) {
1298
+ if (!fields) {
1299
+ return null;
1300
+ }
1301
+ if (typeof fields === "string") {
1302
+ return `$${fields}`;
1303
+ }
1304
+ if (Array.isArray(fields)) {
1305
+ if (fields.length === 0) {
1306
+ return null;
1307
+ }
1308
+ const allStrings = fields.every((field) => typeof field === "string");
1309
+ if (allStrings) {
1310
+ const result = {};
1311
+ for (const field of fields) {
1312
+ result[field] = `$${field}`;
1313
+ }
1314
+ return result;
1315
+ }
1316
+ // Array of objects - merge them to build complex _id structures
1317
+ return fields.reduce((acc, item) => ({ ...acc, ...item }), {});
1318
+ }
1319
+ if (typeof fields === "object") {
1320
+ const normalized = {};
1321
+ Object.entries(fields).forEach(([key, value]) => {
1322
+ if (typeof value === "string" && !value.startsWith("$")) {
1323
+ normalized[key] = `$${value}`;
1324
+ }
1325
+ else {
1326
+ normalized[key] = value;
1327
+ }
1328
+ });
1329
+ return normalized;
1330
+ }
1331
+ return null;
1332
+ }
1333
+ /**
1334
+ * Build a $lookup stage from join operations.
1335
+ *
1336
+ * @param operations - The join operations
1337
+ * @returns The $lookup stage or null
1338
+ */
1339
+ buildLookupStage(operations) {
1340
+ const op = operations[0];
1341
+ const options = op.payload;
1342
+ return {
1343
+ $lookup: {
1344
+ from: options.table,
1345
+ localField: options.localField,
1346
+ foreignField: options.foreignField,
1347
+ as: options.alias || options.table,
1348
+ },
1349
+ };
1350
+ }
1351
+ }exports.MongoQueryParser=MongoQueryParser;//# sourceMappingURL=mongo-query-parser.js.map