@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,1740 @@
1
+ 'use strict';var reinforcements=require('@mongez/reinforcements'),databaseTransactionContext=require('../../context/database-transaction-context.js'),dataSourceRegistry=require('../../data-source/data-source-registry.js'),mongoQueryOperations=require('./mongo-query-operations.js'),mongoQueryParser=require('./mongo-query-parser.js');/* eslint-disable no-case-declarations */
2
+ /**
3
+ * MongoDB-specific query builder implementation using aggregation pipeline.
4
+ */
5
+ class MongoQueryBuilder {
6
+ table;
7
+ /**
8
+ * Ordered list of operations to be converted to MongoDB aggregation pipeline.
9
+ * Public to allow parser access.
10
+ */
11
+ operations = [];
12
+ /**
13
+ * Data source instance
14
+ */
15
+ dataSource;
16
+ /**
17
+ * Lazy-loaded operations helper for constructing pipeline operations.
18
+ */
19
+ _operationsHelper;
20
+ hydrateCallback;
21
+ fetchingCallback;
22
+ hydratingCallback;
23
+ fetchedCallback;
24
+ // Scope properties
25
+ pendingGlobalScopes;
26
+ availableLocalScopes;
27
+ disabledGlobalScopes = new Set();
28
+ scopesApplied = false;
29
+ /**
30
+ * Create a new query builder for the given collection.
31
+ * @param collection - The MongoDB collection to query
32
+ */
33
+ constructor(table, dataSource) {
34
+ this.table = table;
35
+ this.dataSource = dataSource || dataSourceRegistry.dataSourceRegistry.get();
36
+ // TODO: Trigger the fetching event
37
+ }
38
+ /**
39
+ * Gets the operations helper instance, creating it if needed.
40
+ * @returns The operations helper instance
41
+ */
42
+ get operationsHelper() {
43
+ if (!this._operationsHelper) {
44
+ this._operationsHelper = new mongoQueryOperations.MongoQueryOperations(this.operations);
45
+ }
46
+ return this._operationsHelper;
47
+ }
48
+ /**
49
+ * Get collection instance
50
+ */
51
+ get collection() {
52
+ const driver = this.dataSource.driver;
53
+ return driver.database.collection(this.table);
54
+ }
55
+ /**
56
+ * Add hydrate callback function
57
+ */
58
+ hydrate(callback) {
59
+ this.hydrateCallback = callback;
60
+ return this;
61
+ }
62
+ /**
63
+ * Register a callback to be invoked before query execution
64
+ * @returns Unsubscribe function to remove the callback
65
+ */
66
+ onFetching(callback) {
67
+ this.fetchingCallback = callback;
68
+ return () => {
69
+ this.fetchingCallback = undefined;
70
+ };
71
+ }
72
+ /**
73
+ * Register a callback to be invoked after records are fetched but before hydration
74
+ * @returns Unsubscribe function to remove the callback
75
+ */
76
+ onHydrating(callback) {
77
+ this.hydratingCallback = callback;
78
+ return () => {
79
+ this.hydratingCallback = undefined;
80
+ };
81
+ }
82
+ /**
83
+ * Register a callback to be invoked after records are fetched and hydrated
84
+ * @returns Unsubscribe function to remove the callback
85
+ */
86
+ onFetched(callback) {
87
+ this.fetchedCallback = callback;
88
+ return () => {
89
+ this.fetchedCallback = undefined;
90
+ };
91
+ }
92
+ /**
93
+ * Disable one or more global scopes for this query
94
+ */
95
+ withoutGlobalScope(...scopeNames) {
96
+ scopeNames.forEach((name) => this.disabledGlobalScopes.add(name));
97
+ return this;
98
+ }
99
+ /**
100
+ * Disable all global scopes for this query
101
+ */
102
+ withoutGlobalScopes() {
103
+ if (this.pendingGlobalScopes) {
104
+ this.pendingGlobalScopes.forEach((_, name) => {
105
+ this.disabledGlobalScopes.add(name);
106
+ });
107
+ }
108
+ return this;
109
+ }
110
+ /**
111
+ * Apply a local scope to this query
112
+ */
113
+ scope(scopeName) {
114
+ if (!this.availableLocalScopes) {
115
+ throw new Error(`No local scopes available`);
116
+ }
117
+ const scopeCallback = this.availableLocalScopes.get(scopeName);
118
+ if (!scopeCallback) {
119
+ throw new Error(`Local scope "${scopeName}" not found`);
120
+ }
121
+ // Apply scope immediately (not deferred)
122
+ scopeCallback(this);
123
+ return this;
124
+ }
125
+ /**
126
+ * Apply pending global scopes before query execution
127
+ */
128
+ applyPendingScopes() {
129
+ if (!this.pendingGlobalScopes || this.scopesApplied) {
130
+ return;
131
+ }
132
+ const beforeOps = [];
133
+ const afterOps = [];
134
+ for (const [name, { callback, timing }] of this.pendingGlobalScopes) {
135
+ // Skip disabled scopes
136
+ if (this.disabledGlobalScopes.has(name)) {
137
+ continue;
138
+ }
139
+ // Create temporary query builder to capture operations
140
+ const tempBuilder = new MongoQueryBuilder(this.table, this.dataSource);
141
+ callback(tempBuilder);
142
+ // Collect operations based on timing
143
+ if (timing === "before") {
144
+ beforeOps.push(...tempBuilder.operations);
145
+ }
146
+ else {
147
+ afterOps.push(...tempBuilder.operations);
148
+ }
149
+ }
150
+ // Apply: before scopes + user operations + after scopes
151
+ this.operations = [...beforeOps, ...this.operations, ...afterOps];
152
+ this.scopesApplied = true;
153
+ }
154
+ where(...args) {
155
+ this.addWhereClause("where", args);
156
+ return this;
157
+ }
158
+ orWhere(...args) {
159
+ this.addWhereClause("orWhere", args);
160
+ return this;
161
+ }
162
+ /**
163
+ * Adds a raw WHERE clause using MongoDB's native query syntax.
164
+ * @param expression - Raw MongoDB expression
165
+ * @param bindings - Optional parameter bindings for string expressions
166
+ */
167
+ whereRaw(expression, bindings) {
168
+ return this.addRawWhere("whereRaw", expression, bindings);
169
+ }
170
+ /**
171
+ * Adds a raw OR WHERE clause using MongoDB's native query syntax.
172
+ * @param expression - Raw MongoDB expression
173
+ * @param bindings - Optional parameter bindings
174
+ */
175
+ orWhereRaw(expression, bindings) {
176
+ return this.addRawWhere("orWhereRaw", expression, bindings);
177
+ }
178
+ // ============================================================================
179
+ // WHERE CLAUSES - COLUMN COMPARISONS
180
+ // ============================================================================
181
+ /**
182
+ * Adds a WHERE clause comparing two columns/fields directly.
183
+ * @param first - The first field name
184
+ * @param operator - The comparison operator
185
+ * @param second - The second field name
186
+ */
187
+ whereColumn(first, operator, second) {
188
+ this.operationsHelper.addMatchOperation("whereColumn", {
189
+ first,
190
+ operator,
191
+ second,
192
+ });
193
+ return this;
194
+ }
195
+ /**
196
+ * Adds an OR WHERE clause comparing two columns/fields directly.
197
+ * @param first - The first field name
198
+ * @param operator - The comparison operator
199
+ * @param second - The second field name
200
+ */
201
+ orWhereColumn(first, operator, second) {
202
+ this.operationsHelper.addMatchOperation("orWhereColumn", {
203
+ first,
204
+ operator,
205
+ second,
206
+ });
207
+ return this;
208
+ }
209
+ /**
210
+ * Adds multiple column comparison clauses at once.
211
+ * @param comparisons - Array of tuples [leftField, operator, rightField]
212
+ */
213
+ whereColumns(comparisons) {
214
+ for (const [left, operator, right] of comparisons) {
215
+ this.whereColumn(left, operator, right);
216
+ }
217
+ return this;
218
+ }
219
+ /**
220
+ * Filters documents where a field's value falls between two other fields.
221
+ * @param field - The field to check
222
+ * @param lowerColumn - The field defining the lower bound
223
+ * @param upperColumn - The field defining the upper bound
224
+ */
225
+ whereBetweenColumns(field, lowerColumn, upperColumn) {
226
+ this.operationsHelper.addMatchOperation("whereBetweenColumns", {
227
+ field,
228
+ lowerColumn,
229
+ upperColumn,
230
+ });
231
+ return this;
232
+ }
233
+ // ============================================================================
234
+ // WHERE CLAUSES - DATE OPERATIONS
235
+ // ============================================================================
236
+ /**
237
+ * Filters documents where a date field matches the given date (ignoring time).
238
+ * @param field - The date field name
239
+ * @param value - The date to match
240
+ */
241
+ whereDate(field, value) {
242
+ this.operationsHelper.addMatchOperation("whereDate", { field, value });
243
+ return this;
244
+ }
245
+ /**
246
+ * Alias for `whereDate()`. Filters by exact date match (ignoring time).
247
+ * @param field - The date field name
248
+ * @param value - The date to match
249
+ */
250
+ whereDateEquals(field, value) {
251
+ this.operationsHelper.addMatchOperation("whereDateEquals", {
252
+ field,
253
+ value,
254
+ });
255
+ return this;
256
+ }
257
+ /**
258
+ * Filters documents where a date field is before the given date.
259
+ * @param field - The date field name
260
+ * @param value - The cutoff date
261
+ */
262
+ whereDateBefore(field, value) {
263
+ this.operationsHelper.addMatchOperation("whereDateBefore", {
264
+ field,
265
+ value,
266
+ });
267
+ return this;
268
+ }
269
+ /**
270
+ * Filters documents where a date field is after the given date.
271
+ * @param field - The date field name
272
+ * @param value - The cutoff date
273
+ */
274
+ whereDateAfter(field, value) {
275
+ this.operationsHelper.addMatchOperation("whereDateAfter", { field, value });
276
+ return this;
277
+ }
278
+ /**
279
+ * Filters documents where a time field matches the given time (HH:MM:SS format).
280
+ * @param field - The time/datetime field name
281
+ * @param value - The time string in HH:MM:SS format
282
+ */
283
+ whereTime(field, value) {
284
+ this.operationsHelper.addMatchOperation("whereTime", { field, value });
285
+ return this;
286
+ }
287
+ /**
288
+ * Filters documents where the day of the month matches the given value (1-31).
289
+ * @param field - The date field name
290
+ * @param value - The day of the month
291
+ */
292
+ whereDay(field, value) {
293
+ this.operationsHelper.addMatchOperation("whereDay", { field, value });
294
+ return this;
295
+ }
296
+ /**
297
+ * Filters documents where the month matches the given value (1-12).
298
+ * @param field - The date field name
299
+ * @param value - The month number
300
+ */
301
+ whereMonth(field, value) {
302
+ this.operationsHelper.addMatchOperation("whereMonth", { field, value });
303
+ return this;
304
+ }
305
+ /**
306
+ * Filters documents where the year matches the given value.
307
+ * @param field - The date field name
308
+ * @param value - The year
309
+ */
310
+ whereYear(field, value) {
311
+ this.operationsHelper.addMatchOperation("whereYear", { field, value });
312
+ return this;
313
+ }
314
+ // ============================================================================
315
+ // WHERE CLAUSES - JSON OPERATIONS
316
+ // ============================================================================
317
+ /**
318
+ * Filters documents where a JSON field contains the specified value.
319
+ * @param path - The JSON path to check
320
+ * @param value - The value to search for
321
+ */
322
+ whereJsonContains(path, value) {
323
+ this.operationsHelper.addMatchOperation("whereJsonContains", {
324
+ path,
325
+ value,
326
+ });
327
+ return this;
328
+ }
329
+ /**
330
+ * Filters documents where a JSON field does NOT contain the specified value.
331
+ * @param path - The JSON path to check
332
+ * @param value - The value to exclude
333
+ */
334
+ whereJsonDoesntContain(path, value) {
335
+ this.operationsHelper.addMatchOperation("whereJsonDoesntContain", {
336
+ path,
337
+ value,
338
+ });
339
+ return this;
340
+ }
341
+ /**
342
+ * Filters documents where a JSON field contains a specific key.
343
+ * @param path - The JSON path to check for key existence
344
+ */
345
+ whereJsonContainsKey(path) {
346
+ this.operationsHelper.addMatchOperation("whereJsonContainsKey", { path });
347
+ return this;
348
+ }
349
+ /**
350
+ * Filters documents where a JSON array or string has a specific length.
351
+ * @param path - The JSON path to check
352
+ * @param operator - The comparison operator
353
+ * @param value - The length value to compare against
354
+ */
355
+ whereJsonLength(path, operator, value) {
356
+ this.operationsHelper.addMatchOperation("whereJsonLength", {
357
+ path,
358
+ operator,
359
+ value,
360
+ });
361
+ return this;
362
+ }
363
+ /**
364
+ * Filters documents where a JSON field is an array.
365
+ * @param path - The JSON path to check
366
+ */
367
+ whereJsonIsArray(path) {
368
+ this.operationsHelper.addMatchOperation("whereJsonIsArray", { path });
369
+ return this;
370
+ }
371
+ /**
372
+ * Filters documents where a JSON field is an object.
373
+ * @param path - The JSON path to check
374
+ */
375
+ whereJsonIsObject(path) {
376
+ this.operationsHelper.addMatchOperation("whereJsonIsObject", { path });
377
+ return this;
378
+ }
379
+ /**
380
+ * Filters documents where an array field has a specific length.
381
+ * @param field - The array field name
382
+ * @param operator - The comparison operator
383
+ * @param value - The length value to compare against
384
+ */
385
+ whereArrayLength(field, operator, value) {
386
+ this.operationsHelper.addMatchOperation("whereArrayLength", {
387
+ field,
388
+ operator,
389
+ value,
390
+ });
391
+ return this;
392
+ }
393
+ // ============================================================================
394
+ // WHERE CLAUSES - CONVENIENCE METHODS
395
+ // ============================================================================
396
+ /**
397
+ * Filters documents by ID (convenience method for `where("id", value)`).
398
+ * @param value - The ID value to match
399
+ */
400
+ whereId(value) {
401
+ return this.where("id", value);
402
+ }
403
+ /**
404
+ * Filters documents by multiple IDs (convenience method for `whereIn("id", values)`).
405
+ * @param values - Array of ID values to match
406
+ */
407
+ whereIds(values) {
408
+ return this.whereIn("id", values);
409
+ }
410
+ /**
411
+ * Filters documents by UUID (convenience method for `where("uuid", value)`).
412
+ * @param value - The UUID string to match
413
+ */
414
+ whereUuid(value) {
415
+ return this.where("uuid", value);
416
+ }
417
+ /**
418
+ * Filters documents by ULID (convenience method for `where("ulid", value)`).
419
+ * @param value - The ULID string to match
420
+ */
421
+ whereUlid(value) {
422
+ return this.where("ulid", value);
423
+ }
424
+ /**
425
+ * Performs full-text search on one or more fields.
426
+ * @param fields - Field name or array of field names to search
427
+ * @param query - The search query string
428
+ */
429
+ whereFullText(fields, query) {
430
+ const filters = typeof fields === "string" ? { fields: [fields] } : { fields: fields ?? [] };
431
+ this.operationsHelper.addMatchOperation("whereFullText", {
432
+ fields: filters.fields,
433
+ query,
434
+ });
435
+ return this;
436
+ }
437
+ /**
438
+ * Performs full-text search with OR logic.
439
+ * @param fields - Field name or array of field names to search
440
+ * @param query - The search query string
441
+ */
442
+ orWhereFullText(fields, query) {
443
+ const filters = typeof fields === "string" ? { fields: [fields] } : { fields: fields ?? [] };
444
+ this.operationsHelper.addMatchOperation("orWhereFullText", {
445
+ fields: filters.fields,
446
+ query,
447
+ });
448
+ return this;
449
+ }
450
+ /**
451
+ * Alias for `whereFullText()` with a single field.
452
+ * @param field - The field name to search
453
+ * @param query - The search query string
454
+ */
455
+ whereSearch(field, query) {
456
+ return this.whereFullText(field, query);
457
+ }
458
+ /**
459
+ * Negates a set of conditions using a callback.
460
+ * @param callback - Callback function defining conditions to negate
461
+ */
462
+ whereNot(callback) {
463
+ this.operationsHelper.addMatchOperation("where:not", { callback });
464
+ return this;
465
+ }
466
+ /**
467
+ * Negates a set of conditions with OR logic.
468
+ * @param callback - Callback function defining conditions to negate
469
+ */
470
+ orWhereNot(callback) {
471
+ this.operationsHelper.addMatchOperation("orWhere:not", { callback });
472
+ return this;
473
+ }
474
+ // ============================================================================
475
+ // WHERE CLAUSES - COMPARISON OPERATORS
476
+ // ============================================================================
477
+ /**
478
+ * Filters documents where a field's value matches any value in the given array.
479
+ * @param field - The field name to check
480
+ * @param values - Array of values to match against
481
+ */
482
+ whereIn(field, values) {
483
+ this.operationsHelper.addMatchOperation("whereIn", { field, values });
484
+ return this;
485
+ }
486
+ /**
487
+ * Filters documents where a field's value does NOT match any value in the array.
488
+ * @param field - The field name to check
489
+ * @param values - Array of values to exclude
490
+ */
491
+ whereNotIn(field, values) {
492
+ this.operationsHelper.addMatchOperation("whereNotIn", { field, values });
493
+ return this;
494
+ }
495
+ /**
496
+ * Filters documents where a field's value is null or undefined.
497
+ * @param field - The field name to check
498
+ */
499
+ whereNull(field) {
500
+ this.operationsHelper.addMatchOperation("whereNull", { field });
501
+ return this;
502
+ }
503
+ /**
504
+ * Filters documents where a field's value is NOT null or undefined.
505
+ * @param field - The field name to check
506
+ */
507
+ whereNotNull(field) {
508
+ this.operationsHelper.addMatchOperation("whereNotNull", { field });
509
+ return this;
510
+ }
511
+ /**
512
+ * Filters documents where a field's value falls within the given range (inclusive).
513
+ * @param field - The field name to check
514
+ * @param range - Tuple of [min, max] values
515
+ */
516
+ whereBetween(field, range) {
517
+ this.operationsHelper.addMatchOperation("whereBetween", { field, range });
518
+ return this;
519
+ }
520
+ /**
521
+ * Filters documents where a field's value is NOT within the given range.
522
+ * @param field - The field name to check
523
+ * @param range - Tuple of [min, max] values to exclude
524
+ */
525
+ whereNotBetween(field, range) {
526
+ this.operationsHelper.addMatchOperation("whereNotBetween", {
527
+ field,
528
+ range,
529
+ });
530
+ return this;
531
+ }
532
+ // ============================================================================
533
+ // WHERE CLAUSES - PATTERN MATCHING
534
+ // ============================================================================
535
+ /**
536
+ * Filters documents where a field matches the given pattern (case-insensitive).
537
+ * @param field - The field name to search
538
+ * @param pattern - The pattern to match
539
+ */
540
+ whereLike(field, pattern) {
541
+ this.operationsHelper.addMatchOperation("whereLike", { field, pattern });
542
+ return this;
543
+ }
544
+ /**
545
+ * Filters documents where a field does NOT match the given pattern.
546
+ * @param field - The field name to search
547
+ * @param pattern - The pattern to exclude
548
+ */
549
+ whereNotLike(field, pattern) {
550
+ this.operationsHelper.addMatchOperation("whereNotLike", { field, pattern });
551
+ return this;
552
+ }
553
+ /**
554
+ * Filters documents where a field's value starts with the given prefix.
555
+ * @param field - The field name to check
556
+ * @param value - The prefix to match
557
+ */
558
+ whereStartsWith(field, value) {
559
+ this.operationsHelper.addMatchOperation("whereStartsWith", {
560
+ field,
561
+ value,
562
+ });
563
+ return this;
564
+ }
565
+ /**
566
+ * Filters documents where a field's value does NOT start with the given prefix.
567
+ * @param field - The field name to check
568
+ * @param value - The prefix to exclude
569
+ */
570
+ whereNotStartsWith(field, value) {
571
+ this.operationsHelper.addMatchOperation("whereNotStartsWith", {
572
+ field,
573
+ value,
574
+ });
575
+ return this;
576
+ }
577
+ /**
578
+ * Filters documents where a field's value ends with the given suffix.
579
+ * @param field - The field name to check
580
+ * @param value - The suffix to match
581
+ */
582
+ whereEndsWith(field, value) {
583
+ this.operationsHelper.addMatchOperation("whereEndsWith", { field, value });
584
+ return this;
585
+ }
586
+ /**
587
+ * Filters documents where a field's value does NOT end with the given suffix.
588
+ * @param field - The field name to check
589
+ * @param value - The suffix to exclude
590
+ */
591
+ whereNotEndsWith(field, value) {
592
+ this.operationsHelper.addMatchOperation("whereNotEndsWith", {
593
+ field,
594
+ value,
595
+ });
596
+ return this;
597
+ }
598
+ /**
599
+ * Filters documents where a date field falls within the given date range.
600
+ * @param field - The date field name
601
+ * @param range - Tuple of [startDate, endDate]
602
+ */
603
+ whereDateBetween(field, range) {
604
+ this.operationsHelper.addMatchOperation("whereDateBetween", {
605
+ field,
606
+ range,
607
+ });
608
+ return this;
609
+ }
610
+ /**
611
+ * Filters documents where a date field is NOT within the given date range.
612
+ * @param field - The date field name
613
+ * @param range - Tuple of [startDate, endDate] to exclude
614
+ */
615
+ whereDateNotBetween(field, range) {
616
+ this.operationsHelper.addMatchOperation("whereDateNotBetween", {
617
+ field,
618
+ range,
619
+ });
620
+ return this;
621
+ }
622
+ whereExists(param) {
623
+ if (typeof param === "function") {
624
+ this.operationsHelper.addMatchOperation("where:exists", {
625
+ callback: param,
626
+ });
627
+ return this;
628
+ }
629
+ this.operationsHelper.addMatchOperation("whereExists", { field: param });
630
+ return this;
631
+ }
632
+ whereNotExists(param) {
633
+ if (typeof param === "function") {
634
+ this.operationsHelper.addMatchOperation("where:notExists", {
635
+ callback: param,
636
+ });
637
+ return this;
638
+ }
639
+ this.operationsHelper.addMatchOperation("whereNotExists", {
640
+ field: param,
641
+ });
642
+ return this;
643
+ }
644
+ whereSize(field, ...args) {
645
+ if (args.length === 1) {
646
+ this.operationsHelper.addMatchOperation("whereSize", {
647
+ field,
648
+ operator: "=",
649
+ size: args[0],
650
+ });
651
+ }
652
+ else {
653
+ this.operationsHelper.addMatchOperation("whereSize", {
654
+ field,
655
+ operator: args[0],
656
+ size: args[1],
657
+ });
658
+ }
659
+ return this;
660
+ }
661
+ // ============================================================================
662
+ // WHERE CLAUSES - FULL-TEXT SEARCH
663
+ // ============================================================================
664
+ /**
665
+ * Performs a full-text search on the specified fields.
666
+ * @param query - The search query string
667
+ * @param filters - Optional additional filter conditions
668
+ */
669
+ textSearch(query, filters) {
670
+ this.operationsHelper.addMatchOperation("textSearch", { query, filters });
671
+ return this;
672
+ }
673
+ // ============================================================================
674
+ // WHERE CLAUSES - ARRAY OPERATIONS
675
+ // ============================================================================
676
+ /**
677
+ * Filters documents where an array field contains the given value.
678
+ * @param field - The array field name
679
+ * @param value - The value to search for in the array
680
+ * @param key - Optional key to check within array objects
681
+ */
682
+ whereArrayContains(field, value, key) {
683
+ this.operationsHelper.addMatchOperation("whereArrayContains", {
684
+ field,
685
+ value,
686
+ key,
687
+ });
688
+ return this;
689
+ }
690
+ /**
691
+ * Filters documents where an array field does NOT contain the given value.
692
+ * @param field - The array field name
693
+ * @param value - The value to exclude from the array
694
+ * @param key - Optional key to check within array objects
695
+ */
696
+ whereArrayNotContains(field, value, key) {
697
+ this.operationsHelper.addMatchOperation("whereArrayNotContains", {
698
+ field,
699
+ value,
700
+ key,
701
+ });
702
+ return this;
703
+ }
704
+ /**
705
+ * Filters documents where an array field contains the value OR is empty.
706
+ * @param field - The array field name
707
+ * @param value - The value to search for
708
+ * @param key - Optional key to check within array objects
709
+ */
710
+ whereArrayHasOrEmpty(field, value, key) {
711
+ this.operationsHelper.addMatchOperation("whereArrayHasOrEmpty", {
712
+ field,
713
+ value,
714
+ key,
715
+ });
716
+ return this;
717
+ }
718
+ /**
719
+ * Filters documents where an array field does NOT contain the value AND is not empty.
720
+ * @param field - The array field name
721
+ * @param value - The value to exclude
722
+ * @param key - Optional key to check within array objects
723
+ */
724
+ whereArrayNotHaveOrEmpty(field, value, key) {
725
+ this.operationsHelper.addMatchOperation("whereArrayNotHaveOrEmpty", {
726
+ field,
727
+ value,
728
+ key,
729
+ });
730
+ return this;
731
+ }
732
+ /**
733
+ * Internal helper for processing where clause arguments.
734
+ * @param prefix - The operation prefix
735
+ * @param args - The arguments passed to where/orWhere
736
+ */
737
+ addWhereClause(prefix, args) {
738
+ if (args.length === 1) {
739
+ if (typeof args[0] === "function") {
740
+ // Callback-based where
741
+ this.operationsHelper.addMatchOperation(`${prefix}:callback`, args[0]);
742
+ }
743
+ else {
744
+ // Object-based where
745
+ this.operationsHelper.addMatchOperation(`${prefix}:object`, args[0]);
746
+ }
747
+ }
748
+ else if (args.length === 2) {
749
+ // Simple equality: where(field, value)
750
+ this.operationsHelper.addMatchOperation(prefix, {
751
+ field: args[0],
752
+ operator: "=",
753
+ value: args[1],
754
+ });
755
+ }
756
+ else if (args.length === 3) {
757
+ // With operator: where(field, operator, value)
758
+ this.operationsHelper.addMatchOperation(prefix, {
759
+ field: args[0],
760
+ operator: args[1],
761
+ value: args[2],
762
+ });
763
+ }
764
+ }
765
+ /**
766
+ * Internal helper for adding raw where clauses.
767
+ * @param type - The operation type
768
+ * @param expression - The raw expression in MongoDB query language
769
+ * @param bindings - Optional bindings for the expression
770
+ */
771
+ addRawWhere(type, expression, bindings) {
772
+ this.operationsHelper.addMatchOperation(type, { expression, bindings });
773
+ return this;
774
+ }
775
+ /**
776
+ * Normalizes select field arguments into a structured format.
777
+ * @param args - The arguments to normalize
778
+ * @returns Normalized selection object with fields and aliases
779
+ */
780
+ normalizeSelectFields(args) {
781
+ // Single argument cases
782
+ if (args.length === 1) {
783
+ const arg = args[0];
784
+ // Object format: { field: 1, field2: 0, field3: "alias", field4: true }
785
+ if (typeof arg === "object" && !Array.isArray(arg)) {
786
+ return { projection: arg };
787
+ }
788
+ // Array format: ["field1", "field2"]
789
+ if (Array.isArray(arg)) {
790
+ return { fields: arg };
791
+ }
792
+ // Single string: "field"
793
+ if (typeof arg === "string") {
794
+ return { fields: [arg] };
795
+ }
796
+ }
797
+ // Multiple string arguments: select("field1", "field2", "field3")
798
+ return { fields: args.filter((arg) => typeof arg === "string") };
799
+ }
800
+ select(...args) {
801
+ const normalized = this.normalizeSelectFields(args);
802
+ this.operationsHelper.addProjectOperation("select", normalized);
803
+ return this;
804
+ }
805
+ /**
806
+ * Selects a field with an alias.
807
+ * @param field - The field to select
808
+ * @param alias - The alias name for the field
809
+ * @returns The query builder instance
810
+ */
811
+ selectAs(field, alias) {
812
+ return this.select({ [field]: alias });
813
+ }
814
+ /**
815
+ * Adds a computed field using a raw MongoDB expression.
816
+ * @param expression - The raw MongoDB expression
817
+ * @param bindings - Optional parameter bindings for string expressions
818
+ */
819
+ selectRaw(expression, bindings) {
820
+ this.operationsHelper.addProjectOperation("selectRaw", {
821
+ expression,
822
+ bindings,
823
+ });
824
+ return this;
825
+ }
826
+ /**
827
+ * Adds multiple computed fields using raw MongoDB expressions.
828
+ * @param definitions - Array of field definitions with alias, expression, and optional bindings
829
+ */
830
+ selectRawMany(definitions) {
831
+ for (const definition of definitions) {
832
+ this.selectRaw({ [definition.alias]: definition.expression }, definition.bindings);
833
+ }
834
+ return this;
835
+ }
836
+ /**
837
+ * Adds a subquery as a computed field.
838
+ * @param expression - The subquery expression
839
+ * @param alias - The alias for the computed field
840
+ */
841
+ selectSub(expression, alias) {
842
+ this.operationsHelper.addProjectOperation("selectSub", {
843
+ expression,
844
+ alias,
845
+ });
846
+ return this;
847
+ }
848
+ /**
849
+ * Adds an additional subquery field to existing selections.
850
+ * @param expression - The subquery expression
851
+ * @param alias - The alias for the computed field
852
+ */
853
+ addSelectSub(expression, alias) {
854
+ this.operationsHelper.addProjectOperation("addSelectSub", {
855
+ expression,
856
+ alias,
857
+ });
858
+ return this;
859
+ }
860
+ /**
861
+ * Adds an aggregate value as a computed field.
862
+ * @param field - The field to aggregate
863
+ * @param aggregate - The aggregate function to apply
864
+ * @param alias - The alias for the computed field
865
+ */
866
+ selectAggregate(field, aggregate, alias) {
867
+ this.operationsHelper.addProjectOperation("selectAggregate", {
868
+ field,
869
+ aggregate,
870
+ alias,
871
+ });
872
+ return this;
873
+ }
874
+ /**
875
+ * Adds a boolean field indicating whether a related document exists.
876
+ * @param field - The field to check for existence
877
+ * @param alias - The alias for the boolean field
878
+ */
879
+ selectExists(field, alias) {
880
+ this.operationsHelper.addProjectOperation("selectExists", {
881
+ field,
882
+ alias,
883
+ });
884
+ return this;
885
+ }
886
+ /**
887
+ * Adds a count field for a related collection.
888
+ * @param field - The field to count
889
+ * @param alias - The alias for the count field
890
+ */
891
+ selectCount(field, alias) {
892
+ this.operationsHelper.addProjectOperation("selectCount", { field, alias });
893
+ return this;
894
+ }
895
+ /**
896
+ * Adds a CASE-like conditional field using multiple conditions.
897
+ * @param cases - Array of when/then pairs
898
+ * @param otherwise - Default value if no conditions match
899
+ * @param alias - The alias for the computed field
900
+ */
901
+ selectCase(cases, otherwise, alias) {
902
+ this.operationsHelper.addProjectOperation("selectCase", {
903
+ cases,
904
+ otherwise,
905
+ alias,
906
+ });
907
+ return this;
908
+ }
909
+ /**
910
+ * Adds a simple conditional field (if/else).
911
+ * @param condition - The condition to evaluate
912
+ * @param thenValue - Value if condition is true
913
+ * @param elseValue - Value if condition is false
914
+ * @param alias - The alias for the computed field
915
+ */
916
+ selectWhen(condition, thenValue, elseValue, alias) {
917
+ this.operationsHelper.addProjectOperation("selectWhen", {
918
+ condition,
919
+ thenValue,
920
+ elseValue,
921
+ alias,
922
+ });
923
+ return this;
924
+ }
925
+ /**
926
+ * Allows direct manipulation of the MongoDB projection object.
927
+ * @param callback - Function that receives and modifies the projection object
928
+ */
929
+ selectDriverProjection(callback) {
930
+ this.operationsHelper.addProjectOperation("selectDriverProjection", {
931
+ callback,
932
+ });
933
+ return this;
934
+ }
935
+ /**
936
+ * Extracts a JSON field from a document.
937
+ * @param path - The JSON path to extract
938
+ * @param alias - Optional alias for the extracted field
939
+ */
940
+ selectJson(path, alias) {
941
+ this.operationsHelper.addProjectOperation("selectJson", { path, alias });
942
+ return this;
943
+ }
944
+ /**
945
+ * Extracts a JSON field using a raw MongoDB expression.
946
+ * @param path - The JSON path
947
+ * @param expression - The raw expression for extraction
948
+ * @param alias - The alias for the extracted field
949
+ */
950
+ selectJsonRaw(path, expression, alias) {
951
+ this.operationsHelper.addProjectOperation("selectJsonRaw", {
952
+ path,
953
+ expression,
954
+ alias,
955
+ });
956
+ return this;
957
+ }
958
+ /**
959
+ * Excludes a JSON path from the results.
960
+ * @param path - The JSON path to exclude
961
+ */
962
+ deselectJson(path) {
963
+ this.operationsHelper.addProjectOperation("deselectJson", { path });
964
+ return this;
965
+ }
966
+ /**
967
+ * Concatenates multiple fields into a single string field.
968
+ * @param fields - Array of fields or expressions to concatenate
969
+ * @param alias - The alias for the concatenated field
970
+ */
971
+ selectConcat(fields, alias) {
972
+ this.operationsHelper.addProjectOperation("selectConcat", {
973
+ fields,
974
+ alias,
975
+ });
976
+ return this;
977
+ }
978
+ /**
979
+ * Returns the first non-null value from a list of fields.
980
+ * @param fields - Array of fields to check
981
+ * @param alias - The alias for the coalesced field
982
+ */
983
+ selectCoalesce(fields, alias) {
984
+ this.operationsHelper.addProjectOperation("selectCoalesce", {
985
+ fields,
986
+ alias,
987
+ });
988
+ return this;
989
+ }
990
+ /**
991
+ * Adds window function operations to the query.
992
+ * @param spec - The window function specification
993
+ */
994
+ selectWindow(spec) {
995
+ this.operationsHelper.addOperation("$setWindowFields", "selectWindow", { spec }, false);
996
+ return this;
997
+ }
998
+ deselect(...args) {
999
+ const fields = this.normalizeSelectFields(args);
1000
+ this.operationsHelper.addProjectOperation("deselect", { fields });
1001
+ return this;
1002
+ }
1003
+ /**
1004
+ * Returns only distinct values for the specified fields.
1005
+ * @param fields - Optional field names to use for distinctness
1006
+ */
1007
+ distinctValues(fields) {
1008
+ this.operationsHelper.addGroupOperation("distinct", { fields }, false);
1009
+ return this;
1010
+ }
1011
+ addSelect(...args) {
1012
+ const fields = this.normalizeSelectFields(args);
1013
+ this.operationsHelper.addProjectOperation("addSelect", { fields });
1014
+ return this;
1015
+ }
1016
+ /**
1017
+ * Removes all field selection restrictions.
1018
+ */
1019
+ clearSelect() {
1020
+ this.operations = this.operations.filter((op) => op.stage !== "$project");
1021
+ return this;
1022
+ }
1023
+ /**
1024
+ * Alias for `clearSelect()`. Removes all field restrictions.
1025
+ */
1026
+ selectAll() {
1027
+ return this.clearSelect();
1028
+ }
1029
+ /**
1030
+ * Alias for `clearSelect()`. Resets to default field selection.
1031
+ */
1032
+ selectDefault() {
1033
+ return this.clearSelect();
1034
+ }
1035
+ orderBy(fieldOrFields, direction = "asc") {
1036
+ if (typeof fieldOrFields === "string") {
1037
+ // Single field
1038
+ this.operationsHelper.addSortOperation("orderBy", {
1039
+ field: fieldOrFields,
1040
+ direction,
1041
+ });
1042
+ }
1043
+ else {
1044
+ // Multiple fields - add each as a separate operation (they'll be merged)
1045
+ for (const [field, dir] of Object.entries(fieldOrFields)) {
1046
+ this.operationsHelper.addSortOperation("orderBy", {
1047
+ field,
1048
+ direction: dir,
1049
+ });
1050
+ }
1051
+ }
1052
+ return this;
1053
+ }
1054
+ /**
1055
+ * Orders the query results by a field in descending order.
1056
+ * @param field - The field name to sort by
1057
+ */
1058
+ orderByDesc(field) {
1059
+ return this.orderBy(field, "desc");
1060
+ }
1061
+ /**
1062
+ * Orders the query results using a raw MongoDB sort expression.
1063
+ * @param expression - The raw MongoDB sort expression
1064
+ * @param bindings - Optional parameter bindings
1065
+ */
1066
+ orderByRaw(expression, bindings) {
1067
+ this.operationsHelper.addSortOperation("orderByRaw", {
1068
+ expression,
1069
+ bindings,
1070
+ });
1071
+ return this;
1072
+ }
1073
+ /**
1074
+ * Orders the query results randomly.
1075
+ */
1076
+ orderByRandom(limit = 1000) {
1077
+ this.operationsHelper.addSortOperation("orderByRandom", { limit }, false);
1078
+ return this;
1079
+ }
1080
+ /**
1081
+ * Orders results by a date field in descending order (newest first).
1082
+ * @param column - The date column to sort by
1083
+ */
1084
+ latest(column = "createdAt") {
1085
+ return this.orderBy(column, "desc").get();
1086
+ }
1087
+ /**
1088
+ * Orders results by a date field in ascending order (oldest first).
1089
+ * @param column - The date column to sort by
1090
+ */
1091
+ oldest(column = "createdAt") {
1092
+ return this.orderBy(column, "asc");
1093
+ }
1094
+ // ============================================================================
1095
+ // LIMITING / PAGINATION
1096
+ // ============================================================================
1097
+ /**
1098
+ * Limits the number of documents returned by the query.
1099
+ * @param value - The maximum number of documents to return
1100
+ */
1101
+ limit(value) {
1102
+ this.operationsHelper.addOperation("$limit", "limit", { value }, false);
1103
+ return this;
1104
+ }
1105
+ /**
1106
+ * Skips a specified number of documents in the query results.
1107
+ * @param value - The number of documents to skip
1108
+ */
1109
+ skip(value) {
1110
+ this.operationsHelper.addOperation("$skip", "skip", { value }, false);
1111
+ return this;
1112
+ }
1113
+ /**
1114
+ * Alias for `skip()`. Skips a specified number of documents.
1115
+ * @param value - The number of documents to skip
1116
+ */
1117
+ offset(value) {
1118
+ return this.skip(value);
1119
+ }
1120
+ /**
1121
+ * Alias for `limit()`. Limits the number of documents returned.
1122
+ * @param value - The maximum number of documents to return
1123
+ */
1124
+ take(value) {
1125
+ return this.limit(value);
1126
+ }
1127
+ /**
1128
+ * Applies cursor-based filtering for pagination.
1129
+ * @param after - Cursor value for forward pagination
1130
+ * @param before - Cursor value for backward pagination
1131
+ */
1132
+ cursor(after, before) {
1133
+ this.operationsHelper.addMatchOperation("cursor", { after, before });
1134
+ return this;
1135
+ }
1136
+ groupBy(fields, aggregates) {
1137
+ if (aggregates) {
1138
+ this.operationsHelper.addGroupOperation("groupByWithAggregates", { fields, aggregates }, false);
1139
+ }
1140
+ else {
1141
+ this.operationsHelper.addGroupOperation("groupBy", { fields }, false);
1142
+ }
1143
+ return this;
1144
+ }
1145
+ /**
1146
+ * Groups documents using a raw MongoDB expression.
1147
+ * @param expression - The raw grouping expression
1148
+ * @param bindings - Optional parameter bindings
1149
+ */
1150
+ groupByRaw(expression, bindings) {
1151
+ this.operationsHelper.addGroupOperation("groupByRaw", { expression, bindings }, false);
1152
+ return this;
1153
+ }
1154
+ having(...args) {
1155
+ if (args.length === 1) {
1156
+ this.operationsHelper.addMatchOperation("having:condition", args[0], false);
1157
+ }
1158
+ else if (args.length === 2) {
1159
+ this.operationsHelper.addMatchOperation("having", { field: args[0], operator: "=", value: args[1] }, false);
1160
+ }
1161
+ else {
1162
+ this.operationsHelper.addMatchOperation("having", { field: args[0], operator: args[1], value: args[2] }, false);
1163
+ }
1164
+ return this;
1165
+ }
1166
+ /**
1167
+ * Filters grouped results using a raw MongoDB expression.
1168
+ * @param expression - The raw having expression
1169
+ * @param bindings - Optional parameter bindings
1170
+ */
1171
+ havingRaw(expression, bindings) {
1172
+ this.operationsHelper.addMatchOperation("havingRaw", { expression, bindings }, false);
1173
+ return this;
1174
+ }
1175
+ // ============================================================================
1176
+ // JOINS
1177
+ // ============================================================================
1178
+ /**
1179
+ * Performs a left outer join with another collection.
1180
+ * @param options - Join configuration including table, fields, and optional pipeline
1181
+ */
1182
+ join(options) {
1183
+ this.operationsHelper.addLookupOperation("join", options);
1184
+ return this;
1185
+ }
1186
+ // ============================================================================
1187
+ // UTILITY / EXTENSIONS
1188
+ // ============================================================================
1189
+ /**
1190
+ * Allows direct manipulation of the native MongoDB query.
1191
+ * @param builder - Function that receives and modifies the native query
1192
+ */
1193
+ raw(builder) {
1194
+ this.operationsHelper.addMatchOperation("raw", { builder }, false);
1195
+ return this;
1196
+ }
1197
+ /**
1198
+ * Extends the query builder with driver-specific functionality.
1199
+ * @param extension - The extension name
1200
+ * @param _args - Extension-specific arguments
1201
+ * @returns The extension's return value
1202
+ */
1203
+ extend(extension, ..._args) {
1204
+ // Driver-specific extensions can be added here
1205
+ throw new Error(`Extension '${extension}' is not supported by MongoQueryBuilder`);
1206
+ }
1207
+ /**
1208
+ * Creates a deep copy of the query builder.
1209
+ * @returns A new query builder instance with copied operations
1210
+ */
1211
+ clone() {
1212
+ const cloned = new MongoQueryBuilder(this.table, this.dataSource);
1213
+ cloned.operations = [...this.operations];
1214
+ cloned.hydrateCallback = this.hydrateCallback?.bind(cloned);
1215
+ cloned.fetchingCallback = this.fetchingCallback?.bind(cloned);
1216
+ cloned.hydratingCallback = this.hydratingCallback?.bind(cloned);
1217
+ cloned.fetchedCallback = this.fetchedCallback?.bind(cloned);
1218
+ // Copy scope state
1219
+ cloned.pendingGlobalScopes = this.pendingGlobalScopes;
1220
+ cloned.availableLocalScopes = this.availableLocalScopes;
1221
+ cloned.disabledGlobalScopes = new Set(this.disabledGlobalScopes);
1222
+ cloned.scopesApplied = this.scopesApplied;
1223
+ cloned.__operationsHelper = this.__operationsHelper;
1224
+ return cloned;
1225
+ }
1226
+ /**
1227
+ * Executes a callback with the query builder without breaking the chain.
1228
+ * @param callback - Function to execute with the builder
1229
+ */
1230
+ tap(callback) {
1231
+ callback(this);
1232
+ return this;
1233
+ }
1234
+ /**
1235
+ * Conditionally applies query modifications based on a condition.
1236
+ * @param condition - The condition to evaluate
1237
+ * @param callback - Function to execute if condition is true
1238
+ * @param otherwise - Optional function to execute if condition is false
1239
+ *
1240
+ * @example
1241
+ * query.when(searchTerm, (q, term) => q.whereLike('name', term))
1242
+ */
1243
+ when(condition, callback, otherwise) {
1244
+ if (condition) {
1245
+ callback(this, condition);
1246
+ }
1247
+ else if (otherwise) {
1248
+ otherwise(this);
1249
+ }
1250
+ return this;
1251
+ }
1252
+ // ============================================================================
1253
+ // EXECUTION METHODS
1254
+ // ============================================================================
1255
+ /**
1256
+ * Executes the query and returns all matching documents.
1257
+ * @returns an array of matching documents
1258
+ */
1259
+ async get() {
1260
+ const startTime = Date.now();
1261
+ // Emit onFetching event
1262
+ if (this.fetchingCallback) {
1263
+ await this.fetchingCallback(this);
1264
+ }
1265
+ // Execute query and get raw records
1266
+ const rawRecords = await this.execute();
1267
+ // Emit onHydrating event
1268
+ if (this.hydratingCallback) {
1269
+ await this.hydratingCallback(rawRecords, {
1270
+ query: this,
1271
+ hydrateCallback: this.hydrateCallback,
1272
+ });
1273
+ }
1274
+ // Hydrate records
1275
+ const hydratedRecords = this.hydrateCallback
1276
+ ? rawRecords.map(this.hydrateCallback)
1277
+ : rawRecords;
1278
+ // Emit onFetched event
1279
+ if (this.fetchedCallback) {
1280
+ await this.fetchedCallback(hydratedRecords, {
1281
+ query: this,
1282
+ rawRecords,
1283
+ duration: Date.now() - startTime,
1284
+ });
1285
+ }
1286
+ return hydratedRecords;
1287
+ }
1288
+ /**
1289
+ * Execute the query and get first result
1290
+ * This is different than `first` as first adds a `limit = 1` to the pipeline
1291
+ */
1292
+ async getFirst() {
1293
+ return (await this.get())?.[0] ?? null;
1294
+ }
1295
+ /**
1296
+ * Executes the query and returns the first matching document.
1297
+ * @returns the first document or null
1298
+ */
1299
+ async first() {
1300
+ const results = await this.limit(1).get();
1301
+ return results.length > 0 ? results[0] : null;
1302
+ }
1303
+ /**
1304
+ * Executes the query and returns the first matching document, throwing if none found.
1305
+ * @returns the first document
1306
+ */
1307
+ async firstOrFail() {
1308
+ const result = await this.first();
1309
+ if (!result) {
1310
+ throw new Error("No records found matching the query");
1311
+ }
1312
+ return result;
1313
+ }
1314
+ /**
1315
+ * Configures the query to retrieve the last matching document.
1316
+ */
1317
+ last(field = "createdAt") {
1318
+ this.orderBy(field, "desc");
1319
+ return this.first();
1320
+ }
1321
+ /**
1322
+ * Counts the number of documents matching the query.
1323
+ * @returns the count of matching documents
1324
+ */
1325
+ async count() {
1326
+ const pipeline = this.buildPipeline();
1327
+ pipeline.push({ $count: "total" });
1328
+ const results = await this.execute(pipeline);
1329
+ return results.length > 0 ? results[0].total : 0;
1330
+ }
1331
+ /**
1332
+ * Calculates the sum of a numeric field across matching documents.
1333
+ * @param field - The numeric field to sum
1334
+ * @returns the sum value
1335
+ */
1336
+ async sum(field) {
1337
+ this.groupByRaw({
1338
+ _id: null,
1339
+ total: { $sum: `$${field}` },
1340
+ });
1341
+ // make sure to clear the data map callback
1342
+ this.hydrateCallback = undefined;
1343
+ const result = await this.getFirst();
1344
+ return result?.total ?? 0;
1345
+ }
1346
+ /**
1347
+ * Calculates the average value of a numeric field across matching documents.
1348
+ * @param field - The numeric field to average
1349
+ * @returns the average value
1350
+ */
1351
+ async avg(field) {
1352
+ this.groupByRaw({
1353
+ _id: null,
1354
+ average: { $avg: `$${field}` },
1355
+ });
1356
+ // make sure to clear the data map callback
1357
+ this.hydrateCallback = undefined;
1358
+ return (await this.getFirst())?.average ?? 0;
1359
+ }
1360
+ /**
1361
+ * Finds the minimum value of a field across matching documents.
1362
+ * @param field - The field to find the minimum of
1363
+ * @returns the minimum value
1364
+ */
1365
+ async min(field) {
1366
+ this.groupByRaw({
1367
+ _id: null,
1368
+ minimum: { $min: `$${field}` },
1369
+ });
1370
+ // make sure to clear the data map callback
1371
+ this.hydrateCallback = undefined;
1372
+ return (await this.getFirst())?.minimum ?? 0;
1373
+ }
1374
+ /**
1375
+ * Finds the maximum value of a field across matching documents.
1376
+ * @param field - The field to find the maximum of
1377
+ * @returns the maximum value
1378
+ */
1379
+ async max(field) {
1380
+ this.groupByRaw({
1381
+ _id: null,
1382
+ maximum: { $max: `$${field}` },
1383
+ });
1384
+ // make sure to clear the data map callback
1385
+ this.hydrateCallback = undefined;
1386
+ return (await this.getFirst())?.maximum ?? 0;
1387
+ }
1388
+ /**
1389
+ * Returns an array of distinct values for a field, respecting query filters.
1390
+ * @param field - The field to get distinct values from
1391
+ * @returns an array of distinct values
1392
+ */
1393
+ async distinct(field, ignoreNull = true) {
1394
+ if (ignoreNull) {
1395
+ this.whereNotNull(field);
1396
+ }
1397
+ this.groupBy(field);
1398
+ // make sure to clear the data map callback
1399
+ this.hydrateCallback = undefined;
1400
+ const results = await this.get();
1401
+ return results.map((doc) => doc._id);
1402
+ }
1403
+ /**
1404
+ * Count distinct values for a field, respecting query filters.
1405
+ * @param field - The field to count distinct values for
1406
+ * @returns the count of distinct values
1407
+ */
1408
+ async countDistinct(field, ignoreNull = true) {
1409
+ if (ignoreNull) {
1410
+ this.whereNotNull(field);
1411
+ }
1412
+ return await this.groupBy(field).count();
1413
+ }
1414
+ /**
1415
+ * Extracts a single field value from each matching document.
1416
+ * @param field - The field to extract
1417
+ * @returns an array of field values
1418
+ */
1419
+ async pluck(field) {
1420
+ // make sure to clear the data map callback
1421
+ this.hydrateCallback = undefined;
1422
+ // Use object aliasing: { [field]: "value" } to project field as "value"
1423
+ const results = await this.selectAs(field, "value").get();
1424
+ return results.map((doc) => doc.value).filter((value) => value !== undefined);
1425
+ }
1426
+ /**
1427
+ * Gets the value of a single field from the first matching document.
1428
+ * @param field - The field to extract
1429
+ * @returns the field value or null
1430
+ */
1431
+ async value(field) {
1432
+ // make sure to clear the data map callback
1433
+ this.hydrateCallback = undefined;
1434
+ const result = await this.selectAs(field, "value").first();
1435
+ return result?.value ?? null;
1436
+ }
1437
+ /**
1438
+ * Checks if any documents match the query.
1439
+ * @param filter - Optional filter to apply to the query
1440
+ * @returns true if documents exist, false otherwise
1441
+ */
1442
+ async exists(filter) {
1443
+ if (filter) {
1444
+ this.where(filter);
1445
+ }
1446
+ const count = await this.limit(1).count();
1447
+ return count > 0;
1448
+ }
1449
+ /**
1450
+ * Checks if no documents match the query.
1451
+ * @param filter - Optional filter to apply to the query
1452
+ * @returns true if no documents exist, false otherwise
1453
+ */
1454
+ async notExists(filter) {
1455
+ return !(await this.exists(filter));
1456
+ }
1457
+ /**
1458
+ * Increments a numeric field by the specified amount for first matching document.
1459
+ * @param field - The field to increment
1460
+ * @param amount - The amount to increment by (default: 1)
1461
+ * @returns the new value
1462
+ */
1463
+ async increment(field, amount = 1) {
1464
+ const filter = this.buildFilter();
1465
+ const result = await this.collection.findOneAndUpdate(filter, {
1466
+ $inc: { [field]: amount },
1467
+ }, {
1468
+ returnDocument: "after",
1469
+ });
1470
+ return reinforcements.get(result, field, 0);
1471
+ }
1472
+ /**
1473
+ * Decrements a numeric field by the specified amount.
1474
+ * @param field - The field to decrement
1475
+ * @param amount - The amount to decrement by
1476
+ * @returns the new value
1477
+ */
1478
+ async decrement(field, amount = 1) {
1479
+ return this.increment(field, -amount);
1480
+ }
1481
+ /**
1482
+ * Increments a numeric field by the specified amount for all matching documents.
1483
+ * @param field - The field to increment
1484
+ * @param amount - The amount to increment by (default: 1)
1485
+ * @returns the number of documents modified
1486
+ */
1487
+ async incrementMany(field, amount = 1) {
1488
+ const filter = this.buildFilter();
1489
+ const result = await this.dataSource.driver.updateMany(this.table, filter, {
1490
+ $inc: { [field]: amount },
1491
+ });
1492
+ return result.modifiedCount;
1493
+ }
1494
+ /**
1495
+ * Decrements a numeric field by the specified amount for all matching documents.
1496
+ * @param field - The field to decrement
1497
+ * @param amount - The amount to decrement by (default: 1)
1498
+ * @returns the number of documents modified
1499
+ */
1500
+ async decrementMany(field, amount = 1) {
1501
+ return this.incrementMany(field, -amount);
1502
+ }
1503
+ /**
1504
+ * Delete all documents matching the query.
1505
+ */
1506
+ async delete() {
1507
+ const filter = this.buildFilter();
1508
+ return await this.dataSource.driver.deleteMany(this.table, filter);
1509
+ }
1510
+ /**
1511
+ * Delete a single document matching the query.
1512
+ */
1513
+ async deleteOne() {
1514
+ const filter = this.buildFilter();
1515
+ return await this.dataSource.driver.delete(this.table, filter);
1516
+ }
1517
+ /**
1518
+ * Update the given fields for all documents matching the query.
1519
+ */
1520
+ async update(fields) {
1521
+ const filter = this.buildFilter();
1522
+ const result = await this.dataSource.driver.updateMany(this.table, filter, {
1523
+ $set: fields,
1524
+ });
1525
+ return result.modifiedCount;
1526
+ }
1527
+ /**
1528
+ * Unset the given fields from all documents matching the query.
1529
+ */
1530
+ async unset(...fields) {
1531
+ const filter = this.buildFilter();
1532
+ const result = await this.dataSource.driver.updateMany(this.table, filter, {
1533
+ $unset: fields.reduce((acc, field) => {
1534
+ acc[field] = 1;
1535
+ return acc;
1536
+ }, {}),
1537
+ });
1538
+ return result.modifiedCount;
1539
+ }
1540
+ // ============================================================================
1541
+ // CHUNKING / PAGINATION
1542
+ // ============================================================================
1543
+ /**
1544
+ * Processes query results in chunks, executing a callback for each chunk.
1545
+ * @param size - The number of documents per chunk
1546
+ * @param callback - Function to execute for each chunk
1547
+ * @returns void
1548
+ */
1549
+ async chunk(size, callback) {
1550
+ let chunkIndex = 0;
1551
+ let hasMore = true;
1552
+ while (hasMore) {
1553
+ const chunk = await this.clone()
1554
+ .skip(chunkIndex * size)
1555
+ .limit(size)
1556
+ .get();
1557
+ if (chunk.length === 0) {
1558
+ break;
1559
+ }
1560
+ const shouldContinue = await callback(chunk, chunkIndex);
1561
+ if (shouldContinue === false) {
1562
+ break;
1563
+ }
1564
+ hasMore = chunk.length === size;
1565
+ chunkIndex++;
1566
+ }
1567
+ }
1568
+ /**
1569
+ * Executes the query with traditional page-based pagination.
1570
+ * @param options - Pagination options
1571
+ * @returns pagination result with data and metadata
1572
+ */
1573
+ async paginate(options) {
1574
+ const page = options.page ?? 1;
1575
+ const limit = options.limit ?? 10;
1576
+ const skip = (page - 1) * limit;
1577
+ const [data, total] = await Promise.all([
1578
+ this.clone().skip(skip).limit(limit).get(),
1579
+ this.count(),
1580
+ ]);
1581
+ return {
1582
+ data,
1583
+ pagination: {
1584
+ total,
1585
+ page,
1586
+ limit,
1587
+ pages: Math.ceil(total / limit),
1588
+ },
1589
+ };
1590
+ }
1591
+ /**
1592
+ * Executes the query with cursor-based pagination supporting both directions.
1593
+ * @param options - Cursor pagination options
1594
+ * @returns cursor pagination result with data and cursor info
1595
+ */
1596
+ async cursorPaginate(options) {
1597
+ const limit = options.limit;
1598
+ const cursor = options.cursor;
1599
+ const column = options.column ?? "_id";
1600
+ const direction = options.direction ?? "next";
1601
+ // Apply cursor filter
1602
+ if (cursor) {
1603
+ const operator = direction === "next" ? ">" : "<";
1604
+ this.where(column, operator, cursor);
1605
+ }
1606
+ // Apply sorting
1607
+ const sortOrder = direction === "next" ? "asc" : "desc";
1608
+ this.orderBy(column, sortOrder);
1609
+ this.orderBy("_id", sortOrder); // Always sort by _id to ensure consistent order
1610
+ // Fetch one extra to detect if there are more results
1611
+ const results = await this.limit(limit + 1).get();
1612
+ const hasMore = results.length > limit;
1613
+ let data = hasMore ? results.slice(0, limit) : results;
1614
+ // Reverse results if fetching previous page to keep natural order
1615
+ if (direction === "prev") {
1616
+ data = data.reverse();
1617
+ }
1618
+ // Determine cursors based on actual data
1619
+ let nextCursor;
1620
+ let prevCursor;
1621
+ let hasPrev = false;
1622
+ if (data.length > 0) {
1623
+ const firstItem = data[0][column];
1624
+ const lastItem = data[data.length - 1][column];
1625
+ if (direction === "next") {
1626
+ // Forward pagination
1627
+ nextCursor = hasMore ? lastItem : undefined;
1628
+ // Check if there's a previous page
1629
+ if (cursor) {
1630
+ hasPrev = true;
1631
+ prevCursor = firstItem;
1632
+ }
1633
+ }
1634
+ else {
1635
+ // Backward pagination
1636
+ prevCursor = hasMore ? firstItem : undefined;
1637
+ hasPrev = hasMore;
1638
+ // Check if there's a next page
1639
+ if (cursor) {
1640
+ nextCursor = lastItem;
1641
+ }
1642
+ }
1643
+ }
1644
+ return {
1645
+ data,
1646
+ pagination: {
1647
+ hasMore,
1648
+ hasPrev,
1649
+ nextCursor,
1650
+ prevCursor,
1651
+ },
1652
+ };
1653
+ }
1654
+ // ============================================================================
1655
+ // INSPECTION / DEBUGGING
1656
+ // ============================================================================
1657
+ /**
1658
+ * Returns the MongoDB aggregation pipeline that will be executed.
1659
+ * @returns The MongoDB aggregation pipeline array
1660
+ */
1661
+ parse() {
1662
+ return this.buildPipeline();
1663
+ }
1664
+ /**
1665
+ * Returns a formatted string representation of the query pipeline.
1666
+ * @returns A formatted string representation of the pipeline
1667
+ */
1668
+ pretty() {
1669
+ return this.getParser().toPrettyString();
1670
+ }
1671
+ /**
1672
+ * Returns the MongoDB query execution plan.
1673
+ * @returns MongoDB's explain output
1674
+ */
1675
+ async explain() {
1676
+ // TODO: Trigger the explaining event
1677
+ const pipeline = this.buildPipeline();
1678
+ const session = databaseTransactionContext.databaseTransactionContext.getSession();
1679
+ const options = session ? { session, explain: true } : { explain: true };
1680
+ return this.collection.aggregate(pipeline, options).toArray();
1681
+ }
1682
+ // ============================================================================
1683
+ // INTERNAL PIPELINE BUILDING
1684
+ // ============================================================================
1685
+ /**
1686
+ * Get query parser instance
1687
+ */
1688
+ getParser() {
1689
+ this.applyPendingScopes();
1690
+ return new mongoQueryParser.MongoQueryParser({
1691
+ collection: this.collection,
1692
+ operations: this.operations,
1693
+ createSubBuilder: () => new MongoQueryBuilder(this.table, this.dataSource),
1694
+ });
1695
+ }
1696
+ /**
1697
+ * Build the MongoDB aggregation pipeline from the operations list.
1698
+ * @returns The MongoDB aggregation pipeline
1699
+ */
1700
+ buildPipeline() {
1701
+ const parser = this.getParser();
1702
+ return parser.parse();
1703
+ }
1704
+ /**
1705
+ * Build a MongoDB filter object from the query's where clauses.
1706
+ * Used for update operations like increment/decrement.
1707
+ * @returns The MongoDB filter object
1708
+ */
1709
+ buildFilter() {
1710
+ // Get all match operations
1711
+ const matchOperations = this.operations.filter((op) => op.stage === "$match");
1712
+ if (matchOperations.length === 0) {
1713
+ return {}; // No filters, match all documents
1714
+ }
1715
+ // Build the pipeline and extract the first $match stage
1716
+ const pipeline = this.buildPipeline();
1717
+ const matchStage = pipeline.find((stage) => stage.$match);
1718
+ if (matchStage && matchStage.$match) {
1719
+ return matchStage.$match;
1720
+ }
1721
+ return {};
1722
+ }
1723
+ /**
1724
+ * Execute the aggregate command
1725
+ */
1726
+ async execute(pipeline) {
1727
+ const aggregationPipeline = pipeline || this.buildPipeline();
1728
+ const session = databaseTransactionContext.databaseTransactionContext.getSession();
1729
+ const options = { session };
1730
+ // TODO: Trigger the executing event
1731
+ const results = (await this.collection
1732
+ .aggregate(aggregationPipeline, options)
1733
+ .toArray());
1734
+ // TODO: Trigger the fetched event
1735
+ // we need to cleanup the operations list
1736
+ this.operations = [];
1737
+ this.operationsHelper.setOperations(this.operations);
1738
+ return results;
1739
+ }
1740
+ }exports.MongoQueryBuilder=MongoQueryBuilder;//# sourceMappingURL=mongo-query-builder.js.map