@warlock.js/cascade 4.1.15 → 4.2.1

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 (336) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/LICENSE +21 -0
  3. package/cjs/index.cjs +21388 -0
  4. package/cjs/index.cjs.map +1 -0
  5. package/esm/context/database-data-source-context.d.mts +1 -1
  6. package/esm/context/database-data-source-context.d.mts.map +1 -1
  7. package/esm/context/database-data-source-context.mjs +1 -1
  8. package/esm/context/database-data-source-context.mjs.map +1 -1
  9. package/esm/context/database-transaction-context.d.mts +1 -1
  10. package/esm/context/database-transaction-context.d.mts.map +1 -1
  11. package/esm/context/database-transaction-context.mjs +1 -1
  12. package/esm/context/database-transaction-context.mjs.map +1 -1
  13. package/esm/contracts/database-driver.contract.d.mts +1 -1
  14. package/esm/contracts/database-driver.contract.d.mts.map +1 -1
  15. package/esm/contracts/database-id-generator.contract.d.mts +1 -1
  16. package/esm/contracts/database-id-generator.contract.d.mts.map +1 -1
  17. package/esm/contracts/database-remover.contract.d.mts +1 -1
  18. package/esm/contracts/database-remover.contract.d.mts.map +1 -1
  19. package/esm/contracts/database-restorer.contract.d.mts +1 -1
  20. package/esm/contracts/database-restorer.contract.d.mts.map +1 -1
  21. package/esm/contracts/database-writer.contract.d.mts +1 -1
  22. package/esm/contracts/database-writer.contract.d.mts.map +1 -1
  23. package/esm/contracts/driver-blueprint.contract.d.mts +1 -1
  24. package/esm/contracts/driver-blueprint.contract.d.mts.map +1 -1
  25. package/esm/contracts/migration-driver.contract.d.mts +1 -1
  26. package/esm/contracts/migration-driver.contract.d.mts.map +1 -1
  27. package/esm/contracts/query-builder.contract.d.mts +1 -1
  28. package/esm/contracts/query-builder.contract.d.mts.map +1 -1
  29. package/esm/contracts/sync-adapter.contract.d.mts +1 -1
  30. package/esm/contracts/sync-adapter.contract.d.mts.map +1 -1
  31. package/esm/data-source/data-source-registry.d.mts +1 -1
  32. package/esm/data-source/data-source-registry.d.mts.map +1 -1
  33. package/esm/data-source/data-source-registry.mjs +1 -1
  34. package/esm/data-source/data-source-registry.mjs.map +1 -1
  35. package/esm/data-source/data-source.d.mts +1 -1
  36. package/esm/data-source/data-source.d.mts.map +1 -1
  37. package/esm/data-source/data-source.mjs +1 -1
  38. package/esm/data-source/data-source.mjs.map +1 -1
  39. package/esm/database-dirty-tracker.d.mts +1 -1
  40. package/esm/database-dirty-tracker.d.mts.map +1 -1
  41. package/esm/database-dirty-tracker.mjs +1 -1
  42. package/esm/database-dirty-tracker.mjs.map +1 -1
  43. package/esm/drivers/mongodb/mongodb-blueprint.mjs +1 -1
  44. package/esm/drivers/mongodb/mongodb-blueprint.mjs.map +1 -1
  45. package/esm/drivers/mongodb/mongodb-driver.d.mts +1 -1
  46. package/esm/drivers/mongodb/mongodb-driver.d.mts.map +1 -1
  47. package/esm/drivers/mongodb/mongodb-driver.mjs +2 -2
  48. package/esm/drivers/mongodb/mongodb-driver.mjs.map +1 -1
  49. package/esm/drivers/mongodb/mongodb-id-generator.d.mts +1 -1
  50. package/esm/drivers/mongodb/mongodb-id-generator.d.mts.map +1 -1
  51. package/esm/drivers/mongodb/mongodb-id-generator.mjs +1 -1
  52. package/esm/drivers/mongodb/mongodb-id-generator.mjs.map +1 -1
  53. package/esm/drivers/mongodb/mongodb-migration-driver.d.mts +1 -1
  54. package/esm/drivers/mongodb/mongodb-migration-driver.d.mts.map +1 -1
  55. package/esm/drivers/mongodb/mongodb-migration-driver.mjs +1 -1
  56. package/esm/drivers/mongodb/mongodb-migration-driver.mjs.map +1 -1
  57. package/esm/drivers/mongodb/mongodb-query-builder.d.mts +1 -1
  58. package/esm/drivers/mongodb/mongodb-query-builder.d.mts.map +1 -1
  59. package/esm/drivers/mongodb/mongodb-query-builder.mjs +1 -1
  60. package/esm/drivers/mongodb/mongodb-query-builder.mjs.map +1 -1
  61. package/esm/drivers/mongodb/mongodb-query-operations.d.mts +1 -1
  62. package/esm/drivers/mongodb/mongodb-query-operations.d.mts.map +1 -1
  63. package/esm/drivers/mongodb/mongodb-query-operations.mjs +1 -1
  64. package/esm/drivers/mongodb/mongodb-query-operations.mjs.map +1 -1
  65. package/esm/drivers/mongodb/mongodb-query-parser.d.mts +1 -1
  66. package/esm/drivers/mongodb/mongodb-query-parser.d.mts.map +1 -1
  67. package/esm/drivers/mongodb/mongodb-query-parser.mjs +1 -1
  68. package/esm/drivers/mongodb/mongodb-query-parser.mjs.map +1 -1
  69. package/esm/drivers/mongodb/mongodb-sync-adapter.d.mts +1 -1
  70. package/esm/drivers/mongodb/mongodb-sync-adapter.d.mts.map +1 -1
  71. package/esm/drivers/mongodb/mongodb-sync-adapter.mjs +1 -1
  72. package/esm/drivers/mongodb/mongodb-sync-adapter.mjs.map +1 -1
  73. package/esm/drivers/mongodb/types.d.mts +1 -1
  74. package/esm/drivers/mongodb/types.d.mts.map +1 -1
  75. package/esm/drivers/postgres/postgres-blueprint.d.mts +1 -1
  76. package/esm/drivers/postgres/postgres-blueprint.d.mts.map +1 -1
  77. package/esm/drivers/postgres/postgres-blueprint.mjs +1 -1
  78. package/esm/drivers/postgres/postgres-blueprint.mjs.map +1 -1
  79. package/esm/drivers/postgres/postgres-dialect.d.mts +1 -1
  80. package/esm/drivers/postgres/postgres-dialect.d.mts.map +1 -1
  81. package/esm/drivers/postgres/postgres-dialect.mjs +1 -1
  82. package/esm/drivers/postgres/postgres-dialect.mjs.map +1 -1
  83. package/esm/drivers/postgres/postgres-driver.d.mts +1 -1
  84. package/esm/drivers/postgres/postgres-driver.d.mts.map +1 -1
  85. package/esm/drivers/postgres/postgres-driver.mjs +2 -2
  86. package/esm/drivers/postgres/postgres-driver.mjs.map +1 -1
  87. package/esm/drivers/postgres/postgres-migration-driver.d.mts +1 -1
  88. package/esm/drivers/postgres/postgres-migration-driver.d.mts.map +1 -1
  89. package/esm/drivers/postgres/postgres-migration-driver.mjs +1 -1
  90. package/esm/drivers/postgres/postgres-migration-driver.mjs.map +1 -1
  91. package/esm/drivers/postgres/postgres-query-builder.d.mts +1 -1
  92. package/esm/drivers/postgres/postgres-query-builder.d.mts.map +1 -1
  93. package/esm/drivers/postgres/postgres-query-builder.mjs +7 -5
  94. package/esm/drivers/postgres/postgres-query-builder.mjs.map +1 -1
  95. package/esm/drivers/postgres/postgres-query-parser.d.mts +1 -1
  96. package/esm/drivers/postgres/postgres-query-parser.d.mts.map +1 -1
  97. package/esm/drivers/postgres/postgres-query-parser.mjs +1 -1
  98. package/esm/drivers/postgres/postgres-query-parser.mjs.map +1 -1
  99. package/esm/drivers/postgres/postgres-sql-serializer.mjs +1 -1
  100. package/esm/drivers/postgres/postgres-sql-serializer.mjs.map +1 -1
  101. package/esm/drivers/postgres/postgres-sync-adapter.d.mts +1 -1
  102. package/esm/drivers/postgres/postgres-sync-adapter.d.mts.map +1 -1
  103. package/esm/drivers/postgres/postgres-sync-adapter.mjs +1 -1
  104. package/esm/drivers/postgres/postgres-sync-adapter.mjs.map +1 -1
  105. package/esm/drivers/postgres/types.d.mts +1 -1
  106. package/esm/drivers/postgres/types.d.mts.map +1 -1
  107. package/esm/drivers/sql/sql-dialect.contract.d.mts +1 -1
  108. package/esm/drivers/sql/sql-dialect.contract.d.mts.map +1 -1
  109. package/esm/drivers/sql/sql-types.d.mts +1 -1
  110. package/esm/drivers/sql/sql-types.d.mts.map +1 -1
  111. package/esm/errors/missing-data-source.error.d.mts +1 -1
  112. package/esm/errors/missing-data-source.error.d.mts.map +1 -1
  113. package/esm/errors/missing-data-source.error.mjs +1 -1
  114. package/esm/errors/missing-data-source.error.mjs.map +1 -1
  115. package/esm/errors/transaction-rollback.error.d.mts +1 -1
  116. package/esm/errors/transaction-rollback.error.d.mts.map +1 -1
  117. package/esm/errors/transaction-rollback.error.mjs +1 -1
  118. package/esm/errors/transaction-rollback.error.mjs.map +1 -1
  119. package/esm/events/model-events.d.mts +1 -1
  120. package/esm/events/model-events.d.mts.map +1 -1
  121. package/esm/events/model-events.mjs +1 -1
  122. package/esm/events/model-events.mjs.map +1 -1
  123. package/esm/expressions/aggregate-expressions.d.mts +1 -1
  124. package/esm/expressions/aggregate-expressions.d.mts.map +1 -1
  125. package/esm/expressions/aggregate-expressions.mjs +1 -1
  126. package/esm/expressions/aggregate-expressions.mjs.map +1 -1
  127. package/esm/migration/column-builder.d.mts +1 -1
  128. package/esm/migration/column-builder.d.mts.map +1 -1
  129. package/esm/migration/column-builder.mjs +1 -1
  130. package/esm/migration/column-builder.mjs.map +1 -1
  131. package/esm/migration/column-helpers.d.mts +1 -1
  132. package/esm/migration/column-helpers.d.mts.map +1 -1
  133. package/esm/migration/column-helpers.mjs +1 -1
  134. package/esm/migration/column-helpers.mjs.map +1 -1
  135. package/esm/migration/foreign-key-builder.d.mts +1 -1
  136. package/esm/migration/foreign-key-builder.d.mts.map +1 -1
  137. package/esm/migration/foreign-key-builder.mjs +1 -1
  138. package/esm/migration/foreign-key-builder.mjs.map +1 -1
  139. package/esm/migration/migration-runner.d.mts +1 -1
  140. package/esm/migration/migration-runner.d.mts.map +1 -1
  141. package/esm/migration/migration-runner.mjs +1 -1
  142. package/esm/migration/migration-runner.mjs.map +1 -1
  143. package/esm/migration/migration.d.mts +1 -1
  144. package/esm/migration/migration.d.mts.map +1 -1
  145. package/esm/migration/migration.mjs +1 -1
  146. package/esm/migration/migration.mjs.map +1 -1
  147. package/esm/migration/sql-grammar.mjs +1 -1
  148. package/esm/migration/sql-grammar.mjs.map +1 -1
  149. package/esm/migration/sql-serializer.d.mts +1 -1
  150. package/esm/migration/sql-serializer.d.mts.map +1 -1
  151. package/esm/migration/sql-serializer.mjs +1 -1
  152. package/esm/migration/sql-serializer.mjs.map +1 -1
  153. package/esm/migration/types.d.mts +1 -1
  154. package/esm/migration/types.d.mts.map +1 -1
  155. package/esm/model/methods/accessor-methods.mjs +1 -1
  156. package/esm/model/methods/accessor-methods.mjs.map +1 -1
  157. package/esm/model/methods/delete-methods.mjs +1 -1
  158. package/esm/model/methods/delete-methods.mjs.map +1 -1
  159. package/esm/model/methods/dirty-methods.mjs +1 -1
  160. package/esm/model/methods/dirty-methods.mjs.map +1 -1
  161. package/esm/model/methods/hydration-methods.mjs +1 -1
  162. package/esm/model/methods/hydration-methods.mjs.map +1 -1
  163. package/esm/model/methods/instance-event-methods.mjs +1 -1
  164. package/esm/model/methods/instance-event-methods.mjs.map +1 -1
  165. package/esm/model/methods/meta-methods.mjs +1 -1
  166. package/esm/model/methods/meta-methods.mjs.map +1 -1
  167. package/esm/model/methods/pivot-methods.mjs +1 -1
  168. package/esm/model/methods/pivot-methods.mjs.map +1 -1
  169. package/esm/model/methods/query-methods.mjs +1 -1
  170. package/esm/model/methods/query-methods.mjs.map +1 -1
  171. package/esm/model/methods/restore-methods.mjs +1 -1
  172. package/esm/model/methods/restore-methods.mjs.map +1 -1
  173. package/esm/model/methods/scope-methods.mjs +1 -1
  174. package/esm/model/methods/scope-methods.mjs.map +1 -1
  175. package/esm/model/methods/serialization-methods.mjs +1 -1
  176. package/esm/model/methods/serialization-methods.mjs.map +1 -1
  177. package/esm/model/methods/static-event-methods.mjs +1 -1
  178. package/esm/model/methods/static-event-methods.mjs.map +1 -1
  179. package/esm/model/methods/write-methods.mjs +1 -1
  180. package/esm/model/methods/write-methods.mjs.map +1 -1
  181. package/esm/model/model.d.mts +1 -1
  182. package/esm/model/model.d.mts.map +1 -1
  183. package/esm/model/model.mjs +1 -1
  184. package/esm/model/model.mjs.map +1 -1
  185. package/esm/model/model.types.d.mts +1 -1
  186. package/esm/model/model.types.d.mts.map +1 -1
  187. package/esm/model/register-model.d.mts +1 -1
  188. package/esm/model/register-model.d.mts.map +1 -1
  189. package/esm/model/register-model.mjs +1 -1
  190. package/esm/model/register-model.mjs.map +1 -1
  191. package/esm/model/relation-decorators.d.mts +1 -1
  192. package/esm/model/relation-decorators.d.mts.map +1 -1
  193. package/esm/model/relation-decorators.mjs +2 -2
  194. package/esm/model/relation-decorators.mjs.map +1 -1
  195. package/esm/operations/database.d.mts +1 -1
  196. package/esm/operations/database.d.mts.map +1 -1
  197. package/esm/operations/database.mjs +1 -1
  198. package/esm/operations/database.mjs.map +1 -1
  199. package/esm/operations/migrations.d.mts +1 -1
  200. package/esm/operations/migrations.d.mts.map +1 -1
  201. package/esm/operations/migrations.mjs +1 -1
  202. package/esm/operations/migrations.mjs.map +1 -1
  203. package/esm/query-builder/query-builder.d.mts +1 -1
  204. package/esm/query-builder/query-builder.d.mts.map +1 -1
  205. package/esm/query-builder/query-builder.mjs +1 -1
  206. package/esm/query-builder/query-builder.mjs.map +1 -1
  207. package/esm/relations/key-conventions.mjs +1 -1
  208. package/esm/relations/key-conventions.mjs.map +1 -1
  209. package/esm/relations/pivot-operations.d.mts +1 -1
  210. package/esm/relations/pivot-operations.d.mts.map +1 -1
  211. package/esm/relations/pivot-operations.mjs +1 -1
  212. package/esm/relations/pivot-operations.mjs.map +1 -1
  213. package/esm/relations/relation-hydrator.d.mts +1 -1
  214. package/esm/relations/relation-hydrator.d.mts.map +1 -1
  215. package/esm/relations/relation-hydrator.mjs +1 -1
  216. package/esm/relations/relation-hydrator.mjs.map +1 -1
  217. package/esm/relations/relation-loader.d.mts +1 -1
  218. package/esm/relations/relation-loader.d.mts.map +1 -1
  219. package/esm/relations/relation-loader.mjs +1 -1
  220. package/esm/relations/relation-loader.mjs.map +1 -1
  221. package/esm/relations/types.d.mts +1 -1
  222. package/esm/relations/types.d.mts.map +1 -1
  223. package/esm/remover/database-remover.d.mts +1 -1
  224. package/esm/remover/database-remover.d.mts.map +1 -1
  225. package/esm/remover/database-remover.mjs +1 -1
  226. package/esm/remover/database-remover.mjs.map +1 -1
  227. package/esm/restorer/database-restorer.d.mts +1 -1
  228. package/esm/restorer/database-restorer.d.mts.map +1 -1
  229. package/esm/restorer/database-restorer.mjs +1 -1
  230. package/esm/restorer/database-restorer.mjs.map +1 -1
  231. package/esm/sql-database-dirty-tracker.d.mts +1 -1
  232. package/esm/sql-database-dirty-tracker.d.mts.map +1 -1
  233. package/esm/sql-database-dirty-tracker.mjs +1 -1
  234. package/esm/sql-database-dirty-tracker.mjs.map +1 -1
  235. package/esm/sync/model-events.mjs +1 -1
  236. package/esm/sync/model-events.mjs.map +1 -1
  237. package/esm/sync/model-sync-operation.d.mts +1 -1
  238. package/esm/sync/model-sync-operation.d.mts.map +1 -1
  239. package/esm/sync/model-sync-operation.mjs +1 -1
  240. package/esm/sync/model-sync-operation.mjs.map +1 -1
  241. package/esm/sync/model-sync.d.mts +1 -1
  242. package/esm/sync/model-sync.d.mts.map +1 -1
  243. package/esm/sync/model-sync.mjs +1 -1
  244. package/esm/sync/model-sync.mjs.map +1 -1
  245. package/esm/sync/sync-context.d.mts +1 -1
  246. package/esm/sync/sync-context.d.mts.map +1 -1
  247. package/esm/sync/sync-context.mjs +1 -1
  248. package/esm/sync/sync-context.mjs.map +1 -1
  249. package/esm/sync/sync-manager.d.mts +1 -1
  250. package/esm/sync/sync-manager.d.mts.map +1 -1
  251. package/esm/sync/sync-manager.mjs +1 -1
  252. package/esm/sync/sync-manager.mjs.map +1 -1
  253. package/esm/sync/types.d.mts +1 -1
  254. package/esm/sync/types.d.mts.map +1 -1
  255. package/esm/types.d.mts +1 -1
  256. package/esm/types.d.mts.map +1 -1
  257. package/esm/utils/connect-to-database.d.mts +1 -1
  258. package/esm/utils/connect-to-database.d.mts.map +1 -1
  259. package/esm/utils/connect-to-database.mjs +1 -1
  260. package/esm/utils/connect-to-database.mjs.map +1 -1
  261. package/esm/utils/database-writer.utils.d.mts +1 -1
  262. package/esm/utils/database-writer.utils.d.mts.map +1 -1
  263. package/esm/utils/database-writer.utils.mjs +1 -1
  264. package/esm/utils/database-writer.utils.mjs.map +1 -1
  265. package/esm/utils/define-model.d.mts +1 -1
  266. package/esm/utils/define-model.d.mts.map +1 -1
  267. package/esm/utils/define-model.mjs +1 -1
  268. package/esm/utils/define-model.mjs.map +1 -1
  269. package/esm/utils/is-valid-date-value.mjs +1 -1
  270. package/esm/utils/is-valid-date-value.mjs.map +1 -1
  271. package/esm/utils/once-connected.d.mts +1 -1
  272. package/esm/utils/once-connected.d.mts.map +1 -1
  273. package/esm/utils/once-connected.mjs +1 -1
  274. package/esm/utils/once-connected.mjs.map +1 -1
  275. package/esm/validation/database-seal-plugins.mjs +1 -1
  276. package/esm/validation/database-seal-plugins.mjs.map +1 -1
  277. package/esm/validation/database-writer-validation-error.d.mts +1 -1
  278. package/esm/validation/database-writer-validation-error.d.mts.map +1 -1
  279. package/esm/validation/database-writer-validation-error.mjs +1 -1
  280. package/esm/validation/database-writer-validation-error.mjs.map +1 -1
  281. package/esm/validation/mutators/embed-mutator.mjs +1 -1
  282. package/esm/validation/mutators/embed-mutator.mjs.map +1 -1
  283. package/esm/validation/plugins/database-rules-plugin.d.mts +1 -1
  284. package/esm/validation/plugins/database-rules-plugin.d.mts.map +1 -1
  285. package/esm/validation/plugins/database-rules-plugin.mjs +1 -1
  286. package/esm/validation/plugins/database-rules-plugin.mjs.map +1 -1
  287. package/esm/validation/plugins/embed-validator-plugin.d.mts +1 -1
  288. package/esm/validation/plugins/embed-validator-plugin.d.mts.map +1 -1
  289. package/esm/validation/plugins/embed-validator-plugin.mjs +1 -1
  290. package/esm/validation/plugins/embed-validator-plugin.mjs.map +1 -1
  291. package/esm/validation/rules/database-model-rule.mjs +1 -1
  292. package/esm/validation/rules/database-model-rule.mjs.map +1 -1
  293. package/esm/validation/rules/exists-rule.mjs +1 -1
  294. package/esm/validation/rules/exists-rule.mjs.map +1 -1
  295. package/esm/validation/rules/unique-rule.mjs +1 -1
  296. package/esm/validation/rules/unique-rule.mjs.map +1 -1
  297. package/esm/validation/transformers/embed-model-transformer.mjs +1 -1
  298. package/esm/validation/transformers/embed-model-transformer.mjs.map +1 -1
  299. package/esm/validation/types.d.mts +1 -1
  300. package/esm/validation/types.d.mts.map +1 -1
  301. package/esm/validation/validators/embed-validator.d.mts +1 -1
  302. package/esm/validation/validators/embed-validator.d.mts.map +1 -1
  303. package/esm/validation/validators/embed-validator.mjs +1 -1
  304. package/esm/validation/validators/embed-validator.mjs.map +1 -1
  305. package/esm/writer/database-writer.d.mts +1 -1
  306. package/esm/writer/database-writer.d.mts.map +1 -1
  307. package/esm/writer/database-writer.mjs +1 -1
  308. package/esm/writer/database-writer.mjs.map +1 -1
  309. package/llms-full.txt +535 -0
  310. package/llms.txt +1 -0
  311. package/package.json +9 -12
  312. package/skills/README.md +4 -0
  313. package/skills/alter-migration/SKILL.md +531 -0
  314. package/esm/cli/commands/migrate-export-sql.mjs +0 -48
  315. package/esm/cli/commands/migrate-export-sql.mjs.map +0 -1
  316. package/esm/cli/commands/migrate-list.mjs +0 -26
  317. package/esm/cli/commands/migrate-list.mjs.map +0 -1
  318. package/esm/cli/commands/migrate-rollback.mjs +0 -50
  319. package/esm/cli/commands/migrate-rollback.mjs.map +0 -1
  320. package/esm/cli/commands/migrate.mjs +0 -65
  321. package/esm/cli/commands/migrate.mjs.map +0 -1
  322. package/esm/cli/connection-from-env.mjs +0 -181
  323. package/esm/cli/connection-from-env.mjs.map +0 -1
  324. package/esm/cli/index.mjs +0 -31
  325. package/esm/cli/index.mjs.map +0 -1
  326. package/esm/cli/load-migrations.mjs +0 -78
  327. package/esm/cli/load-migrations.mjs.map +0 -1
  328. package/esm/cli/printers.mjs +0 -57
  329. package/esm/cli/printers.mjs.map +0 -1
  330. package/esm/cli/setup-logger.mjs +0 -30
  331. package/esm/cli/setup-logger.mjs.map +0 -1
  332. package/esm/cli/with-cli-connection.mjs +0 -39
  333. package/esm/cli/with-cli-connection.mjs.map +0 -1
  334. package/esm/cli.d.mts +0 -1
  335. package/esm/cli.mjs +0 -26
  336. package/esm/cli.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["Context","contextManager","Context","contextManager","EventEmitter","events","events","colors","VALID_RULE","VALID_RULE","ScalarValidator","StringValidator","NumberValidator","VALID_RULE","BaseValidator","arrayRule","v","events","ctor","colors","colors","EventEmitter","colors","colors","colors"],"sources":["../../../../../../@warlock.js/cascade/src/context/database-data-source-context.ts","../../../../../../@warlock.js/cascade/src/context/database-transaction-context.ts","../../../../../../@warlock.js/cascade/src/data-source/data-source.ts","../../../../../../@warlock.js/cascade/src/errors/missing-data-source.error.ts","../../../../../../@warlock.js/cascade/src/data-source/data-source-registry.ts","../../../../../../@warlock.js/cascade/src/errors/transaction-rollback.error.ts","../../../../../../@warlock.js/cascade/src/database-dirty-tracker.ts","../../../../../../@warlock.js/cascade/src/events/model-events.ts","../../../../../../@warlock.js/cascade/src/model/relation-decorators.ts","../../../../../../@warlock.js/cascade/src/model/register-model.ts","../../../../../../@warlock.js/cascade/src/relations/key-conventions.ts","../../../../../../@warlock.js/cascade/src/relations/relation-loader.ts","../../../../../../@warlock.js/cascade/src/sync/model-events.ts","../../../../../../@warlock.js/cascade/src/sync/sync-context.ts","../../../../../../@warlock.js/cascade/src/sync/sync-manager.ts","../../../../../../@warlock.js/cascade/src/sync/model-sync-operation.ts","../../../../../../@warlock.js/cascade/src/sync/model-sync.ts","../../../../../../@warlock.js/cascade/src/model/methods/accessor-methods.ts","../../../../../../@warlock.js/cascade/src/remover/database-remover.ts","../../../../../../@warlock.js/cascade/src/model/methods/delete-methods.ts","../../../../../../@warlock.js/cascade/src/model/methods/dirty-methods.ts","../../../../../../@warlock.js/cascade/src/relations/relation-hydrator.ts","../../../../../../@warlock.js/cascade/src/model/methods/hydration-methods.ts","../../../../../../@warlock.js/cascade/src/model/methods/instance-event-methods.ts","../../../../../../@warlock.js/cascade/src/validation/database-writer-validation-error.ts","../../../../../../@warlock.js/cascade/src/validation/rules/exists-rule.ts","../../../../../../@warlock.js/cascade/src/validation/rules/unique-rule.ts","../../../../../../@warlock.js/cascade/src/validation/plugins/database-rules-plugin.ts","../../../../../../@warlock.js/cascade/src/validation/mutators/embed-mutator.ts","../../../../../../@warlock.js/cascade/src/validation/rules/database-model-rule.ts","../../../../../../@warlock.js/cascade/src/validation/transformers/embed-model-transformer.ts","../../../../../../@warlock.js/cascade/src/validation/validators/embed-validator.ts","../../../../../../@warlock.js/cascade/src/validation/plugins/embed-validator-plugin.ts","../../../../../../@warlock.js/cascade/src/validation/database-seal-plugins.ts","../../../../../../@warlock.js/cascade/src/writer/database-writer.ts","../../../../../../@warlock.js/cascade/src/model/methods/meta-methods.ts","../../../../../../@warlock.js/cascade/src/relations/pivot-operations.ts","../../../../../../@warlock.js/cascade/src/model/methods/pivot-methods.ts","../../../../../../@warlock.js/cascade/src/model/methods/query-methods.ts","../../../../../../@warlock.js/cascade/src/restorer/database-restorer.ts","../../../../../../@warlock.js/cascade/src/model/methods/restore-methods.ts","../../../../../../@warlock.js/cascade/src/model/methods/scope-methods.ts","../../../../../../@warlock.js/cascade/src/model/methods/serialization-methods.ts","../../../../../../@warlock.js/cascade/src/model/methods/static-event-methods.ts","../../../../../../@warlock.js/cascade/src/model/methods/write-methods.ts","../../../../../../@warlock.js/cascade/src/model/model.ts","../../../../../../@warlock.js/cascade/src/expressions/aggregate-expressions.ts","../../../../../../@warlock.js/cascade/src/utils/is-valid-date-value.ts","../../../../../../@warlock.js/cascade/src/drivers/mongodb/mongodb-blueprint.ts","../../../../../../@warlock.js/cascade/src/drivers/mongodb/mongodb-id-generator.ts","../../../../../../@warlock.js/cascade/src/drivers/mongodb/mongodb-migration-driver.ts","../../../../../../@warlock.js/cascade/src/query-builder/query-builder.ts","../../../../../../@warlock.js/cascade/src/drivers/mongodb/mongodb-query-operations.ts","../../../../../../@warlock.js/cascade/src/drivers/mongodb/mongodb-query-parser.ts","../../../../../../@warlock.js/cascade/src/drivers/mongodb/mongodb-query-builder.ts","../../../../../../@warlock.js/cascade/src/drivers/mongodb/mongodb-sync-adapter.ts","../../../../../../@warlock.js/cascade/src/drivers/mongodb/mongodb-driver.ts","../../../../../../@warlock.js/cascade/src/drivers/postgres/postgres-blueprint.ts","../../../../../../@warlock.js/cascade/src/drivers/postgres/postgres-dialect.ts","../../../../../../@warlock.js/cascade/src/sql-database-dirty-tracker.ts","../../../../../../@warlock.js/cascade/src/drivers/postgres/postgres-migration-driver.ts","../../../../../../@warlock.js/cascade/src/drivers/postgres/postgres-query-parser.ts","../../../../../../@warlock.js/cascade/src/drivers/postgres/postgres-query-builder.ts","../../../../../../@warlock.js/cascade/src/migration/sql-serializer.ts","../../../../../../@warlock.js/cascade/src/drivers/postgres/postgres-sql-serializer.ts","../../../../../../@warlock.js/cascade/src/drivers/postgres/postgres-sync-adapter.ts","../../../../../../@warlock.js/cascade/src/drivers/postgres/postgres-driver.ts","../../../../../../@warlock.js/cascade/src/utils/connect-to-database.ts","../../../../../../@warlock.js/cascade/src/utils/database-writer.utils.ts","../../../../../../@warlock.js/cascade/src/utils/define-model.ts","../../../../../../@warlock.js/cascade/src/utils/once-connected.ts","../../../../../../@warlock.js/cascade/src/migration/column-builder.ts","../../../../../../@warlock.js/cascade/src/migration/foreign-key-builder.ts","../../../../../../@warlock.js/cascade/src/migration/column-helpers.ts","../../../../../../@warlock.js/cascade/src/migration/migration.ts","../../../../../../@warlock.js/cascade/src/migration/sql-grammar.ts","../../../../../../@warlock.js/cascade/src/migration/migration-runner.ts","../../../../../../@warlock.js/cascade/src/operations/database.ts","../../../../../../@warlock.js/cascade/src/operations/migrations.ts"],"sourcesContent":["import { Context, contextManager } from \"@warlock.js/context\";\nimport type { DataSource } from \"../data-source/data-source\";\n\ntype DataSourceContextValue = string | DataSource;\n\ntype DataSourceContextStore = {\n dataSource?: DataSourceContextValue;\n};\n\n/**\n * Database DataSource Context\n *\n * Manages the active database connection/data source using AsyncLocalStorage.\n * Extends the base Context class for consistent API.\n */\nclass DatabaseDataSourceContext extends Context<DataSourceContextStore> {\n /**\n * Get the current data source\n */\n public getDataSource(): DataSourceContextValue | undefined {\n return this.get(\"dataSource\");\n }\n\n /**\n * Set the data source in context\n */\n public setDataSource(dataSource: DataSourceContextValue): void {\n this.set(\"dataSource\", dataSource);\n }\n\n /**\n * Build the initial data source store with defaults\n */\n public buildStore(): DataSourceContextStore {\n return { dataSource: undefined };\n }\n}\n\nexport const databaseDataSourceContext = new DatabaseDataSourceContext();\n\ncontextManager.register(\"db.datasource\", databaseDataSourceContext);\n","import { Context, contextManager } from \"@warlock.js/context\";\n\ninterface TransactionContextStore {\n session?: unknown;\n}\n\n/**\n * Database Transaction Context\n *\n * Manages database transaction sessions using AsyncLocalStorage.\n * Extends the base Context class for consistent API.\n */\nclass DatabaseTransactionContext extends Context<TransactionContextStore> {\n /**\n * Get the current transaction session\n */\n public getSession<TSession = unknown>(): TSession | undefined {\n return this.get(\"session\") as TSession | undefined;\n }\n\n /**\n * Check if there's an active transaction in the current context\n */\n public hasActiveTransaction(): boolean {\n return this.getSession() !== undefined;\n }\n\n /**\n * Set the transaction session in context\n */\n public setSession(session: unknown): void {\n this.set(\"session\", session);\n }\n\n /**\n * Exit the transaction context\n */\n public exit(): void {\n this.clear();\n }\n\n /**\n * Build the initial transaction store with defaults\n */\n public buildStore(): TransactionContextStore {\n return { session: undefined };\n }\n}\n\nexport const databaseTransactionContext = new DatabaseTransactionContext();\n\ncontextManager.register(\"db.transaction\", databaseTransactionContext);\n","import type { DriverContract, IdGeneratorContract } from \"../contracts\";\nimport type { DeleteStrategy, MigrationDefaults, ModelDefaults, RelationDefaults } from \"../types\";\n\n/**\n * Configuration options used when registering a data source.\n */\nexport type DataSourceOptions = {\n /** Unique name identifying the data source. */\n name: string;\n /** Driver bound to the data source. */\n driver: DriverContract;\n /** Whether this data source should be considered the default one. */\n isDefault?: boolean;\n /**\n * Default delete strategy for models using this data source.\n *\n * - MongoDB: Typically `\"trash\"` (uses RecycleBin collection)\n * - PostgreSQL: Typically `\"permanent\"` or `\"soft\"`\n *\n * Can be overridden by model static property or destroy() options.\n *\n * @default undefined (falls back to \"permanent\")\n */\n defaultDeleteStrategy?: DeleteStrategy;\n\n /**\n * Default trash table/collection name for \"trash\" delete strategy.\n *\n * - MongoDB: Typically `\"RecycleBin\"`\n * - If not set, defaults to `{table}Trash` pattern\n *\n * Can be overridden by Model.trashTable static property.\n *\n * @default undefined (uses {table}Trash pattern)\n */\n defaultTrashTable?: string;\n\n /**\n * Default model configuration for all models using this data source.\n *\n * These defaults override driver defaults but are overridden by\n * individual model static properties.\n *\n * @default undefined\n */\n modelDefaults?: Partial<ModelDefaults>;\n\n /**\n * Migration-level defaults (UUID strategy, etc.).\n *\n * These defaults override driver migration defaults but can be\n * overridden by individual migration calls.\n *\n * @default undefined (uses driver defaults)\n */\n migrationDefaults?: MigrationDefaults;\n\n /**\n * Default relation conventions (FK suffix, pivot-table naming order).\n *\n * Consumed by the runtime convention helpers in\n * `relations/key-conventions.ts` whenever a relation definition omits\n * an explicit `foreignKey` / `pivot` / pivot-column override.\n *\n * @default undefined (uses framework defaults)\n */\n relationDefaults?: RelationDefaults;\n\n /**\n * Migration configuration options.\n */\n migrations?: {\n /**\n * Whether to wrap migrations in database transactions.\n *\n * Overrides driver defaults:\n * - PostgreSQL default: `true` (DDL is transactional)\n * - MongoDB default: `false` (DDL cannot be transactional)\n *\n * Individual migrations can override this with their own `transactional` property.\n *\n * @default undefined (uses driver default)\n */\n transactional?: boolean;\n\n /**\n * Name of the migrations tracking table/collection.\n *\n * @default \"_migrations\"\n */\n table?: string;\n };\n};\n\n/**\n * Wrapper that couples a driver with its metadata.\n *\n * A data source represents a database connection with all its associated services.\n * The ID generator (if needed) is provided by the driver itself.\n *\n * @example\n * ```typescript\n * // MongoDB with auto ID generation\n * const mongoDriver = new MongoDbDriver({\n * host: \"localhost\",\n * port: 27017,\n * database: \"myapp\",\n * autoGenerateId: true, // Driver creates its own ID generator\n * });\n *\n * const dataSource = new DataSource({\n * name: \"primary\",\n * driver: mongoDriver,\n * isDefault: true,\n * });\n *\n * // Access ID generator from driver\n * const idGenerator = dataSource.idGenerator;\n * ```\n */\nexport class DataSource {\n /** Unique name identifying this data source. */\n public readonly name: string;\n\n /** Database driver for executing queries. */\n public readonly driver: DriverContract;\n\n /** Whether this is the default data source. */\n public readonly isDefault: boolean;\n\n /** Default delete strategy for models using this data source. */\n public readonly defaultDeleteStrategy?: DeleteStrategy;\n\n /** Default trash table/collection name for \"trash\" delete strategy. */\n public readonly defaultTrashTable?: string;\n\n /** Default model configuration for all models using this data source. */\n public readonly modelDefaults?: Partial<ModelDefaults>;\n\n /** Migration-level defaults (UUID strategy, etc.). */\n public readonly migrationDefaults?: MigrationDefaults;\n\n /** Default relation conventions (FK suffix, pivot ordering). */\n public readonly relationDefaults?: RelationDefaults;\n\n /** Migration configuration options. */\n public readonly migrations?: {\n transactional?: boolean;\n table?: string;\n };\n\n /**\n * Create a new data source.\n *\n * @param options - Configuration options\n */\n public constructor(options: DataSourceOptions) {\n this.name = options.name;\n this.driver = options.driver;\n this.isDefault = Boolean(options.isDefault);\n this.defaultDeleteStrategy = options.defaultDeleteStrategy;\n this.defaultTrashTable = options.defaultTrashTable;\n this.modelDefaults = options.modelDefaults;\n this.migrationDefaults = options.migrationDefaults;\n this.relationDefaults = options.relationDefaults;\n this.migrations = options.migrations;\n }\n\n /**\n * Get the ID generator from the driver (if available).\n *\n * NoSQL drivers like MongoDB can provide their own ID generator.\n * SQL drivers return undefined as they use native AUTO_INCREMENT.\n *\n * @returns The ID generator instance, or undefined\n *\n * @example\n * ```typescript\n * const idGenerator = dataSource.idGenerator;\n * if (idGenerator) {\n * const id = await idGenerator.generateNextId({ table: \"users\" });\n * }\n * ```\n */\n public get idGenerator(): IdGeneratorContract | undefined {\n // Check if driver has a getIdGenerator method (duck typing)\n const driver = this.driver as any;\n if (typeof driver.getIdGenerator === \"function\") {\n return driver.getIdGenerator();\n }\n return undefined;\n }\n}\n","/**\n * Error thrown when a requested data source is not found in the registry.\n *\n * This can occur when:\n * - Attempting to retrieve a non-existent named data source\n * - Trying to get the default data source before any have been registered\n * - Context override references an unregistered data source name\n */\nexport class MissingDataSourceError extends Error {\n /**\n * The name of the data source that was not found (if applicable).\n */\n public readonly dataSourceName?: string;\n\n /**\n * Creates a new MissingDataSourceError.\n *\n * @param message - Descriptive error message\n * @param dataSourceName - Optional data source name that was not found\n */\n public constructor(message: string, dataSourceName?: string) {\n super(message);\n this.name = \"MissingDataSourceError\";\n this.dataSourceName = dataSourceName;\n\n // Maintains proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, MissingDataSourceError);\n }\n }\n}\n","import { EventEmitter } from \"node:events\";\nimport { databaseDataSourceContext } from \"../context/database-data-source-context\";\nimport { MissingDataSourceError } from \"../errors/missing-data-source.error\";\nimport { DataSource, type DataSourceOptions } from \"./data-source\";\n\n/**\n * Event types emitted by the DataSourceRegistry.\n *\n * - `registered`: Emitted when any data source is registered\n * - `default-registered`: Emitted when a default data source is registered\n * - `connected`: Emitted when a data source's driver connects\n * - `disconnected`: Emitted when a data source's driver disconnects\n */\nexport type DataSourceRegistryEvent =\n | \"registered\"\n | \"default-registered\"\n | \"connected\"\n | \"disconnected\";\n\n/**\n * Callback signature for registry events.\n */\nexport type DataSourceRegistryListener = (dataSource: DataSource) => void;\n\n/** Maintains registry of named data sources. */\nclass DataSourceRegistry {\n private readonly sources = new Map<string, DataSource>();\n private defaultSource?: DataSource;\n private readonly events = new EventEmitter();\n\n /**\n * Register a new data source definition.\n *\n * Sets up event forwarding from the driver to the registry, allowing\n * centralized listening for connection state changes.\n *\n * **Emits:**\n * - `registered` - When the data source is registered\n * - `default-registered` - If this becomes the default data source\n * - `connected` - When the driver connects (forwarded from driver)\n * - `disconnected` - When the driver disconnects (forwarded from driver)\n *\n * @param options - Data source configuration\n * @returns The registered data source instance\n */\n public register(options: DataSourceOptions): DataSource {\n const source = new DataSource(options);\n this.sources.set(source.name, source);\n\n const isNewDefault = source.isDefault || !this.defaultSource;\n\n if (isNewDefault) {\n this.defaultSource = source;\n }\n\n // Emit registration events\n this.events.emit(\"registered\", source);\n\n if (isNewDefault) {\n this.events.emit(\"default-registered\", source);\n }\n\n source.driver.on(\"connected\", () => {\n this.events.emit(\"connected\", source);\n });\n\n source.driver.on(\"disconnected\", () => {\n this.events.emit(\"disconnected\", source);\n });\n\n return source;\n }\n\n /**\n * Clean up all data sources and default one\n */\n public clear() {\n this.defaultSource = undefined;\n this.sources.clear();\n }\n\n /**\n * Listen for data source registry events.\n *\n * @param event - The event to listen for\n * @param listener - Callback to execute when event fires\n *\n * @example\n * ```typescript\n * // Listen for registration\n * dataSourceRegistry.on(\"registered\", (ds) => {\n * console.log(`Data source \"${ds.name}\" registered`);\n * console.log(`Driver: ${ds.driver.name}`); // e.g., \"mongodb\"\n * });\n *\n * // Listen for default data source\n * dataSourceRegistry.on(\"default-registered\", (ds) => {\n * console.log(`Default data source set to \"${ds.name}\"`);\n * });\n *\n * // Listen for connection events (forwarded from drivers)\n * dataSourceRegistry.on(\"connected\", (ds) => {\n * console.log(`${ds.driver.name} data source \"${ds.name}\" connected`);\n * });\n *\n * dataSourceRegistry.on(\"disconnected\", (ds) => {\n * console.log(`${ds.driver.name} data source \"${ds.name}\" disconnected`);\n * });\n * ```\n */\n public on(event: DataSourceRegistryEvent, listener: DataSourceRegistryListener): void {\n this.events.on(event, listener);\n }\n\n /**\n * Listen for a data source registration event once.\n *\n * The listener is automatically removed after being called once.\n *\n * @param event - The event to listen for\n * @param listener - Callback to execute when event fires\n */\n public once(event: DataSourceRegistryEvent, listener: DataSourceRegistryListener): void {\n this.events.once(event, listener);\n }\n\n /**\n * Remove a listener for a data source registration event.\n *\n * @param event - The event to stop listening for\n * @param listener - The listener to remove\n */\n public off(event: DataSourceRegistryEvent, listener: DataSourceRegistryListener): void {\n this.events.off(event, listener);\n }\n\n /** Retrieve a data source either by name or the default one. */\n public get(name?: string): DataSource {\n const contextSource = name == null ? databaseDataSourceContext.getDataSource() : null;\n\n if (contextSource) {\n if (contextSource instanceof DataSource) {\n return contextSource;\n }\n\n const override = this.sources.get(contextSource);\n\n if (!override) {\n throw new MissingDataSourceError(\n `Data source \"${contextSource}\" is not registered (context override).`,\n contextSource,\n );\n }\n\n return override;\n }\n\n if (name != null) {\n const source = this.sources.get(name);\n if (!source) {\n throw new MissingDataSourceError(`Data source \"${name}\" is not registered.`, name);\n }\n return source;\n }\n\n if (!this.defaultSource) {\n throw new MissingDataSourceError(\"No default data source registered.\");\n }\n\n return this.defaultSource;\n }\n\n /**\n * Get all registered data sources.\n *\n * Useful for operations that need to iterate over all sources,\n * such as shutting down all connections.\n *\n * @returns Array of all registered data sources\n *\n * @example\n * ```typescript\n * // Shutdown all data sources\n * for (const dataSource of dataSourceRegistry.getAllDataSources()) {\n * await dataSource.driver.disconnect();\n * }\n * ```\n */\n public getAllDataSources(): DataSource[] {\n return Array.from(this.sources.values());\n }\n}\n\nexport const dataSourceRegistry = new DataSourceRegistry();\n","/**\n * Error thrown when a transaction is explicitly rolled back via ctx.rollback().\n *\n * This error is used to signal transaction rollback without representing\n * an application error. It's caught by the transaction wrapper to perform\n * cleanup and then re-thrown.\n */\nexport class TransactionRollbackError extends Error {\n /**\n * The reason for the rollback (if provided).\n */\n public readonly reason?: string;\n\n /**\n * Creates a new TransactionRollbackError.\n *\n * @param reason - Optional reason for rollback (for logging/debugging)\n */\n public constructor(reason?: string) {\n super(reason || \"Transaction rolled back\");\n this.name = \"TransactionRollbackError\";\n this.reason = reason;\n\n // Maintains proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, TransactionRollbackError);\n }\n }\n}\n","import { areEqual, clone } from \"@mongez/reinforcements\";\nimport { isPlainObject } from \"@mongez/supportive-is\";\n\nfunction canBeFlatten(object: unknown): boolean {\n return isPlainObject(object);\n}\n\n/**\n * A fix for flatten as non-plain object is being flatten as well which it should not be\n */\nfunction flatten(\n object: Record<string, unknown>,\n separator = \".\",\n keepNestedOriginalObject = false,\n parent?: string,\n root: Record<string, unknown> = {},\n) {\n if (canBeFlatten(object) === false) {\n return object;\n }\n // object = toPlainObject(object);\n for (const key of Object.keys(object)) {\n const value = object[key];\n const keyChain = parent ? parent + separator + key : key;\n if ((Array.isArray(value) && value.length === 0) || typeof value === \"function\") {\n root[keyChain] = value;\n } else if (canBeFlatten(value)) {\n if (keepNestedOriginalObject) {\n root[keyChain] = value;\n }\n flatten(\n value as Record<string, unknown>,\n separator,\n keepNestedOriginalObject,\n keyChain,\n root,\n );\n } else {\n root[keyChain] = value;\n }\n }\n return root;\n}\n\n/**\n * Flattened record type representing dot-notation paths mapped to their values.\n */\ntype FlatRecord = Record<string, unknown>;\n\n/**\n * Represents the old and new values of a dirty column.\n */\ntype DirtyColumnValues = { oldValue: unknown; newValue: unknown };\n\n/**\n * Tracks changes to model data by maintaining snapshots of initial and current state.\n *\n * The tracker stores both raw (nested) and flattened (dot-notation) versions of the data\n * to accurately detect modifications, additions, and removals at any nesting level.\n *\n * @example\n * ```typescript\n * const tracker = new DatabaseDirtyTracker({ name: \"Alice\", age: 30 });\n * tracker.mergeChanges({ age: 31 });\n * console.log(tracker.hasChanges()); // true\n * console.log(tracker.getDirtyColumns()); // [\"age\"]\n * console.log(tracker.getDirtyColumnsWithValues());\n * // { age: { oldValue: 30, newValue: 31 } }\n * ```\n */\nexport class DatabaseDirtyTracker {\n /**\n * The initial raw data snapshot taken at construction or last reset.\n * Used as the baseline for comparison.\n */\n protected initialRaw: Record<string, unknown>;\n\n /**\n * The current raw data snapshot reflecting all changes made via merge/unset.\n */\n protected currentRaw: Record<string, unknown>;\n\n /**\n * Flattened version of the initial data using dot-notation keys.\n * Example: { \"address.city\": \"NYC\" }\n */\n protected initialFlattened: FlatRecord;\n\n /**\n * Flattened version of the current data using dot-notation keys.\n */\n protected currentFlattened: FlatRecord;\n\n /**\n * Set of column names (dot-notation paths) that have been modified.\n */\n protected readonly dirtyColumns = new Set<string>();\n\n /**\n * Set of column names (dot-notation paths) that existed initially but have been removed.\n */\n protected readonly removedColumns = new Set<string>();\n\n public constructor(data: Record<string, unknown>) {\n this.initialRaw = this.cloneData(data);\n this.currentRaw = this.cloneData(data);\n\n this.initialFlattened = this.flattenData(this.initialRaw);\n this.currentFlattened = { ...this.initialFlattened };\n\n this.updateDirtyState();\n }\n\n /**\n * Returns the list of dirty columns using dot-notation.\n *\n * A column is considered dirty if its value has changed compared to the initial snapshot.\n *\n * @returns An array of column names (dot-notation paths) that have been modified\n *\n * @example\n * ```typescript\n * tracker.mergeChanges({ name: \"Bob\", \"address.city\": \"LA\" });\n * tracker.getDirtyColumns(); // [\"name\", \"address.city\"]\n * ```\n */\n public getDirtyColumns(): string[] {\n return Array.from(this.dirtyColumns);\n }\n\n /**\n * Determines whether there are any tracked changes.\n *\n * Returns `true` if any columns have been modified or removed since the initial snapshot.\n *\n * @returns `true` if there are changes, `false` otherwise\n *\n * @example\n * ```typescript\n * const tracker = new DatabaseDirtyTracker({ name: \"Alice\" });\n * tracker.hasChanges(); // false\n * tracker.mergeChanges({ name: \"Bob\" });\n * tracker.hasChanges(); // true\n * tracker.unset(\"name\");\n * tracker.hasChanges(); // true (removed column counts as a change)\n * ```\n */\n public hasChanges(): boolean {\n return this.dirtyColumns.size > 0 || this.removedColumns.size > 0;\n }\n\n /**\n * Check if the given column is dirty (changed)\n */\n public isDirty(column: string): boolean {\n return this.dirtyColumns.has(column);\n }\n\n /**\n * Returns the set of columns that have been removed compared to the baseline.\n *\n * A column is considered removed if it existed in the initial snapshot but has been\n * explicitly unset or deleted from the current data.\n *\n * @returns An array of column names (dot-notation paths) that have been removed\n *\n * @example\n * ```typescript\n * const tracker = new DatabaseDirtyTracker({ name: \"Alice\", temp: \"value\" });\n * tracker.unset(\"temp\");\n * tracker.getRemovedColumns(); // [\"temp\"]\n * ```\n */\n public getRemovedColumns(): string[] {\n return Array.from(this.removedColumns);\n }\n\n /**\n * Provides a mapping of dirty columns to their previous and current values.\n *\n * This is useful for generating audit logs, building partial update payloads,\n * or displaying change summaries to users.\n *\n * @returns A record mapping each dirty column to an object containing oldValue and newValue\n *\n * @example\n * ```typescript\n * const tracker = new DatabaseDirtyTracker({ name: \"Alice\", age: 30 });\n * tracker.mergeChanges({ age: 31 });\n * tracker.getDirtyColumnsWithValues();\n * // { age: { oldValue: 30, newValue: 31 } }\n * ```\n */\n public getDirtyColumnsWithValues(): Record<string, DirtyColumnValues> {\n const result: Record<string, DirtyColumnValues> = {};\n\n for (const column of this.dirtyColumns) {\n const hasCurrent =\n this.currentFlattened[column] !== undefined || column in this.currentFlattened;\n\n result[column] = {\n oldValue: this.initialFlattened[column],\n newValue: hasCurrent ? this.currentFlattened[column] : undefined,\n };\n }\n\n return result;\n }\n\n /**\n * Replaces the current data snapshot entirely and recomputes the diff.\n *\n * This is useful when you want to replace all current data with a new set,\n * while keeping the initial baseline for comparison.\n *\n * @param data - The new data to set as the current snapshot\n *\n * @example\n * ```typescript\n * const tracker = new DatabaseDirtyTracker({ name: \"Alice\" });\n * tracker.replaceCurrentData({ name: \"Bob\", email: \"bob@example.com\" });\n * tracker.getDirtyColumns(); // [\"name\", \"email\"]\n * ```\n */\n public replaceCurrentData(data: Record<string, unknown>): void {\n this.currentRaw = this.cloneData(data);\n this.currentFlattened = this.flattenData(this.currentRaw);\n this.updateDirtyState();\n }\n\n /**\n * Merges a partial payload into the current snapshot and recomputes the diff.\n *\n * This performs a deep merge, preserving existing nested structures while\n * updating only the specified fields.\n *\n * @param partial - Partial data to merge into the current snapshot\n *\n * @example\n * ```typescript\n * const tracker = new DatabaseDirtyTracker({ name: \"Alice\", address: { city: \"NYC\" } });\n * tracker.mergeChanges({ address: { zip: \"10001\" } });\n * // Current data: { name: \"Alice\", address: { city: \"NYC\", zip: \"10001\" } }\n * tracker.getDirtyColumns(); // [\"address.zip\"]\n * ```\n */\n public mergeChanges(partial: Record<string, unknown>): void {\n this.mergeIntoRaw(this.currentRaw, partial);\n this.currentFlattened = this.flattenData(this.currentRaw);\n this.updateDirtyState();\n }\n\n /**\n * Explicitly removes one or more columns from the current data.\n *\n * Supports both single column names and arrays of column names.\n * Columns can be specified using dot-notation for nested paths.\n *\n * @param columns - A single column name or an array of column names to remove\n *\n * @example\n * ```typescript\n * tracker.unset(\"tempField\");\n * tracker.unset([\"field1\", \"field2\", \"nested.field\"]);\n * tracker.getRemovedColumns(); // [\"tempField\", \"field1\", \"field2\", \"nested.field\"]\n * ```\n */\n public unset(columns: string | string[]): void {\n const targets = Array.isArray(columns) ? columns : [columns];\n\n for (const path of targets) {\n this.deleteFromRaw(path);\n }\n\n this.currentFlattened = this.flattenData(this.currentRaw);\n this.updateDirtyState();\n }\n\n /**\n * Resets both the initial and current snapshots to the provided data.\n *\n * If no data is provided, the current snapshot becomes the new baseline.\n * This clears all tracked changes and removed columns.\n *\n * @param data - Optional new data to use as the baseline. If omitted, uses current data.\n *\n * @example\n * ```typescript\n * const tracker = new DatabaseDirtyTracker({ name: \"Alice\" });\n * tracker.mergeChanges({ name: \"Bob\" });\n * tracker.hasChanges(); // true\n * tracker.reset(); // Make current state the new baseline\n * tracker.hasChanges(); // false\n *\n * // Or reset to entirely new data:\n * tracker.reset({ name: \"Charlie\", age: 25 });\n * ```\n */\n public reset(data?: Record<string, unknown>): void {\n const source = data ?? this.currentRaw;\n this.initialRaw = this.cloneData(source);\n this.currentRaw = this.cloneData(source);\n\n this.initialFlattened = this.flattenData(this.initialRaw);\n this.currentFlattened = this.flattenData(this.currentRaw);\n\n this.dirtyColumns.clear();\n this.removedColumns.clear();\n }\n\n /**\n * Flattens the given data object.\n * Can be overridden by subclasses to change flattening behavior.\n */\n protected flattenData(data: Record<string, unknown>): FlatRecord {\n return flatten(data);\n }\n\n /**\n * Recomputes the dirty and removed column sets by comparing initial and current snapshots.\n *\n * This method is called internally after any operation that modifies the current data.\n * It iterates through all keys in both flattened snapshots and determines which columns\n * have been modified or removed.\n *\n * @protected\n */\n protected updateDirtyState(): void {\n this.dirtyColumns.clear();\n this.removedColumns.clear();\n\n const keys = new Set([\n ...Object.keys(this.initialFlattened),\n ...Object.keys(this.currentFlattened),\n ]);\n\n for (const key of keys) {\n const hasCurrent = this.currentFlattened[key] !== undefined || key in this.currentFlattened;\n const hasInitial = this.initialFlattened[key] !== undefined || key in this.initialFlattened;\n\n if (!hasCurrent && hasInitial) {\n this.removedColumns.add(key);\n }\n\n const initialValue = this.initialFlattened[key];\n const currentValue = hasCurrent ? this.currentFlattened[key] : undefined;\n\n if (!areEqual(initialValue, currentValue)) {\n this.dirtyColumns.add(key);\n }\n }\n }\n\n /**\n * Recursively merges source object into target object, performing a deep merge.\n *\n * For nested objects, the merge is recursive. For arrays and primitives, the source\n * value replaces the target value. All values are cloned to prevent reference sharing.\n *\n * @param target - The object to merge into\n * @param source - The object to merge from\n * @private\n */\n protected mergeIntoRaw(target: Record<string, unknown>, source: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(source)) {\n if (\n value &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n target[key] &&\n typeof target[key] === \"object\" &&\n !Array.isArray(target[key])\n ) {\n this.mergeIntoRaw(target[key] as Record<string, unknown>, value as Record<string, unknown>);\n continue;\n }\n\n target[key] = this.cloneData(value);\n }\n }\n\n /**\n * Deletes a field from the current raw data using a dot-notation path.\n *\n * Supports nested paths (e.g., \"address.city\") and array indices (e.g., \"items.0\").\n * If any segment in the path doesn't exist, the operation is a no-op.\n *\n * @param path - The dot-notation path to the field to delete\n * @private\n */\n protected deleteFromRaw(path: string): void {\n const segments = path.split(\".\");\n let container: unknown = this.currentRaw;\n\n for (let index = 0; index < segments.length - 1; index += 1) {\n if (container === undefined || container === null) {\n return;\n }\n\n container = this.resolveSegment(container, segments[index]);\n }\n\n if (container === undefined || container === null) {\n return;\n }\n\n const lastSegment = segments[segments.length - 1];\n if (Array.isArray(container)) {\n const numericIndex = Number(lastSegment);\n if (!Number.isNaN(numericIndex)) {\n container.splice(numericIndex, 1);\n }\n return;\n }\n\n if (typeof container === \"object\") {\n delete (container as Record<string, unknown>)[lastSegment];\n }\n }\n\n /**\n * Resolves a single segment of a dot-notation path within a container.\n *\n * Handles both object property access and array index access.\n *\n * @param container - The object or array to access\n * @param segment - The property name or array index as a string\n * @returns The value at the specified segment, or undefined if not found\n * @private\n */\n protected resolveSegment(container: unknown, segment: string): unknown {\n if (Array.isArray(container)) {\n const numericIndex = Number(segment);\n if (Number.isNaN(numericIndex)) {\n return undefined;\n }\n\n return container[numericIndex];\n }\n\n if (container && typeof container === \"object\") {\n return (container as Record<string, unknown>)[segment];\n }\n\n return undefined;\n }\n\n /**\n * Creates a deep clone of the provided data.\n *\n * @param data - The data to clone\n * @returns A deep clone of the data\n * @private\n */\n protected cloneData<T>(data: T): T {\n return clone(data);\n }\n}\n","import { QueryBuilderContract } from \"../contracts\";\r\nimport type { Model } from \"../model/model\";\r\nimport { DeleteStrategy } from \"../types\";\r\n\r\ntype OnValidatingEventContext = {\r\n isInsert: boolean;\r\n mode: \"insert\" | \"update\";\r\n};\r\n\r\ntype OnSavingEventContext = {\r\n isInsert: boolean;\r\n mode: \"insert\" | \"update\";\r\n};\r\n\r\ntype OnDeletingEventContext = {\r\n strategy: DeleteStrategy;\r\n primaryKeyValue: string | number;\r\n primaryKey: string;\r\n};\r\n\r\nexport type OnDeletedEventContext = OnDeletingEventContext & {\r\n deletedCount: number;\r\n trashRecord?: Record<string, unknown>;\r\n};\r\n\r\ntype OnFetchingEventContext = {\r\n table: string;\r\n modelClass: any;\r\n};\r\n\r\ntype OnHydratingEventContext = {\r\n query: QueryBuilderContract;\r\n hydrateCallback?: (data: any, index: number) => any;\r\n};\r\n\r\ntype OnFetchedEventContext = {\r\n query: QueryBuilderContract;\r\n rawRecords: any[];\r\n duration: number;\r\n};\r\n\r\n/**\r\n * Lifecycle events understood by Cascade models.\r\n *\r\n * The list mirrors the hooks in the legacy ORM so downstream code can subscribe\r\n * with consistent semantics.\r\n */\r\nexport type ModelEventName =\r\n | \"initializing\"\r\n | \"fetching\"\r\n | \"hydrating\"\r\n | \"fetched\"\r\n | \"validating\"\r\n | \"validated\"\r\n | \"saving\"\r\n | \"saved\"\r\n | \"creating\"\r\n | \"created\"\r\n | \"updating\"\r\n | \"updated\"\r\n | \"deleting\"\r\n | \"deleted\"\r\n | \"restoring\"\r\n | \"restored\";\r\n\r\n/** Signature of an event listener registered against a model lifecycle hook. */\r\nexport type ModelEventListener<TModel, TContext = unknown> = (\r\n model: TModel,\r\n context: TContext,\r\n) => void | Promise<void>;\r\n\r\n/**\r\n * Light-weight async event emitter used to power model lifecycle hooks.\r\n *\r\n * The implementation intentionally avoids any external dependency so we can\r\n * re-use it in drivers, writers, and other core services without pulling in\r\n * heavier event libraries.\r\n */\r\nexport class ModelEvents<TModel> {\r\n public readonly listeners = new Map<ModelEventName, Set<ModelEventListener<TModel>>>();\r\n\r\n /**\r\n * Register a listener for the given event.\r\n * Returns an unsubscribe function for convenience.\r\n */\r\n public on<TContext = unknown>(\r\n event: ModelEventName,\r\n listener: ModelEventListener<TModel, TContext>,\r\n ): () => void {\r\n const listeners = this.ensureListenerSet(event);\r\n listeners.add(listener as ModelEventListener<TModel>);\r\n return () => this.off(event, listener);\r\n }\r\n\r\n /**\r\n * Register a listener that automatically unsubscribes after the first call.\r\n */\r\n public once<TContext = unknown>(\r\n event: ModelEventName,\r\n listener: ModelEventListener<TModel, TContext>,\r\n ): () => void {\r\n const wrapper: ModelEventListener<TModel, TContext> = async (model, context) => {\r\n try {\r\n await listener(model, context);\r\n } finally {\r\n this.off(event, wrapper);\r\n }\r\n };\r\n return this.on(event, wrapper);\r\n }\r\n\r\n /**\r\n * Deregister a listener for the given event.\r\n */\r\n public off<TContext = unknown>(\r\n event: ModelEventName,\r\n listener: ModelEventListener<TModel, TContext>,\r\n ): void {\r\n const listeners = this.listeners.get(event);\r\n if (!listeners) {\r\n return;\r\n }\r\n listeners.delete(listener as ModelEventListener<TModel>);\r\n if (listeners.size === 0) {\r\n this.listeners.delete(event);\r\n }\r\n }\r\n\r\n /**\r\n * Emit an event to all registered listeners.\r\n */\r\n public async emit<TContext = unknown>(\r\n event: ModelEventName,\r\n model: TModel,\r\n context: TContext,\r\n ): Promise<void> {\r\n const listeners = this.listeners.get(event);\r\n if (!listeners || listeners.size === 0) {\r\n return;\r\n }\r\n for (const listener of Array.from(listeners)) {\r\n await listener(model, context);\r\n }\r\n }\r\n\r\n /**\r\n * Emit events for fetching\r\n */\r\n public async emitFetching<TContext = unknown>(\r\n query: QueryBuilderContract,\r\n context?: TContext,\r\n ): Promise<void> {\r\n await this.emit(\"fetching\", query as any, context);\r\n }\r\n\r\n /**\r\n * Remove all registered listeners.\r\n */\r\n public clear(): void {\r\n this.listeners.clear();\r\n }\r\n\r\n /**\r\n * Registers a listener for the \"saving\" event.\r\n *\r\n * Fired before a model is persisted (both insert and update), and before validation.\r\n * Use this hook for data enrichment and preparation (e.g., setting createdBy, updatedBy).\r\n *\r\n * @param listener - The callback to invoke\r\n * @returns An unsubscribe function\r\n */\r\n public onSaving<TContext = OnSavingEventContext>(\r\n listener: ModelEventListener<TModel, TContext>,\r\n ): () => void {\r\n return this.on(\"saving\", listener);\r\n }\r\n\r\n /**\r\n * Registers a listener for the \"saved\" event.\r\n *\r\n * Fired after a model has been successfully persisted.\r\n *\r\n * @param listener - The callback to invoke\r\n * @returns An unsubscribe function\r\n */\r\n public onSaved<TContext = unknown>(listener: ModelEventListener<TModel, TContext>): () => void {\r\n return this.on(\"saved\", listener);\r\n }\r\n\r\n /**\r\n * Registers a listener for the \"creating\" event.\r\n *\r\n * Fired before a new model is inserted into the database.\r\n *\r\n * @param listener - The callback to invoke\r\n * @returns An unsubscribe function\r\n */\r\n public onCreating<TContext = unknown>(\r\n listener: ModelEventListener<TModel, TContext>,\r\n ): () => void {\r\n return this.on(\"creating\", listener);\r\n }\r\n\r\n /**\r\n * Registers a listener for the \"created\" event.\r\n *\r\n * Fired after a new model has been successfully inserted.\r\n *\r\n * @param listener - The callback to invoke\r\n * @returns An unsubscribe function\r\n */\r\n public onCreated<TContext = unknown>(listener: ModelEventListener<TModel, TContext>): () => void {\r\n return this.on(\"created\", listener);\r\n }\r\n\r\n /**\r\n * Registers a listener for the \"updating\" event.\r\n *\r\n * Fired before an existing model is updated in the database.\r\n *\r\n * @param listener - The callback to invoke\r\n * @returns An unsubscribe function\r\n */\r\n public onUpdating<TContext = unknown>(\r\n listener: ModelEventListener<TModel, TContext>,\r\n ): () => void {\r\n return this.on(\"updating\", listener);\r\n }\r\n\r\n /**\r\n * Registers a listener for the \"updated\" event.\r\n *\r\n * Fired after an existing model has been successfully updated.\r\n *\r\n * @param listener - The callback to invoke\r\n * @returns An unsubscribe function\r\n */\r\n public onUpdated<TContext = unknown>(listener: ModelEventListener<TModel, TContext>): () => void {\r\n return this.on(\"updated\", listener);\r\n }\r\n\r\n /**\r\n * Registers a listener for the \"deleting\" event.\r\n *\r\n * Fired before a model is deleted from the database.\r\n *\r\n * @param listener - The callback to invoke\r\n * @returns An unsubscribe function\r\n */\r\n public onDeleting<TContext = OnDeletingEventContext>(\r\n listener: ModelEventListener<TModel, TContext>,\r\n ): () => void {\r\n return this.on(\"deleting\", listener);\r\n }\r\n\r\n /**\r\n * Registers a listener for the \"deleted\" event.\r\n *\r\n * Fired after a model has been successfully deleted.\r\n *\r\n * @param listener - The callback to invoke\r\n * @returns An unsubscribe function\r\n */\r\n public onDeleted<TContext = OnDeletedEventContext>(\r\n listener: ModelEventListener<TModel, TContext>,\r\n ): () => void {\r\n return this.on(\"deleted\", listener);\r\n }\r\n\r\n /**\r\n * Registers a listener for the \"validating\" event.\r\n *\r\n * Fired before model validation is performed.\r\n *\r\n * @param listener - The callback to invoke\r\n * @returns An unsubscribe function\r\n */\r\n public onValidating<TContext = OnValidatingEventContext>(\r\n listener: ModelEventListener<TModel, TContext>,\r\n ): () => void {\r\n return this.on(\"validating\", listener);\r\n }\r\n\r\n /**\r\n * Registers a listener for the \"validated\" event.\r\n *\r\n * Fired after model validation has completed.\r\n *\r\n * @param listener - The callback to invoke\r\n * @returns An unsubscribe function\r\n */\r\n public onValidated<TContext = unknown>(\r\n listener: ModelEventListener<TModel, TContext>,\r\n ): () => void {\r\n return this.on(\"validated\", listener);\r\n }\r\n\r\n /**\r\n * Registers a listener for the \"fetching\" event.\r\n *\r\n * Fired before a query is executed to fetch models.\r\n * Receives the query builder instance, allowing modification before execution.\r\n *\r\n * @param listener - The callback to invoke\r\n * @returns An unsubscribe function\r\n */\r\n public onFetching<TContext = OnFetchingEventContext>(\r\n listener: ModelEventListener<TModel, TContext>,\r\n ): () => void {\r\n return this.on(\"fetching\", listener);\r\n }\r\n\r\n /**\r\n * Registers a listener for the \"hydrating\" event.\r\n *\r\n * Fired after raw records are fetched but before they are hydrated into model instances.\r\n * Allows modification of raw data before hydration.\r\n *\r\n * @param listener - The callback to invoke\r\n * @returns An unsubscribe function\r\n */\r\n public onHydrating<TContext = OnHydratingEventContext>(\r\n listener: ModelEventListener<TModel, TContext>,\r\n ): () => void {\r\n return this.on(\"hydrating\", listener);\r\n }\r\n\r\n /**\r\n * Registers a listener for the \"fetched\" event.\r\n *\r\n * Fired after models have been fetched and hydrated.\r\n * Receives hydrated model instances and query context.\r\n *\r\n * @param listener - The callback to invoke\r\n * @returns An unsubscribe function\r\n */\r\n public onFetched<TContext = OnFetchedEventContext>(\r\n listener: ModelEventListener<TModel, TContext>,\r\n ): () => void {\r\n return this.on(\"fetched\", listener);\r\n }\r\n\r\n /**\r\n * Registers a listener for the \"restoring\" event.\r\n *\r\n * Fired before a soft-deleted model is restored.\r\n *\r\n * @param listener - The callback to invoke\r\n * @returns An unsubscribe function\r\n */\r\n public onRestoring<TContext = unknown>(\r\n listener: ModelEventListener<TModel, TContext>,\r\n ): () => void {\r\n return this.on(\"restoring\", listener);\r\n }\r\n\r\n /**\r\n * Registers a listener for the \"restored\" event.\r\n *\r\n * Fired after a soft-deleted model has been successfully restored.\r\n *\r\n * @param listener - The callback to invoke\r\n * @returns An unsubscribe function\r\n */\r\n public onRestored<TContext = unknown>(\r\n listener: ModelEventListener<TModel, TContext>,\r\n ): () => void {\r\n return this.on(\"restored\", listener);\r\n }\r\n\r\n /**\r\n * Ensures a listener set exists for the given event.\r\n *\r\n * @param event - The event name\r\n * @returns The listener set for the event\r\n * @private\r\n */\r\n private ensureListenerSet(event: ModelEventName): Set<ModelEventListener<TModel>> {\r\n let listeners = this.listeners.get(event);\r\n if (!listeners) {\r\n listeners = new Set();\r\n this.listeners.set(event, listeners);\r\n }\r\n return listeners;\r\n }\r\n}\r\n\r\n/**\r\n * Global event emitter invoked for every model instance, regardless of type.\r\n * Useful for cross-cutting concerns like auditing or request-scoped enrichment.\r\n */\r\nexport const globalModelEvents = new ModelEvents<Model>();\r\n","/**\n * @fileoverview TC39 Stage 3 class field decorators for declaring model\n * relations directly on the field.\n *\n * Replaces the legacy `static relations = { name: hasMany(\"Foo\") }` shape\n * with co-located, single-declaration syntax:\n *\n * @example\n * ```ts\n * @RegisterModel()\n * class User extends Model {\n * @BelongsTo(\"Organization\") organization?: Organization;\n * @HasOne(\"Profile\") profile?: Profile;\n * @HasMany(\"Post\") posts?: Post[];\n * @BelongsToMany(\"Group\") groups?: Group[];\n * }\n * ```\n *\n * Foreign keys, local keys, and pivot tables are inferred from model names\n * via the convention helpers in `relations/key-conventions.ts`. Inline\n * options on the decorator override the conventions per relation.\n *\n * @module @warlock.js/cascade/model/relation-decorators\n */\n\nimport { capitalize, type Lazy } from \"@mongez/reinforcements\";\nimport type {\n BelongsToManyOptions,\n BelongsToOptions,\n HasManyOptions,\n HasOneOptions,\n RelationDefinition,\n RelationType,\n} from \"../relations/types\";\nimport type { ChildModel, Model } from \"./model\";\n\n// ============================================================================\n// INTERNAL — REGISTRATION\n// ============================================================================\n\n/**\n * Type-erased options bag — each relation type accepts a different subset\n * but the registration helper treats them uniformly.\n */\ntype AnyRelationOptions =\n | (BelongsToOptions & { localKey?: string; pivot?: string })\n | HasManyOptions\n | HasOneOptions\n | BelongsToManyOptions;\n\n/**\n * Map raw decorator inputs into a `RelationDefinition` of the canonical\n * shape consumed by the relation loader, pivot operations, etc.\n *\n * Note: foreign-key / pivot-table defaults are NOT resolved here — they\n * live on each runtime resolution path (`RelationLoader`, `PivotOperations`,\n * the postgres query builder) and read from `key-conventions.ts`. Recording\n * `undefined` here keeps a single source of truth for the inference logic.\n */\nfunction buildRelationDefinition(\n type: RelationType,\n model: string | ChildModel<Model> | Lazy<unknown>,\n options?: AnyRelationOptions,\n): RelationDefinition {\n // BelongsTo stores its \"owner key\" in the shared `localKey` slot. Other\n // types just pass `localKey` through.\n const localKey =\n type === \"belongsTo\"\n ? (options as BelongsToOptions)?.ownerKey\n : (options as HasManyOptions)?.localKey;\n\n return {\n type,\n model,\n foreignKey: options?.foreignKey,\n localKey,\n pivot: (options as BelongsToManyOptions)?.pivot,\n pivotLocalKey: (options as BelongsToManyOptions)?.pivotLocalKey,\n pivotForeignKey: (options as BelongsToManyOptions)?.pivotForeignKey,\n select: options?.select,\n };\n}\n\n/**\n * Stash a relation definition into the class-level decorator metadata bag.\n *\n * **Why metadata, not addInitializer?** `context.addInitializer` on a\n * *field* decorator fires per-instance, not per-class — so it only runs\n * when `new ModelClass(...)` is called. Class-level operations like\n * `Organization.withCount(\"users\")` never construct instances, which means\n * an initializer-based registration would leave `Organization.relations`\n * permanently empty.\n *\n * TC39 stage 3 `context.metadata` is the right tool: a shared object across\n * every decorator on the same class declaration. Field decorators write\n * into it during decoration; `@RegisterModel` (a class decorator that runs\n * AFTER all field decorators) reads it back and copies the relations onto\n * the class's static `relations` map.\n *\n * The metadata object also prototype-chains to the parent class's metadata\n * (per spec), so a subclass naturally inherits its parent's relations.\n */\nfunction stashRelationInMetadata(\n metadata: DecoratorMetadataObject,\n relationName: string,\n definition: RelationDefinition,\n): void {\n let relations = metadata[RELATION_METADATA_KEY] as Record<string, RelationDefinition> | undefined;\n\n // Promote inherited relations to an own property before mutating, so\n // writing on the subclass doesn't leak into the parent's bag.\n if (!Object.prototype.hasOwnProperty.call(metadata, RELATION_METADATA_KEY)) {\n relations = { ...(relations ?? {}) };\n metadata[RELATION_METADATA_KEY] = relations;\n }\n\n relations![relationName] = definition;\n}\n\n/**\n * Key used to stash relation definitions on the decorator metadata object.\n * Exported so `@RegisterModel` (in `register-model.ts`) can read it back.\n */\nexport const RELATION_METADATA_KEY = Symbol.for(\"@warlock.js/cascade:relations\");\n\n// ============================================================================\n// INTERNAL — DECORATOR FACTORY\n// ============================================================================\n\n/**\n * Builds a TC39 stage 3 class-field decorator that registers a relation\n * of the given `type`. Each public decorator (`@BelongsTo`, `@HasMany`,\n * etc.) is a thin specialisation of this factory.\n */\nfunction makeRelationDecorator<Options extends AnyRelationOptions | undefined>(type: RelationType) {\n return function (\n modelRelation: string | ChildModel<Model> | Lazy<unknown>,\n options?: Options | string,\n ) {\n return function <This>(_value: undefined, context: ClassFieldDecoratorContext<This>): void {\n if (context.kind !== \"field\") {\n throw new Error(\n `@${capitalize(type)} can only be applied to class fields — got \"${context.kind}\".`,\n );\n }\n\n const relationName = String(context.name);\n const resolvedOptions = resolveOptions(options);\n const definition = buildRelationDefinition(type, modelRelation, resolvedOptions);\n\n if (context.metadata) {\n stashRelationInMetadata(context.metadata, relationName, definition);\n }\n };\n };\n}\n\n/**\n * Normalise the decorator's second argument.\n *\n * Accepts three shapes:\n * - Omitted (`undefined`): all defaults come from the runtime convention\n * helpers (`inferBelongsToForeignKey`, `inferHasForeignKey`, …) per\n * relation type. We must NOT pre-fill `foreignKey` here — the right\n * convention depends on the relation type AND the *owner* model name,\n * which the decorator doesn't know.\n * - String: shorthand for `{ foreignKey: <string> }`, matching the legacy\n * `belongsTo(\"Foo\", \"fk_col\")` helper.\n * - Object: passed through as-is.\n */\nfunction resolveOptions(\n options: AnyRelationOptions | string | undefined,\n): AnyRelationOptions | undefined {\n if (typeof options === \"string\") {\n return { foreignKey: options } as AnyRelationOptions;\n }\n\n return options;\n}\n\n// ============================================================================\n// PUBLIC — RELATION DECORATORS\n// ============================================================================\n\n/**\n * Declares a `belongsTo` relation on a model field.\n *\n * The foreign key lives on **this** model and points at the related\n * model's primary key. Defaults: FK column inferred as `{relationName}_id`\n * (snake-cased) — e.g. `organization_id` for `organization?: Organization`.\n *\n * @param model - The related model, in any of three forms:\n * - `\"User\"` — registered name (requires `@RegisterModel()` on target).\n * - `User` — direct class reference (cleanest for non-cycle relations).\n * - `lazy(() => User)` — typed but cycle-safe (use when the two model\n * files import each other).\n * @param options - Inline overrides for FK / owner key / column select\n *\n * @example\n * ```ts\n * import { lazy } from \"@mongez/reinforcements\";\n *\n * class User extends Model {\n * @BelongsTo(Organization) public organization?: Organization;\n * @BelongsTo(\"User\", { foreignKey: \"manager_id\" }) public manager?: User;\n * @BelongsTo(lazy(() => Team)) public team?: Team; // cycle case\n * }\n * ```\n */\nexport const BelongsTo = makeRelationDecorator<BelongsToOptions>(\"belongsTo\");\n\n/**\n * Declares a `hasOne` relation on a model field.\n *\n * The foreign key lives on the **related** model and points back at this\n * model's primary key. Defaults: FK column inferred as\n * `{thisModelSnakeName}_id` (e.g. `user_id` on the `Profile` table).\n *\n * @example\n * ```ts\n * class User extends Model {\n * @HasOne(\"Profile\") profile?: Profile;\n * @HasOne(\"UserSettings\", { foreignKey: \"owner_id\" }) settings?: UserSettings;\n * }\n * ```\n */\nexport const HasOne = makeRelationDecorator<HasOneOptions>(\"hasOne\");\n\n/**\n * Declares a `hasMany` relation on a model field.\n *\n * Same shape as `@HasOne` but loads an array. The foreign key lives on\n * the related model. Defaults: FK column inferred as\n * `{thisModelSnakeName}_id`.\n *\n * @example\n * ```ts\n * class User extends Model {\n * @HasMany(\"Post\") posts?: Post[];\n * @HasMany(\"Comment\", { foreignKey: \"author_id\" }) comments?: Comment[];\n * }\n * ```\n */\nexport const HasMany = makeRelationDecorator<HasManyOptions>(\"hasMany\");\n\n/**\n * Declares a `belongsToMany` relation on a model field.\n *\n * Defaults: pivot table inferred as the alphabetical snake-case join of\n * the two model names (`Post` + `Tag` → `post_tag`); pivot columns\n * inferred as `{modelSnakeName}_id` on each side.\n *\n * @example\n * ```ts\n * class Post extends Model {\n * @BelongsToMany(\"Tag\") tags?: Tag[];\n * @BelongsToMany(\"User\", { pivot: \"post_collaborators\" }) collaborators?: User[];\n * }\n * ```\n */\nexport const BelongsToMany = makeRelationDecorator<BelongsToManyOptions>(\"belongsToMany\");\n","import { isLazy, type Lazy } from \"@mongez/reinforcements\";\nimport type { RelationDefinition } from \"../relations/types\";\nimport type { ChildModel, Model } from \"./model\";\nimport { RELATION_METADATA_KEY } from \"./relation-decorators\";\n\n/**\n * Any way a relation target can be expressed: a string name registered\n * via `@RegisterModel()`, a direct class reference, or a `lazy(() => X)`\n * deferred class reference (for cycle-prone pairs).\n *\n * The lazy variant is typed as `Lazy<unknown>` (not `Lazy<ChildModel<Model>>`)\n * because `RelationDefinition.model` storage uses the same broader shape —\n * keeping the parameter type aligned avoids forcing every call site to\n * narrow before invoking the resolver. The helpers cast the resolved\n * class to `ChildModel<Model>` internally; the user's `lazy(() => X)`\n * call already guarantees the shape at the source.\n */\nexport type ModelRef = ChildModel<Model> | string | Lazy<unknown>;\n\n/**\n * Options for the RegisterModel decorator\n */\nexport type RegisterModelOptions = {\n /**\n * Custom name for the model in the global registry.\n * If not provided, uses the class name.\n *\n * @example\n * ```typescript\n * @RegisterModel({ name: \"CustomUser\" })\n * export class User extends Model {}\n * ```\n */\n name?: string;\n};\n\n/**\n * Global model registry that maps model class names to their constructors.\n * This allows for string-based model references to avoid circular dependencies.\n */\nconst modelsRegistry = new Map<string, ChildModel<Model>>();\n\n/**\n * Class decorator that registers a model in the global registry.\n *\n * This is an opt-in mechanism that allows models to be referenced by string name\n * instead of direct class imports, helping avoid circular dependencies.\n *\n * Uses the **TC39 Stage 3 decorator** signature (standard since TypeScript 5.0).\n * Requires `experimentalDecorators: false` (or unset) in `tsconfig.json`.\n *\n * @param options - Optional configuration for registration\n *\n * @example\n * ```typescript\n * // Auto-capture class name\n * @RegisterModel()\n * export class User extends Model {\n * static table = \"users\";\n * }\n *\n * // Custom name\n * @RegisterModel({ name: \"UserModel\" })\n * export class User extends Model {\n * static table = \"users\";\n * }\n *\n * // Later, retrieve by name:\n * const UserModel = getModelFromRegistry(\"User\");\n * ```\n */\nexport function RegisterModel(options?: RegisterModelOptions) {\n return function <T extends ChildModel<Model>>(value: T, context: ClassDecoratorContext<T>): T {\n if (context.kind !== \"class\") {\n throw new Error(`@RegisterModel can only be applied to classes — got \"${context.kind}\".`);\n }\n\n const modelName = options?.name || (context.name ?? value.name);\n\n if (!modelName) {\n throw new Error(\n \"@RegisterModel decorator: Unable to determine model name. \" +\n \"Please provide a name in options or ensure your class has a name.\",\n );\n }\n\n if (modelsRegistry.has(modelName)) {\n console.warn(\n `⚠️ Model \"${modelName}\" is already registered. ` +\n `This will overwrite the previous registration.`,\n );\n }\n\n // Hoist relation definitions stashed by `@BelongsTo` / `@HasMany` /\n // etc. on this class's decorator-metadata bag onto the class's static\n // `relations` map. Field-decorator initializers are instance-level in\n // TC39 stage 3 — they never fire for class-level operations like\n // `Model.withCount(\"rel\")`. Reading via shared `context.metadata` is\n // the right hand-off point because all field decorators have already\n // run by the time the class decorator executes.\n const decoratorRelations = context.metadata?.[RELATION_METADATA_KEY] as\n | Record<string, RelationDefinition>\n | undefined;\n\n if (decoratorRelations && Object.keys(decoratorRelations).length > 0) {\n const ownRelations = Object.prototype.hasOwnProperty.call(value, \"relations\")\n ? (value as unknown as { relations: Record<string, RelationDefinition> }).relations\n : { ...((value as unknown as { relations?: Record<string, RelationDefinition> }).relations ?? {}) };\n\n (value as unknown as { relations: Record<string, RelationDefinition> }).relations = {\n ...ownRelations,\n ...decoratorRelations,\n };\n }\n\n modelsRegistry.set(modelName, value);\n\n return value;\n };\n}\n\nexport function registerModelInRegistry(name: string, model: ChildModel<Model>) {\n modelsRegistry.set(name, model);\n}\n\n/**\n * Get a model class by its name from the global registry.\n *\n * @param name - The model class name\n * @returns The model class or undefined if not found\n *\n * @example\n * ```typescript\n * const UserModel = getModelFromRegistry(\"User\");\n * if (UserModel) {\n * const user = await UserModel.find(1);\n * }\n * ```\n */\nexport function getModelFromRegistry(name: string) {\n return modelsRegistry.get(name);\n}\n\n/**\n * Get all registered models from the global registry.\n *\n * @returns A Map of all registered model classes by name\n *\n * @example\n * ```typescript\n * const allModels = getAllModelsFromRegistry();\n * for (const [name, ModelClass] of allModels) {\n * console.log(`Found model: ${name}`);\n * }\n * ```\n */\nexport function getAllModelsFromRegistry() {\n return new Map(modelsRegistry);\n}\n\n/**\n * Clean up all models from register\n */\nexport function cleanupModelsRegistery() {\n modelsRegistry.clear();\n}\n\nexport function removeModelFromRegistery(name: string) {\n modelsRegistry.delete(name);\n}\n\nexport function resolveModelClass(model: ModelRef): ChildModel<Model> {\n if (typeof model === \"string\") return getModelFromRegistry(model)!;\n if (isLazy(model)) return model.resolve() as ChildModel<Model>;\n\n return model;\n}\n\n/**\n * Like `resolveModelClass`, but returns `undefined` instead of asserting\n * a non-null result when a string ref isn't in the registry. Use this\n * at call sites that already handle the missing-model case explicitly\n * (e.g. join builders that throw their own contextual error).\n */\nexport function tryResolveModelClass(\n model: ModelRef | undefined,\n): ChildModel<Model> | undefined {\n if (model === undefined) return undefined;\n if (typeof model === \"string\") return getModelFromRegistry(model);\n if (isLazy(model)) return model.resolve() as ChildModel<Model>;\n\n return model;\n}\n\n/**\n * Read the model's registered name from any `ModelRef`. Used by\n * convention helpers (`inferPivotTable`, `inferPivotKey`) that derive\n * table / column names from the related model's class name.\n *\n * For string refs the value passes through. For class and lazy refs\n * the class's `.name` is returned — same string the registry would\n * key the class under, so conventions stay consistent across ref shapes.\n */\nexport function resolveModelName(model: ModelRef): string {\n if (typeof model === \"string\") return model;\n if (isLazy(model)) return (model.resolve() as ChildModel<Model>).name;\n\n return model.name;\n}\n\n/**\n * Walk every registered model and verify that every relation declared on it\n * points at another registered model. Throws fast at boot with a clear error\n * naming the unresolved target — much better signal than the runtime\n * \"Model not found\" thrown deep inside a query.\n *\n * Call this once during app bootstrap, after every `@RegisterModel`-decorated\n * model module has been imported.\n *\n * @returns The number of relations verified (success case)\n * @throws Error listing every unresolved relation target if any are missing\n *\n * @example\n * ```typescript\n * // Inside your app bootstrap, after model imports:\n * import { verifyRegisteredRelations } from \"@warlock.js/cascade\";\n * verifyRegisteredRelations();\n * ```\n */\nexport function verifyRegisteredRelations(): number {\n type RelationDef = { type: string; model: string };\n const failures: Array<{ caller: string; relation: string; target: string }> = [];\n\n let verifiedCount = 0;\n\n for (const [callerName, ModelClass] of modelsRegistry) {\n const relations = (ModelClass as { relations?: Record<string, RelationDef> }).relations;\n\n if (!relations) {\n continue;\n }\n\n for (const [relationName, definition] of Object.entries(relations)) {\n verifiedCount++;\n const targetName = definition.model;\n\n if (typeof targetName !== \"string\") {\n // Direct class reference or `lazy(() => X)` — class binding is\n // captured by the decorator at definition time; can't drift.\n continue;\n }\n\n if (!modelsRegistry.has(targetName)) {\n failures.push({ caller: callerName, relation: relationName, target: targetName });\n }\n }\n }\n\n if (failures.length > 0) {\n const list = failures\n .map((f) => ` - ${f.caller}.${f.relation} → \"${f.target}\" is not registered`)\n .join(\"\\n\");\n throw new Error(\n `verifyRegisteredRelations: ${failures.length} unresolved relation target(s):\\n${list}\\n` +\n `Each target must be decorated with @RegisterModel() and imported before bootstrap.`,\n );\n }\n\n return verifiedCount;\n}\n","/**\n * @fileoverview Foreign-key naming conventions for relation defaults.\n *\n * Single source of truth for default FK / pivot column names when a relation\n * definition omits an explicit `foreignKey`. Centralised so the three\n * relation-resolution code paths (RelationLoader, applyJoinRelations,\n * applyCountRelations) stay consistent — historically each path defaulted\n * differently, producing silent wrong-column bugs.\n *\n * Convention: snake_case + `_id` suffix. Matches PostgreSQL idiom and the\n * existing column convention used throughout `src/app/**` (`organization_id`,\n * `chat_id`, `image_id`, …).\n *\n * @module @warlock.js/cascade/relations/key-conventions\n */\n\nimport { toSnakeCase } from \"@mongez/reinforcements\";\nimport type { RelationDefaults } from \"../types\";\n\nconst DEFAULT_FK_SUFFIX = \"_id\";\nconst DEFAULT_PIVOT_ORDER: NonNullable<RelationDefaults[\"pivotTableNamingOrder\"]> = \"alphabetical\";\n\n// ============================================================================\n// PRIVATE — STRING NORMALISATION\n// ============================================================================\n\n/**\n * Convert a model class name or relation name to snake_case.\n *\n * Wraps `toSnakeCase` from `@mongez/reinforcements` because the lib's regex\n * loses the leading letters in runs of consecutive uppercase\n * (`toSnakeCase(\"AIModel\")` → `\"imodel\"`). The two pre-normalisation passes\n * here insert separators at run boundaries before delegating, so acronym-\n * prefixed model names (`AIModel`, `AIUsage`, `AITrip`, `HTTPSConnection`)\n * snake correctly.\n *\n * Once an upstream fix lands in `@mongez/reinforcements`, this wrapper can\n * be deleted and `toSnakeCase` called directly at the consumer sites.\n *\n * @example\n * snake(\"User\") // \"user\"\n * snake(\"BlogPost\") // \"blog_post\"\n * snake(\"AIModel\") // \"ai_model\"\n * snake(\"HTTPSConnection\") // \"https_connection\"\n * snake(\"organization\") // \"organization\" (idempotent)\n * snake(\"organizationId\") // \"organization_id\"\n */\nfunction snake(input: string): string {\n const normalised = input\n // Split a run of caps from a final cap+lower: \"AIModel\" → \"AI_Model\"\n .replace(/([A-Z]+)([A-Z][a-z])/g, \"$1_$2\")\n // Split a lower/digit boundary from the next cap: \"BlogPost\" → \"Blog_Post\"\n .replace(/([a-z\\d])([A-Z])/g, \"$1_$2\");\n\n return toSnakeCase(normalised).toLowerCase();\n}\n\n// ============================================================================\n// PUBLIC — DEFAULT FOREIGN-KEY INFERENCE\n// ============================================================================\n\n/**\n * Default foreign-key column name for a `belongsTo` relation.\n *\n * The FK lives on THIS model (the owner of the `belongsTo` def) and is\n * named after the *role* the relation plays — not the target model class.\n * Matches Laravel/Rails convention: `Post.author_id` (not `Post.user_id`)\n * because the relation is named \"author\".\n *\n * @param relationName - The relation key as declared in `static relations`\n *\n * @example\n * inferBelongsToForeignKey(\"author\") // \"author_id\"\n * inferBelongsToForeignKey(\"organization\") // \"organization_id\"\n * inferBelongsToForeignKey(\"parentItem\") // \"parent_item_id\"\n */\nexport function inferBelongsToForeignKey(\n relationName: string,\n options?: RelationDefaults,\n): string {\n return `${snake(relationName)}${options?.foreignKeySuffix ?? DEFAULT_FK_SUFFIX}`;\n}\n\n/**\n * Default foreign-key column name for a `hasMany` or `hasOne` relation.\n *\n * The FK lives on the RELATED model's table and points back to THIS model,\n * so the column is named after the self model class.\n *\n * @param selfModelName - The owning model's class name (e.g. `User`)\n *\n * @example\n * inferHasForeignKey(\"User\") // \"user_id\" — used as posts.user_id\n * inferHasForeignKey(\"AIModel\") // \"ai_model_id\" — used as ai_trips.ai_model_id\n */\nexport function inferHasForeignKey(\n selfModelName: string,\n options?: RelationDefaults,\n): string {\n return `${snake(selfModelName)}${options?.foreignKeySuffix ?? DEFAULT_FK_SUFFIX}`;\n}\n\n/**\n * Default column name in a many-to-many pivot table for either side\n * (the side referenced determines the model name passed in).\n *\n * - For the self-side pivot column: pass the self model name.\n * - For the related-side pivot column: pass the related model name.\n *\n * @param modelName - The model class name being referenced from the pivot\n *\n * @example\n * // For `Post.belongsToMany(\"Tag\", { pivot: \"post_tags\" })`:\n * inferPivotKey(\"Post\") // \"post_id\" — pivot column post_tags.post_id\n * inferPivotKey(\"Tag\") // \"tag_id\" — pivot column post_tags.tag_id\n */\nexport function inferPivotKey(modelName: string, options?: RelationDefaults): string {\n return `${snake(modelName)}${options?.foreignKeySuffix ?? DEFAULT_FK_SUFFIX}`;\n}\n\n/**\n * Default pivot-table name for a many-to-many relation when none is\n * explicitly configured. Joins the two model snake-names alphabetically\n * with an underscore — matches Laravel/Rails convention.\n *\n * Alphabetical ordering means the same pivot name resolves regardless of\n * which side of the relation declares the `@BelongsToMany`, so\n * `Post.belongsToMany(\"Tag\")` and `Tag.belongsToMany(\"Post\")` both pick\n * the table `post_tag`.\n *\n * @example\n * inferPivotTable(\"Post\", \"Tag\") // \"post_tag\"\n * inferPivotTable(\"User\", \"Group\") // \"group_user\"\n * inferPivotTable(\"AIModel\", \"Tenant\") // \"ai_model_tenant\"\n */\nexport function inferPivotTable(\n selfModelName: string,\n relatedModelName: string,\n options?: RelationDefaults,\n): string {\n const selfSnake = snake(selfModelName);\n const relatedSnake = snake(relatedModelName);\n const order = options?.pivotTableNamingOrder ?? DEFAULT_PIVOT_ORDER;\n\n if (order === \"owner_first\") {\n return `${selfSnake}_${relatedSnake}`;\n }\n\n return [selfSnake, relatedSnake].sort().join(\"_\");\n}\n","/**\n * @fileoverview Core relation loading logic for the Cascade ORM.\n *\n * The RelationLoader is responsible for efficiently loading related models\n * while preventing N+1 query problems through batch loading strategies.\n *\n * @module @warlock.js/cascade/relations/relation-loader\n */\n\nimport { isLazy, type Lazy } from \"@mongez/reinforcements\";\nimport type { ChildModel, Model } from \"../model/model\";\nimport { getModelFromRegistry, resolveModelName } from \"../model/register-model\";\nimport {\n inferBelongsToForeignKey,\n inferHasForeignKey,\n inferPivotKey,\n inferPivotTable,\n} from \"./key-conventions\";\nimport type {\n LoadedRelationResult,\n RelationConstraintCallback,\n RelationConstraints,\n RelationDefinition,\n} from \"./types\";\n\n// ============================================================================\n// SHARED HELPER — SINGLE SOURCE OF TRUTH FOR LOADED RELATIONS\n// ============================================================================\n\n/**\n * Attach a loaded relation onto a model instance, keeping the\n * `loadedRelations` Map and the direct property access in sync.\n *\n * The property is installed as a `defineProperty` getter/setter façade over\n * the Map — `model.posts` reads from `loadedRelations.get(\"posts\")`, and\n * assigning `model.posts = newPosts` writes back to the Map. Eliminates the\n * historical drift between the two storage slots: any mutation visible via\n * one path is visible via the other.\n *\n * Used by both `RelationLoader` (the `with()` path) and the Postgres\n * driver's `attachJoinedRelations` (the `joinWith()` path).\n *\n * @example\n * attachLoadedRelation(user, \"posts\", postsArray);\n * user.posts === user.loadedRelations.get(\"posts\"); // always true\n */\nexport function attachLoadedRelation(\n model: object,\n name: string,\n value: LoadedRelationResult,\n): void {\n const modelWithRelations = model as {\n loadedRelations?: Map<string, LoadedRelationResult>;\n };\n\n if (!modelWithRelations.loadedRelations) {\n modelWithRelations.loadedRelations = new Map();\n }\n\n const relations = modelWithRelations.loadedRelations;\n relations.set(name, value);\n\n // Install a getter/setter on the instance so direct property access reads\n // from (and writes to) the Map. `configurable: true` lets a later reload\n // re-define the property; `enumerable: true` so JSON.stringify and\n // Object.keys see the relation.\n Object.defineProperty(model, name, {\n configurable: true,\n enumerable: true,\n get(): LoadedRelationResult | undefined {\n return relations.get(name);\n },\n set(next: LoadedRelationResult): void {\n relations.set(name, next);\n },\n });\n}\n\n// ============================================================================\n// RELATION LOADER CLASS\n// ============================================================================\n\n/**\n * Efficiently loads relationships for one or more model instances.\n *\n * The RelationLoader handles:\n * - Batch loading to prevent N+1 query problems\n * - Nested relation loading via dot notation\n * - Constrained loading with query callbacks\n * - All relation types (hasOne, hasMany, belongsTo, belongsToMany)\n *\n * @template TModel - The type of model being loaded\n *\n * @example\n * ```typescript\n * const users = await User.query().get();\n * const loader = new RelationLoader(users, User);\n *\n * // Load single relation\n * await loader.load(\"posts\");\n *\n * // Load multiple relations\n * await loader.load([\"posts\", \"organization\"]);\n *\n * // Load nested relations\n * await loader.load(\"posts.comments.author\");\n *\n * // Load with constraints\n * await loader.load(\"posts\", {\n * posts: (query) => query.where(\"isPublished\", true),\n * });\n * ```\n */\nexport class RelationLoader<TModel extends Model = Model> {\n // ==========================================================================\n // PRIVATE PROPERTIES\n // ==========================================================================\n\n /**\n * The model instances to load relations for.\n */\n private readonly models: TModel[];\n\n /**\n * The model class constructor.\n */\n private readonly modelClass: ChildModel<TModel>;\n\n // ==========================================================================\n // CONSTRUCTOR\n // ==========================================================================\n\n /**\n * Creates a new RelationLoader instance.\n *\n * @param models - The model instances to load relations for\n * @param modelClass - The model class constructor\n */\n public constructor(models: TModel[], modelClass: ChildModel<TModel>) {\n this.models = models;\n this.modelClass = modelClass;\n }\n\n /**\n * Read the configured relation conventions from this model's data\n * source. Returns `undefined` when no overrides are set — the inference\n * helpers fall back to framework defaults in that case.\n */\n private get relationDefaults() {\n try {\n return this.modelClass.getDataSource()?.relationDefaults;\n } catch {\n return undefined;\n }\n }\n\n // ==========================================================================\n // PUBLIC METHODS\n // ==========================================================================\n\n /**\n * Loads one or more relations for all model instances.\n *\n * @param relations - A single relation name, array of names, or constraints object\n * @param constraints - Optional constraints to apply to the loading query\n *\n * @example\n * ```typescript\n * // Single relation\n * await loader.load(\"posts\");\n *\n * // Multiple relations\n * await loader.load([\"posts\", \"organization\"]);\n *\n * // With constraints\n * await loader.load(\"posts\", {\n * posts: (query) => query.where(\"status\", \"active\"),\n * });\n * ```\n */\n public async load(\n relations: string | string[],\n constraints?: RelationConstraints,\n ): Promise<void> {\n // If no models, nothing to load\n if (this.models.length === 0) {\n return;\n }\n\n // Normalize to array\n const relationNames = Array.isArray(relations) ? relations : [relations];\n\n // Load each relation\n for (const relationName of relationNames) {\n const constraint = constraints?.[relationName];\n const callbackConstraint = typeof constraint === \"function\" ? constraint : undefined;\n\n await this.loadRelation(relationName, callbackConstraint);\n }\n }\n\n // ==========================================================================\n // PRIVATE METHODS - RELATION LOADING\n // ==========================================================================\n\n /**\n * Loads a single relation, handling nested relations via dot notation.\n *\n * @param name - The relation name, possibly with dot notation for nesting\n * @param constraint - Optional constraint callback\n */\n private async loadRelation(name: string, constraint?: RelationConstraintCallback): Promise<void> {\n const path = this.parseNestedRelation(name);\n const rootRelation = path[0];\n\n // Get the relation definition from the model class\n const definition = this.getRelationDefinition(rootRelation);\n\n if (!definition) {\n throw new Error(\n `Relation \"${rootRelation}\" is not defined on model \"${this.modelClass.name}\". ` +\n `Make sure to define it in the static 'relations' property.`,\n );\n }\n\n // Load based on relation type\n switch (definition.type) {\n case \"hasMany\":\n await this.loadHasMany(rootRelation, definition, constraint);\n break;\n\n case \"hasOne\":\n await this.loadHasOne(rootRelation, definition, constraint);\n break;\n\n case \"belongsTo\":\n await this.loadBelongsTo(rootRelation, definition, constraint);\n break;\n\n case \"belongsToMany\":\n await this.loadBelongsToMany(rootRelation, definition, constraint);\n break;\n }\n\n // If there are nested relations, load them recursively\n if (path.length > 1) {\n await this.loadNestedRelations(rootRelation, path.slice(1), constraint);\n }\n }\n\n /**\n * Loads a hasMany relation for all models.\n *\n * @param name - The relation name\n * @param definition - The relation definition\n * @param constraint - Optional constraint callback\n */\n private async loadHasMany(\n name: string,\n definition: RelationDefinition,\n constraint?: RelationConstraintCallback,\n ): Promise<void> {\n const RelatedModel = this.resolveModelClass(definition.model);\n const localKey = definition.localKey ?? this.modelClass.primaryKey ?? \"id\";\n const foreignKey = definition.foreignKey ?? inferHasForeignKey(this.modelClass.name, this.relationDefaults);\n\n // Collect all local key values\n const localKeyValues = this.collectKeyValues(localKey);\n\n if (localKeyValues.length === 0) {\n // No values to query, set empty arrays\n this.setRelationOnModels(name, () => []);\n return;\n }\n\n // Build and execute query\n const query = RelatedModel.query().whereIn(foreignKey, localKeyValues);\n\n if (constraint) {\n constraint(query);\n }\n\n const relatedRecords = await query.get();\n\n // Group by foreign key and assign to models\n const recordsByForeignKey = this.groupBy(relatedRecords as Model[], foreignKey);\n\n this.setRelationOnModels(name, (model) => {\n const keyValue = model.get(localKey);\n return recordsByForeignKey.get(keyValue) ?? [];\n });\n }\n\n /**\n * Loads a hasOne relation for all models.\n *\n * @param name - The relation name\n * @param definition - The relation definition\n * @param constraint - Optional constraint callback\n */\n private async loadHasOne(\n name: string,\n definition: RelationDefinition,\n constraint?: RelationConstraintCallback,\n ): Promise<void> {\n const RelatedModel = this.resolveModelClass(definition.model);\n const localKey = definition.localKey ?? this.modelClass.primaryKey ?? \"id\";\n const foreignKey = definition.foreignKey ?? inferHasForeignKey(this.modelClass.name, this.relationDefaults);\n\n // Collect all local key values\n const localKeyValues = this.collectKeyValues(localKey);\n\n if (localKeyValues.length === 0) {\n this.setRelationOnModels(name, () => null);\n return;\n }\n\n // Build and execute query\n const query = RelatedModel.query().whereIn(foreignKey, localKeyValues);\n\n if (constraint) {\n constraint(query);\n }\n\n const relatedRecords = await query.get();\n\n // Index by foreign key\n const recordsByForeignKey = new Map<unknown, Model>();\n for (const record of relatedRecords as Model[]) {\n const fkValue = record.get(foreignKey);\n // For hasOne, take the first match only\n if (!recordsByForeignKey.has(fkValue)) {\n recordsByForeignKey.set(fkValue, record);\n }\n }\n\n this.setRelationOnModels(name, (model) => {\n const keyValue = model.get(localKey);\n return recordsByForeignKey.get(keyValue) ?? null;\n });\n }\n\n /**\n * Loads a belongsTo relation for all models.\n *\n * @param name - The relation name\n * @param definition - The relation definition\n * @param constraint - Optional constraint callback\n */\n private async loadBelongsTo(\n name: string,\n definition: RelationDefinition,\n constraint?: RelationConstraintCallback,\n ): Promise<void> {\n const RelatedModel = this.resolveModelClass(definition.model);\n const foreignKey = definition.foreignKey ?? inferBelongsToForeignKey(name, this.relationDefaults);\n const ownerKey = definition.localKey ?? RelatedModel.primaryKey ?? \"id\";\n\n // Collect all foreign key values from the models\n const foreignKeyValues = this.collectKeyValues(foreignKey);\n\n if (foreignKeyValues.length === 0) {\n this.setRelationOnModels(name, () => null);\n return;\n }\n\n // Build and execute query\n const query = RelatedModel.query().whereIn(ownerKey, foreignKeyValues);\n\n if (constraint) {\n constraint(query);\n }\n\n const relatedRecords = await query.get();\n\n // Index by owner key\n const recordsByOwnerKey = new Map<unknown, Model>();\n for (const record of relatedRecords as Model[]) {\n const keyValue = record.get(ownerKey);\n recordsByOwnerKey.set(keyValue, record);\n }\n\n this.setRelationOnModels(name, (model) => {\n const fkValue = model.get(foreignKey);\n return recordsByOwnerKey.get(fkValue) ?? null;\n });\n }\n\n /**\n * Loads a belongsToMany relation for all models.\n *\n * @param name - The relation name\n * @param definition - The relation definition\n * @param constraint - Optional constraint callback\n */\n private async loadBelongsToMany(\n name: string,\n definition: RelationDefinition,\n constraint?: RelationConstraintCallback,\n ): Promise<void> {\n const RelatedModel = this.resolveModelClass(definition.model);\n const relatedModelName = resolveModelName(definition.model);\n const pivotTable =\n definition.pivot ??\n inferPivotTable(this.modelClass.name, relatedModelName, this.relationDefaults);\n const localKey = definition.pivotLocalKey ?? this.modelClass.primaryKey ?? \"id\";\n const pivotLocalKey =\n definition.localKey ?? inferPivotKey(this.modelClass.name, this.relationDefaults);\n const pivotForeignKey =\n definition.foreignKey ?? inferPivotKey(relatedModelName, this.relationDefaults);\n const relatedKey = definition.pivotForeignKey ?? RelatedModel.primaryKey ?? \"id\";\n\n // Collect all local key values\n const localKeyValues = this.collectKeyValues(localKey);\n\n if (localKeyValues.length === 0) {\n this.setRelationOnModels(name, () => []);\n return;\n }\n\n // Step 1: Query the pivot table to get the relationships\n const dataSource = this.modelClass.getDataSource();\n const pivotQuery = dataSource.driver\n .queryBuilder(pivotTable)\n .whereIn(pivotLocalKey, localKeyValues);\n\n const pivotRecords = (await pivotQuery.get()) as Record<string, unknown>[];\n\n if (pivotRecords.length === 0) {\n this.setRelationOnModels(name, () => []);\n return;\n }\n\n // Step 2: Collect related model IDs from pivot\n const relatedIds = [...new Set(pivotRecords.map((p) => p[pivotForeignKey]))];\n\n // Step 3: Query the related model\n const relatedQuery = RelatedModel.query().whereIn(relatedKey, relatedIds);\n\n if (constraint) {\n constraint(relatedQuery);\n }\n\n const relatedRecords = await relatedQuery.get();\n\n // Step 4: Index related records by their key\n const relatedById = new Map<unknown, Model>();\n for (const record of relatedRecords as Model[]) {\n relatedById.set(record.get(relatedKey), record);\n }\n\n // Step 5: Build the relationship map from pivot data\n const relationshipMap = new Map<unknown, Model[]>();\n\n for (const pivot of pivotRecords) {\n const localValue = pivot[pivotLocalKey];\n const foreignValue = pivot[pivotForeignKey];\n const relatedRecord = relatedById.get(foreignValue);\n\n if (relatedRecord) {\n if (!relationshipMap.has(localValue)) {\n relationshipMap.set(localValue, []);\n }\n relationshipMap.get(localValue)!.push(relatedRecord);\n }\n }\n\n this.setRelationOnModels(name, (model) => {\n const keyValue = model.get(localKey);\n return relationshipMap.get(keyValue) ?? [];\n });\n }\n\n // ==========================================================================\n // PRIVATE METHODS - NESTED RELATIONS\n // ==========================================================================\n\n /**\n * Loads nested relations recursively.\n *\n * @param parentRelation - The name of the parent relation\n * @param remainingPath - The remaining path segments to load\n * @param constraint - Optional constraint callback\n */\n private async loadNestedRelations(\n parentRelation: string,\n remainingPath: string[],\n constraint?: RelationConstraintCallback,\n ): Promise<void> {\n // Collect all loaded related models from the parent relation\n const relatedModels: Model[] = [];\n\n for (const model of this.models) {\n const loaded = this.getLoadedRelation(model, parentRelation);\n\n if (Array.isArray(loaded)) {\n relatedModels.push(...loaded);\n } else if (loaded) {\n relatedModels.push(loaded);\n }\n }\n\n if (relatedModels.length === 0) {\n return;\n }\n\n // Get the related model class\n const parentDefinition = this.getRelationDefinition(parentRelation);\n if (!parentDefinition) return;\n\n const RelatedModelClass = this.resolveModelClass(parentDefinition.model);\n\n // Create a new loader for the nested relation\n const nestedLoader = new RelationLoader(relatedModels, RelatedModelClass as ChildModel<Model>);\n\n // Load the next level\n const nextRelation = remainingPath.join(\".\");\n await nestedLoader.load(nextRelation, constraint ? { [nextRelation]: constraint } : undefined);\n }\n\n // ==========================================================================\n // PRIVATE METHODS - UTILITIES\n // ==========================================================================\n\n /**\n * Parses a dot-notation relation path into segments.\n *\n * @param path - The relation path (e.g., \"posts.comments.author\")\n * @returns An array of relation names\n */\n private parseNestedRelation(path: string): string[] {\n return path.split(\".\");\n }\n\n /**\n * Resolves a model class from the registry by name.\n *\n * @param name - The registered model name\n * @returns The model class constructor\n * @throws Error if the model is not found in the registry\n */\n private resolveModelClass(\n model: string | ChildModel<Model> | Lazy<unknown>,\n ): ChildModel<Model> {\n if (typeof model === \"function\") return model;\n if (isLazy(model)) return model.resolve() as ChildModel<Model>;\n\n const ModelClass = getModelFromRegistry(model);\n\n if (!ModelClass) {\n const callerName = this.modelClass.name || \"unknown\";\n throw new Error(\n `Cannot resolve relation target — model \"${model}\" is not registered.\\n` +\n ` Caller: ${callerName} (relation target reference)\\n` +\n ` Common causes:\\n` +\n ` - The target model is missing the @RegisterModel() decorator\\n` +\n ` - The target model's module is not imported anywhere at startup\\n` +\n ` - Circular import between the caller and target — one of them sees\\n` +\n ` the other as undefined during module load\\n` +\n ` Fix: add an explicit \\`import \"<path-to-${model}-model>\";\\` to your app's\\n` +\n ` entry point so the decorator runs before any query consults this relation.\\n` +\n ` Alternative: declare the relation with \\`lazy(() => ${model})\\` instead of a string\\n` +\n ` to bind directly to the class (no registry lookup needed).`,\n );\n }\n\n return ModelClass;\n }\n\n /**\n * Gets the relation definition from the model class.\n *\n * @param name - The relation name\n * @returns The relation definition or undefined\n */\n private getRelationDefinition(name: string): RelationDefinition | undefined {\n const relations = (\n this.modelClass as unknown as { relations?: Record<string, RelationDefinition> }\n ).relations;\n return relations?.[name];\n }\n\n /**\n * Collects unique key values from all models.\n *\n * @param key - The key to collect values for\n * @returns An array of unique key values\n */\n private collectKeyValues(key: string): unknown[] {\n const values = new Set<unknown>();\n\n for (const model of this.models) {\n const value = model.get(key);\n if (value !== undefined && value !== null) {\n values.add(value);\n }\n }\n\n return [...values];\n }\n\n /**\n * Groups records by a key value.\n *\n * @param records - The records to group\n * @param key - The key to group by\n * @returns A map of key values to records\n */\n private groupBy(records: Model[], key: string): Map<unknown, Model[]> {\n const groups = new Map<unknown, Model[]>();\n\n for (const record of records) {\n const keyValue = record.get(key);\n\n if (!groups.has(keyValue)) {\n groups.set(keyValue, []);\n }\n\n groups.get(keyValue)!.push(record);\n }\n\n return groups;\n }\n\n /**\n * Sets a relation value on all models using a getter function.\n *\n * @param name - The relation name\n * @param getter - Function that returns the relation value for each model\n */\n private setRelationOnModels(name: string, getter: (model: TModel) => LoadedRelationResult): void {\n for (const model of this.models) {\n const value = getter(model);\n this.setLoadedRelation(model, name, value);\n }\n }\n\n /**\n * Gets a loaded relation from a model instance.\n *\n * @param model - The model instance\n * @param name - The relation name\n * @returns The loaded relation value or undefined\n */\n private getLoadedRelation(model: TModel, name: string): LoadedRelationResult | undefined {\n const loadedRelations = (\n model as unknown as { loadedRelations?: Map<string, LoadedRelationResult> }\n ).loadedRelations;\n return loadedRelations?.get(name);\n }\n\n /**\n * Sets a loaded relation on a model instance.\n *\n * @param model - The model instance\n * @param name - The relation name\n * @param value - The relation value\n */\n private setLoadedRelation(model: TModel, name: string, value: LoadedRelationResult): void {\n attachLoadedRelation(model as object, name, value);\n }\n}\n","/**\n * Model sync event name helpers.\n *\n * Provides type-safe event names for model sync operations.\n * Avoids hardcoded string literals throughout the codebase.\n *\n * @module cascade-next/sync/model-events\n */\n\nimport type { ChildModel, Model } from \"../model/model\";\n\n/**\n * Event name prefix for all model sync events.\n */\nexport const MODEL_EVENT_PREFIX = \"model\";\n\n/**\n * Model sync event types.\n */\nexport const ModelSyncEventType = {\n UPDATED: \"updated\",\n DELETED: \"deleted\",\n} as const;\n\nexport type ModelSyncEventTypeName = (typeof ModelSyncEventType)[keyof typeof ModelSyncEventType];\n\n/**\n * Get the event name for a model update.\n *\n * @param modelClass - The model class\n * @returns Event name string (e.g., \"model.Category.updated\")\n *\n * @example\n * ```typescript\n * const eventName = getModelUpdatedEvent(Category);\n * // Returns: \"model.Category.updated\"\n * ```\n */\nexport function getModelUpdatedEvent(modelClass: ChildModel<Model>): string {\n return `${MODEL_EVENT_PREFIX}.${modelClass.name}.${ModelSyncEventType.UPDATED}`;\n}\n\n/**\n * Get the event name for a model deletion.\n *\n * @param modelClass - The model class\n * @returns Event name string (e.g., \"model.Category.deleted\")\n *\n * @example\n * ```typescript\n * const eventName = getModelDeletedEvent(Category);\n * // Returns: \"model.Category.deleted\"\n * ```\n */\nexport function getModelDeletedEvent(modelClass: ChildModel<Model>): string {\n return `${MODEL_EVENT_PREFIX}.${modelClass.name}.${ModelSyncEventType.DELETED}`;\n}\n\n/**\n * Get the event name for a model by name string.\n *\n * @param modelName - The model class name\n * @param eventType - The event type\n * @returns Event name string\n *\n * @example\n * ```typescript\n * const eventName = getModelEvent(\"Category\", \"updated\");\n * // Returns: \"model.Category.updated\"\n * ```\n */\nexport function getModelEvent(modelName: string, eventType: ModelSyncEventTypeName): string {\n return `${MODEL_EVENT_PREFIX}.${modelName}.${eventType}`;\n}\n","/**\n * Sync context management and validation.\n *\n * @module cascade-next/sync/sync-context\n */\n\nimport type { SyncContext, SyncInstruction } from \"./types\";\n\n/**\n * Default maximum sync depth.\n * Prevents infinite sync chains.\n */\nexport const DEFAULT_MAX_SYNC_DEPTH = 3;\n\n/**\n * Manages sync context and provides validation utilities.\n */\nexport class SyncContextManager {\n /**\n * Creates a new sync context from a sync instruction.\n *\n * @param instruction - The sync instruction to create context from\n * @param affectedCount - Number of documents affected\n * @returns A new sync context\n */\n public static createContext(\n instruction: SyncInstruction,\n affectedCount: number,\n ): SyncContext {\n return {\n sourceModel: instruction.sourceModel,\n sourceId: instruction.sourceId,\n currentDepth: instruction.depth,\n syncChain: [...instruction.chain],\n targetModel: instruction.targetModel,\n filter: { ...instruction.filter },\n update: { ...instruction.update },\n affectedCount,\n timestamp: new Date(),\n };\n }\n\n /**\n * Validates if a sync operation can proceed based on depth and cycle detection.\n *\n * @param depth - Current sync depth\n * @param chain - Current sync chain\n * @param targetModel - Target model name\n * @param maxDepth - Maximum allowed depth\n * @param preventCircular - Whether to prevent circular references\n * @returns Validation result with success flag and optional error message\n */\n public static validate(\n depth: number,\n chain: string[],\n targetModel: string,\n maxDepth: number,\n preventCircular: boolean,\n ): { valid: boolean; error?: string } {\n // Check depth limit\n if (depth > maxDepth) {\n return {\n valid: false,\n error: `Sync depth limit exceeded: ${depth} > ${maxDepth}. Chain: ${chain.join(\" → \")}`,\n };\n }\n\n // Check for circular references\n if (preventCircular && this.hasCycle(chain, targetModel)) {\n return {\n valid: false,\n error: `Circular sync detected: ${targetModel} already exists in chain [${chain.join(\" → \")}]`,\n };\n }\n\n return { valid: true };\n }\n\n /**\n * Checks if adding a target model would create a cycle in the sync chain.\n *\n * @param chain - Current sync chain\n * @param targetModel - Model to be added to the chain\n * @returns True if adding the model would create a cycle\n */\n public static hasCycle(chain: string[], targetModel: string): boolean {\n return chain.includes(targetModel);\n }\n\n /**\n * Creates a new sync chain by appending a model name.\n *\n * @param chain - Current sync chain\n * @param modelName - Model name to append\n * @returns New sync chain array\n */\n public static extendChain(chain: string[], modelName: string): string[] {\n return [...chain, modelName];\n }\n\n /**\n * Formats a sync chain for display.\n *\n * @param chain - Sync chain to format\n * @returns Formatted string (e.g., \"Category → Product → Module\")\n */\n public static formatChain(chain: string[]): string {\n return chain.join(\" → \");\n }\n\n /**\n * Checks if the current depth allows for further syncing.\n *\n * @param currentDepth - Current depth in the chain\n * @param maxDepth - Maximum allowed depth\n * @returns True if more syncing is allowed\n */\n public static canSyncDeeper(\n currentDepth: number,\n maxDepth: number,\n ): boolean {\n return currentDepth < maxDepth;\n }\n}\n\n","/**\n * Sync manager service for handling multi-level sync operations.\n *\n * @module cascade-next/sync/sync-manager\n */\n\nimport type { DriverContract } from \"../contracts/database-driver.contract\";\nimport { ChildModel, Model } from \"../model/model\";\nimport { DEFAULT_MAX_SYNC_DEPTH, SyncContextManager } from \"./sync-context\";\nimport type {\n CollectInstructionsPayload,\n SyncConfig,\n SyncEventPayload,\n SyncInstruction,\n SyncInstructionOptions,\n SyncResult,\n} from \"./types\";\n\n/**\n * Manages sync operations across models with multi-level support.\n */\nexport class SyncManager {\n private readonly sourceModel: ChildModel<Model>;\n private readonly driver: DriverContract;\n\n /**\n * Creates a new sync manager.\n *\n * @param sourceModel - The source model class\n * @param driver - The database driver\n */\n public constructor(sourceModel: ChildModel<Model>, driver: DriverContract) {\n this.sourceModel = sourceModel;\n this.driver = driver;\n }\n\n /**\n * Executes sync operations for a model update.\n *\n * @param sourceId - The source model ID\n * @param updatedData - The updated data to sync (Model instance or plain data)\n * @param changedFields - Fields that were changed (for filtering)\n * @returns Sync result with success status and details\n */\n public async syncUpdate(\n sourceId: string | number,\n updatedData: Record<string, unknown> | Model,\n changedFields: string[],\n ): Promise<SyncResult> {\n try {\n const syncConfigs = this.getSyncConfigs();\n\n if (syncConfigs.length === 0) {\n return this.createEmptyResult();\n }\n\n const options: SyncInstructionOptions = {\n currentDepth: 1,\n syncChain: [this.sourceModel.name],\n maxDepth: DEFAULT_MAX_SYNC_DEPTH,\n preventCircular: true,\n };\n\n const instructions = await this.collectInstructions({\n sourceId,\n updatedData,\n changedFields,\n syncConfigs,\n options,\n });\n\n return await this.executeInstructions(instructions);\n } catch (error) {\n // Catch-all error handler for unexpected failures\n console.error(`Sync update failed for ${this.sourceModel.name}#${sourceId}:`, error);\n\n return {\n success: false,\n attempted: 0,\n succeeded: 0,\n failed: 1,\n errors: [\n {\n instruction: {\n targetTable: \"\",\n targetModel: \"\",\n filter: {},\n update: {},\n depth: 0,\n chain: [this.sourceModel.name],\n sourceModel: this.sourceModel.name,\n sourceId,\n },\n error: error instanceof Error ? error : new Error(String(error)),\n },\n ],\n depthReached: 0,\n contexts: [],\n };\n }\n }\n\n /**\n * Executes sync operations for a model update with a specific config.\n * Used by ModelSyncOperation for event-based sync.\n *\n * @param sourceId - The source model ID\n * @param updatedData - The updated data to sync\n * @param changedFields - Fields that were changed\n * @param config - The sync configuration to use\n * @returns Sync result with success status and details\n */\n public async syncUpdateWithConfig(\n sourceId: string | number,\n updatedData: Record<string, unknown> | Model,\n changedFields: string[],\n config: SyncConfig,\n ): Promise<SyncResult> {\n try {\n const options: SyncInstructionOptions = {\n currentDepth: 1,\n syncChain: [this.sourceModel.name],\n maxDepth: config.maxSyncDepth,\n preventCircular: config.preventCircularSync,\n };\n\n const instructions = await this.collectInstructions({\n sourceId,\n updatedData,\n changedFields,\n syncConfigs: [config],\n options,\n });\n\n return await this.executeInstructions(instructions);\n } catch (error) {\n console.error(\n `Sync update with config failed for ${this.sourceModel.name}#${sourceId}:`,\n error,\n );\n\n return {\n success: false,\n attempted: 0,\n succeeded: 0,\n failed: 1,\n errors: [\n {\n instruction: {\n targetTable: \"\",\n targetModel: \"\",\n filter: {},\n update: {},\n depth: 0,\n chain: [this.sourceModel.name],\n sourceModel: this.sourceModel.name,\n sourceId,\n },\n error: error instanceof Error ? error : new Error(String(error)),\n },\n ],\n depthReached: 0,\n contexts: [],\n };\n }\n }\n\n /**\n * Executes sync delete operations with a specific config.\n * Used by ModelSyncOperation for event-based sync.\n *\n * @param sourceId - The source model ID\n * @param config - The sync configuration to use\n * @returns Sync result with success status and details\n */\n public async syncDeleteWithConfig(\n sourceId: string | number,\n config: SyncConfig,\n ): Promise<SyncResult> {\n try {\n if (!config.unsetOnDelete) {\n return this.createEmptyResult();\n }\n\n const options: SyncInstructionOptions = {\n currentDepth: 1,\n syncChain: [this.sourceModel.name],\n maxDepth: config.maxSyncDepth,\n preventCircular: config.preventCircularSync,\n };\n\n const instructions = await this.collectDeleteInstructions(sourceId, [config], options);\n\n return await this.executeInstructions(instructions);\n } catch (error) {\n console.error(\n `Sync delete with config failed for ${this.sourceModel.name}#${sourceId}:`,\n error,\n );\n\n return {\n success: false,\n attempted: 0,\n succeeded: 0,\n failed: 1,\n errors: [\n {\n instruction: {\n targetTable: \"\",\n targetModel: \"\",\n filter: {},\n update: {},\n depth: 0,\n chain: [this.sourceModel.name],\n sourceModel: this.sourceModel.name,\n sourceId,\n },\n error: error instanceof Error ? error : new Error(String(error)),\n },\n ],\n depthReached: 0,\n contexts: [],\n };\n }\n }\n\n /**\n * Executes sync operations for a model deletion.\n *\n * @param sourceId - The source model ID\n * @returns Sync result with success status and details\n */\n public async syncDelete(sourceId: string | number): Promise<SyncResult> {\n try {\n const syncConfigs = this.getSyncConfigs();\n\n if (syncConfigs.length === 0) {\n return this.createEmptyResult();\n }\n\n const options: SyncInstructionOptions = {\n currentDepth: 1,\n syncChain: [this.sourceModel.name],\n maxDepth: DEFAULT_MAX_SYNC_DEPTH,\n preventCircular: true,\n };\n\n const instructions = await this.collectDeleteInstructions(sourceId, syncConfigs, options);\n\n return await this.executeInstructions(instructions);\n } catch (error) {\n // Catch-all error handler for unexpected failures\n console.error(`Sync delete failed for ${this.sourceModel.name}#${sourceId}:`, error);\n\n return {\n success: false,\n attempted: 0,\n succeeded: 0,\n failed: 1,\n errors: [\n {\n instruction: {\n targetTable: \"\",\n targetModel: \"\",\n filter: {},\n update: {},\n depth: 0,\n chain: [this.sourceModel.name],\n sourceModel: this.sourceModel.name,\n sourceId,\n },\n error: error instanceof Error ? error : new Error(String(error)),\n },\n ],\n depthReached: 0,\n contexts: [],\n };\n }\n }\n\n /**\n * Collects sync instructions recursively with depth limiting.\n *\n * @param payload - Data payload\n * @returns Array of sync instructions\n */\n private async collectInstructions(\n payload: CollectInstructionsPayload,\n ): Promise<SyncInstruction[]> {\n const { sourceId, updatedData, changedFields, syncConfigs, options } = payload;\n const instructions: SyncInstruction[] = [];\n\n for (const config of syncConfigs) {\n // Check if we should sync based on watched fields\n if (!this.shouldSync(config, changedFields)) {\n continue;\n }\n\n // Validate depth and circular references\n const validation = SyncContextManager.validate(\n options.currentDepth,\n options.syncChain,\n config.targetModelClass.name,\n config.maxSyncDepth,\n config.preventCircularSync,\n );\n\n if (!validation.valid) {\n console.warn(`Sync validation failed: ${validation.error}`);\n continue;\n }\n\n // Get embedded data (handle both Model instance and plain data)\n const embedData = await this.getEmbedData(updatedData, config);\n\n // Build instruction\n const instruction = this.buildUpdateInstruction(sourceId, config, embedData, options);\n\n instructions.push(instruction);\n\n // Emit syncing event\n await this.emitSyncingEvent(instruction);\n\n // Recursively collect instructions for next level\n if (SyncContextManager.canSyncDeeper(options.currentDepth, config.maxSyncDepth)) {\n const nextLevelInstructions = await this.collectNextLevelInstructions(\n instruction,\n embedData,\n changedFields,\n config,\n options,\n );\n instructions.push(...nextLevelInstructions);\n }\n }\n\n return instructions;\n }\n\n /**\n * Collects delete sync instructions.\n *\n * @param sourceId - Source model ID\n * @param syncConfigs - Sync configurations\n * @param options - Instruction options\n * @returns Array of sync instructions\n */\n private async collectDeleteInstructions(\n sourceId: string | number,\n syncConfigs: SyncConfig[],\n options: SyncInstructionOptions,\n ): Promise<SyncInstruction[]> {\n const instructions: SyncInstruction[] = [];\n\n for (const config of syncConfigs) {\n if (!config.unsetOnDelete) {\n continue;\n }\n\n const validation = SyncContextManager.validate(\n options.currentDepth,\n options.syncChain,\n config.targetModelClass.name,\n config.maxSyncDepth,\n config.preventCircularSync,\n );\n\n if (!validation.valid) {\n continue;\n }\n\n const instruction = this.buildDeleteInstruction(sourceId, config, options);\n instructions.push(instruction);\n\n await this.emitSyncingEvent(instruction);\n }\n\n return instructions;\n }\n\n /**\n * Collects instructions for the next level in the sync chain.\n *\n * @param parentInstruction - The parent instruction\n * @param embedData - Embedded data from parent\n * @param changedFields - Changed fields\n * @param parentConfig - Parent sync config\n * @param parentOptions - Parent instruction options\n * @returns Array of next-level sync instructions\n */\n private async collectNextLevelInstructions(\n parentInstruction: SyncInstruction,\n embedData: Record<string, unknown>,\n changedFields: string[],\n parentConfig: SyncConfig,\n parentOptions: SyncInstructionOptions,\n ): Promise<SyncInstruction[]> {\n const targetModelClass = parentConfig.targetModelClass;\n const targetSyncConfigs = this.getSyncConfigsForModel(targetModelClass);\n\n if (targetSyncConfigs.length === 0) {\n return [];\n }\n\n const nextOptions: SyncInstructionOptions = {\n currentDepth: parentOptions.currentDepth + 1,\n syncChain: SyncContextManager.extendChain(parentOptions.syncChain, targetModelClass.name),\n maxDepth: Math.min(parentConfig.maxSyncDepth, parentOptions.maxDepth),\n preventCircular: parentOptions.preventCircular && parentConfig.preventCircularSync,\n };\n\n // Get the ID from embed data for next level\n const sourceId = embedData[parentConfig.identifierField] as string | number;\n\n return await this.collectInstructions({\n sourceId,\n updatedData: embedData,\n changedFields,\n syncConfigs: targetSyncConfigs,\n options: nextOptions,\n });\n }\n\n /**\n * Builds an update sync instruction.\n *\n * @param sourceId - Source model ID\n * @param config - Sync configuration\n * @param embedData - Embedded data to sync\n * @param options - Instruction options\n * @returns Sync instruction\n */\n private buildUpdateInstruction(\n sourceId: string | number,\n config: SyncConfig,\n embedData: Record<string, unknown>,\n options: SyncInstructionOptions,\n ): SyncInstruction {\n const targetModelClass = config.targetModelClass;\n const filter = this.buildFilter(sourceId, config);\n const update = this.buildUpdate(embedData, config);\n\n const instruction: SyncInstruction = {\n targetTable: targetModelClass.table,\n targetModel: targetModelClass.name,\n filter,\n update,\n depth: options.currentDepth,\n chain: [...options.syncChain],\n sourceModel: this.sourceModel.name,\n sourceId,\n };\n\n // Add array update metadata if needed\n if (config.isMany) {\n instruction.isArrayUpdate = true;\n instruction.arrayField = config.targetField;\n instruction.identifierField = config.identifierField;\n instruction.identifierValue = sourceId;\n }\n\n return instruction;\n }\n\n /**\n * Builds a delete sync instruction.\n *\n * @param sourceId - Source model ID\n * @param config - Sync configuration\n * @param options - Instruction options\n * @returns Sync instruction\n */\n private buildDeleteInstruction(\n sourceId: string | number,\n config: SyncConfig,\n options: SyncInstructionOptions,\n ): SyncInstruction {\n const targetModelClass = config.targetModelClass;\n const filter = this.buildFilter(sourceId, config);\n const update = { $unset: { [config.targetField]: 1 } };\n\n return {\n targetTable: targetModelClass.table,\n targetModel: targetModelClass.name,\n filter,\n update,\n depth: options.currentDepth,\n chain: [...options.syncChain],\n sourceModel: this.sourceModel.name,\n sourceId,\n };\n }\n\n /**\n * Builds a filter for identifying target documents.\n *\n * @param sourceId - Source model ID\n * @param config - Sync configuration\n * @returns Filter object\n */\n private buildFilter(sourceId: string | number, config: SyncConfig): Record<string, unknown> {\n if (config.isMany) {\n // For arrays: { \"products.id\": productId }\n return { [`${config.targetField}.${config.identifierField}`]: sourceId };\n } else {\n // For single: { \"category.id\": categoryId }\n return { [`${config.targetField}.${config.identifierField}`]: sourceId };\n }\n }\n\n /**\n * Builds an update operation for syncing data.\n *\n * @param embedData - Embedded data to sync\n * @param config - Sync configuration\n * @returns Update operation object\n */\n private buildUpdate(\n embedData: Record<string, unknown>,\n config: SyncConfig,\n ): Record<string, unknown> {\n if (config.isMany) {\n // For arrays: use positional operator $\n return { $set: { [`${config.targetField}.$`]: embedData } };\n } else {\n // For single: direct set\n return { $set: { [config.targetField]: embedData } };\n }\n }\n\n /**\n * Executes sync instructions with batch optimization.\n * Groups by depth and target table for optimal batching.\n *\n * @param instructions - Array of sync instructions\n * @returns Sync result\n */\n private async executeInstructions(instructions: SyncInstruction[]): Promise<SyncResult> {\n const result: SyncResult = {\n success: true,\n attempted: instructions.length,\n succeeded: 0,\n failed: 0,\n errors: [],\n depthReached: 0,\n contexts: [],\n };\n\n if (instructions.length === 0) {\n return result;\n }\n\n // Group instructions by depth for sequential execution\n const instructionsByDepth = this.groupByDepth(instructions);\n\n for (const [depth, depthInstructions] of instructionsByDepth) {\n result.depthReached = Math.max(result.depthReached, depth);\n\n // Further group by target table for better batching\n const instructionsByTable = this.groupByTable(depthInstructions);\n\n for (const [table, tableInstructions] of instructionsByTable) {\n try {\n // Try batch execution first (all instructions for this table)\n await this.executeBatch(tableInstructions, result);\n } catch (batchError) {\n // Fallback to individual execution on batch failure\n console.warn(\n `Batch execution failed for table ${table} at depth ${depth}, falling back to individual execution`,\n );\n await this.executeIndividual(tableInstructions, result);\n }\n }\n }\n\n result.success = result.failed === 0;\n return result;\n }\n\n /**\n * Executes instructions in batch.\n *\n * @param instructions - Instructions to execute\n * @param result - Result object to update\n */\n private async executeBatch(instructions: SyncInstruction[], result: SyncResult): Promise<void> {\n for (const instruction of instructions) {\n try {\n const updateResult = await this.driver.updateMany(\n instruction.targetTable,\n instruction.filter,\n instruction.update,\n );\n\n const context = SyncContextManager.createContext(instruction, updateResult.modifiedCount);\n result.contexts.push(context);\n result.succeeded++;\n\n await this.emitSyncedEvent(context);\n } catch (error) {\n throw error; // Re-throw for batch fallback\n }\n }\n }\n\n /**\n * Executes instructions individually (fallback).\n * Provides detailed error reporting for each failed instruction.\n *\n * @param instructions - Instructions to execute\n * @param result - Result object to update\n */\n private async executeIndividual(\n instructions: SyncInstruction[],\n result: SyncResult,\n ): Promise<void> {\n for (const instruction of instructions) {\n try {\n const updateResult = await this.driver.updateMany(\n instruction.targetTable,\n instruction.filter,\n instruction.update,\n );\n\n const context = SyncContextManager.createContext(instruction, updateResult.modifiedCount);\n result.contexts.push(context);\n result.succeeded++;\n\n await this.emitSyncedEvent(context);\n } catch (error) {\n result.failed++;\n\n const errorMessage = this.formatSyncError(instruction, error);\n const syncError = new Error(errorMessage);\n\n // Preserve original error stack if available\n if (error instanceof Error && error.stack) {\n syncError.stack = error.stack;\n }\n\n result.errors.push({\n instruction,\n error: syncError,\n });\n\n // Log detailed error for debugging\n console.error(`Sync operation failed:`, {\n sourceModel: instruction.sourceModel,\n sourceId: instruction.sourceId,\n targetModel: instruction.targetModel,\n targetTable: instruction.targetTable,\n depth: instruction.depth,\n chain: SyncContextManager.formatChain(instruction.chain),\n filter: instruction.filter,\n error: errorMessage,\n });\n }\n }\n }\n\n /**\n * Formats a sync error with detailed context.\n *\n * @param instruction - The failed instruction\n * @param error - The error that occurred\n * @returns Formatted error message\n */\n private formatSyncError(instruction: SyncInstruction, error: unknown): string {\n const baseMessage = error instanceof Error ? error.message : String(error);\n const chain = SyncContextManager.formatChain(instruction.chain);\n\n return [\n `Sync failed at depth ${instruction.depth}:`,\n `Chain: ${chain} → ${instruction.targetModel}`,\n `Source: ${instruction.sourceModel}#${instruction.sourceId}`,\n `Target: ${instruction.targetTable}`,\n `Error: ${baseMessage}`,\n ].join(\" | \");\n }\n\n /**\n * Groups instructions by depth for batch processing.\n *\n * @param instructions - Instructions to group\n * @returns Map of depth to instructions (sorted ascending)\n */\n private groupByDepth(instructions: SyncInstruction[]): Map<number, SyncInstruction[]> {\n const grouped = new Map<number, SyncInstruction[]>();\n\n for (const instruction of instructions) {\n const depth = instruction.depth;\n if (!grouped.has(depth)) {\n grouped.set(depth, []);\n }\n grouped.get(depth)!.push(instruction);\n }\n\n // Sort by depth (ascending) for sequential execution\n return new Map([...grouped.entries()].sort((a, b) => a[0] - b[0]));\n }\n\n /**\n * Groups instructions by target table for batch optimization.\n *\n * @param instructions - Instructions to group\n * @returns Map of table name to instructions\n */\n private groupByTable(instructions: SyncInstruction[]): Map<string, SyncInstruction[]> {\n const grouped = new Map<string, SyncInstruction[]>();\n\n for (const instruction of instructions) {\n const table = instruction.targetTable;\n if (!grouped.has(table)) {\n grouped.set(table, []);\n }\n grouped.get(table)!.push(instruction);\n }\n\n return grouped;\n }\n\n /**\n * Checks if sync should proceed based on watched fields.\n *\n * @param config - Sync configuration\n * @param changedFields - Fields that changed\n * @returns True if sync should proceed\n */\n private shouldSync(config: SyncConfig, changedFields: string[]): boolean {\n if (config.watchFields.length === 0) {\n return true; // Watch all fields\n }\n\n return config.watchFields.some((field) => changedFields.includes(field));\n }\n\n /**\n * Gets embedded data from the source model.\n *\n * @param data - Source model data or Model instance\n * @param config - Sync configuration\n * @returns Embedded data\n */\n private async getEmbedData(\n data: Record<string, unknown> | Model,\n config: SyncConfig,\n ): Promise<Record<string, unknown>> {\n // If data is a Model instance, call the embed method on it\n if (data instanceof Model) {\n if (Array.isArray(config.embedKey)) {\n return data.only(config.embedKey);\n }\n\n if (typeof data[config.embedKey as keyof Model] !== \"function\") {\n return data[config.embedKey as keyof Model] as Record<string, unknown>;\n }\n // Fallback: use embedData() if available\n if (typeof data.embedData === \"function\") {\n return data.embedData;\n }\n // Last resort: return model data\n return data.data;\n }\n\n // Otherwise, return the data as-is\n return data as Record<string, unknown>;\n }\n\n /**\n * Gets sync configurations from the source model.\n *\n * @returns Array of sync configurations\n */\n private getSyncConfigs(): SyncConfig[] {\n const syncWith = (this.sourceModel as any).syncWith;\n\n if (!syncWith || !Array.isArray(syncWith)) {\n return [];\n }\n\n return syncWith.map((builder: any) =>\n typeof builder.build === \"function\" ? builder.build() : builder,\n );\n }\n\n /**\n * Gets sync configurations for a specific model.\n *\n * @param modelClass - The model class\n * @returns Array of sync configurations\n */\n private getSyncConfigsForModel(modelClass: ChildModel<Model>): SyncConfig[] {\n const syncWith = (modelClass as any).syncWith;\n\n if (!syncWith || !Array.isArray(syncWith)) {\n return [];\n }\n\n return syncWith.map((builder: any) =>\n typeof builder.build === \"function\" ? builder.build() : builder,\n );\n }\n\n /**\n * Emits a syncing event.\n *\n * @param instruction - The sync instruction\n */\n private async emitSyncingEvent(instruction: SyncInstruction): Promise<void> {\n const payload: SyncEventPayload = {\n sourceModel: instruction.sourceModel,\n sourceId: instruction.sourceId,\n targetModel: instruction.targetModel,\n filter: instruction.filter,\n update: instruction.update,\n affectedCount: 0, // Not yet known\n depth: instruction.depth,\n chain: instruction.chain,\n };\n\n // Emit on source model\n if (typeof (this.sourceModel as any).emitSyncEvent === \"function\") {\n await (this.sourceModel as any).emitSyncEvent(\"syncing\", payload);\n }\n }\n\n /**\n * Emits a synced event.\n *\n * @param context - The sync context\n */\n private async emitSyncedEvent(context: any): Promise<void> {\n const payload: SyncEventPayload = {\n sourceModel: context.sourceModel,\n sourceId: context.sourceId,\n targetModel: context.targetModel,\n filter: context.filter,\n update: context.update,\n affectedCount: context.affectedCount,\n depth: context.currentDepth,\n chain: context.syncChain,\n };\n\n // Emit on source model\n if (typeof (this.sourceModel as any).emitSyncEvent === \"function\") {\n await (this.sourceModel as any).emitSyncEvent(\"synced\", payload);\n }\n }\n\n /**\n * Creates an empty sync result.\n *\n * @returns Empty sync result\n */\n private createEmptyResult(): SyncResult {\n return {\n success: true,\n attempted: 0,\n succeeded: 0,\n failed: 0,\n errors: [],\n depthReached: 0,\n contexts: [],\n };\n }\n}\n","/**\n * Model sync operation class.\n *\n * Manages a single sync relationship between a source and target model.\n * Subscribes to source model events and triggers sync operations when\n * the source is updated or deleted.\n *\n * @module cascade-next/sync/model-sync-operation\n */\n\nimport events, { type EventSubscription } from \"@mongez/events\";\nimport type { ChildModel, Model } from \"../model/model\";\nimport { getModelDeletedEvent, getModelUpdatedEvent } from \"./model-events\";\nimport { DEFAULT_MAX_SYNC_DEPTH } from \"./sync-context\";\nimport { SyncManager } from \"./sync-manager\";\nimport type { ModelSyncConfig, ModelSyncOperationContract } from \"./types\";\n\n/**\n * Manages a single model sync operation.\n *\n * Subscribes to source model events (updated, deleted) and triggers\n * sync operations to update embedded data in target models.\n *\n * @example\n * ```typescript\n * // Created via modelSync.sync() or Model.sync()\n * const operation = new ModelSyncOperation(Category, Product, \"category\", false);\n * operation\n * .embed(\"embedMinimal\")\n * .watchFields([\"name\", \"slug\"])\n * .unsetOnDelete();\n * ```\n */\nexport class ModelSyncOperation implements ModelSyncOperationContract {\n /**\n * Configuration for this sync operation.\n */\n private readonly config: ModelSyncConfig;\n\n /**\n * Active event subscriptions for cleanup.\n */\n private readonly subscriptions: EventSubscription[] = [];\n\n /**\n * Whether this operation is currently subscribed to events.\n */\n private isSubscribed = false;\n\n /**\n * Create a new model sync operation.\n *\n * @param sourceModel - Source model class that triggers sync\n * @param targetModel - Target model class that receives data\n * @param targetField - Field path in target model\n * @param isMany - Whether this syncs to an array field\n */\n public constructor(\n sourceModelClass: ChildModel<Model>,\n targetModelClass: ChildModel<Model>,\n targetField: string,\n isMany: boolean,\n ) {\n this.config = {\n sourceModel: sourceModelClass,\n targetModel: targetModelClass,\n targetField,\n isMany,\n embedKey: \"embedData\",\n identifierField: \"id\",\n maxSyncDepth: DEFAULT_MAX_SYNC_DEPTH,\n watchFields: [],\n unsetOnDelete: false,\n removeOnDelete: false,\n };\n\n this.subscribe();\n }\n\n // ============================================================================\n // FLUENT CONFIGURATION\n // ============================================================================\n\n /**\n * Set the embed method to call on source model.\n *\n * @param embed - getter property name (e.g., \"embedData\", \"embedMinimal\") Or Array of fields\n * @returns This operation for chaining\n *\n * @example\n * ```typescript\n * Category.sync(Product, \"category\").embed(\"embedMinimal\");\n * ```\n */\n public embed(method: string | string[]): this {\n this.config.embedKey = method;\n return this;\n }\n\n /**\n * Set the identifier field for array matching.\n * Required when syncing to array fields (syncMany).\n *\n * @param field - Field name used as identifier (default: \"id\")\n * @returns This operation for chaining\n *\n * @example\n * ```typescript\n * Tag.syncMany(Post, \"tags\").identifyBy(\"tagId\");\n * ```\n */\n public identifyBy(field: string): this {\n this.config.identifierField = field;\n return this;\n }\n\n /**\n * Set the maximum sync depth for chained operations.\n *\n * @param depth - Maximum depth (default: 3)\n * @returns This operation for chaining\n *\n * @example\n * ```typescript\n * Category.sync(Product, \"category\").maxDepth(2);\n * ```\n */\n public maxDepth(depth: number): this {\n this.config.maxSyncDepth = depth;\n return this;\n }\n\n /**\n * Set which fields to watch for changes.\n * Sync only triggers when these fields change.\n *\n * @param fields - Array of field names to watch (empty = all)\n * @returns This operation for chaining\n *\n * @example\n * ```typescript\n * Category.sync(Product, \"category\").watchFields([\"name\", \"slug\"]);\n * ```\n */\n public watchFields(fields: string[]): this {\n this.config.watchFields = fields;\n return this;\n }\n\n /**\n * Unset the target field when source is deleted.\n *\n * @returns This operation for chaining\n *\n * @example\n * ```typescript\n * Category.sync(Product, \"category\").unsetOnDelete();\n * ```\n */\n public unsetOnDelete(): this {\n this.config.unsetOnDelete = true;\n return this;\n }\n\n /**\n * Delete target documents when source is deleted.\n *\n * @returns This operation for chaining\n *\n * @example\n * ```typescript\n * User.sync(Profile, \"user\").removeOnDelete();\n * ```\n */\n public removeOnDelete(): this {\n this.config.removeOnDelete = true;\n return this;\n }\n\n // ============================================================================\n // LIFECYCLE\n // ============================================================================\n\n /**\n * Subscribe to source model events.\n * Called automatically in constructor.\n */\n private subscribe(): void {\n if (this.isSubscribed) {\n return;\n }\n\n const sourceModel = this.config.sourceModel;\n\n // Subscribe to model.updated event\n this.subscriptions.push(\n events.subscribe(getModelUpdatedEvent(sourceModel), this.handleModelUpdated),\n );\n\n // Subscribe to model.deleted event\n this.subscriptions.push(\n events.subscribe(getModelDeletedEvent(sourceModel), this.handleModelDeleted),\n );\n\n this.isSubscribed = true;\n }\n\n /**\n * Unsubscribe from all events and cleanup.\n * Called automatically when using modelSync.register().\n */\n public unsubscribe(): void {\n for (const subscription of this.subscriptions) {\n subscription.unsubscribe?.();\n }\n\n this.subscriptions.length = 0;\n this.isSubscribed = false;\n }\n\n /**\n * Cleanup the sync operations\n */\n public $cleanup() {\n return this.unsubscribe();\n }\n\n // ============================================================================\n // EVENT HANDLERS\n // ============================================================================\n\n /**\n * Handle model updated event.\n * Triggers sync to update embedded data in target models.\n */\n private handleModelUpdated = async (model: Model, changedFields: string[]): Promise<void> => {\n // Check if we should sync based on watched fields\n if (!this.shouldSync(changedFields)) {\n return;\n }\n\n try {\n const primaryKey = (this.config.sourceModel as any).primaryKey || \"id\";\n const sourceId = model.get(primaryKey) as string | number;\n\n if (!sourceId) {\n return;\n }\n\n // Get the driver from the source model's data source\n const dataSource = this.config.sourceModel.getDataSource();\n const driver = dataSource.driver;\n\n // Create sync manager and execute\n const syncManager = new SyncManager(this.config.sourceModel, driver);\n await syncManager.syncUpdateWithConfig(\n sourceId,\n model,\n changedFields,\n this.buildSyncConfig(),\n );\n } catch (error) {\n console.error(\n `[ModelSync] Failed to sync ${this.config.sourceModel.name} -> ${this.config.targetModel.name}:`,\n error,\n );\n }\n };\n\n /**\n * Handle model deleted event.\n * Triggers unset or remove based on configuration.\n */\n private handleModelDeleted = async (model: Model): Promise<void> => {\n if (!this.config.unsetOnDelete && !this.config.removeOnDelete) {\n return;\n }\n\n try {\n const primaryKey = (this.config.sourceModel as any).primaryKey || \"id\";\n const sourceId = model.get(primaryKey) as string | number;\n\n if (!sourceId) {\n return;\n }\n\n const dataSource = this.config.sourceModel.getDataSource();\n const driver = dataSource.driver;\n\n if (this.config.removeOnDelete) {\n // Delete all target documents that reference this source\n await this.removeTargetDocuments(sourceId, driver);\n } else if (this.config.unsetOnDelete) {\n // Unset the field in target documents\n const syncManager = new SyncManager(this.config.sourceModel, driver);\n await syncManager.syncDeleteWithConfig(sourceId, this.buildSyncConfig());\n }\n } catch (error) {\n console.error(\n `[ModelSync] Failed to handle delete for ${this.config.sourceModel.name}:`,\n error,\n );\n }\n };\n\n // ============================================================================\n // HELPERS\n // ============================================================================\n\n /**\n * Check if sync should proceed based on watched fields.\n */\n private shouldSync(changedFields: string[]): boolean {\n if (this.config.watchFields.length === 0) {\n return true; // Watch all fields\n }\n\n return this.config.watchFields.some((field) => changedFields.includes(field));\n }\n\n /**\n * Build sync config compatible with SyncManager.\n */\n private buildSyncConfig(): any {\n return {\n targetField: this.config.targetField,\n isMany: this.config.isMany,\n embedKey: this.config.embedKey,\n identifierField: this.config.identifierField,\n maxSyncDepth: this.config.maxSyncDepth,\n preventCircularSync: true,\n watchFields: this.config.watchFields,\n unsetOnDelete: this.config.unsetOnDelete,\n targetModelClass: this.config.targetModel,\n };\n }\n\n /**\n * Remove target documents that reference the deleted source.\n */\n private async removeTargetDocuments(sourceId: string | number, driver: any): Promise<void> {\n const filter = this.config.isMany\n ? { [`${this.config.targetField}.${this.config.identifierField}`]: sourceId }\n : { [`${this.config.targetField}.${this.config.identifierField}`]: sourceId };\n\n await driver.deleteMany(this.config.targetModel.table, filter);\n }\n\n /**\n * Get the current configuration (for debugging/testing).\n */\n public getConfig(): Readonly<ModelSyncConfig> {\n return { ...this.config };\n }\n}\n","/**\n * ModelSync facade for registering sync operations.\n *\n * Provides a clean API for defining sync relationships between models\n * with automatic cleanup support for HMR (Hot Module Replacement).\n *\n * @module cascade-next/sync/model-sync\n */\n\nimport type { ChildModel, Model } from \"../model/model\";\nimport { ModelSyncOperation } from \"./model-sync-operation\";\nimport type { ModelSyncContract, ModelSyncOperationContract } from \"./types\";\n\n/**\n * ModelSync facade implementation.\n *\n * Manages sync operation registration with scoped cleanup support.\n * Uses a registration stack to track operations created during\n * a `register()` callback for proper HMR cleanup.\n *\n * @example\n * ```typescript\n * // In events file\n * export const cleanup = modelSync.register(() => {\n * Category.sync(Product, \"category\");\n * Tag.syncMany(Post, \"tags\").identifyBy(\"id\");\n * });\n * ```\n */\nclass ModelSyncFacade implements ModelSyncContract {\n /**\n * All active sync operations.\n */\n private readonly operations: ModelSyncOperation[] = [];\n\n /**\n * Stack for tracking operations during register() callbacks.\n * Each element is an array of operations created in that scope.\n */\n private readonly registrationStack: ModelSyncOperation[][] = [];\n\n // ============================================================================\n // PUBLIC API\n // ============================================================================\n\n /**\n * Create a sync operation for a single embedded document.\n *\n * When the source model is updated, the target model's field\n * will be updated with the embedded data.\n *\n * @param source - Source model class that triggers sync\n * @param target - Target model class that receives data\n * @param field - Field path in target model\n * @returns Sync operation for chaining configuration\n *\n * @example\n * ```typescript\n * // When Category updates, update Product.category\n * modelSync.sync(Category, Product, \"category\");\n *\n * // With configuration\n * modelSync.sync(Category, Product, \"category\")\n * .embed(\"embedMinimal\")\n * .watchFields([\"name\", \"slug\"]);\n * ```\n */\n public sync(\n source: ChildModel<Model>,\n target: ChildModel<Model>,\n field: string,\n ): ModelSyncOperationContract {\n const operation = new ModelSyncOperation(source, target, field, false);\n this.trackOperation(operation);\n return operation;\n }\n\n /**\n * Create a sync operation for an array of embedded documents.\n *\n * When the source model is updated, the corresponding element\n * in the target model's array field will be updated.\n *\n * @param source - Source model class that triggers sync\n * @param target - Target model class that receives data\n * @param field - Array field path in target model\n * @returns Sync operation for chaining configuration\n *\n * @example\n * ```typescript\n * // When Tag updates, update Post.tags[i] where tags[i].id matches\n * modelSync.syncMany(Tag, Post, \"tags\").identifyBy(\"id\");\n * ```\n */\n public syncMany(\n source: ChildModel<Model>,\n target: ChildModel<Model>,\n field: string,\n ): ModelSyncOperationContract {\n const operation = new ModelSyncOperation(source, target, field, true);\n this.trackOperation(operation);\n return operation;\n }\n\n /**\n * Register sync operations with automatic cleanup.\n *\n * Executes the callback function which should contain sync registrations.\n * Returns a cleanup function that unsubscribes all operations created\n * during the callback - perfect for HMR module cleanup.\n *\n * @param callback - Function that registers sync operations\n * @returns Cleanup function that unsubscribes all registered operations\n *\n * @example\n * ```typescript\n * // In src/app/blog/events/sync.ts\n * export const cleanup = modelSync.register(() => {\n * Category.sync(Product, \"category\");\n * Tag.syncMany(Post, \"tags\").identifyBy(\"id\");\n * Author.sync(Article, \"author\").unsetOnDelete();\n * });\n * ```\n */\n public register(callback: () => void): () => void {\n // Create a new scope for tracking operations\n const scopedOperations: ModelSyncOperation[] = [];\n this.registrationStack.push(scopedOperations);\n\n try {\n // Execute callback - operations are tracked via trackOperation()\n callback();\n } finally {\n // Remove the scope from stack\n this.registrationStack.pop();\n }\n\n // Return cleanup function for just these scoped operations\n return () => {\n for (const operation of scopedOperations) {\n operation.unsubscribe();\n\n // Remove from global operations array\n const index = this.operations.indexOf(operation);\n if (index !== -1) {\n this.operations.splice(index, 1);\n }\n }\n };\n }\n\n /**\n * Clear all registered sync operations.\n * Useful for testing or complete reset.\n */\n public clear(): void {\n for (const operation of this.operations) {\n operation.unsubscribe();\n }\n this.operations.length = 0;\n }\n\n /**\n * Get count of active sync operations.\n * Useful for debugging and testing.\n */\n public get count(): number {\n return this.operations.length;\n }\n\n // ============================================================================\n // PRIVATE HELPERS\n // ============================================================================\n\n /**\n * Track a new operation in global list and current registration scope.\n */\n private trackOperation(operation: ModelSyncOperation): void {\n // Always add to global operations\n this.operations.push(operation);\n\n // If inside a register() callback, also track in the current scope\n const currentScope = this.registrationStack[this.registrationStack.length - 1];\n if (currentScope) {\n currentScope.push(operation);\n }\n }\n}\n\n/**\n * Global modelSync facade instance.\n *\n * Use this to register sync operations between models.\n *\n * @example\n * ```typescript\n * import { modelSync } from \"@warlock.js/cascade\";\n *\n * export const cleanup = modelSync.register(() => {\n * Category.sync(Product, \"category\");\n * });\n * ```\n */\nexport const modelSync = new ModelSyncFacade();\n","import { get, merge, only, set, unset } from \"@mongez/reinforcements\";\nimport type { Model } from \"../model\";\n\n/**\n * Sentinel symbol to distinguish a genuinely missing field from a field\n * whose value is `undefined`. Encapsulated here — callers use `hasField()`.\n */\nconst MISSING_VALUE = Symbol(\"missing\");\n\nexport function getFieldValue(model: Model, field: string, defaultValue?: unknown): any {\n return get(model.data, field, defaultValue);\n}\n\nexport function setFieldValue(model: Model, field: string, value: unknown): Model {\n const path = String(field);\n set(model.data, path, value);\n\n const partial: Record<string, unknown> = {};\n set(partial, path, value);\n model.dirtyTracker.mergeChanges(partial);\n\n return model;\n}\n\nexport function hasField(model: Model, field: string): boolean {\n return get(model.data, field, MISSING_VALUE as any) !== MISSING_VALUE;\n}\n\nexport function incrementField(model: Model, field: string, amount?: number): Model {\n const value = getFieldValue(model, field, 0) as number;\n const incrementedValue = value + (amount ?? 1);\n return setFieldValue(model, field, incrementedValue);\n}\n\nexport function decrementField(model: Model, field: string, amount?: number): Model {\n const value = getFieldValue(model, field, 0) as number;\n const decrementedValue = value - (amount ?? 1);\n return setFieldValue(model, field, decrementedValue);\n}\n\nexport function unsetFields(model: Model, ...fields: string[]): Model {\n model.data = unset(model.data, fields);\n model.dirtyTracker.unset(fields);\n\n return model;\n}\n\nexport function mergeFields(model: Model, values: Record<string, unknown>): Model {\n model.data = merge(model.data, values) as any;\n model.dirtyTracker.mergeChanges(values);\n return model;\n}\n\nexport function getOnlyFields(model: Model, fields: string[]): Record<string, unknown> {\n return only(model.data, fields);\n}\n\nexport function getStringField(model: Model, key: string, defaultValue?: string): string | undefined {\n return getFieldValue(model, key, defaultValue) as string | undefined;\n}\n\nexport function getNumberField(model: Model, key: string, defaultValue?: number): number | undefined {\n return getFieldValue(model, key, defaultValue) as number | undefined;\n}\n\nexport function getBooleanField(model: Model, key: string, defaultValue?: boolean): boolean | undefined {\n return getFieldValue(model, key, defaultValue) as boolean | undefined;\n}\n","import events from \"@mongez/events\";\nimport type { DriverContract, UpdateOperations } from \"../contracts/database-driver.contract\";\nimport type {\n RemoverContract,\n RemoverOptions,\n RemoverResult,\n} from \"../contracts/database-remover.contract\";\nimport type { OnDeletedEventContext } from \"../events/model-events\";\nimport type { ChildModel, Model } from \"../model/model\";\nimport { getModelDeletedEvent } from \"../sync/model-events\";\nimport type { DataSource } from \"./../data-source/data-source\";\n\n/**\n * Database remover service that orchestrates model deletion.\n *\n * Handles the complete deletion pipeline:\n * 1. Strategy resolution (options → model static → data source default)\n * 2. Validation (check if model is new, has primary key)\n * 3. Event emission (deleting, deleted)\n * 4. Driver execution (based on strategy: trash, permanent, or soft)\n * 5. Post-deletion cleanup (mark as new, reset state)\n *\n * @example\n * ```typescript\n * const user = await User.find(1);\n * const remover = new DatabaseRemover(user);\n * const result = await remover.destroy();\n *\n * console.log(result.success); // true\n * console.log(result.strategy); // \"trash\" | \"permanent\" | \"soft\"\n * ```\n */\nexport class DatabaseRemover implements RemoverContract {\n /** The model instance being deleted */\n private readonly model: Model;\n\n /** Model constructor reference */\n private readonly ctor: ChildModel<Model>;\n\n /** Data source containing driver */\n private readonly dataSource: DataSource;\n\n /** Database driver for executing queries */\n private readonly driver: DriverContract;\n\n /** Table/collection name */\n private readonly table: string;\n\n /** Primary key field name */\n private readonly primaryKey: string;\n\n /**\n * Create a new remover instance for a model.\n *\n * @param model - The model instance to delete\n *\n * @example\n * ```typescript\n * const user = await User.find(1);\n * const remover = new DatabaseRemover(user);\n * await remover.destroy();\n * ```\n */\n public constructor(model: Model) {\n this.model = model;\n this.ctor = model.constructor as ChildModel<Model>;\n this.dataSource = this.ctor.getDataSource();\n this.driver = this.dataSource.driver;\n this.table = this.ctor.table;\n this.primaryKey = this.ctor.primaryKey;\n }\n\n /**\n * Destroy (delete) the model instance from the database.\n *\n * @param options - Remover options\n * @returns Result containing success status, strategy used, and metadata\n * @throws {Error} If model is new (not saved) or if deletion fails\n */\n public async destroy(options: RemoverOptions = {}): Promise<RemoverResult> {\n // 1. Resolve strategy (options → model static → data source default → permanent)\n const strategy =\n options.strategy ??\n this.ctor.deleteStrategy ??\n this.dataSource.defaultDeleteStrategy ??\n \"permanent\";\n\n // 2. Validate model is not new and has primary key\n if (this.model.isNew) {\n throw new Error(\n `Cannot destroy ${this.ctor.name} instance that hasn't been saved to the database.`,\n );\n }\n\n const primaryKeyValue = this.model.get(this.primaryKey);\n if (!primaryKeyValue) {\n throw new Error(\n `Cannot destroy ${this.ctor.name} instance: primary key (${this.primaryKey}) is missing.`,\n );\n }\n\n // 3. Emit deleting event (unless skipEvents)\n if (!options.skipEvents) {\n await this.model.emitEvent(\"deleting\", {\n strategy,\n primaryKeyValue,\n primaryKey: this.primaryKey,\n });\n }\n\n // 4. Execute deletion based on strategy\n let deletedCount = 0;\n let trashRecord: Record<string, unknown> | undefined;\n\n const filter = { [this.primaryKey]: primaryKeyValue };\n\n const context: Partial<OnDeletedEventContext> = {\n strategy,\n primaryKeyValue,\n primaryKey: this.primaryKey,\n };\n\n switch (strategy) {\n case \"trash\": {\n // Move to trash table, then delete\n const trashTable = this.resolveTrashTable();\n const documentData = { ...this.model.data };\n\n // Prepare trash record with metadata and handle ID conflicts\n const trashData = this.prepareTrashRecord(documentData);\n\n // Insert into trash table\n const insertResult = await this.driver.insert(trashTable, trashData);\n trashRecord = insertResult.document as Record<string, unknown>;\n\n context.trashRecord = trashRecord;\n\n // Delete original\n const result = await this.driver.delete(this.table, filter);\n deletedCount = result > 0 ? 1 : 0;\n break;\n }\n\n case \"permanent\": {\n // Direct deletion\n const result = await this.driver.delete(this.table, filter);\n deletedCount = result > 0 ? 1 : 0;\n break;\n }\n\n case \"soft\": {\n // Set deletedAt timestamp (using resolved column name)\n const deletedAtColumn = this.ctor.deletedAtColumn;\n \n // Only proceed if deletedAtColumn is configured (not false or undefined)\n if (deletedAtColumn === false || deletedAtColumn === undefined) {\n throw new Error(\n `Cannot perform soft delete on ${this.ctor.name}: deletedAtColumn is not configured. ` +\n `Set a column name or use a different delete strategy.`,\n );\n }\n \n const updateOperations: UpdateOperations = {\n $set: { [deletedAtColumn]: new Date() },\n };\n const updateResult = await this.driver.update(this.table, filter, updateOperations);\n deletedCount = updateResult.modifiedCount > 0 ? 1 : 0;\n break;\n }\n }\n\n if (deletedCount === 0) {\n throw new Error(`Failed to destroy ${this.ctor.name} instance: record not found.`);\n }\n\n context.deletedCount = deletedCount;\n\n // 5. Post-deletion cleanup\n // Only mark as new for permanent and trash (soft delete keeps the record)\n if (strategy !== \"soft\") {\n this.model.isNew = true;\n }\n\n // 6. Emit deleted event (unless skipEvents)\n if (!options.skipEvents) {\n await this.model.emitEvent(\"deleted\", context);\n }\n\n // 7. Trigger sync operations (fire-and-forget, non-blocking)\n if (!options.skipSync) {\n void this.triggerSync();\n }\n\n return {\n success: true,\n deletedCount,\n strategy,\n trashRecord,\n };\n }\n\n /**\n * Prepare the trash record by preserving all original fields and adding deletion metadata.\n *\n * Keeps all original fields intact for easy restoration and adds:\n * - `deletedAt`: Timestamp when the record was deleted\n * - `originalTable`: The table/collection the record came from (for filtering in restoreAll)\n *\n * **ID Handling:**\n * - MongoDB with `_id`: Keeps `_id` as-is (unique across database)\n * - MongoDB with auto-increment `id`: Keeps `id` as a regular field (not primary key)\n * - SQL: Keeps original `id` as a regular field (trash table uses its own auto-increment primary key)\n *\n * The trash table should use its own primary key structure:\n * - MongoDB: Uses `_id` (ObjectId) as primary key, original `id` is just a field\n * - SQL: Uses auto-increment `trashId` as primary key, original `id` is just a field\n *\n * @param documentData - The original document data\n * @returns Prepared trash record data with all original fields + deletedAt + originalTable\n * @private\n */\n private prepareTrashRecord(documentData: Record<string, unknown>): Record<string, unknown> {\n // Preserve all original fields and add deletion metadata\n return {\n ...documentData,\n deletedAt: new Date(),\n originalTable: this.table,\n };\n }\n\n /**\n * Resolve the trash table/collection name.\n *\n * Priority:\n * 1. Model.trashTable (if set)\n * 2. Data source defaultTrashTable (e.g., \"RecycleBin\" for MongoDB)\n * 3. Default pattern: `{table}Trash`\n *\n * @returns The trash table/collection name\n * @private\n */\n private resolveTrashTable(): string {\n if (this.ctor.trashTable) {\n return this.ctor.trashTable;\n }\n\n if (this.dataSource.defaultTrashTable) {\n return this.dataSource.defaultTrashTable;\n }\n\n return `${this.table}Trash`;\n }\n\n /**\n * Trigger sync operations after successful deletion.\n *\n * Emits a model.deleted event that ModelSyncOperation listens to.\n * The sync is handled by registered sync operations, not directly here.\n *\n * @private\n */\n private async triggerSync(): Promise<void> {\n // Emit model.deleted event - ModelSyncOperation listens to these\n await events.triggerAll(getModelDeletedEvent(this.ctor), this.model);\n }\n}\n","import { DatabaseRemover } from \"../../remover/database-remover\";\nimport type { DeleteStrategy } from \"../../types\";\nimport type { RemoverResult } from \"../../contracts\";\nimport type { ChildModel, Model } from \"../model\";\n\nexport async function destroyModel(\n model: Model,\n options?: { strategy?: DeleteStrategy; skipEvents?: boolean },\n): Promise<RemoverResult> {\n const remover = new DatabaseRemover(model);\n return remover.destroy(options);\n}\n\nexport async function deleteRecords(\n ModelClass: ChildModel<any>,\n filter?: Record<string, unknown>,\n): Promise<number> {\n return ModelClass.getDriver().deleteMany(ModelClass.table, filter);\n}\n\nexport async function deleteOneRecord(\n ModelClass: ChildModel<any>,\n filter?: Record<string, unknown>,\n): Promise<number> {\n return ModelClass.getDriver().delete(ModelClass.table, filter);\n}\n","import type { Model } from \"../model\";\n\nexport function checkHasChanges(model: Model): boolean {\n return model.dirtyTracker.hasChanges();\n}\n\nexport function checkIsDirty(model: Model, column: string): boolean {\n return model.dirtyTracker.isDirty(column);\n}\n\nexport function getDirtyColumnsWithValues(model: Model): Record<string, { oldValue: unknown; newValue: unknown }> {\n return model.dirtyTracker.getDirtyColumnsWithValues();\n}\n\nexport function getRemovedColumns(model: Model): string[] {\n return model.dirtyTracker.getRemovedColumns();\n}\n\nexport function getDirtyColumns(model: Model): string[] {\n return model.dirtyTracker.getDirtyColumns();\n}\n","/**\n * @fileoverview Restores relation data onto model instances from a plain object snapshot.\n *\n * This is the cache-restoration counterpart to RelationLoader (which loads from the DB).\n * It is intentionally decoupled from query execution — it only deals with instantiating\n * related models from already-serialized data.\n *\n * @module @warlock.js/cascade/relations/relation-hydrator\n *\n * @example\n * ```typescript\n * // Restoring a model + its relations from a cache snapshot:\n * const snapshot = await cache.get(key);\n * const chat = Chat.fromSnapshot(snapshot);\n * // chat.unit, chat.organization etc. are fully hydrated Model instances.\n * ```\n */\n\nimport type { ChildModel, Model } from \"../model/model\";\nimport { resolveModelClass } from \"../model/register-model\";\nimport type { RelationDefinition } from \"./types\";\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\n/**\n * The serialized shape of a single relation entry inside a model snapshot.\n * Each value is either:\n * - `null` — the relation was loaded and resolved to nothing (e.g. belongsTo with no match)\n * - A nested snapshot object `{ data, relations }` — a single related model\n * - An array of nested snapshot objects — a collection relation\n */\nexport type SerializedRelation = null | ModelSnapshot | ModelSnapshot[];\n\n/**\n * The plain-object shape produced by `model.toSnapshot()` and consumed by\n * `Model.fromSnapshot()`. The `relations` map uses the same relation names\n * defined in the model's static `relations` property.\n */\nexport type ModelSnapshot = {\n data: Record<string, unknown>;\n relations: Record<string, SerializedRelation>;\n};\n\n// ============================================================================\n// RELATION HYDRATOR CLASS\n// ============================================================================\n\n/**\n * Restores eager-loaded relations from a plain snapshot onto a model instance.\n *\n * Mirrors the interface of RelationLoader but instead of issuing DB queries,\n * it recursively instantiates related models from serialized snapshot data.\n *\n * @example\n * ```typescript\n * // Used internally by Model.fromSnapshot():\n * const model = new Chat(snapshot.data);\n * RelationHydrator.hydrate(model, Chat.relations, snapshot.relations);\n * ```\n */\nexport class RelationHydrator {\n /**\n * Hydrate all relations from a snapshot onto `model`.\n *\n * - Looks up each relation name in `relationDefs` to find the target model class.\n * - Recursively calls `fromSnapshot` on nested snapshots so deeply nested\n * relations are fully hydrated as well.\n * - Sets each relation on both `model.loadedRelations` (Map) and as a direct\n * property (`model[name]`) to match the behaviour of RelationLoader.\n * - Intentionally preserves `null` entries — a null relation was explicitly\n * loaded and resolved to nothing; this is different from a missing relation.\n *\n * @param model - The model instance to attach relations to\n * @param relationDefs - The static `relations` map from the model class\n * @param relationsSnapshot - The `relations` portion of a `ModelSnapshot`\n */\n public static hydrate(\n model: Model,\n relationDefs: Record<string, RelationDefinition>,\n relationsSnapshot: Record<string, SerializedRelation> | undefined,\n ): void {\n if (!relationsSnapshot) return;\n\n for (const [name, snapshot] of Object.entries(relationsSnapshot)) {\n const def = relationDefs[name];\n\n // Relation name not in definition — skip gracefully rather than throwing,\n // since the snapshot could be from an older schema version.\n if (!def) continue;\n\n const RelModel = resolveModelClass(def.model) as ChildModel<Model> | undefined;\n if (!RelModel) continue;\n\n let hydrated: Model | Model[] | null;\n\n if (snapshot === null) {\n // Explicitly loaded relation that resolved to nothing — keep as null.\n hydrated = null;\n } else if (Array.isArray(snapshot)) {\n // Collection relation (hasMany / belongsToMany)\n hydrated = snapshot.map((item) => RelModel.fromSnapshot(item));\n } else {\n // Single relation (belongsTo / hasOne)\n hydrated = RelModel.fromSnapshot(snapshot);\n }\n\n // Set on the Map for getRelation() / isLoaded() API\n model.loadedRelations.set(name, hydrated);\n\n // Set as direct property for convenient access (model.unit, model.posts, …)\n (model as unknown as Record<string, unknown>)[name] = hydrated;\n }\n }\n}\n","import { RelationHydrator, type ModelSnapshot, type SerializedRelation } from \"../../relations/relation-hydrator\";\nimport type { ChildModel, Model } from \"../model\";\n\nexport function hydrateModel<TModel extends Model = Model>(\n ModelClass: ChildModel<TModel>,\n data: Record<string, unknown>,\n): TModel {\n const model = new ModelClass(ModelClass.getDriver().deserialize(data));\n model.isNew = false;\n return model;\n}\n\nexport function modelFromSnapshot<TModel extends Model>(\n ModelClass: ChildModel<TModel>,\n snapshot: ModelSnapshot,\n): TModel {\n const model = ModelClass.hydrate(snapshot.data) as TModel;\n RelationHydrator.hydrate(model, ModelClass.relations, snapshot.relations);\n return model;\n}\n\nexport function modelToSnapshot(model: Model): ModelSnapshot {\n const driver = (model.constructor as typeof Model).getDataSource().driver;\n const relations: Record<string, SerializedRelation> = {};\n\n for (const [name, related] of model.loadedRelations) {\n if (related === null) {\n relations[name] = null;\n } else if (Array.isArray(related)) {\n relations[name] = related.map((m) => (m instanceof Object && typeof m.toSnapshot === \"function\" ? m.toSnapshot() : m));\n } else if (related instanceof Object && typeof related.toSnapshot === \"function\") {\n relations[name] = related.toSnapshot();\n }\n }\n\n return {\n data: driver.serialize({ ...model.data }) as Record<string, unknown>,\n relations,\n };\n}\n\nexport function serializeModel(model: Model) {\n return (model.constructor as typeof Model).getDataSource().driver.serialize(model.data);\n}\n\nexport function cloneModel<TModel extends Model>(model: TModel): TModel {\n const clonedData = JSON.parse(JSON.stringify(model.data));\n const ModelClass = model.self();\n const clonedModel = new ModelClass(clonedData) as TModel;\n\n clonedModel.isNew = model.isNew;\n deepFreezeObject(clonedModel.data);\n clonedModel.dirtyTracker.reset();\n\n return clonedModel;\n}\n\nexport function deepFreezeObject<T>(obj: T): T {\n Object.freeze(obj);\n\n Object.getOwnPropertyNames(obj).forEach((prop) => {\n const value = (obj as any)[prop];\n if (\n value !== null &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n !Object.isFrozen(value)\n ) {\n deepFreezeObject(value);\n }\n });\n\n return obj;\n}\n\nexport function replaceModelData<TModel extends Model>(\n model: TModel,\n data: Record<string, unknown>,\n): void {\n model.data = data as any;\n model.dirtyTracker.replaceCurrentData(data);\n}\n","import {\n globalModelEvents,\n type ModelEventListener,\n type ModelEventName,\n} from \"../../events/model-events\";\nimport type { Model } from \"../model\";\n\nexport async function emitModelEvent<TContext = unknown>(\n model: Model,\n event: ModelEventName,\n context?: TContext,\n): Promise<void> {\n const ctor = model.constructor as any;\n await model.events.emit(event, model, context as TContext);\n await ctor.events().emit(event, model, context as TContext);\n await globalModelEvents.emit(event, model, context as TContext);\n}\n\nexport function onModelEvent<TContext = unknown>(\n model: Model,\n event: ModelEventName,\n listener: ModelEventListener<any, TContext>,\n): () => void {\n return model.events.on(event, listener);\n}\n\nexport function onceModelEvent<TContext = unknown>(\n model: Model,\n event: ModelEventName,\n listener: ModelEventListener<any, TContext>,\n): () => void {\n return model.events.once(event, listener);\n}\n\nexport function offModelEvent<TContext = unknown>(\n model: Model,\n event: ModelEventName,\n listener: ModelEventListener<any, TContext>,\n): void {\n model.events.off(event, listener);\n}\n","import { colors } from \"@mongez/copper\";\nimport type { ValidationResult } from \"@warlock.js/seal\";\n\n/**\n * Error thrown when model validation fails during database write operations.\n *\n * Contains detailed information about all validation errors,\n * including field paths, error messages, and validation rules that failed.\n *\n * @example\n * ```typescript\n * try {\n * const user = new User({ name: \"\", age: -5 });\n * await user.save();\n * } catch (error) {\n * if (error instanceof DatabaseWriterValidationError) {\n * console.log(error.message); // \"Validation failed\"\n * console.log(error.errors);\n * // [\n * // { path: \"name\", error: \"name is required\", rule: \"required\" },\n * // { path: \"age\", error: \"age must be at least 0\", rule: \"min\" }\n * // ]\n * }\n * }\n * ```\n */\nexport class DatabaseWriterValidationError extends Error {\n /**\n * Array of validation errors from @warlock.js/seal.\n *\n * Each error contains:\n * - `path`: Dot-notation path to the field (e.g., \"address.city\")\n * - `error`: Human-readable error message\n * - `rule`: The validation rule that failed (e.g., \"required\", \"email\")\n * - Additional context depending on the rule\n */\n public readonly errors: ValidationResult[\"errors\"];\n\n /**\n * Create a new DatabaseWriterValidationError.\n *\n * @param message - Error message (typically \"Validation failed\")\n * @param errors - Array of validation errors from seal\n *\n * @example\n * ```typescript\n * const error = new DatabaseWriterValidationError(\"Validation failed\", [\n * { path: \"email\", error: \"email must be valid\", rule: \"email\" }\n * ]);\n * ```\n */\n public constructor(message: string, errors: ValidationResult[\"errors\"]) {\n super(message);\n this.name = \"DatabaseWriterValidationError\";\n this.errors = errors;\n\n // Maintain proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, DatabaseWriterValidationError);\n }\n\n // Override Node.js inspect to use our formatted output\n Object.defineProperty(this, \"inspect\", {\n value: () => this.toString(),\n enumerable: false,\n });\n }\n\n /**\n * Custom inspect method for Node.js console output.\n * This makes console.log and error logging use our beautiful format.\n */\n [Symbol.for(\"nodejs.util.inspect.custom\")](): string {\n return this.toString();\n }\n\n /**\n * Get a formatted string representation of all validation errors.\n *\n * Provides beautiful, colored terminal output with clear field-by-field breakdown.\n *\n * @returns Multi-line string with all errors, formatted for terminal\n *\n * @example\n * ```typescript\n * console.log(error.toString());\n * // ❌ Validation Error: UserModel\n * //\n * // Field: email\n * // Error: Email already exists\n * // Value: \"john@example.com\"\n * ```\n */\n public toString(): string {\n // Extract model name from message (e.g., \"[UserModel Model]\")\n const modelMatch = this.message.match(/\\[(\\w+)\\s+Model\\]/);\n const modelName = modelMatch ? modelMatch[1] : \"Model\";\n const operation = this.message.includes(\"Insert\") ? \"Insert\" : \"Update\";\n\n // Build header\n const lines: string[] = [];\n lines.push(\"\");\n lines.push(colors.red(`❌ Validation Error: ${modelName} (${operation})`));\n lines.push(\"\");\n\n // Group errors by field for better readability\n const errorsByField = new Map<string, Array<{ error: string; type?: string; value?: any }>>();\n\n for (const err of this.errors) {\n const fieldName = err.input || \"unknown\";\n if (!errorsByField.has(fieldName)) {\n errorsByField.set(fieldName, []);\n }\n errorsByField.get(fieldName)!.push({\n error: err.error,\n type: err.type,\n value: (err as any).value,\n });\n }\n\n // Format each field's errors\n for (const [fieldName, fieldErrors] of errorsByField) {\n lines.push(colors.yellow(` Field: ${fieldName}`));\n\n for (const fieldError of fieldErrors) {\n lines.push(colors.white(` Error: ${fieldError.error}`));\n\n if (fieldError.value !== undefined) {\n const valueStr =\n typeof fieldError.value === \"string\"\n ? `\"${fieldError.value}\"`\n : JSON.stringify(fieldError.value);\n lines.push(colors.gray(` Value: ${valueStr}`));\n }\n\n if (fieldError.type) {\n lines.push(colors.cyan(` Type: ${fieldError.type}`));\n }\n }\n\n lines.push(\"\"); // Blank line between fields\n }\n\n return lines.join(\"\\n\");\n }\n\n /**\n * Get validation errors for a specific field.\n *\n * @param fieldPath - Dot-notation path to the field\n * @returns Array of errors for that field\n *\n * @example\n * ```typescript\n * const emailErrors = error.getFieldErrors(\"email\");\n * console.log(emailErrors);\n * // [{ path: \"email\", error: \"email must be valid\", rule: \"email\" }]\n * ```\n */\n public getFieldErrors(fieldPath: string): ValidationResult[\"errors\"] {\n return this.errors.filter((err) => err.input === fieldPath);\n }\n\n /**\n * Check if a specific field has validation errors.\n *\n * @param fieldPath - Dot-notation path to the field\n * @returns True if the field has errors\n *\n * @example\n * ```typescript\n * if (error.hasFieldError(\"email\")) {\n * console.log(\"Email is invalid\");\n * }\n * ```\n */\n public hasFieldError(fieldPath: string): boolean {\n return this.errors.some((err) => err.input === fieldPath);\n }\n}\n","import { invalidRule, VALID_RULE, type SchemaRule } from \"@warlock.js/seal\";\nimport { resolveModelClass } from \"../../model/register-model\";\nimport type { ExistsRuleOptions } from \"../types\";\n\n/**\n * Validates that a record exists in the database for the given column/value.\n *\n * @example\n * v.string().exists(Organization, { column: \"id\" });\n */\nexport const existsRule: SchemaRule<ExistsRuleOptions> = {\n name: \"exists\",\n defaultErrorMessage: \"The :input must exist\",\n async validate(value: any, context) {\n const { Model, query, column = context.key } = this.context.options;\n\n const ResolvedModelClass = resolveModelClass(Model);\n\n const dbQuery = ResolvedModelClass.query();\n\n dbQuery.where(column, value);\n\n if (query) {\n await query({\n query: dbQuery,\n value,\n allValues: context.allValues,\n });\n }\n\n const document = await dbQuery.first();\n\n return document ? VALID_RULE : invalidRule(this, context);\n },\n};\n","import { get } from \"@mongez/reinforcements\";\nimport { invalidRule, VALID_RULE, type SchemaRule } from \"@warlock.js/seal\";\nimport { resolveModelClass } from \"../../model/register-model\";\nimport type { UniqueRuleOptions } from \"../types\";\n\n/**\n * Validates that a value is unique against a database column.\n *\n * Supports three exclusion modes:\n * - `except`: read a sibling input's value and exclude rows where that\n * column equals the sibling's value\n * - `exceptColumnName` + `exceptValue`: exclude rows where the named\n * column equals the supplied value (used by request-aware wrappers)\n * - Custom `query` callback for anything more involved\n *\n * @example\n * v.email().unique(\"User\");\n * v.string().unique(\"User\", { except: \"id\" });\n */\nexport const uniqueRule: SchemaRule<UniqueRuleOptions> = {\n name: \"unique\",\n defaultErrorMessage: \"The :input must be unique\",\n async validate(value: any, context) {\n const {\n Model,\n except,\n column = context.key,\n exceptColumnName,\n exceptValue,\n query,\n } = this.context.options;\n\n const ResolvedModelClass = resolveModelClass(Model);\n\n const dbQuery = ResolvedModelClass.query();\n\n dbQuery.where(column, value);\n\n if (except) {\n const exceptVal = get(context.allValues, except);\n\n if (exceptVal !== undefined) {\n dbQuery.where(except, \"!=\", exceptVal);\n }\n }\n\n if (exceptColumnName !== undefined) {\n dbQuery.where(exceptColumnName, \"!=\", exceptValue);\n }\n\n if (query) {\n await query({\n query: dbQuery,\n value,\n allValues: context.allValues,\n });\n }\n\n const document = await dbQuery.first();\n\n return document ? invalidRule(this, context) : VALID_RULE;\n },\n};\n","/**\n * Database Rules Plugin\n *\n * Injects the `.unique()` and `.exists()` method-chain entries onto Seal's\n * scalar validators. These are the Cascade-owned, DB-aware validation rules.\n *\n * Request-aware variants (`uniqueExceptCurrentUser`, etc.) live in\n * `@warlock.js/core` because they depend on the HTTP request store, which\n * Cascade has no business knowing about.\n */\n\nimport type { SealPlugin } from \"@warlock.js/seal\";\nimport { NumberValidator, ScalarValidator, StringValidator } from \"@warlock.js/seal\";\nimport type { ChildModel, Model } from \"../../model/model\";\nimport { existsRule } from \"../rules/exists-rule\";\nimport { uniqueRule } from \"../rules/unique-rule\";\nimport type { ExistsRuleOptions, UniqueRuleOptions } from \"../types\";\n\ndeclare module \"@warlock.js/seal\" {\n interface ScalarValidator {\n /** Value must be unique in database */\n unique(\n model: ChildModel<Model> | string,\n optionsList?: Partial<UniqueRuleOptions> & {\n errorMessage?: string;\n },\n ): this;\n\n /** Value must exist in database */\n exists(\n model: ChildModel<Model> | string,\n optionsList?: Partial<ExistsRuleOptions> & {\n errorMessage?: string;\n },\n ): this;\n }\n\n interface StringValidator {\n unique: ScalarValidator[\"unique\"];\n exists: ScalarValidator[\"exists\"];\n }\n\n interface NumberValidator {\n unique: ScalarValidator[\"unique\"];\n exists: ScalarValidator[\"exists\"];\n }\n}\n\n/**\n * Cascade's database-rules plugin for Seal.\n */\nexport const databaseRulesPlugin: SealPlugin = {\n name: \"cascade-database-rules\",\n version: \"1.0.0\",\n description: \"Adds unique() and exists() database validation methods to Seal scalar validators\",\n\n install() {\n Object.assign(ScalarValidator.prototype, {\n unique(\n this: ScalarValidator,\n model: ChildModel<Model> | string,\n optionsList?: Partial<UniqueRuleOptions> & {\n errorMessage?: string;\n },\n ) {\n const { errorMessage, ...options } = optionsList || {};\n\n return this.addRule(uniqueRule, errorMessage, {\n Model: model,\n ...options,\n });\n },\n\n exists(\n this: ScalarValidator,\n model: ChildModel<Model> | string,\n optionsList?: Partial<ExistsRuleOptions> & {\n errorMessage?: string;\n },\n ) {\n const { errorMessage, ...options } = optionsList || {};\n\n return this.addRule(existsRule, errorMessage, {\n Model: model,\n ...options,\n });\n },\n });\n\n Object.assign(StringValidator.prototype, {\n unique: ScalarValidator.prototype.unique,\n exists: ScalarValidator.prototype.exists,\n });\n\n Object.assign(NumberValidator.prototype, {\n unique: ScalarValidator.prototype.unique,\n exists: ScalarValidator.prototype.exists,\n });\n },\n};\n","import type { Mutator } from \"@warlock.js/seal\";\nimport { ChildModel, Model } from \"../../model/model\";\nimport { getModelFromRegistry } from \"../../model/register-model\";\n\ntype DatabaseModelMutatorOptions = {\n model: ChildModel<any> | string;\n};\n\nexport const databaseModelMutator: Mutator<DatabaseModelMutatorOptions> = async (\n value,\n context,\n) => {\n let { model: ModelClass } = context?.options || {};\n\n if (typeof ModelClass === \"string\") {\n ModelClass = getModelFromRegistry(ModelClass)!;\n }\n\n if (!ModelClass) {\n throw new Error(`Model ${ModelClass} not found in registry`);\n }\n\n if (value instanceof Model) return value;\n\n if (typeof value === \"object\" && value?.id) {\n value = Number(value.id);\n }\n\n if (typeof value !== \"number\") return value;\n\n return await ModelClass.find(value);\n};\n\nexport const databaseModelsMutator: Mutator<DatabaseModelMutatorOptions> = async (\n value,\n context,\n) => {\n if (!Array.isArray(value)) return value;\n\n let { model: ModelClass } = context?.options || {};\n\n if (typeof ModelClass === \"string\") {\n ModelClass = getModelFromRegistry(ModelClass)!;\n }\n\n if (!ModelClass) {\n throw new Error(`Model ${ModelClass} not found in registry`);\n }\n\n // first, if all values are list of models, then return them.\n if (value.every((item) => item instanceof Model)) return value;\n\n const ids = value.map((item) => item?.id || item).filter((item) => item !== undefined);\n\n return await ModelClass.query().whereIn(\"id\", ids).get();\n};\n","import { invalidRule, VALID_RULE, type SchemaRule } from \"@warlock.js/seal\";\r\nimport { ChildModel, Model } from \"./../../model/model\";\r\nimport { getModelFromRegistry } from \"./../../model/register-model\";\r\n\r\nexport const databaseModelRule: SchemaRule = {\r\n name: \"databaseModel\",\r\n defaultErrorMessage: \"The :input must be a valid :model model\",\r\n async validate(value, context) {\r\n if (value instanceof Model === false) {\r\n this.context.attributesList.model = this.context.options.model?.name;\r\n return invalidRule(this, context);\r\n }\r\n\r\n return VALID_RULE;\r\n },\r\n};\r\n\r\nexport const databaseModelsRule: SchemaRule<{ model: ChildModel<any> | string }> = {\r\n name: \"databaseModels\",\r\n defaultErrorMessage: \"The :input must be a list of valid :model\",\r\n async validate(value, context) {\r\n let { model } = this.context.options;\r\n if (typeof model === \"string\") {\r\n model = getModelFromRegistry(model)!;\r\n }\r\n\r\n this.context.attributesList.model = model.name;\r\n\r\n if (!Array.isArray(value)) return invalidRule(this, context);\r\n\r\n if (value.every((item) => item instanceof Model)) return VALID_RULE;\r\n\r\n return invalidRule(this, context);\r\n },\r\n};\r\n","import { type TransformerCallback } from \"@warlock.js/seal\";\nimport { Model } from \"../../model/model\";\n\nexport const databaseModelTransformer: TransformerCallback = (value, context) => {\n const embed = context.options.embed ?? \"embedData\";\n\n if (value instanceof Model === false && !Array.isArray(value)) {\n return value;\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => {\n if (typeof embed === \"string\") {\n return item[embed];\n }\n\n return item.only(embed);\n });\n }\n\n if (typeof embed === \"string\") {\n return (value as any)[embed];\n }\n\n return value.only(embed);\n};\n","import { arrayRule, BaseValidator } from \"@warlock.js/seal\";\nimport { Model, type ChildModel } from \"../../model/model\";\nimport { databaseModelMutator, databaseModelsMutator } from \"../mutators/embed-mutator\";\nimport { databaseModelRule, databaseModelsRule } from \"../rules/database-model-rule\";\nimport { databaseModelTransformer } from \"../transformers/embed-model-transformer\";\n\nexport class EmbedModelValidator extends BaseValidator {\n /**\n * Check if value is a string type\n */\n public matchesType(value: any): boolean {\n return (\n value instanceof Model ||\n typeof value === \"number\" ||\n (Array.isArray(value) && value.every((item) => item instanceof Model))\n );\n }\n\n /**\n * Mutate the value to be a model, also fail if the mutated value is not a valid model\n */\n public model(model: ChildModel<any> | string, errorMessage?: string): EmbedModelValidator {\n this.addMutator(databaseModelMutator, {\n model,\n });\n\n return this.addRule(databaseModelRule, errorMessage, {\n model,\n });\n }\n\n /**\n * Validate the value is a list of models\n */\n public models(model: ChildModel<any> | string, errorMessage?: string): EmbedModelValidator {\n const instance = this.instance;\n instance.addMutator(databaseModelsMutator, {\n model,\n });\n\n instance.addMutableRule(arrayRule);\n instance.addMutableRule(databaseModelsRule, errorMessage, {\n model,\n });\n\n return instance;\n }\n\n /**\n * Determine how the data will be stored as an embedded document\n */\n public embed(embed?: string | string[]): EmbedModelValidator {\n return this.addTransformer(databaseModelTransformer, {\n embed,\n });\n }\n}\n","/**\n * Embed Validator Plugin\n *\n * Adds embed validation to Seal v factory\n */\n\nimport type { SealPlugin } from \"@warlock.js/seal\";\nimport { v } from \"@warlock.js/seal\";\nimport type { ChildModel } from \"../../model/model\";\nimport { EmbedModelValidator } from \"../validators/embed-validator\";\n\ntype EmbedOptions = {\n errorMessage?: string;\n embed?: string | string[];\n};\n\ndeclare module \"@warlock.js/seal\" {\n interface ValidatorV {\n embed(model: ChildModel<any> | string, options?: EmbedOptions): EmbedModelValidator;\n embedMany(model: ChildModel<any> | string, options?: EmbedOptions): EmbedModelValidator;\n }\n}\n\n/**\n * File validation plugin for Seal\n */\nexport const embedValidator: SealPlugin = {\n name: \"embed\",\n version: \"1.0.0\",\n description: \"Adds embed validation (v.embed())\",\n\n install() {\n // Inject embed() method into v factory\n v.embed = (model: ChildModel<any> | string, options?: EmbedOptions) =>\n new EmbedModelValidator().model(model).embed(options?.embed);\n v.embedMany = (model: ChildModel<any> | string, options?: EmbedOptions) =>\n new EmbedModelValidator().models(model).embed(options?.embed);\n },\n};\n","import { registerPlugin } from \"@warlock.js/seal\";\nimport { databaseRulesPlugin } from \"./plugins/database-rules-plugin\";\nimport { embedValidator } from \"./plugins/embed-validator-plugin\";\n\nregisterPlugin(embedValidator);\nregisterPlugin(databaseRulesPlugin);\n\n/**\n * This file registers database seal plugins as a side effect.\n * Import this file to ensure the plugins are registered.\n *\n * @example\n * ```ts\n * import \"./validation/database-seal-plugins\";\n * ```\n */\nexport type DatabaseSealPlugins = typeof embedValidator | typeof databaseRulesPlugin;\n","import events from \"@mongez/events\";\r\nimport { getSealConfig, v, type ObjectValidator } from \"@warlock.js/seal\";\r\nimport type {\r\n DriverContract,\r\n InsertResult,\r\n UpdateOperations,\r\n UpdateResult,\r\n} from \"../contracts/database-driver.contract\";\r\nimport type {\r\n WriterContract,\r\n WriterOptions,\r\n WriterResult,\r\n} from \"../contracts/database-writer.contract\";\r\nimport type { ChildModel, Model } from \"../model/model\";\r\nimport { getModelUpdatedEvent } from \"../sync/model-events\";\r\nimport type { StrictMode } from \"../types\";\r\nimport { DatabaseWriterValidationError } from \"../validation\";\r\nimport type { DataSource } from \"./../data-source/data-source\";\r\n\r\n/**\r\n * Database writer service that orchestrates model persistence.\r\n *\r\n * Handles the complete save pipeline:\r\n * 1. Check for changes (skip if no changes and not new)\r\n * 2. Emit `saving` event (for data enrichment)\r\n * 3. Emit `validating` event\r\n * 4. Validate and cast data via @warlock.js/seal schema\r\n * 5. Emit `validated` event\r\n * 6. Generate ID (for new NoSQL records)\r\n * 7. Emit `creating`/`updating` events\r\n * 8. Execute insert or update via driver\r\n * 9. Merge returned data into model\r\n * 10. Reset dirty tracker and update `isNew` flag\r\n * 11. Emit `saved` and `created`/`updated` events\r\n *\r\n * @example\r\n * ```typescript\r\n * const user = new User({ name: \"Alice\", email: \"alice@example.com\" });\r\n * const writer = new DatabaseWriter(user);\r\n * await writer.save();\r\n *\r\n * console.log(user.get(\"id\")); // 1 (auto-generated)\r\n * console.log(user.get(\"_id\")); // ObjectId(\"...\")\r\n *\r\n * // Update existing record\r\n * user.set(\"name\", \"Alice Smith\");\r\n * await writer.save();\r\n * // Only updates the \"name\" field (partial update)\r\n *\r\n * // Silent save (no events)\r\n * await writer.save({ skipEvents: true });\r\n * ```\r\n */\r\nexport class DatabaseWriter implements WriterContract {\r\n /** The model instance being persisted */\r\n private readonly model: Model;\r\n\r\n /** Model constructor reference */\r\n private readonly ctor: ChildModel<Model>;\r\n\r\n /** Data source containing driver and ID generator */\r\n private readonly dataSource: DataSource;\r\n\r\n /** Database driver for executing queries */\r\n private readonly driver: DriverContract;\r\n\r\n /** Table/collection name */\r\n private readonly table: string;\r\n\r\n /** Primary key field name */\r\n private readonly primaryKey: string;\r\n\r\n /** Validation schema (if defined) */\r\n private readonly schema?: ObjectValidator;\r\n\r\n /** Strict mode configuration */\r\n private readonly strictMode: StrictMode;\r\n\r\n /**\r\n * Create a new writer instance for a model.\r\n *\r\n * @param model - The model instance to persist\r\n *\r\n * @example\r\n * ```typescript\r\n * const user = new User({ name: \"Alice\" });\r\n * const writer = new DatabaseWriter(user);\r\n * await writer.save();\r\n * ```\r\n */\r\n public constructor(model: Model) {\r\n this.model = model;\r\n this.ctor = model.constructor as ChildModel<Model>;\r\n this.dataSource = this.ctor.getDataSource();\r\n this.driver = this.dataSource.driver;\r\n this.table = this.ctor.table;\r\n this.primaryKey = this.ctor.primaryKey;\r\n this.schema = this.ctor.schema;\r\n this.strictMode = this.ctor.strictMode;\r\n }\r\n\r\n /**\r\n * Save the model instance to the database.\r\n *\r\n * @param options - Save options\r\n * @returns Result with success status, document, and metadata\r\n * @throws {ValidationError} If validation fails\r\n */\r\n public async save(options: WriterOptions = {}): Promise<WriterResult> {\r\n const isInsert = this.model.isNew;\r\n\r\n // 1. Check if model has changes (skip if no changes and not new)\r\n if (!isInsert && !this.model.hasChanges()) {\r\n return {\r\n success: true,\r\n document: this.model.data,\r\n isNew: false,\r\n modifiedCount: 0,\r\n };\r\n }\r\n\r\n // 2. Emit saving event (before validation for data enrichment)\r\n if (!options.skipEvents) {\r\n await this.model.emitEvent(\"saving\", {\r\n isInsert,\r\n options,\r\n mode: isInsert ? \"insert\" : \"update\",\r\n });\r\n }\r\n\r\n // 3. Validate and cast data\r\n await this.validateAndCast(isInsert, options);\r\n\r\n // 4. Execute insert or update\r\n let result: InsertResult | UpdateResult;\r\n\r\n if (isInsert) {\r\n result = await this.performInsert(options);\r\n } else {\r\n result = await this.performUpdate(options);\r\n }\r\n\r\n // 5. Reset dirty tracker and update isNew flag\r\n const changedFields = isInsert ? [] : this.model.getDirtyColumns();\r\n this.model.dirtyTracker.reset();\r\n this.model.isNew = false;\r\n\r\n // 6. Emit post-save events\r\n if (!options.skipEvents) {\r\n await this.model.emitEvent(\"saved\");\r\n await this.model.emitEvent(isInsert ? \"created\" : \"updated\");\r\n }\r\n\r\n // 7. Trigger sync operations (fire-and-forget, non-blocking)\r\n if (!options.skipSync && !isInsert) {\r\n void this.triggerSync(changedFields);\r\n }\r\n\r\n return {\r\n success: true,\r\n document: this.model.data,\r\n isNew: isInsert,\r\n modifiedCount: isInsert ? undefined : (result as UpdateResult).modifiedCount,\r\n };\r\n }\r\n\r\n /**\r\n * Validate and cast model data using the schema.\r\n *\r\n * Updates the model's data in-place with validated/casted values.\r\n *\r\n * @param isInsert - Whether this is an insert operation\r\n * @param options - Save options\r\n * @throws {ValidationError} If validation fails\r\n * @private\r\n */\r\n private async validateAndCast(isInsert: boolean, options: WriterOptions): Promise<void> {\r\n // Emit validating event\r\n if (!options.skipEvents) {\r\n await this.model.emitEvent(\"validating\", {\r\n isInsert,\r\n options,\r\n mode: isInsert ? \"insert\" : \"update\",\r\n });\r\n }\r\n\r\n // Skip validation if requested or no schema defined\r\n if (options.skipValidation || !this.schema) {\r\n return;\r\n }\r\n\r\n // Clone schema for partial data (updates only)\r\n const validationSchema = isInsert\r\n ? this.schema.clone()\r\n : this.schema.clone(Object.keys(this.model.data)).extend({\r\n id: v.scalar().optional(),\r\n _id: v.any().optional(),\r\n [this.ctor.createdAtColumn as string]: v.date().optional(),\r\n [this.ctor.updatedAtColumn as string]: v.date().optional(),\r\n });\r\n\r\n // Apply strict mode\r\n if (this.strictMode === \"strip\") {\r\n validationSchema.stripUnknown();\r\n } else if (this.strictMode === \"fail\") {\r\n validationSchema.allowUnknown(false);\r\n } else if (this.strictMode === \"allow\") {\r\n validationSchema.allowUnknown(true);\r\n }\r\n\r\n // Run validation\r\n const result = await v.validate(validationSchema, this.model.data, {\r\n context: {\r\n model: this.model,\r\n },\r\n ...getSealConfig(),\r\n });\r\n\r\n if (!result.isValid) {\r\n console.trace(result.errors);\r\n\r\n const error = new DatabaseWriterValidationError(\r\n `[${this.model.constructor.name} Model] ${isInsert ? \"Insert\" : \"Update\"} Validation failed`,\r\n result.errors,\r\n );\r\n if (!options.skipEvents) {\r\n await this.model.emitEvent(\"validated\", { result, error });\r\n }\r\n throw error;\r\n }\r\n\r\n // Update model data with validated/casted data\r\n this.model.replaceData(result.data);\r\n\r\n // Emit validated event\r\n if (!options.skipEvents) {\r\n await this.model.emitEvent(\"validated\", { result });\r\n }\r\n }\r\n\r\n /**\r\n * Perform an insert operation.\r\n *\r\n * @param options - Save options\r\n * @returns Insert result\r\n * @private\r\n */\r\n private async performInsert(options: WriterOptions): Promise<InsertResult> {\r\n // Generate ID if needed (NoSQL only)\r\n await this.generateNextId();\r\n\r\n // Get data to insert (already validated and casted)\r\n const dataToInsert = this.model.data;\r\n\r\n // Add createdAt and updatedAt to the data (using resolved column names)\r\n // The column names are already resolved through the hierarchy:\r\n // Model static property > Database config > Driver defaults > undefined\r\n const createdAtColumn = this.ctor.createdAtColumn;\r\n\r\n if (createdAtColumn) {\r\n dataToInsert[createdAtColumn] = new Date();\r\n }\r\n\r\n const updatedAtColumn = this.ctor.updatedAtColumn;\r\n if (updatedAtColumn) {\r\n dataToInsert[updatedAtColumn] = new Date();\r\n }\r\n\r\n // Emit creating event\r\n if (!options.skipEvents) {\r\n await this.model.emitEvent(\"creating\");\r\n }\r\n\r\n // INSERT: use full validated data\r\n const result = await this.driver.insert(this.table, dataToInsert);\r\n\r\n // Merge returned data (e.g., generated _id, timestamps)\r\n // Note: We use merge here because the result might not include all fields\r\n // (e.g., our generated 'id' field), and we don't want to lose them\r\n this.model.merge(result.document as Record<string, unknown>);\r\n\r\n // Reset dirty tracker immediately after merge to prevent\r\n // database-generated fields (like _id) from being marked as dirty\r\n this.model.dirtyTracker.reset();\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Perform an update operation.\r\n *\r\n * @param options - Save options\r\n * @returns Update result\r\n * @private\r\n */\r\n private async performUpdate(options: WriterOptions): Promise<UpdateResult> {\r\n // Emit updating event\r\n if (!options.skipEvents) {\r\n await this.model.emitEvent(\"updating\");\r\n }\r\n\r\n // Update the updatedAt timestamp (using resolved column name)\r\n const updatedAtColumn = this.ctor.updatedAtColumn;\r\n if (updatedAtColumn) {\r\n this.model.set(updatedAtColumn, new Date());\r\n }\r\n\r\n if (options.replace) {\r\n const document = await this.driver.replace(\r\n this.table,\r\n {\r\n [this.primaryKey]: this.model.get(this.primaryKey),\r\n },\r\n this.model.data,\r\n );\r\n\r\n if (document) {\r\n this.model.replaceData(document as Record<string, unknown>);\r\n }\r\n\r\n return { modifiedCount: document ? 1 : 0 };\r\n }\r\n\r\n // Build operations from dirty tracker\r\n const operations = this.buildUpdateOperations();\r\n\r\n // Build filter using primary key\r\n const filter = { [this.primaryKey]: this.model.get(this.primaryKey) };\r\n\r\n // Execute update with operations\r\n return await this.driver.update(this.table, filter, operations);\r\n }\r\n\r\n /**\r\n * Generate ID for the model if auto-generation is enabled.\r\n *\r\n * @private\r\n */\r\n public async generateNextId(): Promise<void> {\r\n if (!this.ctor.autoGenerateId || this.model.get(\"id\")) {\r\n return;\r\n }\r\n\r\n const idGenerator = this.dataSource.idGenerator;\r\n if (!idGenerator) {\r\n return;\r\n }\r\n\r\n // Resolve ID generation options from model configuration\r\n const initialId = this.resolveInitialId();\r\n\r\n const incrementIdBy = this.resolveIncrementBy();\r\n\r\n const id = await idGenerator.generateNextId({\r\n table: this.table,\r\n initialId,\r\n incrementIdBy,\r\n });\r\n\r\n this.model.set(\"id\", id);\r\n }\r\n\r\n /**\r\n * Build update operations from the model's dirty tracker.\r\n *\r\n * Handles both modified fields ($set) and removed fields ($unset).\r\n *\r\n * @returns Update operations for the driver\r\n * @private\r\n *\r\n * @example\r\n * ```typescript\r\n * // Model with changes\r\n * user.set(\"name\", \"Alice\");\r\n * user.unset(\"tempField\");\r\n *\r\n * const operations = this.buildUpdateOperations();\r\n * // {\r\n * // $set: { name: \"Alice\" },\r\n * // $unset: { tempField: 1 }\r\n * // }\r\n * ```\r\n */\r\n private buildUpdateOperations(): UpdateOperations {\r\n const operations: UpdateOperations = {};\r\n\r\n // Get dirty columns (modified fields)\r\n const dirtyColumns = this.model.getDirtyColumns();\r\n\r\n if (dirtyColumns.length > 0) {\r\n operations.$set = {};\r\n for (const column of dirtyColumns) {\r\n const value = this.model.get(column);\r\n if (value === undefined) continue;\r\n\r\n operations.$set[column] = this.model.get(column);\r\n }\r\n }\r\n\r\n // Get removed columns\r\n const removedColumns = this.model.getRemovedColumns();\r\n if (removedColumns.length > 0) {\r\n operations.$unset = {};\r\n for (const column of removedColumns) {\r\n operations.$unset[column] = 1;\r\n }\r\n }\r\n\r\n return operations;\r\n }\r\n\r\n /**\r\n * Resolve the initial ID from model configuration.\r\n *\r\n * Priority:\r\n * 1. Model.initialId (explicit value)\r\n * 2. Model.randomInitialId (random or function)\r\n * 3. Default: 1\r\n *\r\n * @returns The initial ID value\r\n * @private\r\n */\r\n private resolveInitialId(): number {\r\n if (this.ctor.initialId) {\r\n return this.ctor.initialId;\r\n }\r\n\r\n if (this.ctor.randomInitialId) {\r\n return typeof this.ctor.randomInitialId === \"function\"\r\n ? this.ctor.randomInitialId()\r\n : this.randomInt(10000, 499999);\r\n }\r\n\r\n return 1; // Default initial ID\r\n }\r\n\r\n /**\r\n * Resolve the increment value from model configuration.\r\n *\r\n * Priority:\r\n * 1. Model.incrementIdBy (explicit value)\r\n * 2. Model.randomIncrement (random or function)\r\n * 3. Default: 1\r\n *\r\n * @returns The increment value\r\n * @private\r\n */\r\n private resolveIncrementBy(): number {\r\n if (this.ctor.incrementIdBy) {\r\n return this.ctor.incrementIdBy;\r\n }\r\n\r\n if (this.ctor.randomIncrement) {\r\n return typeof this.ctor.randomIncrement === \"function\"\r\n ? this.ctor.randomIncrement()\r\n : this.randomInt(1, 10);\r\n }\r\n\r\n return 1; // Default increment\r\n }\r\n\r\n /**\r\n * Generate a random integer between min and max (inclusive).\r\n *\r\n * @param min - Minimum value\r\n * @param max - Maximum value\r\n * @returns Random integer\r\n * @private\r\n */\r\n private randomInt(min: number, max: number): number {\r\n return Math.floor(Math.random() * (max - min + 1)) + min;\r\n }\r\n\r\n /**\r\n * Trigger sync operations after successful save.\r\n *\r\n * Emits a model.updated event that ModelSyncOperation listens to.\r\n * The sync is handled by registered sync operations, not directly here.\r\n *\r\n * @param changedFields - Fields that were changed (for filtering)\r\n * @private\r\n */\r\n private async triggerSync(changedFields: string[]): Promise<void> {\r\n // Emit model.updated event - ModelSyncOperation listens to these\r\n await events.triggerAll(getModelUpdatedEvent(this.ctor), this.model, changedFields);\r\n }\r\n}\r\n","import { DatabaseWriter } from \"../../writer/database-writer\";\nimport type { Model } from \"../model\";\n\nexport function applyDefaultsToModel(ModelClass: any, defaults: any): void {\n // Only apply defaults if model doesn't have its own value\n\n // ============================================================================\n // ID Generation\n // ============================================================================\n if (defaults.autoGenerateId !== undefined && ModelClass.autoGenerateId === undefined) {\n ModelClass.autoGenerateId = defaults.autoGenerateId;\n }\n if (defaults.initialId !== undefined && ModelClass.initialId === undefined) {\n ModelClass.initialId = defaults.initialId;\n }\n if (defaults.randomInitialId !== undefined && ModelClass.randomInitialId === undefined) {\n ModelClass.randomInitialId = defaults.randomInitialId;\n }\n if (defaults.incrementIdBy !== undefined && ModelClass.incrementIdBy === undefined) {\n ModelClass.incrementIdBy = defaults.incrementIdBy;\n }\n if (defaults.randomIncrement !== undefined && ModelClass.randomIncrement === undefined) {\n ModelClass.randomIncrement = defaults.randomIncrement;\n }\n\n // ============================================================================\n // Timestamps\n // ============================================================================\n if (defaults.createdAtColumn !== undefined && ModelClass.createdAtColumn === undefined) {\n ModelClass.createdAtColumn = defaults.createdAtColumn;\n }\n\n if (defaults.updatedAtColumn !== undefined && ModelClass.updatedAtColumn === undefined) {\n ModelClass.updatedAtColumn = defaults.updatedAtColumn;\n }\n\n // ============================================================================\n // Deletion\n // ============================================================================\n if (defaults.deleteStrategy !== undefined && ModelClass.deleteStrategy === undefined) {\n ModelClass.deleteStrategy = defaults.deleteStrategy;\n }\n if (defaults.deletedAtColumn !== undefined && ModelClass.deletedAtColumn === undefined) {\n ModelClass.deletedAtColumn = defaults.deletedAtColumn;\n }\n if (defaults.trashTable !== undefined && ModelClass.trashTable === undefined) {\n // Handle function-based trash table\n if (typeof defaults.trashTable === \"function\") {\n ModelClass.trashTable = defaults.trashTable(ModelClass.table);\n } else {\n ModelClass.trashTable = defaults.trashTable;\n }\n }\n\n // ============================================================================\n // Validation\n // ============================================================================\n if (defaults.strictMode !== undefined && ModelClass.strictMode === undefined) {\n ModelClass.strictMode = defaults.strictMode;\n }\n}\n\nexport async function generateModelNextId(model: Model): Promise<number | string> {\n const writer = new DatabaseWriter(model);\n await writer.generateNextId();\n return model.id!;\n}\n\nexport async function performAtomicUpdate(\n model: Model,\n operations: Record<string, unknown>,\n): Promise<number> {\n return model.self().atomic({ id: model.id! }, operations);\n}\n\nexport async function performAtomicIncrement<T extends string>(\n model: Model,\n field: T,\n amount = 1,\n): Promise<number> {\n model.increment(field, amount);\n return performAtomicUpdate(model, {\n $inc: {\n [field]: amount,\n },\n });\n}\n\nexport async function performAtomicDecrement<T extends string>(\n model: Model,\n field: T,\n amount = 1,\n): Promise<number> {\n model.decrement(field, amount);\n return performAtomicUpdate(model, {\n $inc: {\n [field]: -amount,\n },\n });\n}\n","/**\n * @fileoverview Pivot table operations for many-to-many relationships.\n *\n * This module provides methods for managing the pivot table in\n * belongsToMany relationships: attach, detach, sync, and toggle.\n *\n * @module @warlock.js/cascade/relations/pivot-operations\n */\n\nimport type { ChildModel, Model } from \"../model/model\";\nimport { resolveModelClass, resolveModelName } from \"../model/register-model\";\nimport { inferPivotKey, inferPivotTable } from \"./key-conventions\";\nimport type { PivotData, PivotIds, RelationDefinition } from \"./types\";\n\n// ============================================================================\n// PIVOT OPERATIONS CLASS\n// ============================================================================\n\n/**\n * Manages pivot table operations for many-to-many relationships.\n *\n * Provides attach, detach, sync, and toggle operations for managing\n * the connections between two models through a pivot table.\n *\n * @example\n * ```typescript\n * const pivotOps = new PivotOperations(post, \"tags\", tagsDefinition);\n *\n * // Attach tags\n * await pivotOps.attach([1, 2, 3]);\n *\n * // Attach with pivot data\n * await pivotOps.attach([4], { addedBy: userId });\n *\n * // Detach specific tags\n * await pivotOps.detach([2]);\n *\n * // Sync (replace all)\n * await pivotOps.sync([1, 5, 6]);\n *\n * // Toggle (attach if missing, detach if present)\n * await pivotOps.toggle([1, 7]);\n * ```\n */\nexport class PivotOperations {\n // ==========================================================================\n // PRIVATE PROPERTIES\n // ==========================================================================\n\n /**\n * The model instance performing the pivot operation.\n */\n private readonly model: Model;\n\n /**\n * The name of the relation.\n */\n private readonly relationName: string;\n\n /**\n * The relation definition with pivot table configuration.\n */\n private readonly definition: RelationDefinition;\n\n /**\n * The model class of the source model.\n */\n private readonly modelClass: ChildModel<Model>;\n\n // ==========================================================================\n // CONSTRUCTOR\n // ==========================================================================\n\n /**\n * Creates a new PivotOperations instance.\n *\n * @param model - The model instance performing the operation\n * @param relationName - The name of the belongsToMany relation\n * @param definition - The relation definition\n * @param modelClass - The model class constructor\n */\n public constructor(\n model: Model,\n relationName: string,\n definition: RelationDefinition,\n modelClass: ChildModel<Model>,\n ) {\n if (definition.type !== \"belongsToMany\") {\n throw new Error(\n `Pivot operations are only available for belongsToMany relations. ` +\n `Relation \"${relationName}\" is of type \"${definition.type}\".`,\n );\n }\n\n this.model = model;\n this.relationName = relationName;\n this.definition = definition;\n this.modelClass = modelClass;\n }\n\n /**\n * Read the configured relation conventions from this pivot's owning\n * data source. Returns `undefined` when no overrides are set.\n */\n private get relationDefaults() {\n try {\n return this.modelClass.getDataSource()?.relationDefaults;\n } catch {\n return undefined;\n }\n }\n\n // ==========================================================================\n // PUBLIC METHODS\n // ==========================================================================\n\n /**\n * Attaches one or more related models via the pivot table.\n *\n * Creates new records in the pivot table linking this model to the\n * specified related model IDs. Existing attachments are not duplicated.\n *\n * @param ids - The IDs of the related models to attach\n * @param pivotData - Optional additional data to store in the pivot record\n *\n * @example\n * ```typescript\n * // Attach tags to a post\n * await post.attach(\"tags\", [1, 2, 3]);\n *\n * // Attach with additional pivot data\n * await post.attach(\"tags\", [4], { addedBy: currentUserId });\n * ```\n */\n public async attach(ids: PivotIds, pivotData?: PivotData): Promise<void> {\n if (ids.length === 0) return;\n\n const { pivotTable, localKeyValue, pivotLocalKey, pivotForeignKey } = this.getPivotConfig();\n\n // Get existing attachments to avoid duplicates\n const existingIds = await this.getExistingPivotIds();\n const newIds = ids.filter((id) => !existingIds.has(id));\n\n if (newIds.length === 0) return;\n\n // Create pivot records\n const records = newIds.map((id) => ({\n [pivotLocalKey]: localKeyValue,\n [pivotForeignKey]: id,\n ...pivotData,\n }));\n\n const dataSource = this.modelClass.getDataSource();\n await dataSource.driver.insertMany(pivotTable, records);\n }\n\n /**\n * Detaches one or more related models from the pivot table.\n *\n * Removes records from the pivot table. If no IDs are specified,\n * all attachments for this model are removed.\n *\n * @param ids - Optional IDs to detach. If omitted, detaches all.\n *\n * @example\n * ```typescript\n * // Detach specific tags\n * await post.detach(\"tags\", [2, 3]);\n *\n * // Detach all tags\n * await post.detach(\"tags\");\n * ```\n */\n public async detach(ids?: PivotIds): Promise<void> {\n const { pivotTable, localKeyValue, pivotLocalKey, pivotForeignKey } = this.getPivotConfig();\n\n const dataSource = this.modelClass.getDataSource();\n\n // Build filter based on local key and optionally foreign keys\n const filter: Record<string, unknown> = { [pivotLocalKey]: localKeyValue };\n\n if (ids && ids.length > 0) {\n // Use $in operator style for filtering by multiple IDs\n filter[pivotForeignKey] = { $in: ids };\n }\n\n await dataSource.driver.deleteMany(pivotTable, filter);\n }\n\n /**\n * Synchronizes the pivot table to match the specified IDs.\n *\n * Attaches any new IDs and detaches any IDs not in the list.\n * After sync, the pivot table will contain exactly the specified IDs.\n *\n * @param ids - The IDs that should be attached after sync\n * @param pivotData - Optional data for newly attached records\n *\n * @example\n * ```typescript\n * // Set tags to exactly [1, 3, 5], removing any others\n * await post.sync(\"tags\", [1, 3, 5]);\n * ```\n */\n public async sync(ids: PivotIds, pivotData?: PivotData): Promise<void> {\n const existingIds = await this.getExistingPivotIds();\n const newIdSet = new Set(ids);\n\n // Find IDs to detach (in existing but not in new)\n const toDetach: PivotIds = [];\n for (const existingId of existingIds) {\n if (!newIdSet.has(existingId)) {\n toDetach.push(existingId);\n }\n }\n\n // Find IDs to attach (in new but not in existing)\n const toAttach = ids.filter((id) => !existingIds.has(id));\n\n // Perform operations\n if (toDetach.length > 0) {\n await this.detach(toDetach);\n }\n\n if (toAttach.length > 0) {\n await this.attach(toAttach, pivotData);\n }\n }\n\n /**\n * Toggles the attachment status of the specified IDs.\n *\n * For each ID: if attached, detaches it; if not attached, attaches it.\n *\n * @param ids - The IDs to toggle\n * @param pivotData - Optional data for newly attached records\n *\n * @example\n * ```typescript\n * // Toggle tags - attached become detached, detached become attached\n * await post.toggle(\"tags\", [1, 4]);\n * ```\n */\n public async toggle(ids: PivotIds, pivotData?: PivotData): Promise<void> {\n if (ids.length === 0) return;\n\n const existingIds = await this.getExistingPivotIds();\n\n const toAttach: PivotIds = [];\n const toDetach: PivotIds = [];\n\n for (const id of ids) {\n if (existingIds.has(id)) {\n toDetach.push(id);\n } else {\n toAttach.push(id);\n }\n }\n\n if (toDetach.length > 0) {\n await this.detach(toDetach);\n }\n\n if (toAttach.length > 0) {\n await this.attach(toAttach, pivotData);\n }\n }\n\n // ==========================================================================\n // PRIVATE METHODS\n // ==========================================================================\n\n /**\n * Gets the pivot table configuration.\n *\n * @returns The pivot configuration object\n */\n private getPivotConfig(): {\n pivotTable: string;\n localKeyValue: unknown;\n pivotLocalKey: string;\n pivotForeignKey: string;\n relatedKey: string;\n } {\n const conventions = this.relationDefaults;\n const relatedModelName = resolveModelName(this.definition.model);\n const pivotTable =\n this.definition.pivot ??\n inferPivotTable(this.modelClass.name, relatedModelName, conventions);\n const RelatedModel = resolveModelClass(this.definition.model);\n const localKey = this.definition.pivotLocalKey ?? this.modelClass.primaryKey ?? \"id\";\n const pivotLocalKey =\n this.definition.localKey ?? inferPivotKey(this.modelClass.name, conventions);\n const pivotForeignKey =\n this.definition.foreignKey ?? inferPivotKey(relatedModelName, conventions);\n const relatedKey = this.definition.pivotForeignKey ?? RelatedModel?.primaryKey ?? \"id\";\n const localKeyValue = this.model.get(localKey);\n\n return {\n pivotTable,\n localKeyValue,\n pivotLocalKey,\n pivotForeignKey,\n relatedKey,\n };\n }\n\n /**\n * Gets all currently attached IDs from the pivot table.\n *\n * @returns A set of attached foreign key values\n */\n private async getExistingPivotIds(): Promise<Set<number | string>> {\n const { pivotTable, localKeyValue, pivotLocalKey, pivotForeignKey } = this.getPivotConfig();\n\n const dataSource = this.modelClass.getDataSource();\n const records = await dataSource.driver\n .queryBuilder(pivotTable)\n .select([pivotForeignKey])\n .where(pivotLocalKey, localKeyValue)\n .get();\n\n const ids = new Set<number | string>();\n for (const record of records as Record<string, unknown>[]) {\n const id = record[pivotForeignKey];\n if (id !== undefined && id !== null) {\n ids.add(id as number | string);\n }\n }\n\n return ids;\n }\n\n}\n\n// ============================================================================\n// FACTORY FUNCTION\n// ============================================================================\n\n/**\n * Creates a PivotOperations instance for a model and relation.\n *\n * @param model - The model instance\n * @param relationName - The name of the belongsToMany relation\n * @returns A PivotOperations instance\n * @throws Error if the relation is not a belongsToMany or not defined\n */\nexport function createPivotOperations(model: Model, relationName: string): PivotOperations {\n const ModelClass = model.constructor as ChildModel<Model>;\n const relations = (ModelClass as unknown as { relations?: Record<string, RelationDefinition> })\n .relations;\n\n if (!relations || !relations[relationName]) {\n throw new Error(`Relation \"${relationName}\" is not defined on model \"${ModelClass.name}\".`);\n }\n\n return new PivotOperations(model, relationName, relations[relationName], ModelClass);\n}\n","import { createPivotOperations, type PivotOperations } from \"../../relations/pivot-operations\";\nimport type { PivotData, PivotIds } from \"../../relations/types\";\nimport type { Model } from \"../model\";\n\n/**\n * Get the pivot-operations handle for a `belongsToMany` relation.\n *\n * Returns the `PivotOperations` object exposing `attach` / `detach` /\n * `sync` / `toggle` for the named relation's pivot table.\n *\n * @throws Error if the relation is not a belongsToMany relation.\n *\n * @example\n * await post.pivot(\"tags\").attach([1, 2, 3]);\n * await post.pivot(\"tags\").sync([1, 3, 5]);\n * await post.pivot(\"tags\").toggle([1, 7]);\n */\nexport function pivotRelation(model: Model, relation: string): PivotOperations {\n return createPivotOperations(model, relation);\n}\n\n/**\n * Attach one or more related records to a belongsToMany pivot table.\n *\n * @throws Error if the relation is not a belongsToMany relation.\n *\n * @example\n * await post.attach(\"tags\", [1, 2, 3]);\n * await post.attach(\"tags\", [4], { addedBy: currentUserId });\n */\nexport async function attachPivotRelation(\n model: Model,\n relation: string,\n ids: PivotIds,\n pivotData?: PivotData,\n): Promise<void> {\n return createPivotOperations(model, relation).attach(ids, pivotData);\n}\n\n/**\n * Detach related records from a belongsToMany pivot table. Omit `ids` to\n * detach every row for this side of the relation.\n *\n * @throws Error if the relation is not a belongsToMany relation.\n *\n * @example\n * await post.detach(\"tags\", [2]);\n * await post.detach(\"tags\"); // detach all\n */\nexport async function detachPivotRelation(\n model: Model,\n relation: string,\n ids?: PivotIds,\n): Promise<void> {\n return createPivotOperations(model, relation).detach(ids);\n}\n","import type {\r\n PaginationOptions,\r\n PaginationResult,\r\n QueryBuilderContract,\r\n UpdateOperations,\r\n} from \"../../contracts\";\r\nimport type { DataSource } from \"../../data-source/data-source\";\r\nimport { dataSourceRegistry } from \"../../data-source/data-source-registry\";\r\nimport type { ChildModel, GlobalScopeDefinition, Model } from \"../model\";\r\n\r\nexport function buildQuery<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n BaseModel: typeof Model,\r\n): QueryBuilderContract<TModel> {\r\n const queryBuilder = ModelClass.newQueryBuilder<TModel>();\r\n const qb = queryBuilder;\r\n\r\n // Collect global scopes from base Model and child model\r\n const allGlobalScopes = new Map<string, GlobalScopeDefinition>([\r\n ...BaseModel.globalScopes,\r\n ...ModelClass.globalScopes,\r\n ]);\r\n\r\n queryBuilder.pendingGlobalScopes = allGlobalScopes;\r\n queryBuilder.availableLocalScopes = ModelClass.localScopes;\r\n queryBuilder.disabledGlobalScopes = new Set();\r\n queryBuilder.relationDefinitions = ModelClass.relations;\r\n queryBuilder.modelClass = ModelClass;\r\n\r\n ModelClass.events().emitFetching(queryBuilder, {\r\n table: ModelClass.table,\r\n modelClass: ModelClass,\r\n });\r\n\r\n queryBuilder.hydrate((data: any) => {\r\n return ModelClass.hydrate(data);\r\n });\r\n\r\n // Eager-loading runs inside the driver's `get()` so it works for any\r\n // builder construction path (Model.query, Model.newQueryBuilder, custom\r\n // subclassed builders). This hook only handles the model-level `fetched`\r\n // event emission.\r\n queryBuilder.onFetched(async (models: any[]) => {\r\n await ModelClass.events().emit(\"fetched\", models as any, {});\r\n });\r\n\r\n return queryBuilder;\r\n}\r\n\r\nexport function buildNewQueryBuilder<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n): QueryBuilderContract<TModel> {\r\n const dataSource = ModelClass.getDataSource();\r\n\r\n if (ModelClass.builder) {\r\n const BuilderClass = ModelClass.builder;\r\n return new BuilderClass(ModelClass.table, dataSource) as QueryBuilderContract<TModel>;\r\n }\r\n\r\n const queryBuilder = dataSource.driver.queryBuilder<TModel>(ModelClass.table);\r\n return queryBuilder;\r\n}\r\n\r\nexport async function findFirst<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n filter?: Record<string, unknown>,\r\n): Promise<TModel | null> {\r\n const query = ModelClass.query();\r\n if (filter) {\r\n query.where(filter);\r\n }\r\n return query.first();\r\n}\r\n\r\nexport async function findLast<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n filter?: Record<string, unknown>,\r\n): Promise<TModel | null> {\r\n const query = ModelClass.query();\r\n if (filter) {\r\n query.where(filter);\r\n }\r\n\r\n return query.last();\r\n}\r\n\r\nexport async function findAll<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n filter?: Record<string, unknown>,\r\n): Promise<TModel[]> {\r\n const query = ModelClass.query();\r\n if (filter) {\r\n query.where(filter);\r\n }\r\n return query.get();\r\n}\r\n\r\nexport function countRecords<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n filter?: Record<string, unknown>,\r\n): Promise<number> {\r\n const query = ModelClass.query();\r\n if (filter) {\r\n query.where(filter);\r\n }\r\n return query.count();\r\n}\r\n\r\nexport async function findById<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n id: string | number,\r\n): Promise<TModel | null> {\r\n const query = ModelClass.query();\r\n return query.where(ModelClass.primaryKey, id).first();\r\n}\r\n\r\nexport async function paginateRecords<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n options: PaginationOptions & { filter?: Record<string, unknown> } = {},\r\n): Promise<PaginationResult<TModel>> {\r\n const query = ModelClass.query();\r\n if (options.filter) {\r\n query.where(options.filter);\r\n }\r\n\r\n return query.paginate({\r\n limit: options.limit,\r\n page: options.page,\r\n });\r\n}\r\n\r\nexport async function findLatest<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n filter?: Record<string, unknown>,\r\n): Promise<TModel[]> {\r\n const query = ModelClass.query();\r\n if (filter) {\r\n query.where(filter);\r\n }\r\n return (await query.latest()) as unknown as TModel[];\r\n}\r\n\r\nexport function increaseField<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n filter: Record<string, unknown>,\r\n field: string,\r\n amount: number,\r\n): Promise<number> {\r\n const query = ModelClass.query().where(filter);\r\n return query.increment(field, amount);\r\n}\r\n\r\nexport function decreaseField<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n filter: Record<string, unknown>,\r\n field: string,\r\n amount: number,\r\n): Promise<number> {\r\n const query = ModelClass.query().where(filter);\r\n return query.decrement(field, amount);\r\n}\r\n\r\nexport async function performAtomic<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n filter: Record<string, unknown>,\r\n operations: UpdateOperations,\r\n): Promise<number> {\r\n const result = await ModelClass.getDriver().atomic(ModelClass.table, filter, operations);\r\n return result.modifiedCount;\r\n}\r\n\r\nexport async function updateById<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n id: string | number,\r\n data: Record<string, unknown>,\r\n): Promise<number> {\r\n const result = await ModelClass.getDriver().update(ModelClass.table, { [ModelClass.primaryKey]: id }, { $set: data });\r\n return result.modifiedCount;\r\n}\r\n\r\nexport async function findAndUpdateRecords<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n filter: Record<string, unknown>,\r\n update: UpdateOperations,\r\n): Promise<TModel[]> {\r\n await performAtomic(ModelClass, filter, update);\r\n return await ModelClass.query().where(filter).get();\r\n}\r\n\r\nexport async function findOneAndUpdateRecord<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n filter: Record<string, unknown>,\r\n update: UpdateOperations,\r\n): Promise<TModel | null> {\r\n const result = await ModelClass.getDriver().findOneAndUpdate(ModelClass.table, filter, update);\r\n if (!result) return null;\r\n const ctor = ModelClass as any;\r\n return new ctor(result);\r\n}\r\n\r\nexport async function findAndReplaceRecord<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n filter: Record<string, unknown>,\r\n document: Record<string, unknown>,\r\n): Promise<TModel | null> {\r\n const result = await ModelClass.getDriver().replace(ModelClass.table, filter, document);\r\n if (!result) return null;\r\n const ctor = ModelClass as any;\r\n return new ctor(result);\r\n}\r\n\r\nexport async function findOneAndDeleteRecord<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n filter: Record<string, unknown>,\r\n options?: Record<string, unknown>,\r\n): Promise<TModel | null> {\r\n const driver = ModelClass.getDriver();\r\n const result = await driver.findOneAndDelete(ModelClass.table, filter, options);\r\n\r\n if (!result) {\r\n return null;\r\n }\r\n\r\n const model = ModelClass.hydrate(result as Record<string, unknown>);\r\n model.dirtyTracker.reset();\r\n return model;\r\n}\r\n\r\nexport function resolveDataSource<TModel extends Model>(\r\n ModelClass: ChildModel<TModel>,\r\n): DataSource {\r\n const ref = ModelClass.dataSource;\r\n let dataSource: DataSource;\r\n\r\n if (typeof ref === \"string\") {\r\n dataSource = dataSourceRegistry.get(ref);\r\n } else if (ref) {\r\n dataSource = ref;\r\n } else {\r\n dataSource = dataSourceRegistry.get();\r\n }\r\n\r\n if (!ModelClass.hasOwnProperty(\"_defaultsApplied\")) {\r\n const driverDefaults = dataSource.driver.modelDefaults || {};\r\n const dataSourceDefaults = dataSource.modelDefaults || {};\r\n\r\n const mergedDefaults = {\r\n ...driverDefaults,\r\n ...dataSourceDefaults,\r\n };\r\n\r\n if (Object.keys(mergedDefaults).length > 0) {\r\n (ModelClass as any).applyModelDefaults(mergedDefaults);\r\n }\r\n\r\n (ModelClass as any)._defaultsApplied = true;\r\n }\r\n\r\n return dataSource;\r\n}\r\n","import type { DriverContract, UpdateOperations } from \"../contracts/database-driver.contract\";\nimport type {\n RestorerContract,\n RestorerOptions,\n RestorerResult,\n} from \"../contracts/database-restorer.contract\";\nimport type { DataSource } from \"../data-source/data-source\";\nimport type { Model } from \"../model/model\";\nimport type { DeleteStrategy } from \"../types\";\n\n/**\n * Database restorer service that orchestrates model restoration.\n *\n * Handles the complete restoration pipeline:\n * 1. Strategy detection (trash vs soft delete)\n * 2. Record retrieval from trash table or soft-deleted records\n * 3. ID conflict resolution\n * 4. Event emission (restoring, restored)\n * 5. Driver execution (insert back to original table, remove from trash/clear deletedAt)\n *\n * @example\n * ```typescript\n * const restorer = new DatabaseRestorer(User);\n * const result = await restorer.restore(123);\n *\n * console.log(result.success); // true\n * console.log(result.strategy); // \"trash\" | \"soft\"\n * ```\n */\nexport class DatabaseRestorer implements RestorerContract {\n /** Model constructor reference */\n private readonly ctor: typeof Model;\n\n /** Data source containing driver */\n private readonly dataSource: DataSource;\n\n /** Database driver for executing queries */\n private readonly driver: DriverContract;\n\n /** Table/collection name */\n private readonly table: string;\n\n /** Primary key field name */\n private readonly primaryKey: string;\n\n /**\n * Create a new restorer instance for a model class.\n *\n * @param modelClass - The model class (static context)\n *\n * @example\n * ```typescript\n * const restorer = new DatabaseRestorer(User);\n * await restorer.restore(123);\n * ```\n */\n public constructor(modelClass: typeof Model) {\n this.ctor = modelClass;\n this.dataSource = modelClass.getDataSource();\n this.driver = this.dataSource.driver;\n this.table = modelClass.table;\n this.primaryKey = modelClass.primaryKey;\n }\n\n /**\n * Restore a single deleted record by its ID.\n *\n * @param id - The primary key value of the record to restore\n * @param options - Restorer options\n * @returns Result containing success status, strategy used, and restored record\n * @throws {Error} If record not found in trash or soft-deleted records\n * @throws {Error} If ID conflict and onIdConflict is \"fail\"\n */\n public async restore(\n id: string | number,\n options: RestorerOptions = {},\n ): Promise<RestorerResult> {\n const onIdConflict = options.onIdConflict ?? \"assignNew\";\n const skipEvents = options.skipEvents ?? false;\n\n // 1. Resolve strategy (options → model static → data source default)\n const strategy = this.resolveStrategy(options.strategy);\n\n // 2. Validate strategy (cannot restore permanent deletes)\n if (strategy === \"permanent\") {\n throw new Error(\n `Cannot restore ${this.ctor.name} with ${this.primaryKey} ${id}: permanently deleted records cannot be restored.`,\n );\n }\n\n // 3. Fetch record based on strategy\n const recordData = await this.fetchRecordByStrategy(id, strategy);\n\n if (!recordData) {\n throw new Error(\n `Cannot restore ${this.ctor.name} with ${this.primaryKey} ${id}: record not found in ${strategy === \"trash\" ? \"trash table\" : \"soft-deleted records\"}.`,\n );\n }\n\n // 4. Prepare record data (remove metadata fields)\n const restoredData = { ...recordData };\n delete restoredData.deletedAt;\n delete restoredData.originalTable;\n\n // 5. Check for ID conflict and handle\n const finalData = await this.handleIdConflict(restoredData, id, onIdConflict);\n\n // 6. Create temporary model instance for event emission\n // Note: Model is abstract, but at runtime this.ctor is a concrete subclass\n const model = new (this.ctor as any)(finalData) as Model;\n\n // 7. Emit restoring event (unless skipEvents)\n if (!skipEvents) {\n await model.emitEvent(\"restoring\");\n }\n\n // 8. Restore based on strategy\n if (strategy === \"trash\") {\n // Insert record back into original table (was moved to trash)\n await this.driver.insert(this.table, finalData);\n model.isNew = false;\n\n // Remove from trash table\n await this.driver.delete(this.resolveTrashTable(), {\n [this.primaryKey]: id,\n });\n } else if (strategy === \"soft\") {\n // Record still exists, just unset deletedAt (don't insert - would create duplicate!)\n const deletedAtColumn = this.ctor.deletedAtColumn ?? \"deletedAt\";\n if (deletedAtColumn) {\n const filter = { [this.primaryKey]: id };\n const updateOperations: UpdateOperations = {\n $unset: { [deletedAtColumn]: 1 },\n };\n\n await this.driver.update(this.table, filter, updateOperations);\n model.isNew = false;\n }\n }\n\n // 10. Emit restored event (unless skipEvents)\n if (!skipEvents) {\n await model.emitEvent(\"restored\");\n }\n\n return {\n success: true,\n restoredCount: 1,\n strategy,\n restoredRecord: model,\n };\n }\n\n /**\n * Restore all deleted records for the model's table.\n *\n * @param options - Restorer options\n * @returns Result containing success status, strategy used, and aggregate counts\n */\n public async restoreAll(options: RestorerOptions = {}): Promise<RestorerResult> {\n const onIdConflict = options.onIdConflict ?? \"assignNew\";\n const skipEvents = options.skipEvents ?? false;\n\n // 1. Resolve strategy (options → model static → data source default)\n const strategy = this.resolveStrategy(options.strategy);\n\n // 2. Validate strategy (cannot restore permanent deletes)\n if (strategy === \"permanent\") {\n throw new Error(\n `Cannot restore all ${this.ctor.name} records: permanently deleted records cannot be restored.`,\n );\n }\n\n // 3. Fetch all records based on strategy\n const recordsToRestore = await this.fetchAllRecordsByStrategy(strategy);\n\n if (recordsToRestore.length === 0) {\n return {\n success: true,\n restoredCount: 0,\n strategy,\n };\n }\n\n // 4. Restore each record\n let restoredCount = 0;\n const conflicts: Array<{ id: string | number; reason: string }> = [];\n\n const restoredRecords: Model[] = [];\n\n for (const recordData of recordsToRestore) {\n const id = recordData[this.primaryKey] as string | number;\n\n try {\n // Prepare record data (remove metadata fields)\n const restoredData = { ...recordData };\n delete restoredData.deletedAt;\n delete restoredData.originalTable;\n\n // Check for ID conflict\n const idExists = await this.checkIdExists(id);\n if (idExists) {\n if (onIdConflict === \"fail\") {\n throw new Error(\n `Cannot restore ${this.ctor.name} with ${this.primaryKey} ${id}: ID already exists in target table.`,\n );\n }\n\n // Assign new ID\n const finalData = await this.assignNewId(restoredData);\n conflicts.push({\n id,\n reason: `ID ${id} already exists, assigned new ID ${finalData[this.primaryKey]}`,\n });\n\n // Create temporary model for events\n const model = new (this.ctor as any)(finalData) as Model;\n\n // Emit restoring event\n if (!skipEvents) {\n await model.emitEvent(\"restoring\");\n }\n\n // Restore based on strategy\n if (strategy === \"trash\") {\n // Insert with new ID (was moved to trash)\n await this.driver.insert(this.table, finalData);\n model.isNew = false;\n } else if (strategy === \"soft\") {\n // Record still exists, just unset deletedAt\n const deletedAtColumn = this.ctor.deletedAtColumn ?? \"deletedAt\";\n if (deletedAtColumn) {\n const filter = { [this.primaryKey]: id };\n const updateOperations: UpdateOperations = {\n $unset: { [deletedAtColumn]: 1 },\n };\n await this.driver.update(this.table, filter, updateOperations);\n model.isNew = false;\n }\n }\n\n restoredRecords.push(model);\n\n // Emit restored event\n if (!skipEvents) {\n await model.emitEvent(\"restored\");\n }\n } else {\n // No conflict, restore with original ID\n const model = new (this.ctor as any)(restoredData) as Model;\n\n // Emit restoring event\n if (!skipEvents) {\n await model.emitEvent(\"restoring\");\n }\n\n // Restore based on strategy\n if (strategy === \"trash\") {\n // Insert with original ID (was moved to trash)\n await this.driver.insert(this.table, restoredData);\n model.isNew = false;\n } else if (strategy === \"soft\") {\n // Record still exists, just unset deletedAt\n const deletedAtColumn = this.ctor.deletedAtColumn ?? \"deletedAt\";\n if (deletedAtColumn) {\n const filter = { [this.primaryKey]: id };\n const updateOperations: UpdateOperations = {\n $unset: { [deletedAtColumn]: 1 },\n };\n await this.driver.update(this.table, filter, updateOperations);\n model.isNew = false;\n }\n }\n\n restoredRecords.push(model);\n\n // Emit restored event\n if (!skipEvents) {\n await model.emitEvent(\"restored\");\n }\n }\n\n // Remove from trash (only for trash strategy)\n if (strategy === \"trash\") {\n const trashTable = this.resolveTrashTable();\n const trashFilter = { [this.primaryKey]: id };\n await this.driver.delete(trashTable, trashFilter);\n }\n\n restoredCount++;\n } catch (error) {\n if (onIdConflict === \"fail\") {\n throw error;\n }\n // Continue with next record if assignNew mode\n conflicts.push({\n id,\n reason: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n return {\n success: true,\n restoredCount,\n restoredRecords,\n strategy,\n conflicts: conflicts.length > 0 ? conflicts : undefined,\n };\n }\n\n /**\n * Resolve the delete strategy.\n *\n * Priority: options → model static → data source default → \"permanent\"\n *\n * @param strategyOption - Optional strategy override from options\n * @returns The resolved delete strategy\n * @private\n */\n private resolveStrategy(strategyOption?: \"trash\" | \"soft\"): DeleteStrategy {\n return (\n strategyOption ??\n this.ctor.deleteStrategy ??\n this.dataSource.defaultDeleteStrategy ??\n \"permanent\"\n );\n }\n\n /**\n * Fetch a record by ID based on the delete strategy.\n *\n * @param id - The primary key value\n * @param strategy - The delete strategy to use\n * @returns The record data, or null if not found\n * @private\n */\n private async fetchRecordByStrategy(id: string | number, strategy: \"trash\" | \"soft\") {\n if (strategy === \"trash\") {\n const trashTable = this.resolveTrashTable();\n try {\n const trashQuery = await this.driver\n .queryBuilder(trashTable)\n .where(this.primaryKey, id)\n .first<Record<string, unknown>>();\n\n return trashQuery;\n } catch {\n return null;\n }\n } else if (strategy === \"soft\") {\n const deletedAtColumn = this.ctor.deletedAtColumn ?? \"deletedAt\";\n if (!deletedAtColumn) {\n return null;\n }\n\n try {\n const softDeletedQuery = await this.driver\n .queryBuilder(this.table)\n .where(this.primaryKey, id)\n .whereNotNull(deletedAtColumn)\n .first<Record<string, unknown>>();\n\n return softDeletedQuery;\n } catch {\n return null;\n }\n }\n\n return null;\n }\n\n /**\n * Fetch all records based on the delete strategy.\n *\n * @param strategy - The delete strategy to use\n * @returns Array of record data\n * @private\n */\n private async fetchAllRecordsByStrategy(\n strategy: \"trash\" | \"soft\",\n ): Promise<Record<string, unknown>[]> {\n if (strategy === \"trash\") {\n const trashTable = this.resolveTrashTable();\n try {\n const trashQuery = this.driver\n .queryBuilder(trashTable)\n .where(\"originalTable\", this.table)\n .get();\n\n return (await trashQuery) as Record<string, unknown>[];\n } catch {\n return [];\n }\n } else if (strategy === \"soft\") {\n const deletedAtColumn = this.ctor.deletedAtColumn ?? \"deletedAt\";\n if (!deletedAtColumn) {\n return [];\n }\n\n try {\n const softDeletedQuery = this.driver\n .queryBuilder(this.table)\n .whereNotNull(deletedAtColumn)\n .get();\n\n return (await softDeletedQuery) as Record<string, unknown>[];\n } catch {\n return [];\n }\n }\n\n return [];\n }\n\n /**\n * Handle ID conflict by checking if ID exists and assigning new one if needed.\n *\n * @param recordData - The record data to restore\n * @param originalId - The original ID value\n * @param onIdConflict - Conflict resolution strategy\n * @returns Record data with potentially new ID\n * @private\n */\n private async handleIdConflict(\n recordData: Record<string, unknown>,\n originalId: string | number,\n onIdConflict: \"fail\" | \"assignNew\",\n ): Promise<Record<string, unknown>> {\n const idExists = await this.checkIdExists(originalId);\n\n if (idExists) {\n if (onIdConflict === \"fail\") {\n throw new Error(\n `Cannot restore ${this.ctor.name} with ${this.primaryKey} ${originalId}: ID already exists in target table.`,\n );\n }\n\n // Assign new ID\n return await this.assignNewId(recordData);\n }\n\n return recordData;\n }\n\n /**\n * Check if an ID already exists in the target table.\n *\n * @param id - The ID to check\n * @returns True if ID exists, false otherwise\n * @private\n */\n private async checkIdExists(id: string | number): Promise<boolean> {\n try {\n const query = this.driver.queryBuilder(this.table).where(this.primaryKey, id).exists();\n\n return await query;\n } catch {\n return false;\n }\n }\n\n /**\n * Assign a new ID to the record data.\n *\n * For MongoDB: Generates new ObjectId for `_id`, keeps `id` if it exists\n * For SQL: Removes `id` to let database auto-increment\n *\n * @param recordData - The record data\n * @returns Record data with new ID assigned\n * @private\n */\n private async assignNewId(recordData: Record<string, unknown>): Promise<Record<string, unknown>> {\n const isMongoDb = this.driver.name === \"mongodb\";\n const newData = { ...recordData };\n\n if (isMongoDb) {\n // MongoDB: Generate new ObjectId for _id\n if (this.primaryKey === \"_id\") {\n // Remove _id to let MongoDB generate new one\n delete newData._id;\n } else if (this.primaryKey === \"id\") {\n // Remove id to let ID generator create new one\n delete newData.id;\n }\n } else {\n // SQL: Remove primary key to let database auto-increment\n delete newData[this.primaryKey];\n }\n\n return newData;\n }\n\n /**\n * Resolve the trash table/collection name.\n *\n * Priority:\n * 1. Model.trashTable (if set)\n * 2. Data source defaultTrashTable (e.g., \"RecycleBin\" for MongoDB)\n * 3. Default pattern: `{table}Trash`\n *\n * @returns The trash table/collection name\n * @private\n */\n private resolveTrashTable(): string {\n if (this.ctor.trashTable) {\n return this.ctor.trashTable;\n }\n\n if (this.dataSource.defaultTrashTable) {\n return this.dataSource.defaultTrashTable;\n }\n\n return `${this.table}Trash`;\n }\n}\n","import { DatabaseRestorer } from \"../../restorer/database-restorer\";\nimport type { ChildModel, Model } from \"../model\";\n\nexport async function restoreRecord<TModel extends Model>(\n ModelClass: ChildModel<TModel>,\n id: string | number,\n options?: { onIdConflict?: \"fail\" | \"assignNew\"; skipEvents?: boolean },\n): Promise<TModel> {\n const restorer = new DatabaseRestorer(ModelClass as unknown as typeof Model);\n const result = await restorer.restore(id, options);\n\n if (!result.restoredRecord) {\n throw new Error(\n `Failed to restore ${ModelClass.name} with ${ModelClass.primaryKey} ${id}: no record returned.`,\n );\n }\n\n return result.restoredRecord as TModel;\n}\n\nexport async function restoreAllRecords<TModel extends Model>(\n ModelClass: ChildModel<TModel>,\n options?: { onIdConflict?: \"fail\" | \"assignNew\"; skipEvents?: boolean },\n): Promise<TModel[]> {\n const restorer = new DatabaseRestorer(ModelClass as unknown as typeof Model);\n const result = await restorer.restoreAll(options);\n\n return result.restoredCount === 0 ? [] : (result.restoredRecords as TModel[]);\n}\n","import type { QueryBuilderContract } from \"../../contracts\";\nimport type { GlobalScopeOptions, LocalScopeCallback, ChildModel, Model } from \"../model\";\n\nexport function addGlobalModelScope(\n ModelClass: ChildModel<any>,\n name: string,\n callback: (query: QueryBuilderContract) => void,\n options: GlobalScopeOptions = {},\n): void {\n ModelClass.globalScopes.set(name, {\n callback,\n timing: options.timing || \"before\",\n });\n}\n\nexport function removeGlobalModelScope(ModelClass: ChildModel<any>, name: string): void {\n ModelClass.globalScopes.delete(name);\n}\n\nexport function addLocalModelScope(\n ModelClass: ChildModel<any>,\n name: string,\n callback: LocalScopeCallback,\n): void {\n ModelClass.localScopes.set(name, callback);\n}\n\nexport function removeLocalModelScope(ModelClass: ChildModel<any>, name: string): void {\n ModelClass.localScopes.delete(name);\n}\n","import type { GenericObject } from \"@mongez/reinforcements\";\nimport type { Model } from \"../model\";\n\nexport function modelToJSON(model: Model): Record<string, unknown> {\n const ModelClass = model.self();\n const resource = ModelClass.resource;\n\n if (!resource) {\n const toJsonColumns = ModelClass.toJsonColumns;\n if (toJsonColumns && toJsonColumns.length > 0) {\n return model.only(toJsonColumns);\n }\n return model.data;\n }\n\n const resourceColumns = ModelClass.resourceColumns;\n let data: GenericObject =\n resourceColumns !== undefined && resourceColumns.length > 0\n ? model.only(resourceColumns)\n : { ...model.data };\n\n for (const [relationName, relatedModel] of model.loadedRelations) {\n if (Array.isArray(relatedModel)) {\n data[relationName] = relatedModel.map((m) =>\n m instanceof Object && typeof m.toJSON === \"function\" ? m.toJSON() : m,\n );\n } else if (relatedModel instanceof Object && typeof relatedModel.toJSON === \"function\") {\n data[relationName] = relatedModel.toJSON();\n } else {\n data[relationName] = relatedModel;\n }\n }\n\n return new resource(data).toJSON();\n}\n","import {\n ModelEvents,\n globalModelEvents,\n type ModelEventListener,\n type ModelEventName,\n} from \"../../events/model-events\";\nimport { removeModelFromRegistery } from \"../register-model\";\nimport type { ChildModel, Model } from \"../model\";\n\n/**\n * Isolated event emitter registry — one ModelEvents instance per model constructor.\n * Encapsulated here so no other module needs to know it exists.\n */\nconst modelEventsRegistry = new WeakMap<any, any>();\n\nexport function getModelEvents<TModel extends Model>(\n ModelClass: any,\n): ModelEvents<TModel> {\n let events = modelEventsRegistry.get(ModelClass);\n if (!events) {\n events = new ModelEvents<TModel>();\n modelEventsRegistry.set(ModelClass, events);\n }\n return events as ModelEvents<TModel>;\n}\n\nexport function cleanupModelEvents(ModelClass: any): void {\n modelEventsRegistry.delete(ModelClass);\n removeModelFromRegistery(ModelClass.name);\n}\n\nexport function onStaticEvent<TModel extends Model = Model, TContext = unknown>(\n ModelClass: ChildModel<TModel>,\n event: ModelEventName,\n listener: ModelEventListener<TModel, TContext>,\n): () => void {\n return ModelClass.events<TModel>().on(event, listener);\n}\n\nexport function onceStaticEvent<TModel extends Model = Model, TContext = unknown>(\n ModelClass: ChildModel<TModel>,\n event: ModelEventName,\n listener: ModelEventListener<TModel, TContext>,\n): () => void {\n return ModelClass.events<TModel>().once(event, listener);\n}\n\nexport function offStaticEvent<TModel extends Model = Model, TContext = unknown>(\n ModelClass: ChildModel<TModel>,\n event: ModelEventName,\n listener: ModelEventListener<TModel, TContext>,\n): void {\n ModelClass.events<TModel>().off(event, listener);\n}\n\nexport function getGlobalEvents(): ModelEvents<Model> {\n return globalModelEvents;\n}\n","import { DatabaseWriter } from \"../../writer/database-writer\";\nimport type { WriterOptions } from \"../../contracts\";\nimport type { ChildModel, Model, ModelSchema } from \"../model\";\nimport { emitModelEvent } from \"./instance-event-methods\";\n\nexport async function saveModel<TModel extends Model>(\n model: TModel,\n options?: WriterOptions & { merge?: Partial<ModelSchema> },\n): Promise<TModel> {\n if (options?.merge) {\n model.merge(options.merge);\n }\n const writer = new DatabaseWriter(model);\n await writer.save(options);\n return model;\n}\n\nexport async function createRecord<\n TModel extends Model,\n TSchema extends ModelSchema = TModel extends Model<infer S> ? S : ModelSchema,\n>(ModelClass: ChildModel<TModel>, data: Partial<TSchema>): Promise<TModel> {\n const model = new ModelClass(data);\n await model.save();\n return model;\n}\n\nexport async function createManyRecords<\n TModel extends Model,\n TSchema extends ModelSchema = TModel extends Model<infer S> ? S : ModelSchema,\n>(ModelClass: ChildModel<TModel>, data: Partial<TSchema>[]): Promise<TModel[]> {\n return await Promise.all(data.map((item) => createRecord(ModelClass, item)));\n}\n\nexport async function findOrCreateRecord<\n TModel extends Model,\n TSchema extends ModelSchema = TModel extends Model<infer S> ? S : ModelSchema,\n>(\n ModelClass: ChildModel<TModel>,\n filter: Partial<TSchema>,\n data: Partial<TSchema>,\n): Promise<TModel> {\n const existing = await ModelClass.first(filter as Record<string, unknown>);\n\n if (existing) {\n return existing;\n }\n\n return await createRecord(ModelClass, { ...filter, ...data } as Partial<TSchema>);\n}\n\nexport async function upsertRecord<\n TModel extends Model,\n TSchema extends ModelSchema = TModel extends Model<infer S> ? S : ModelSchema,\n>(\n ModelClass: ChildModel<TModel>,\n filter: Partial<TSchema>,\n data: Partial<TSchema>,\n options?: Record<string, unknown>,\n): Promise<TModel> {\n const driver = ModelClass.getDriver();\n const mergedData = { ...filter, ...data } as Record<string, unknown>;\n\n const tempModel = new ModelClass(mergedData as Partial<TSchema>);\n tempModel.isNew = true;\n\n await emitModelEvent(tempModel, \"saving\", {\n isInsert: true,\n options,\n mode: \"upsert\",\n });\n\n const createdAtColumn = ModelClass.createdAtColumn;\n const updatedAtColumn = ModelClass.updatedAtColumn;\n\n if (createdAtColumn !== false && createdAtColumn !== undefined) {\n const createdAtKey = createdAtColumn as string;\n if (!mergedData[createdAtKey]) {\n mergedData[createdAtKey] = new Date();\n }\n }\n\n if (updatedAtColumn !== false && updatedAtColumn !== undefined) {\n const updatedAtKey = updatedAtColumn as string;\n mergedData[updatedAtKey] = new Date();\n }\n\n await emitModelEvent(tempModel, \"saving\", { filter, data: mergedData, options, mode: \"upsert\" });\n\n const result = await driver.upsert(ModelClass.table, filter as Record<string, unknown>, mergedData, options);\n\n const model = ModelClass.hydrate(result as Record<string, unknown>) as TModel;\n model.dirtyTracker.reset();\n\n await emitModelEvent(model, \"saved\", { filter, data: result, options, mode: \"upsert\" });\n\n return model;\n}\n","import { type GenericObject } from \"@mongez/reinforcements\";\nimport type { ObjectValidator } from \"@warlock.js/seal\";\nimport type {\n DriverContract,\n PaginationOptions,\n PaginationResult,\n RemoverResult,\n UpdateOperations,\n WriterOptions,\n} from \"../contracts\";\nimport { QueryBuilderContract, WhereCallback, WhereObject, WhereOperator } from \"../contracts\";\nimport type { DataSource } from \"../data-source/data-source\";\nimport { DatabaseDirtyTracker } from \"../database-dirty-tracker\";\nimport type { ModelEventListener, ModelEventName } from \"../events/model-events\";\nimport { ModelEvents } from \"../events/model-events\";\nimport type { PivotOperations } from \"../relations/pivot-operations\";\nimport type { ModelSnapshot } from \"../relations/relation-hydrator\";\nimport { attachLoadedRelation, RelationLoader } from \"../relations/relation-loader\";\nimport type {\n LoadedRelationResult,\n PivotData,\n PivotIds,\n RelationDefinition,\n} from \"../relations/types\";\nimport { modelSync } from \"../sync/model-sync\";\nimport type { ModelSyncOperationContract } from \"../sync/types\";\nimport type { DeleteStrategy, StrictMode } from \"../types\";\nimport {\n decrementField,\n getBooleanField,\n getFieldValue,\n getNumberField,\n getOnlyFields,\n getStringField,\n hasField,\n incrementField,\n mergeFields,\n setFieldValue,\n unsetFields,\n} from \"./methods/accessor-methods\";\nimport { deleteOneRecord, deleteRecords, destroyModel } from \"./methods/delete-methods\";\nimport {\n checkHasChanges,\n checkIsDirty,\n getDirtyColumns,\n getDirtyColumnsWithValues,\n getRemovedColumns,\n} from \"./methods/dirty-methods\";\nimport {\n cloneModel,\n deepFreezeObject,\n hydrateModel,\n modelFromSnapshot,\n modelToSnapshot,\n replaceModelData,\n serializeModel,\n} from \"./methods/hydration-methods\";\nimport {\n emitModelEvent,\n offModelEvent,\n onceModelEvent,\n onModelEvent,\n} from \"./methods/instance-event-methods\";\nimport {\n applyDefaultsToModel,\n generateModelNextId,\n performAtomicDecrement,\n performAtomicIncrement,\n performAtomicUpdate,\n} from \"./methods/meta-methods\";\nimport { attachPivotRelation, detachPivotRelation, pivotRelation } from \"./methods/pivot-methods\";\nimport {\n buildNewQueryBuilder,\n buildQuery,\n countRecords,\n decreaseField,\n findAll,\n findAndReplaceRecord,\n findAndUpdateRecords,\n findById,\n findFirst,\n findLast,\n findLatest,\n findOneAndDeleteRecord,\n findOneAndUpdateRecord,\n increaseField,\n paginateRecords,\n performAtomic,\n resolveDataSource,\n updateById,\n} from \"./methods/query-methods\";\nimport { restoreAllRecords, restoreRecord } from \"./methods/restore-methods\";\nimport {\n addGlobalModelScope,\n addLocalModelScope,\n removeGlobalModelScope,\n removeLocalModelScope,\n} from \"./methods/scope-methods\";\nimport { modelToJSON } from \"./methods/serialization-methods\";\nimport {\n cleanupModelEvents,\n getGlobalEvents,\n getModelEvents,\n offStaticEvent,\n onceStaticEvent,\n onStaticEvent,\n} from \"./methods/static-event-methods\";\nimport {\n createManyRecords,\n createRecord,\n findOrCreateRecord,\n saveModel,\n upsertRecord,\n} from \"./methods/write-methods\";\nimport type {\n ChildModel,\n GlobalScopeDefinition,\n GlobalScopeOptions,\n LocalScopeCallback,\n ModelSchema,\n} from \"./model.types\";\nimport { getAllModelsFromRegistry, getModelFromRegistry } from \"./register-model\";\nexport type {\n ChildModel,\n GlobalScopeDefinition,\n GlobalScopeOptions,\n LocalScopeCallback,\n ModelSchema,\n ScopeTiming,\n} from \"./model.types\";\n\n/**\n * Base class that powers all Cascade models.\n *\n * Provides:\n * - Type-safe value accessors with dot-notation support (get, set, has, unset, merge)\n * - Automatic dirty tracking for efficient partial updates\n * - Lifecycle event hooks (saving, created, deleting, etc.)\n * - Integration with the data-source registry for multi-database support\n * - Support for both per-model and global event listeners\n *\n * @template TSchema - The shape of the model's underlying data\n *\n * @example\n * ```typescript\n * interface UserSchema {\n * id: number;\n * name: string;\n * email: string;\n * }\n *\n * class User extends Model<UserSchema> {\n * public static table = \"users\";\n * }\n *\n * const user = new User({ name: \"Alice\" });\n * user.set(\"email\", \"alice@example.com\");\n * console.log(user.hasChanges()); // true\n * ```\n */\nexport abstract class Model<TSchema extends ModelSchema = ModelSchema> {\n /**\n * The database table or collection name associated with this model.\n *\n * Must be defined by each concrete model subclass.\n *\n * @example\n * ```typescript\n * class User extends Model {\n * public static table = \"users\";\n * }\n * ```\n */\n public static table: string;\n\n /**\n * Resource for this model.\n * It is a class that holds a toJSON function\n * Called when the model is being converted to JSON (by calling toJSON or JSON.stringify(model))\n *\n * @example\n * ```typescript\n * class User extends Model {\n * public static resource = UserResource;\n * }\n * ```\n */\n public static resource?: any;\n\n /**\n * Resource columns\n * Define what columns should be sent to the resource (if any) when converting to JSON\n */\n public static resourceColumns?: string[];\n\n /**\n * JSON keys for this model.\n * This could be used if resource is not passed\n * It will select only these keys from the model\n * @example\n * ```typescript\n * class User extends Model {\n * public static toJsonColumns = [\"id\", \"name\"];\n * }\n * ```\n */\n public static toJsonColumns?: string[];\n\n /**\n * Data source reference for this model.\n *\n * Can be:\n * - A string name registered in the data-source registry\n * - A DataSource instance\n * - Undefined (falls back to the default data source)\n *\n * @example\n * ```typescript\n * class User extends Model {\n * public static dataSource = \"primary\";\n * }\n * ```\n */\n public static dataSource?: string | DataSource;\n\n /**\n * Query builder class\n */\n public static builder?: new (...args: any[]) => QueryBuilderContract<Model>;\n\n /**\n * Primary key field name used to identify records.\n *\n * @default \"id\"\n *\n * @example\n * ```typescript\n * class User extends Model {\n * public static primaryKey = \"_id\"; // MongoDB\n * }\n *\n * class Product extends Model {\n * public static primaryKey = \"id\"; // SQL\n * }\n * ```\n */\n public static primaryKey: string = \"id\";\n\n /**\n * Embeded fields when document is Being embeded\n */\n public static embed?: string[];\n\n /**\n * Validation and casting schema using @warlock.js/seal.\n *\n * Defines validation rules and data transformations for the model.\n * Used automatically during save operations.\n *\n * @example\n * ```typescript\n * import { v } from \"@warlock.js/seal\";\n *\n * class User extends Model {\n * public static schema = v.object({\n * name: v.string().required().trim(),\n * age: v.number().min(0).max(120),\n * email: v.string().email().required().toLowerCase(),\n * createdAt: v.date().default(() => new Date()),\n * });\n * }\n * ```\n */\n public static schema?: ObjectValidator;\n\n /**\n * Strict mode behavior for unknown fields.\n *\n * - `\"strip\"`: Remove unknown fields silently (default, recommended for APIs)\n * - `\"fail\"`: Throw validation error on unknown fields (strict validation)\n * - `\"allow\"`: Allow unknown fields to pass through (permissive)\n *\n * @default \"strip\"\n *\n * @example\n * ```typescript\n * import { Model, type StrictMode } from \"@warlock.js/cascade\";\n *\n * class User extends Model {\n * public static strictMode: StrictMode = \"fail\"; // Throw on unknown fields\n * }\n *\n * const user = new User({ name: \"Alice\", unknownField: \"value\" });\n * await user.save(); // DatabaseWriterValidationError: unknown field\n * ```\n */\n public static strictMode: StrictMode = \"strip\";\n\n /**\n * Auto-generate incremental `id` field on insert (NoSQL only).\n *\n * When enabled, the ID generator creates a sequential integer ID\n * separate from the database's native ID (_id for MongoDB).\n *\n * **Note:** SQL databases use native AUTO_INCREMENT and don't need this.\n *\n * @default true\n *\n * @example\n * ```typescript\n * class User extends Model {\n * public static autoGenerateId = true;\n * }\n *\n * const user = new User({ name: \"Alice\" });\n * await user.save();\n * console.log(user.get(\"_id\")); // ObjectId(\"...\") - MongoDB\n * console.log(user.get(\"id\")); // 1 - Generated\n * ```\n */\n public static autoGenerateId = true;\n\n /**\n * Initial ID value for the first record.\n *\n * If not set, defaults to 1 or uses `randomInitialId`.\n *\n * @example\n * ```typescript\n * class User extends Model {\n * public static initialId = 1000; // Start from 1000\n * }\n * ```\n */\n public static initialId?: number;\n\n /**\n * Randomly generate the initial ID.\n *\n * Can be:\n * - `true`: Generate random ID between 10000-499999\n * - Function: Custom random ID generator\n * - `false`: Use `initialId` or default to 1\n *\n * @default false\n *\n * @example\n * ```typescript\n * class User extends Model {\n * public static randomInitialId = true; // Random 10000-499999\n * }\n *\n * class Product extends Model {\n * public static randomInitialId = () => Math.floor(Math.random() * 1000000);\n * }\n * ```\n */\n public static randomInitialId?: boolean | (() => number);\n\n /**\n * Amount to increment ID by for each new record.\n *\n * If not set, defaults to 1 or uses `randomIncrement`.\n *\n * @default 1\n *\n * @example\n * ```typescript\n * class User extends Model {\n * public static incrementIdBy = 5; // Increment by 5\n * }\n * ```\n */\n public static incrementIdBy?: number = 1;\n\n /**\n * Randomly generate the increment amount.\n *\n * Can be:\n * - `true`: Generate random increment between 1-10\n * - Function: Custom random increment generator\n * - `false`: Use `incrementIdBy` or default to 1\n *\n * @default false\n *\n * @example\n * ```typescript\n * class User extends Model {\n * public static randomIncrement = true; // Random 1-10\n * }\n *\n * class Product extends Model {\n * public static randomIncrement = () => Math.floor(Math.random() * 100);\n * }\n * ```\n */\n public static randomIncrement?: boolean | (() => number);\n\n /**\n * Created at column name.\n */\n public static createdAtColumn?: string | false;\n\n /**\n * Updated at column name.\n */\n public static updatedAtColumn?: string | false;\n\n /**\n * Delete strategy for this model.\n *\n * Controls how models are deleted:\n * - `\"trash\"` - Moves to trash collection, then deletes\n * - `\"permanent\"` - Direct deletion (hard delete)\n * - `\"soft\"` - Sets deletedAt timestamp (soft delete)\n *\n * Can be overridden by destroy() options.\n * Falls back to data source default if not set.\n *\n * @example\n * ```typescript\n * class User extends Model {\n * public static deleteStrategy: DeleteStrategy = \"soft\";\n * }\n * ```\n */\n public static deleteStrategy?: DeleteStrategy;\n\n /**\n * Column name for soft delete timestamp.\n *\n * Used when delete strategy is \"soft\".\n *\n * @default \"deletedAt\"\n *\n * @example\n * ```typescript\n * class User extends Model {\n * public static deletedAtColumn = \"archivedAt\";\n * }\n * ```\n */\n public static deletedAtColumn: string | false = \"deletedAt\";\n\n /**\n * Trash table/collection name override.\n *\n * If not set, defaults to `{table}Trash` or data source default.\n * Used when delete strategy is \"trash\".\n *\n * @example\n * ```typescript\n * class User extends Model {\n * public static trashTable = \"userRecycleBin\";\n * }\n * ```\n */\n public static trashTable?: string;\n\n /**\n * Global scopes that are automatically applied to all queries.\n * These scopes are inherited by child models.\n */\n public static globalScopes = new Map<string, GlobalScopeDefinition>();\n\n /**\n * Local scopes that can be manually applied to queries.\n * These are reusable query snippets that developers opt into.\n */\n public static localScopes = new Map<string, LocalScopeCallback>();\n\n /**\n * Relation definitions for this model.\n *\n * Define relationships to other models using helper functions:\n * - `hasMany()` - One-to-many (User has many Posts)\n * - `hasOne()` - One-to-one (User has one Profile)\n * - `belongsTo()` - Inverse of hasMany/hasOne (Post belongs to User)\n * - `belongsToMany()` - Many-to-many with pivot table (User has many Roles)\n *\n * @example\n * ```typescript\n * import { hasMany, belongsTo, belongsToMany, hasOne } from \"@warlock.js/cascade\";\n *\n * class User extends Model {\n * public posts?: Post[]; // Optional: for TypeScript autocomplete\n *\n * static relations = {\n * posts: hasMany(\"Post\"),\n * profile: hasOne(\"Profile\"),\n * organization: belongsTo(\"Organization\"),\n * roles: belongsToMany(\"Role\", { pivot: \"user_roles\" }),\n * };\n * }\n *\n * // Usage:\n * const users = await User.query().with(\"posts\").get();\n * console.log(users[0].posts); // Post[]\n * ```\n */\n public static relations: Readonly<Record<string, RelationDefinition>> = {};\n\n /**\n * Flag indicating whether this model instance represents a new (unsaved) record.\n *\n * - `true`: The model has not been persisted to the database yet\n * - `false`: The model represents an existing database record\n *\n * This flag is used by the writer to determine whether to perform an insert or update.\n */\n public isNew = true;\n\n /**\n * The raw mutable data backing this model instance.\n *\n * All field accessors (get, set, merge, etc.) operate on this object.\n */\n public data: TSchema;\n\n /**\n * Dirty tracker that monitors changes to the model's data.\n *\n * Tracks:\n * - Which fields have been modified (dirty columns)\n * - Which fields have been removed\n * - Original vs. current values for each dirty field\n *\n * Used by the writer to generate efficient partial update payloads.\n */\n public readonly dirtyTracker: DatabaseDirtyTracker;\n\n /**\n * Model instance events.\n * Allows registering listeners for lifecycle events on this specific instance.\n */\n public events: ModelEvents<any> = new ModelEvents();\n\n /**\n * Map of loaded relations for this model instance.\n *\n * Populated automatically when using `with()` for eager loading,\n * or when calling `load()` for lazy loading.\n *\n * @example\n * ```typescript\n * const user = await User.query().with(\"posts\").first();\n * console.log(user.loadedRelations.get(\"posts\")); // Post[]\n *\n * // Also accessible as direct properties:\n * console.log(user.posts); // Post[]\\n * ```\n */\n public loadedRelations: Map<string, any> = new Map();\n\n /**\n * Column name for active status.\n */\n protected isActiveColumn = \"isActive\";\n\n /**\n * Constructs a new model instance with optional initial data.\n *\n * Initializes the dirty tracker with a snapshot of the provided data.\n *\n * @param initialData - Partial data to populate the model\n *\n * @example\n * ```typescript\n * const user = new User({ name: \"Alice\", email: \"alice@example.com\" });\n * ```\n */\n public constructor(initialData: Partial<TSchema> = {}) {\n this.data = initialData as TSchema;\n this.dirtyTracker = this.self().getDriver().getDirtyTracker(this.data);\n }\n\n /**\n * Lazily load one or more relations for this model instance.\n *\n * This method loads relations on-demand after the model has been fetched.\n * The loaded relations are attached directly to the model instance and\n * also stored in `loadedRelations` map.\n *\n * @param relations - Relation name(s) to load\n * @returns This model instance for chaining\n *\n * @example\n * ```typescript\n * const user = await User.first();\n *\n * // Load single relation\n * await user.load(\"posts\");\n * console.log(user.posts); // Post[]\n *\n * // Load multiple relations\n * await user.load(\"posts\", \"organization\");\n *\n * // Chain with other operations\n * const posts = await user.load(\"posts\").then(() => user.posts);\n * ```\n */\n public async load(...relations: string[]): Promise<this> {\n const ModelClass = this.constructor as ChildModel<Model>;\n const loader = new RelationLoader([this], ModelClass);\n await loader.load(relations);\n return this;\n }\n\n /**\n * Check if a relation has been loaded.\n *\n * @param relationName - Name of the relation to check\n * @returns True if the relation has been loaded\n *\n * @example\n * ```typescript\n * const user = await User.first();\n *\n * console.log(user.isLoaded(\"posts\")); // false\n * await user.load(\"posts\");\n * console.log(user.isLoaded(\"posts\")); // true\n * ```\n */\n\n public isLoaded(relationName: string): boolean {\n return this.loadedRelations.has(relationName);\n }\n\n /**\n * Set relation manually\n *\n * @param relationName\n * @param relationData\n */\n public setRelation(relationName: string, relationData: LoadedRelationResult): void {\n attachLoadedRelation(this, relationName, relationData);\n }\n\n /**\n * Get a loaded relation by name.\n *\n * Returns undefined if the relation has not been loaded.\n *\n * @param relationName - Name of the relation to get\n * @returns The loaded relation data, or undefined\n *\n * @example\n * ```typescript\n * const user = await User.query().with(\"posts\").first();\n *\n * const posts = user.getRelation<Post[]>(\"posts\");\n * console.log(posts?.length);\n * ```\n */\n public getRelation<TRelation = any>(relationName: string): TRelation | undefined {\n return this.loadedRelations.get(relationName) as TRelation | undefined;\n }\n\n /**\n * Get a model class by its name from the global registry.\n *\n * Models must be decorated with @RegisterModel() to be available in the registry.\n *\n * @param name - The model class name\n * @returns The model class or undefined if not found\n *\n * @example\n * ```typescript\n * const UserModel = Model.getModel(\"User\");\n * if (UserModel) {\n * const user = await UserModel.find(1);\n * }\n * ```\n */\n public static getModel(name: string) {\n return getModelFromRegistry(name);\n }\n\n /**\n * Get all registered models from the global registry.\n *\n * Only models decorated with @RegisterModel() will appear here.\n *\n * @returns A Map of all registered model classes by name\n *\n * @example\n * ```typescript\n * const allModels = Model.getAllModels();\n * for (const [name, ModelClass] of allModels) {\n * console.log(`Found model: ${name} with table: ${ModelClass.table}`);\n * }\n * ```\n */\n public static getAllModels() {\n return getAllModelsFromRegistry();\n }\n\n // ============================================================================\n // STATIC SYNC METHODS\n // ============================================================================\n\n /**\n * Create a sync operation for a single embedded document.\n *\n * When this model is updated, the target model's field\n * will be updated with the embedded data.\n *\n * @param TargetModel - Target model class that receives data\n * @param targetField - Field path in target model\n * @returns Sync operation for chaining configuration\n *\n * @example\n * ```typescript\n * // When Category updates, update Product.category\n * Category.sync(Product, \"category\");\n * ```\n */\n public static sync<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n TargetModel: ChildModel<Model>,\n targetField: string,\n ): ModelSyncOperationContract {\n return modelSync.sync(this, TargetModel, targetField);\n }\n\n /**\n * Create a sync operation for an array of embedded documents.\n *\n * When this model is updated, the corresponding element\n * in the target model's array field will be updated.\n *\n * @param TargetModel - Target model class that receives data\n * @param targetField - Array field path in target model\n * @returns Sync operation for chaining configuration\n *\n * @example\n * ```typescript\n * // When Tag updates, update Post.tags[i] where tags[i].id matches\n * Tag.syncMany(Post, \"tags\").identifyBy(\"id\");\n * ```\n */\n public static syncMany<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n TargetModel: ChildModel<Model>,\n targetField: string,\n ): ModelSyncOperationContract {\n return modelSync.syncMany(this, TargetModel, targetField);\n }\n\n /**\n * Get model id\n */\n public get id(): number | string {\n return this.get(\"id\");\n }\n\n /**\n * String-typed accessor for the model's primary id.\n *\n * The underlying `id` field is `string | number` (MongoDB's ObjectId-as-string\n * vs SQL's auto-increment integer), which forces consumers to write\n * `string | number` everywhere they pass an id around. This getter narrows\n * the contract to `string` so callers can write functions that accept a\n * single id type without leaking the engine difference.\n *\n * The name `uuid` is historical — it does NOT validate or coerce the value\n * to a UUID. It simply returns the id, typed as a string.\n *\n * @example\n * ```typescript\n * function shareLink(modelId: string) { ... }\n * shareLink(user.uuid); // works regardless of whether the underlying id is\n * // a Mongo ObjectId string or a SQL integer\n * ```\n */\n public get uuid(): string {\n return this.get(\"id\");\n }\n\n /**\n * Retrieves a field value from the model's data.\n *\n * Supports both top-level keys and dot-notation paths for nested access.\n *\n * @param field - The field name or dot-notation path (e.g., \"address.city\")\n * @param defaultValue - Value to return if the field is missing\n * @returns The field value or the default value if not found\n *\n * @example\n * ```typescript\n * user.get(\"name\"); // \"Alice\"\n * user.get(\"address.city\", \"Unknown\"); // \"Unknown\" if address.city is missing\n * ```\n */\n public get<TKey extends keyof TSchema & string>(field: TKey): TSchema[TKey];\n public get<TKey extends keyof TSchema & string>(\n field: TKey,\n defaultValue: TSchema[TKey],\n ): TSchema[TKey];\n public get<Type extends unknown = any>(field: string): Type;\n public get<Type extends unknown = any>(field: string, defaultValue: Type): Type;\n public get(field: string, defaultValue?: unknown): any {\n return getFieldValue(this, field, defaultValue);\n }\n\n /**\n * Get only the values of the given fields\n */\n public only<TKey extends keyof TSchema & string>(fields: TKey[]): Record<TKey, TSchema[TKey]>;\n public only(fields: string[]): Record<string, unknown>;\n public only(fields: string[]): Record<string, unknown> {\n return getOnlyFields(this, fields);\n }\n\n /**\n * Get a string value\n */\n public string(key: string, defaultValue?: string): string | undefined {\n return getStringField(this, key, defaultValue);\n }\n\n /**\n * Get a number value\n */\n public number(key: string, defaultValue?: number): number | undefined {\n return getNumberField(this, key, defaultValue);\n }\n\n /**\n * Get a boolean value\n */\n public boolean(key: string, defaultValue?: boolean): boolean | undefined {\n return getBooleanField(this, key, defaultValue);\n }\n\n /**\n * Sets a field value in the model's data and marks it as dirty.\n *\n * Supports both top-level keys and dot-notation paths for nested assignment.\n * Automatically updates the dirty tracker to reflect the change.\n *\n * @param field - The field name or dot-notation path (e.g., \"address.city\")\n * @param value - The value to assign\n * @returns The model instance for method chaining\n *\n * @example\n * ```typescript\n * user.set(\"name\", \"Bob\").set(\"address.city\", \"NYC\");\n * ```\n */\n public set<TKey extends keyof TSchema & string>(field: TKey, value: TSchema[TKey]): this;\n public set(field: string, value: unknown): this;\n public set(field: string, value: unknown): this {\n return setFieldValue(this, field, value) as this;\n }\n\n /**\n * Checks whether a field exists in the model's data.\n *\n * Supports both top-level keys and dot-notation paths.\n *\n * @param field - The field name or dot-notation path\n * @returns `true` if the field exists, `false` otherwise\n *\n * @example\n * ```typescript\n * user.has(\"name\"); // true\n * user.has(\"address.zipCode\"); // false\n * ```\n */\n public has<TKey extends keyof TSchema & string>(field: TKey): boolean;\n public has(field: string): boolean;\n public has(field: string): boolean {\n return hasField(this, field);\n }\n\n /**\n * Increment the given field by the given amount\n */\n public increment<TKey extends keyof TSchema & string>(field: TKey, amount: number): this;\n public increment(field: string, amount?: number): this;\n public increment(field: string, amount?: number): this {\n return incrementField(this, field, amount) as this;\n }\n\n /**\n * Decrement the given field by the given amount\n */\n public decrement<TKey extends keyof TSchema & string>(field: TKey, amount: number): this;\n public decrement(field: string, amount?: number): this;\n public decrement(field: string, amount?: number): this {\n return decrementField(this, field, amount) as this;\n }\n\n /**\n * Removes one or more fields from the model's data and marks them as removed.\n *\n * Supports both top-level keys and dot-notation paths.\n * Automatically updates the dirty tracker to reflect the removal.\n *\n * @param fields - One or more field names or dot-notation paths to remove\n * @returns The model instance for method chaining\n *\n * @example\n * ```typescript\n * user.unset(\"tempField\", \"address.oldZip\");\n * ```\n */\n public unset(...fields: (keyof TSchema & string)[]): this;\n public unset(...fields: string[]): this;\n public unset(...fields: string[]): this {\n return unsetFields(this, ...fields) as this;\n }\n\n /**\n * Merges new values into the model's data and marks changed fields as dirty.\n *\n * Performs a deep merge, preserving existing nested structures.\n * Automatically updates the dirty tracker to reflect all changes.\n *\n * @param values - Partial data to merge into the model\n * @returns The model instance for method chaining\n *\n * @example\n * ```typescript\n * user.merge({ name: \"Charlie\", address: { city: \"LA\" } });\n * ```\n */\n public merge(values: Partial<TSchema>): this;\n public merge(values: Record<string, unknown>): this;\n public merge(values: Record<string, unknown>): this {\n return mergeFields(this, values) as this;\n }\n\n /**\n * Perform atomoic update from current model instance\n * Please note that it would require the id to be existing in the current\n * model instance\n * @returns number of affected records\n */\n public async atomicUpdate(operations: Record<string, unknown>): Promise<number> {\n return performAtomicUpdate(this, operations);\n }\n\n /**\n * Perform atomic increment\n * This would issue a query update and update the given field without\n * saving the model\n */\n public async atomicIncrement<T extends keyof TSchema & string>(\n field: T,\n amount: number = 1,\n ): Promise<number> {\n return performAtomicIncrement(this, field, amount);\n }\n\n /**\n * Perform atomic decrement\n * This would issue a query update and update the given field without\n * saving the model\n */\n public async atomicDecrement<T extends keyof TSchema & string>(\n field: T,\n amount: number = 1,\n ): Promise<number> {\n return performAtomicDecrement(this, field, amount);\n }\n\n /**\n * Determine if current model is active\n */\n public get isActive(): boolean {\n return this.get<boolean>(this.isActiveColumn);\n }\n\n /**\n * Get created at date\n */\n public get createdAt(): Date | undefined {\n const createdAtColumn = this.self().createdAtColumn;\n\n if (!createdAtColumn) return;\n\n return this.get<Date>(createdAtColumn);\n }\n\n /**\n * Get updated at date\n */\n public get updatedAt(): Date | undefined {\n const updatedAtColumn = this.self().updatedAtColumn;\n\n if (!updatedAtColumn) return;\n\n return this.get<Date>(updatedAtColumn);\n }\n\n /**\n * Check if current model record is created by the given user model\n */\n public isCreatedBy(user: Model | GenericObject): boolean {\n return this.get(`createdBy.id`) === user.id;\n }\n\n /**\n * Checks whether the model's data has changed since instantiation or last reset.\n *\n * @returns `true` if any fields have been modified or removed, `false` otherwise\n *\n * @example\n * ```typescript\n * const user = new User({ name: \"Alice\" });\n * user.hasChanges(); // false\n * user.set(\"name\", \"Bob\");\n * user.hasChanges(); // true\n * ```\n */\n public hasChanges(): boolean {\n return checkHasChanges(this);\n }\n\n /**\n * Check if the given column has been modified.\n *\n * @param column - The column name to check\n * @returns `true` if the column has been modified, `false` otherwise\n *\n * @example\n * ```typescript\n * user.set(\"name\", \"Bob\");\n * user.isDirty(\"name\"); // true\n * ```\n */\n public isDirty(column: string): boolean {\n return checkIsDirty(this, column);\n }\n\n /**\n * Retrieves all dirty columns with their old and new values.\n *\n * @returns A record mapping each dirty column to its previous and current value\n *\n * @example\n * ```typescript\n * user.set(\"name\", \"Bob\");\n * user.getDirtyColumnsWithValues();\n * // { name: { oldValue: \"Alice\", newValue: \"Bob\" } }\n * ```\n */\n public getDirtyColumnsWithValues(): Record<string, { oldValue: unknown; newValue: unknown }> {\n return getDirtyColumnsWithValues(this);\n }\n\n /**\n * Lists all columns that have been removed from the model's data.\n *\n * @returns An array of field names that were present initially but have been unset\n *\n * @example\n * ```typescript\n * user.unset(\"tempField\");\n * user.getRemovedColumns(); // [\"tempField\"]\n * ```\n */\n public getRemovedColumns(): string[] {\n return getRemovedColumns(this);\n }\n\n /**\n * Lists all columns that have been modified since instantiation or last reset.\n *\n * @returns An array of field names that have changed\n *\n * @example\n * ```typescript\n * user.set(\"name\", \"Bob\");\n * user.getDirtyColumns(); // [\"name\"]\n * ```\n */\n public getDirtyColumns(): string[] {\n return getDirtyColumns(this);\n }\n\n /**\n * Emits a lifecycle event to both per-model and global listeners.\n *\n * This method is public so that external services (like the writer) can trigger\n * lifecycle events when appropriate.\n *\n * @param event - The event name (e.g., \"saving\", \"created\", \"deleting\")\n * @param context - Optional context data to pass to listeners\n *\n * @example\n * ```typescript\n * await user.emitEvent(\"saving\");\n * await user.emitEvent(\"validated\", { errors: [] });\n * ```\n */\n public async emitEvent<TContext = unknown>(\n event: ModelEventName,\n context?: TContext,\n ): Promise<void> {\n return emitModelEvent(this, event, context);\n }\n\n /**\n * Register a listener for a model lifecycle event on this instance.\n *\n * @param event - Event name (e.g., \"saving\", \"updated\")\n * @param listener - Callback function\n * @returns Unsubscribe function\n */\n public on<TContext = unknown>(\n event: ModelEventName,\n listener: ModelEventListener<this, TContext>,\n ): () => void {\n return onModelEvent(this, event, listener as any);\n }\n\n /**\n * Register a one-time listener for a model lifecycle event on this instance.\n *\n * @param event - Event name\n * @param listener - Callback function\n * @returns Unsubscribe function\n */\n public once<TContext = unknown>(\n event: ModelEventName,\n listener: ModelEventListener<this, TContext>,\n ): () => void {\n return onceModelEvent(this, event, listener as any);\n }\n\n /**\n * Remove a listener from this instance.\n *\n * @param event - Event name\n * @param listener - Callback function to remove\n */\n public off<TContext = unknown>(\n event: ModelEventName,\n listener: ModelEventListener<this, TContext>,\n ): void {\n offModelEvent(this, event, listener as any);\n }\n\n /**\n * Resolves the data source associated with this model.\n *\n * Resolution order:\n * 1. If `dataSource` is a string, looks it up in the data-source registry\n * 2. If `dataSource` is a DataSource instance, returns it directly\n * 3. Otherwise, returns the default data source from the registry\n *\n * @returns The resolved DataSource instance\n * @throws Error if no data source is found\n *\n * @example\n * ```typescript\n * class User extends Model {\n * public static dataSource = \"primary\";\n * }\n *\n * const ds = User.getDataSource();\n * ```\n */\n public static getDataSource(): DataSource {\n return resolveDataSource(this as any);\n }\n\n /**\n * Get driver instance\n */\n public static getDriver(): DriverContract {\n return this.getDataSource().driver;\n }\n\n /**\n * Generate next id and set it to current model's id\n */\n public async generateNextId(): Promise<number | string> {\n return generateModelNextId(this);\n }\n\n /**\n * Apply model defaults from data source configuration.\n *\n * This is called automatically by getDataSource() the first time\n * a model accesses its data source. Defaults are only applied if\n * the model doesn't already have its own value set.\n *\n * The hierarchy is:\n * 1. Model static property (highest priority - skipped here)\n * 2. Database config modelDefaults (passed here)\n * 3. Driver modelDefaults (merged before passing here)\n * 4. Framework defaults (fallback values in the code)\n *\n * @param defaults - Model default configuration from data source\n */\n public static applyModelDefaults(defaults: any): void {\n applyDefaultsToModel(this, defaults);\n }\n\n /**\n * Add a global scope that is automatically applied to all queries.\n *\n * Global scopes are inherited by child models and applied before query execution.\n * Use for security filters, multi-tenancy, soft deletes, etc.\n *\n * @param name - Unique name for the scope\n * @param callback - Function that modifies the query\n * @param options - Scope options (timing: 'before' | 'after')\n *\n * @example\n * ```typescript\n * // Multi-tenancy scope\n * Model.addGlobalScope('tenant', (query) => {\n * query.where('tenantId', getCurrentTenant());\n * }, { timing: 'before' });\n *\n * // Soft delete scope\n * User.addGlobalScope('notDeleted', (query) => {\n * query.whereNull('deletedAt');\n * });\n * ```\n */\n public static addGlobalScope(\n name: string,\n callback: (query: QueryBuilderContract) => void,\n options: GlobalScopeOptions = {},\n ): void {\n addGlobalModelScope(this as any, name, callback, options);\n }\n\n /**\n * Remove a global scope by name.\n *\n * @param name - Name of the scope to remove\n *\n * @example\n * ```typescript\n * Model.removeGlobalScope('tenant');\n * ```\n */\n public static removeGlobalScope(name: string): void {\n removeGlobalModelScope(this as any, name);\n }\n\n /**\n * Add a local scope that can be manually applied to queries.\n *\n * Local scopes are reusable query snippets that developers opt into.\n * They are not automatically applied.\n *\n * @param name - Unique name for the scope\n * @param callback - Function that modifies the query\n *\n * @example\n * ```typescript\n * // Define reusable scopes\n * User.addScope('active', (query) => {\n * query.where('isActive', true);\n * });\n *\n * User.addScope('admins', (query) => {\n * query.where('role', 'admin');\n * });\n *\n * // Use explicitly\n * await User.query().scope('active').get();\n * await User.query().scope('admins').get();\n * ```\n */\n public static addScope(name: string, callback: LocalScopeCallback): void {\n addLocalModelScope(this as any, name, callback);\n }\n\n /**\n * Remove a local scope by name.\n *\n * @param name - Name of the scope to remove\n *\n * @example\n * ```typescript\n * User.removeScope('active');\n * ```\n */\n public static removeScope(name: string): void {\n removeLocalModelScope(this as any, name);\n }\n\n /**\n * Create a new query builder for this model\n */\n public static query<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n ): QueryBuilderContract<TModel> {\n return buildQuery(this, Model);\n }\n\n // Short hand for the query builder method with\n /**\n * Eagerly load one or more relations with the query results.\n *\n * Relations are loaded in separate optimized queries to prevent N+1 problems.\n * The loaded relations are attached to each model instance.\n *\n * @param relation - Single relation name to load\n * @returns Query builder for chaining\n *\n * @example\n * ```typescript\n * // Load single relation\n * const user = await User.query().with(\"posts\").find(1);\n * console.log(user.posts); // Post[]\n *\n * // Load multiple relations\n * const user = await User.query().with(\"posts\", \"organization\").find(1);\n *\n * // Load nested relations\n * const user = await User.query().with(\"posts.comments.author\").find(1);\n * ```\n */\n public static with<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n relation: string,\n ): QueryBuilderContract<TModel>;\n\n /**\n * Eagerly load multiple relations.\n *\n * @param relations - Relation names to load\n * @returns Query builder for chaining\n */\n public static with<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n ...relations: string[]\n ): QueryBuilderContract<TModel>;\n\n /**\n * Eagerly load a relation with a constraint callback.\n *\n * The callback receives the relation query builder, allowing you to\n * add conditions, ordering, or limits to the related query.\n *\n * @param relation - Relation name to load\n * @param constraint - Callback to configure the relation query\n * @returns Query builder for chaining\n *\n * @example\n * ```typescript\n * const user = await User.query()\n * .with(\"posts\", (query) => {\n * query.where(\"isPublished\", true)\n * .orderBy(\"createdAt\", \"desc\")\n * .limit(5);\n * })\n * .find(1);\n * ```\n */\n public static with<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n relation: string,\n constraint: (query: QueryBuilderContract) => void,\n ): QueryBuilderContract<TModel>;\n\n /**\n * Eagerly load multiple relations with constraints.\n *\n * Pass an object where keys are relation names and values are either:\n * - `true` to load without constraints\n * - A callback function to configure the relation query\n *\n * @param relations - Object mapping relation names to constraints\n * @returns Query builder for chaining\n *\n * @example\n * ```typescript\n * const user = await User.query()\n * .with({\n * posts: (query) => query.where(\"isPublished\", true),\n * organization: true,\n * roles: (query) => query.orderBy(\"priority\"),\n * })\n * .find(1);\n * ```\n */\n public static with<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n relations: Record<string, boolean | ((query: QueryBuilderContract) => void)>,\n ): QueryBuilderContract<TModel>;\n\n public static with<TModel extends Model = Model>(this: ChildModel<TModel>, ...args: any[]) {\n return this.query().with(...args);\n }\n\n /**\n * Add a count of related records as a virtual field on each result row.\n *\n * Each relation produces a `${relationName}Count` column by default. Use\n * the `\"name as alias\"` shorthand or the object form to customise the\n * output alias or apply per-relation where-clause constraints.\n *\n * @param relation - Relation name (optionally with `as <alias>`)\n * @returns Query builder for chaining\n *\n * @example\n * ```typescript\n * const users = await User.withCount(\"posts\").get();\n * console.log(users[0].postsCount); // number\n * ```\n */\n public static withCount<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n relation: string,\n ): QueryBuilderContract<TModel>;\n\n /**\n * Add counts for multiple relations at once.\n *\n * @example\n * ```typescript\n * await User.withCount(\"posts\", \"comments\", \"followers\").get();\n * ```\n */\n public static withCount<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n ...relations: string[]\n ): QueryBuilderContract<TModel>;\n\n /**\n * Add counts for multiple relations supplied as an array.\n */\n public static withCount<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n relations: string[],\n ): QueryBuilderContract<TModel>;\n\n /**\n * Add counts with optional per-relation constraints and alias overrides.\n *\n * Values may be `true`, an alias string, or a callback that applies\n * where-clauses inside the count subquery. Use the `as <alias>` shorthand\n * in the key to count the same relation more than once.\n *\n * @example\n * ```typescript\n * await Post.withCount({\n * comments: true,\n * \"comments as approvedCount\": (q) => q.where(\"approved\", true),\n * tags: \"tagCount\",\n * }).get();\n * ```\n */\n public static withCount<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n relations: Record<string, true | string | ((query: QueryBuilderContract) => void)>,\n ): QueryBuilderContract<TModel>;\n\n public static withCount<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n ...args: any[]\n ): QueryBuilderContract<TModel> {\n return this.query().withCount(...args);\n }\n\n /**\n * Load relations using database JOINs in a single query.\n *\n * Unlike `with()` which uses separate queries, `joinWith()` uses\n * LEFT JOIN (SQL) or $lookup (MongoDB) to fetch related data\n * in a single query. The related data is hydrated into proper\n * model instances and attached to the main model.\n *\n * Best for: belongsTo and hasOne relations where you need\n * efficient single-query loading.\n *\n * @param relations - Relation names to load via JOIN\n * @returns Query builder for chaining\n *\n * @example\n * ```typescript\n * // Single relation\n * const post = await Post.joinWith(\"author\").first();\n * console.log(post.author); // User model instance\n * console.log(post.data); // { id, title, authorId } - no author data\n *\n * // Multiple relations\n * const post = await Post.joinWith(\"author\", \"category\").first();\n * ```\n */\n public static joinWith<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n ...relations: string[]\n ): QueryBuilderContract<TModel> {\n return this.query().joinWith(...relations);\n }\n\n /**\n * Create new query builder.\n *\n * If the model has a static `builder` property set to a query builder class,\n * it will be instantiated instead of the default driver query builder.\n *\n * @example\n * ```typescript\n * class UserQueryBuilder<T = User> extends MongoQueryBuilder<T> {\n * active() { return this.where(\"isActive\", true); }\n * }\n *\n * class User extends Model {\n * static builder = UserQueryBuilder; // That's it! ✨\n * }\n *\n * // Now User.query() returns UserQueryBuilder<User> with autocomplete!\n * ```\n */\n public static newQueryBuilder<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n ): QueryBuilderContract<TModel> {\n return buildNewQueryBuilder(this);\n }\n\n /**\n * Get First matched record for the given filter\n */\n public static async first<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n filter?: Record<string, unknown>,\n ): Promise<TModel | null> {\n return findFirst(this, filter);\n }\n\n /**\n * Get last matched record for the given filter\n */\n public static async last<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n filter?: Record<string, unknown>,\n ): Promise<TModel | null> {\n return findLast(this, filter);\n }\n\n /**\n * Use where clause directly\n */\n public static where<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n field: string,\n value: unknown,\n ): QueryBuilderContract<TModel>;\n public static where<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n field: string,\n operator: WhereOperator,\n value: unknown,\n ): QueryBuilderContract<TModel>;\n public static where<TModel extends Model = Model>(\n this: (new (...args: any[]) => TModel) &\n Pick<typeof Model, \"query\" | \"getDataSource\" | \"table\">,\n conditions: WhereObject,\n ): QueryBuilderContract<TModel>;\n public static where<TModel extends Model = Model>(\n this: (new (...args: any[]) => TModel) &\n Pick<typeof Model, \"query\" | \"getDataSource\" | \"table\">,\n callback: WhereCallback<TModel>,\n ): QueryBuilderContract<TModel>;\n public static where<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n ...args: any[]\n ): QueryBuilderContract<TModel> {\n return (this.query().where as any)(...args);\n }\n\n /**\n * Count the number of records in the table\n * @param filter - The filter to apply to the query\n */\n public static count<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n filter?: Record<string, unknown>,\n ): Promise<number> {\n return countRecords(this, filter);\n }\n\n /**\n * Find record by id\n */\n public static async find<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n id: string | number,\n ): Promise<TModel | null> {\n return findById(this, id);\n }\n\n /**\n * Get all records from the table\n *\n * @param filter - The filter to apply to the query\n * @returns All records from the table\n */\n public static async all<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n filter?: Record<string, unknown>,\n ): Promise<TModel[]> {\n return findAll(this, filter);\n }\n\n /**\n * Perform pagination\n */\n public static async paginate<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n options: PaginationOptions & {\n filter?: Record<string, unknown>;\n } = {},\n ): Promise<PaginationResult<TModel>> {\n return paginateRecords(this, options);\n }\n\n /**\n * Get latest records from the table\n *\n * @param filter - The filter to apply to the query\n */\n public static async latest<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n filter?: Record<string, unknown>,\n ): Promise<TModel[]> {\n return findLatest(this, filter);\n }\n\n /**\n * Increment the given field by the given amount using atomic update\n *\n * @example ```typescript\n * // Increase age by 1 for user id 1\n * User.increment({id: 1}, \"age\", 1);\n * // Increase age by 1 and views by 2 for user id 1\n * User.increment({id: 1}, {age: 1, views: 2});\n * ```\n */\n public static increase<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n filter: Record<string, unknown>,\n field: string,\n amount: number,\n ): Promise<number> {\n return increaseField(this, filter, field, amount);\n }\n\n /**\n * Decrement the given field by the given amount using atomic update\n * @example ```typescript\n * // Decrease age by 1 for user id 1\n * User.decrement({id: 1}, \"age\", 1);\n * // Decrease age by 1 and views by 2 for user id 1\n * User.decrement({id: 1}, {age: 1, views: 2});\n * ```\n */\n public static decrease<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n filter: Record<string, unknown>,\n field: string,\n amount: number,\n ): Promise<number> {\n return decreaseField(this, filter, field, amount);\n }\n\n /**\n * Perform atomic operation\n * Example\n *\n * ```typescript\n * const user = await User.atomic({id: 1}, {$inc: {age: 1}})\n * Returns user model with updated age\n */\n public static async atomic<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n filter: Record<string, unknown>,\n operations: UpdateOperations,\n ): Promise<number> {\n return performAtomic(this, filter, operations);\n }\n\n /**\n * Perform an atomic update for the given id\n */\n public static async update<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n id: string | number,\n data: Record<string, unknown>,\n ): Promise<number> {\n return updateById(this, id, data);\n }\n\n /**\n * Find one and update multiple records that matches the provided filter and return the updated record\n * @param filter - Filter conditions\n * @param update - Update operations ($set, $unset, $inc)\n * @returns The updated records\n */\n public static async findAndUpdate<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n filter: Record<string, unknown>,\n update: UpdateOperations,\n ): Promise<TModel[]> {\n return findAndUpdateRecords(this, filter, update);\n }\n\n /**\n * Find one and update a single record that matches the provided filter and return the updated record\n * @param filter - Filter conditions\n * @param update - Update operations ($set, $unset, $inc)\n * @returns The updated record or null\n */\n public static async findOneAndUpdate<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n filter: Record<string, unknown>,\n update: UpdateOperations,\n ): Promise<TModel | null> {\n return findOneAndUpdateRecord(this, filter, update);\n }\n\n /**\n * Find and replace the entire document that matches the provided filter and return the replaced document\n */\n public static async findAndReplace<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n filter: Record<string, unknown>,\n document: Record<string, unknown>,\n ): Promise<TModel | null> {\n return findAndReplaceRecord(this, filter, document);\n }\n\n /**\n * Destroy (delete) the current model instance from the database.\n *\n * Emits lifecycle events:\n * - `deleting` - Before deletion\n * - `deleted` - After successful deletion\n *\n * @param options - Destroy options (strategy override, skipEvents)\n * @throws {Error} If the model is new (not saved) or if deletion fails\n *\n * @example\n * ```typescript\n * const user = await User.find(1);\n * await user.destroy(); // Uses default strategy\n * await user.destroy({ strategy: \"permanent\" }); // Override strategy\n * await user.destroy({ skipEvents: true }); // Silent delete\n * ```\n */\n public async destroy(options?: {\n strategy?: DeleteStrategy;\n skipEvents?: boolean;\n }): Promise<RemoverResult> {\n return destroyModel(this, options);\n }\n\n /**\n * Attach one or more related records to a `belongsToMany` pivot table.\n *\n * Thin wrapper over `createPivotOperations(this, relation).attach(ids, pivotData)`.\n * Throws if the named relation is not a `belongsToMany` relation.\n *\n * @example\n * ```typescript\n * await post.attach(\"tags\", [1, 2, 3]);\n * await post.attach(\"tags\", [4], { addedBy: currentUserId });\n * ```\n */\n public async attach(relation: string, ids: PivotIds, pivotData?: PivotData): Promise<void> {\n return attachPivotRelation(this, relation, ids, pivotData);\n }\n\n /**\n * Detach related records from a `belongsToMany` pivot table. Omit `ids`\n * to detach every row for this side of the relation.\n *\n * Thin wrapper over `createPivotOperations(this, relation).detach(ids)`.\n * Throws if the named relation is not a `belongsToMany` relation.\n *\n * @example\n * ```typescript\n * await post.detach(\"tags\", [2]);\n * await post.detach(\"tags\"); // detach all\n * ```\n */\n public async detach(relation: string, ids?: PivotIds): Promise<void> {\n return detachPivotRelation(this, relation, ids);\n }\n\n /**\n * Get the pivot-operations handle for a `belongsToMany` relation.\n *\n * Returns a `PivotOperations` object exposing `attach` / `detach` /\n * `sync` / `toggle` for the named relation's pivot table. Routing every\n * pivot mutation through `model.pivot(relation)` keeps the join-table\n * `sync` distinct from `Model.sync(Target, field)` (the denormalization\n * feature). Throws if the named relation is not a `belongsToMany` relation.\n *\n * @example\n * ```typescript\n * await post.pivot(\"tags\").attach([1, 2, 3]);\n * await post.pivot(\"tags\").sync([1, 3, 5]); // replace the whole set\n * await post.pivot(\"tags\").toggle([1, 7]); // flip each\n * ```\n */\n public pivot(relation: string): PivotOperations {\n return pivotRelation(this, relation);\n }\n\n /**\n * Get the class constructor from an instance.\n *\n * This helper method allows instance methods to access static properties\n * and methods of the model class in a type-safe way.\n *\n * @returns The model class constructor\n *\n * @example\n * ```typescript\n * const constructor = this.self();\n * const table = constructor.table;\n * await constructor.deleteOne({ id: 1 });\n * ```\n */\n public self<TModel extends Model = this>(): ChildModel<TModel> {\n return this.constructor as any as ChildModel<TModel>;\n }\n\n /**\n * Creates an immutable clone of the model with its current state.\n *\n * The cloned model:\n * - Contains a deep copy of all current data\n * - Has frozen (immutable) data that cannot be modified\n * - Preserves the `isNew` flag from the original\n * - Has no dirty changes (clean state)\n * - Cannot be saved or modified\n *\n * This is useful for:\n * - Creating snapshots of model state\n * - Passing read-only model data to other parts of the application\n * - Preventing accidental mutations\n * - Maintaining historical records\n *\n * @returns A new immutable model instance with the current state\n *\n * @example\n * ```typescript\n * const user = new User({ name: \"Alice\", email: \"alice@example.com\" });\n * await user.save();\n *\n * // Create an immutable snapshot\n * const snapshot = user.clone();\n *\n * // This will throw an error because the clone is immutable\n * snapshot.set(\"name\", \"Bob\"); // TypeError: Cannot assign to read only property\n *\n * // Original can still be modified\n * user.set(\"name\", \"Bob\");\n * await user.save();\n * ```\n */\n public clone(): this {\n return cloneModel(this);\n }\n\n /**\n * Recursively freezes an object and all its nested properties.\n *\n * @param obj - The object to freeze\n * @returns The frozen object\n */\n public deepFreeze<T>(obj: T): T {\n return deepFreezeObject(obj);\n }\n\n /**\n * Get table name\n */\n public getTableName(): string {\n return this.self().table;\n }\n\n /**\n * Get primary key name\n */\n public getPrimaryKey(): string {\n return this.self().primaryKey;\n }\n\n /**\n * Get model schema\n */\n public getSchema() {\n return this.self().schema;\n }\n\n /**\n * Check if schema has the given key\n */\n public schemaHas(key: string): boolean {\n return this.self().schema?.schema[key] !== undefined;\n }\n\n /**\n * Get strict mode\n */\n public getStrictMode(): StrictMode {\n return this.self().strictMode;\n }\n\n /**\n * Get data source (Connection)\n */\n public getConnection(): DataSource {\n return this.self().getDataSource();\n }\n\n /**\n * Delete all matching documents from the table.\n */\n public static async delete<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n filter?: Record<string, unknown>,\n ): Promise<number> {\n return deleteRecords(this, filter);\n }\n\n /**\n * Delete a single matching document from the table.\n */\n public static async deleteOne<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n filter?: Record<string, unknown>,\n ): Promise<number> {\n return deleteOneRecord(this, filter);\n }\n\n /**\n * Restore a single deleted record by its ID.\n *\n * Automatically detects whether the record was deleted via \"trash\" or \"soft\" strategy.\n * Handles ID conflicts based on options.\n *\n * @param id - The primary key value of the record to restore\n * @param options - Restorer options (onIdConflict, skipEvents)\n * @returns The restored model instance\n *\n * @throws {Error} If record not found in trash or soft-deleted records\n * @throws {Error} If ID conflict and onIdConflict is \"fail\"\n *\n * @example\n * ```typescript\n * // Restore with default options (assign new ID if conflict)\n * const user = await User.restore(123);\n *\n * // Restore and fail if ID conflict\n * const user = await User.restore(123, { onIdConflict: \"fail\" });\n *\n * // Silent restore (skip events)\n * const user = await User.restore(123, { skipEvents: true });\n * ```\n */\n public static async restore<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n id: string | number,\n options?: {\n onIdConflict?: \"fail\" | \"assignNew\";\n skipEvents?: boolean;\n },\n ): Promise<TModel> {\n return restoreRecord(this, id, options);\n }\n\n /**\n * Restore all deleted records for the model's table.\n *\n * Restores all records from the trash table (if using trash strategy)\n * or all soft-deleted records (if using soft strategy).\n *\n * @param options - Restorer options (onIdConflict, skipEvents)\n * @returns Array of restored model instances\n *\n * @example\n * ```typescript\n * // Restore all with default options\n * const users = await User.restoreAll();\n *\n * // Restore all and fail on any ID conflict\n * const users = await User.restoreAll({ onIdConflict: \"fail\" });\n * ```\n */\n public static async restoreAll<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n options?: {\n onIdConflict?: \"fail\" | \"assignNew\";\n skipEvents?: boolean;\n },\n ): Promise<TModel[]> {\n return restoreAllRecords(this, options);\n }\n\n /**\n * Create a new record in database and return the model instance.\n *\n * The data type is automatically inferred from the model's schema type.\n *\n * @param data - Partial data matching the model's schema type\n * @returns The created model instance\n *\n * @example\n * ```typescript\n * // TypeScript automatically infers UserSchema from User model\n * const user = await User.create({\n * name: \"Alice\",\n * email: \"alice@example.com\",\n * age: 30\n * });\n * // Type: User (with UserSchema inferred)\n * ```\n */\n public static async create<\n TModel extends Model = Model,\n TSchema extends ModelSchema = TModel extends Model<infer S> ? S : ModelSchema,\n >(this: ChildModel<TModel>, data: Partial<TSchema>): Promise<TModel> {\n return createRecord(this, data);\n }\n\n /**\n * Create many documents and return an array of created models\n */\n public static async createMany<\n TModel extends Model = Model,\n TSchema extends ModelSchema = TModel extends Model<infer S> ? S : ModelSchema,\n >(this: ChildModel<TModel>, data: Partial<TSchema>[]): Promise<TModel[]> {\n return createManyRecords(this, data);\n }\n\n /**\n * Find a record or create it if not found.\n *\n * Does NOT update existing records - returns them as-is.\n * Useful when you want to ensure a record exists without modifying it.\n *\n * @param filter - Conditions to find by\n * @param data - Data to create if not found (merged with filter)\n * @returns Promise resolving to found or created model\n *\n * @example\n * ```typescript\n * // Ensure default admin exists (don't modify if exists)\n * const admin = await User.findOrCreate(\n * { email: \"admin@example.com\" },\n * { email: \"admin@example.com\", name: \"Admin\", role: \"admin\" }\n * );\n * // If admin exists, returns existing (password unchanged)\n * // If not found, creates new admin\n * ```\n */\n public static async findOrCreate<\n TModel extends Model = Model,\n TSchema extends ModelSchema = TModel extends Model<infer S> ? S : ModelSchema,\n >(this: ChildModel<TModel>, filter: Partial<TSchema>, data: Partial<TSchema>): Promise<TModel> {\n return findOrCreateRecord(this, filter, data);\n }\n\n /**\n * Upsert (insert or update) a record atomically.\n *\n * Uses the driver's native upsert operation for atomic insert-or-update.\n * More efficient than updateOrCreate as it's a single database operation.\n *\n * Includes full Model features:\n * - ID generation (if creating)\n * - createdAt timestamp (if creating)\n * - updatedAt timestamp (always)\n * - Validation & casting\n * - Lifecycle events\n *\n * @param filter - Conditions to find by (used for conflict detection)\n * @param data - Data to update or create (merged with filter)\n * @param options - Upsert options (conflictColumns for PostgreSQL, etc.)\n * @returns Promise resolving to upserted model\n *\n * @example\n * ```typescript\n * // PostgreSQL: upsert on unique email\n * const user = await User.upsert(\n * { email: \"user@example.com\" },\n * {\n * email: \"user@example.com\",\n * name: \"John Updated\",\n * lastSyncedAt: new Date()\n * },\n * { conflictColumns: [\"email\"] }\n * );\n *\n * // MongoDB: upsert by filter\n * const user = await User.upsert(\n * { externalId: \"ext-123\" },\n * {\n * externalId: \"ext-123\",\n * name: \"John Updated\",\n * email: \"john.new@example.com\"\n * }\n * );\n * ```\n */\n public static async upsert<\n TModel extends Model = Model,\n TSchema extends ModelSchema = TModel extends Model<infer S> ? S : ModelSchema,\n >(\n this: ChildModel<TModel>,\n filter: Partial<TSchema>,\n data: Partial<TSchema>,\n options?: Record<string, unknown>,\n ): Promise<TModel> {\n return upsertRecord(this, filter, data, options);\n }\n\n /**\n * Update a record or create it if not found (upsert).\n *\n * @deprecated Use `upsert()` instead for better performance and atomicity.\n * This method is kept for backward compatibility but uses upsert internally.\n *\n * @param filter - Conditions to find by\n * @param data - Data to update or create (merged with filter)\n * @returns Promise resolving to updated or created model\n */\n public static async updateOrCreate<\n TModel extends Model = Model,\n TSchema extends ModelSchema = TModel extends Model<infer S> ? S : ModelSchema,\n >(\n this: ChildModel<TModel>,\n filter: Partial<TSchema>,\n data: Partial<TSchema>,\n options?: Record<string, unknown>,\n ): Promise<TModel> {\n // Use upsert internally for better performance\n return await (this as any).upsert(filter, data, options);\n }\n\n /**\n * Find one and delete a record that matches the filter and return the deleted record.\n *\n * @param filter - Filter conditions\n * @param options - Optional delete options\n * @returns The deleted model instance or null if not found\n *\n * @example\n * ```typescript\n * const deleted = await User.findOneAndDelete({ id: 1 });\n * if (deleted) {\n * console.log('Deleted user:', deleted.get('name'));\n * }\n * ```\n */\n public static async findOneAndDelete<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n filter: Record<string, unknown>,\n options?: Record<string, unknown>,\n ): Promise<TModel | null> {\n return findOneAndDeleteRecord(this, filter, options);\n }\n\n /**\n * Returns embedded data for sync operations.\n * Excludes internal MongoDB fields and ensures proper date serialization.\n *\n * @returns Embedded data object suitable for syncing\n *\n * @example\n * ```typescript\n * const user = await User.find(1);\n * const embedData = user.embedData;\n * // Returns: { id: 1, name: \"Alice\", email: \"alice@example.com\", ... }\n * // Excludes: _id\n * ```\n */\n public get embedData(): Record<string, unknown> {\n return this.self().embed ? this.only(this.self().embed as any) : this.data;\n }\n\n /**\n * Tear down framework-level registrations attached to this Model class.\n *\n * Called by Warlock's HMR machinery when a model file (or any file in its\n * dependency graph) is reloaded. Removes the event listeners and registry\n * entries the Model installed at module-load time so the reloaded class\n * does not double-register.\n *\n * The `$` prefix marks this as framework-internal — application code should\n * not call this. It is part of the public surface only because the HMR\n * system needs to invoke it from outside the Model class.\n *\n * @internal\n */\n public static $cleanup() {\n cleanupModelEvents(this);\n }\n\n /**\n * Accesses the event emitter dedicated to this model constructor.\n *\n * Each model subclass gets its own isolated event emitter, allowing you to\n * register lifecycle hooks that only apply to that specific model.\n *\n * @returns The ModelEvents instance for this model constructor\n *\n * @example\n * ```typescript\n * User.events().onSaving((user) => {\n * console.log(\"User is being saved:\", user);\n * });\n * ```\n */\n public static events<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n ): ModelEvents<TModel> {\n return getModelEvents<TModel>(this);\n }\n\n /**\n * Registers an event listener for this model constructor.\n *\n * Convenience shorthand for `Model.events().on(...)`.\n *\n * @param event - The event name (e.g., \"saving\", \"created\")\n * @param listener - The callback to invoke when the event fires\n * @returns An unsubscribe function\n *\n * @example\n * ```typescript\n * const unsubscribe = User.on(\"saving\", (user) => {\n * console.log(\"Saving user:\", user);\n * });\n * ```\n */\n public static on<TModel extends Model = Model, TContext = unknown>(\n this: ChildModel<TModel>,\n event: ModelEventName,\n listener: ModelEventListener<TModel, TContext>,\n ): () => void {\n return onStaticEvent<TModel, TContext>(this, event, listener);\n }\n\n /**\n * Registers a one-time event listener for this model constructor.\n *\n * The listener will automatically unsubscribe after its first invocation.\n * Convenience shorthand for `Model.events().once(...)`.\n *\n * @param event - The event name (e.g., \"saving\", \"created\")\n * @param listener - The callback to invoke when the event fires\n * @returns An unsubscribe function\n *\n * @example\n * ```typescript\n * User.once(\"created\", (user) => {\n * console.log(\"First user created:\", user);\n * });\n * ```\n */\n public static once<TModel extends Model = Model, TContext = unknown>(\n this: ChildModel<TModel>,\n event: ModelEventName,\n listener: ModelEventListener<TModel, TContext>,\n ): () => void {\n return onceStaticEvent<TModel, TContext>(this, event, listener);\n }\n\n /**\n * Removes an event listener from this model constructor.\n *\n * Convenience shorthand for `Model.events().off(...)`.\n *\n * @param event - The event name\n * @param listener - The callback to remove\n *\n * @example\n * ```typescript\n * const listener = (user) => console.log(user);\n * User.on(\"saving\", listener);\n * User.off(\"saving\", listener);\n * ```\n */\n public static off<TModel extends Model = Model, TContext = unknown>(\n this: ChildModel<TModel>,\n event: ModelEventName,\n listener: ModelEventListener<TModel, TContext>,\n ): void {\n offStaticEvent<TModel, TContext>(this, event, listener);\n }\n\n /**\n * Accesses the global event emitter shared by all model instances.\n *\n * Use this for cross-cutting concerns like auditing, logging, or injecting\n * common fields (e.g., `createdBy`, `updatedBy`) across all models.\n *\n * @returns The global ModelEvents instance\n *\n * @example\n * ```typescript\n * Model.globalEvents().onSaving((model) => {\n * model.set(\"updatedAt\", new Date());\n * });\n * ```\n */\n public static globalEvents(): ModelEvents<Model> {\n return getGlobalEvents();\n }\n\n /**\n * Replace the model's data entirely.\n *\n * Used internally by the writer after validation to update the model\n * with validated/casted data.\n *\n * **Warning:** This replaces all data and updates the dirty tracker.\n * Use with caution in application code.\n *\n * @param data - New data to replace current data\n *\n * @example\n * ```typescript\n * // Internal usage by writer\n * model.replaceData(validatedData);\n * ```\n */\n public replaceData(data: Record<string, unknown>): void {\n replaceModelData(this, data);\n }\n\n /**\n * Save the model to the database.\n *\n * Performs insert if `isNew === true`, otherwise performs update.\n * Automatically validates, casts, generates IDs, and emits lifecycle events.\n *\n * **Features:**\n * - Validation via @warlock.js/seal schema\n * - Data casting (string → number, etc.)\n * - ID generation (NoSQL only)\n * - Partial updates (only changed fields)\n * - Lifecycle events (validating, saving, created/updated, saved)\n *\n * @param data - Optional data to merge before saving\n * @param options - Save options\n * @returns The model instance for method chaining\n *\n * @throws {ValidationError} If validation fails\n * @throws {Error} If database operation fails\n *\n * @example\n * ```typescript\n * // Simple save\n * const user = new User({ name: \"Alice\" });\n * await user.save();\n *\n * // Merge data before saving\n * await user.save({ age: 31, email: \"alice@example.com\" });\n *\n * // Silent save (no events)\n * await user.save(null, { skipEvents: true });\n *\n * // Skip validation\n * await user.save(null, { skipValidation: true });\n *\n * // Method chaining\n * await user.set(\"name\", \"Bob\").save();\n * ```\n */\n public async save(options?: WriterOptions & { merge?: Partial<TSchema> }): Promise<this> {\n return saveModel(this as any, options) as Promise<this>;\n }\n\n /**\n * Serialize the model data for storage in the database.\n *\n * Uses the driver's `serialize` to apply driver-specific type transformations\n * (e.g. Date → ISO string, BigInt → string for Postgres).\n *\n * **Not** the same as `toSnapshot` — this is a DB write concern, not a cache concern.\n */\n public serialize() {\n return serializeModel(this);\n }\n\n /**\n * Produce a plain-object snapshot of this model suitable for cache storage.\n *\n * - `data`: The model's own fields, serialized via the driver (handles Dates, BigInt, ObjectId).\n * - `relations`: Each entry in `loadedRelations` recursively snapshotted via `toSnapshot`.\n * A relation that was loaded but resolved to `null` is stored as `null` (not omitted),\n * so that `fromSnapshot` can distinguish \"loaded + null\" from \"never loaded\".\n *\n * Use `Model.fromSnapshot(snapshot)` to reconstruct.\n *\n * @example\n * ```typescript\n * await cache.set(key, chat.toSnapshot());\n * ```\n */\n public toSnapshot(): ModelSnapshot {\n return modelToSnapshot(this);\n }\n\n /**\n * Reconstruct a model instance (with relations) from a cache snapshot.\n *\n * Counterpart to `toSnapshot`. Applies driver deserialization (e.g. ISO string → Date)\n * and recursively hydrates any nested relation snapshots via `RelationHydrator`.\n *\n * @example\n * ```typescript\n * const snapshot = await cache.get(key);\n * const chat = Chat.fromSnapshot(snapshot);\n * chat.unit; // Unit model instance, fully hydrated\n * ```\n */\n public static fromSnapshot<TModel extends Model>(\n this: ChildModel<TModel>,\n snapshot: ModelSnapshot,\n ): TModel {\n return modelFromSnapshot(this, snapshot);\n }\n\n /**\n * Create a model instance from raw data (no relations).\n *\n * This is the data-only hydration path, used by the query builder when\n * converting a raw DB row into a model instance. Relations are NOT restored\n * here — use `fromSnapshot` when restoring from a cache snapshot that\n * includes relation data.\n *\n * @example\n * ```typescript\n * // Query builder internals:\n * const user = User.hydrate(rawRow);\n * ```\n */\n public static hydrate<TModel extends Model = Model>(\n this: ChildModel<TModel>,\n data: Record<string, unknown>,\n ): TModel {\n return hydrateModel(this, data);\n }\n\n /**\n * Convert the model into JSON\n */\n public toJSON() {\n return modelToJSON(this);\n }\n}\n","/**\n * Database-agnostic aggregation expressions.\n *\n * `count` / `sum` / `avg` / `min` / `max` are **cross-driver** — the same\n * call compiles to the native shape on every supported database (MongoDB\n * `{ $sum: \"$field\" }`, SQL `SUM(field)`, ...).\n *\n * `distinct` / `floor` / `first` / `last` are **MongoDB-only**. They have no\n * single-scalar `GROUP BY` equivalent in SQL, so on Postgres they throw a\n * fail-fast error at the `.groupBy()` call (naming the `selectRaw` /\n * `havingRaw` escape hatch) rather than emit a silently-different query.\n *\n * @example\n * ```typescript\n * import { $agg } from '@warlock.js/cascade';\n *\n * // Works for both MongoDB and SQL\n * Lesson.query()\n * .groupBy(\"type\", {\n * count: $agg.count(),\n * total: $agg.sum(\"duration\"),\n * avg: $agg.avg(\"rating\")\n * })\n * .get();\n * ```\n */\n\n/**\n * Abstract aggregate expression format.\n *\n * This format is database-agnostic and will be translated by each driver\n * to their native syntax.\n */\nexport type AggregateExpression = {\n /** The aggregate function type */\n __agg: AggregateFunction;\n /** The field to aggregate (null for count) */\n __field: string | null;\n};\n\n/**\n * Supported aggregate functions.\n */\nexport type AggregateFunction =\n | \"count\"\n | \"sum\"\n | \"avg\"\n | \"min\"\n | \"max\"\n | \"first\"\n | \"last\"\n | \"distinct\"\n | \"floor\";\n\n/**\n * Checks if a value is an abstract aggregate expression.\n */\nexport function isAggregateExpression(value: unknown): value is AggregateExpression {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"__field\" in value &&\n typeof (value as AggregateExpression).__agg === \"string\"\n );\n}\n\n/**\n * Database-agnostic aggregation expression helpers.\n *\n * These helpers create abstract expressions that each driver translates\n * to their native format.\n */\nexport const $agg = {\n /**\n * Count documents in each group.\n *\n * @returns Abstract count expression\n *\n * @example\n * ```typescript\n * query.groupBy(\"type\", {\n * count: $agg.count()\n * });\n * ```\n *\n * Translates to:\n * - MongoDB: `{ $sum: 1 }`\n * - SQL: `COUNT(*)`\n */\n count(): AggregateExpression {\n return { __agg: \"count\", __field: null };\n },\n\n /**\n * Sum a numeric field across documents in each group.\n *\n * @param field - The field name to sum\n * @returns Abstract sum expression\n *\n * @example\n * ```typescript\n * query.groupBy(\"type\", {\n * totalDuration: $agg.sum(\"duration\")\n * });\n * ```\n *\n * Translates to:\n * - MongoDB: `{ $sum: \"$duration\" }`\n * - SQL: `SUM(duration)`\n */\n sum(field: string): AggregateExpression {\n return { __agg: \"sum\", __field: field };\n },\n\n /**\n * Calculate the average value of a field across documents in each group.\n *\n * @param field - The field name to average\n * @returns Abstract average expression\n *\n * @example\n * ```typescript\n * query.groupBy(\"type\", {\n * avgRating: $agg.avg(\"rating\")\n * });\n * ```\n *\n * Translates to:\n * - MongoDB: `{ $avg: \"$rating\" }`\n * - SQL: `AVG(rating)`\n */\n avg(field: string): AggregateExpression {\n return { __agg: \"avg\", __field: field };\n },\n\n /**\n * Get the minimum value of a field across documents in each group.\n *\n * @param field - The field name\n * @returns Abstract min expression\n *\n * @example\n * ```typescript\n * query.groupBy(\"type\", {\n * minPrice: $agg.min(\"price\")\n * });\n * ```\n *\n * Translates to:\n * - MongoDB: `{ $min: \"$price\" }`\n * - SQL: `MIN(price)`\n */\n min(field: string): AggregateExpression {\n return { __agg: \"min\", __field: field };\n },\n\n /**\n * Get the maximum value of a field across documents in each group.\n *\n * @param field - The field name\n * @returns Abstract max expression\n *\n * @example\n * ```typescript\n * query.groupBy(\"type\", {\n * maxPrice: $agg.max(\"price\")\n * });\n * ```\n *\n * Translates to:\n * - MongoDB: `{ $max: \"$price\" }`\n * - SQL: `MAX(price)`\n */\n max(field: string): AggregateExpression {\n return { __agg: \"max\", __field: field };\n },\n\n /**\n * Get the distinct values of a field across documents in each group.\n *\n * @param field - The field name\n * @returns Abstract distinct expression\n *\n * @example\n * ```typescript\n * query.groupBy(\"type\", {\n * distinctColors: $agg.distinct(\"color\")\n * });\n * ```\n *\n * **MongoDB-only.** MongoDB: `{ $distinct: \"$color\" }` (returns the array\n * of distinct values). On Postgres this throws — SQL `DISTINCT` is a set\n * quantifier, not a scalar aggregate, so there is no equivalent single\n * value to put in a `GROUP BY` projection. Use `selectRaw` if you need a\n * Postgres-specific shape (e.g. `array_agg(DISTINCT color)`).\n */\n distinct(field: string): AggregateExpression {\n return { __agg: \"distinct\", __field: field };\n },\n\n /**\n * Get the floor value of a field across documents in each group.\n *\n * @param field - The field name\n * @returns Abstract floor expression\n *\n * @example\n * ```typescript\n * query.groupBy(\"type\", {\n * floorPrice: $agg.floor(\"price\")\n * });\n * ```\n *\n * **MongoDB-only.** MongoDB: `{ $floor: \"$price\" }`. On Postgres this\n * throws — `FLOOR` is a scalar function, not an aggregate, so it is\n * meaningless inside a bare `$group` / `GROUP BY`. Use `selectRaw` with\n * `FLOOR(...)` over the aggregated value if you need it on Postgres.\n */\n floor(field: string): AggregateExpression {\n return { __agg: \"floor\", __field: field };\n },\n\n /**\n * Get the first value of a field in each group (order-dependent).\n *\n * @param field - The field name\n * @returns Abstract first expression\n *\n * @example\n * ```typescript\n * query.groupBy(\"type\", {\n * firstName: $agg.first(\"name\")\n * });\n * ```\n *\n * **MongoDB-only.** MongoDB: `{ $first: \"$name\" }` (group-order\n * dependent). On Postgres this throws — the SQL equivalent is\n * `FIRST_VALUE(name) OVER (ORDER BY ...)`, a window function needing an\n * ordering context the `$agg` API doesn't carry. Use `selectRaw` with an\n * explicit window function if you need it on Postgres.\n */\n first(field: string): AggregateExpression {\n return { __agg: \"first\", __field: field };\n },\n\n /**\n * Get the last value of a field in each group (order-dependent).\n *\n * @param field - The field name\n * @returns Abstract last expression\n *\n * @example\n * ```typescript\n * query.groupBy(\"type\", {\n * lastName: $agg.last(\"name\")\n * });\n * ```\n *\n * **MongoDB-only.** MongoDB: `{ $last: \"$name\" }` (group-order\n * dependent). On Postgres this throws — the SQL equivalent is\n * `LAST_VALUE(name) OVER (ORDER BY ...)`, a window function needing an\n * ordering context the `$agg` API doesn't carry. Use `selectRaw` with an\n * explicit window function if you need it on Postgres.\n */\n last(field: string): AggregateExpression {\n return { __agg: \"last\", __field: field };\n },\n};\n","const isoRegex = /^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z?)?$/;\n\n/**\n * Check if the given value is a valid date value\n */\nexport function isValidDateValue(value: unknown): boolean {\n // ✅ Handle timestamps\n if (typeof value === \"number\") {\n if (!Number.isFinite(value)) return false;\n\n const date = new Date(value);\n return !Number.isNaN(date.getTime());\n }\n\n // ❌ Only allow strict ISO strings\n if (typeof value !== \"string\") return false;\n\n if (!isoRegex.test(value)) return false;\n\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return false;\n\n // 🔥 Critical step: prevent JS auto-correction\n // Example: \"2023-02-31\" → March 3 (WRONG but \"valid\")\n const [y, m, d] = value.split(\"T\")[0].split(\"-\").map(Number);\n\n return date.getUTCFullYear() === y && date.getUTCMonth() + 1 === m && date.getUTCDate() === d;\n}\n","import { colors } from \"@mongez/copper\";\nimport type { Db, IndexDescriptionInfo } from \"mongodb\";\nimport {\n DriverBlueprintContract,\n TableIndexInformation,\n} from \"../../contracts/driver-blueprint.contract\";\n\nexport class MongoDBBlueprint implements DriverBlueprintContract {\n /**\n * Constructor\n */\n public constructor(protected database: Db) {}\n\n /**\n * List all tables in the database\n */\n public async listTables(): Promise<string[]> {\n const collections = await this.database.listCollections().toArray();\n return collections.map((collection) => collection.name);\n }\n\n /**\n * List all indexes for a specific table\n */\n public async listIndexes(table: string): Promise<TableIndexInformation[]> {\n const collection = this.database.collection(table);\n const indexes = await collection.indexes();\n return indexes.map(this.buildIndexInformation);\n }\n\n /**\n * Build index information\n */\n protected buildIndexInformation(index: IndexDescriptionInfo): TableIndexInformation {\n return {\n name: index.name!,\n type: index.type,\n columns: Object.keys(index.key),\n unique: !!index.unique,\n partial: !!index.partialFilterExpression,\n options: index,\n };\n }\n\n /**\n * List all columns for a specific table\n */\n public async listColumns(table: string): Promise<string[]> {\n console.log(\n colors.yellowBright(\n `MongoDBBlueprint: listColumns(${table}) MongoDB does not have static columns`,\n ),\n );\n\n return [];\n }\n\n /**\n * Check if the given table exists\n */\n public async tableExists(table: string): Promise<boolean> {\n const collections = await this.database.listCollections().toArray();\n return collections.some((collection) => collection.name === table);\n }\n}\n","import type { GenerateIdOptions, IdGeneratorContract } from \"../../contracts\";\nimport type { MongoDbDriver } from \"./mongodb-driver\";\n\n/**\n * MongoDB-specific ID generator for auto-incrementing integer IDs.\n *\n * Maintains a separate collection that tracks the last generated ID for each table.\n * Generates auto-incrementing IDs similar to SQL's AUTO_INCREMENT feature.\n *\n * **Collection Structure:**\n * ```json\n * {\n * \"collection\": \"users\",\n * \"id\": 12345\n * }\n * ```\n *\n * **Features:**\n * - Atomic ID generation using findOneAndUpdate with aggregation pipeline\n * - Automatic transaction support (driver handles session context)\n * - Configurable initial ID and increment values\n * - Thread-safe and concurrent-safe\n *\n * @example\n * ```typescript\n * const mongoDriver = new MongoDbDriver(config);\n * const idGenerator = new MongoIdGenerator(mongoDriver);\n *\n * const dataSource = new DataSource({\n * name: \"primary\",\n * driver: mongoDriver,\n * idGenerator,\n * });\n *\n * // Generate IDs with custom configuration\n * const id = await idGenerator.generateNextId({\n * table: \"users\",\n * initialId: 1000,\n * incrementIdBy: 1\n * });\n * ```\n */\nexport class MongoIdGenerator implements IdGeneratorContract {\n /**\n * The collection name that stores ID counters.\n * Each document tracks the last ID for a specific table.\n *\n * Named \"MasterMind\" for backward compatibility with legacy Cascade.\n */\n public readonly counterCollection: string = \"MasterMind\";\n\n /**\n * Create a new MongoDB ID generator instance.\n *\n * @param driver - The MongoDB driver instance\n * @param counterCollection - Name of the collection storing ID counters (default: \"MasterMind\")\n *\n * @example\n * ```typescript\n * const idGenerator = new MongoIdGenerator(mongoDriver, \"id_counters\");\n * ```\n */\n public constructor(\n private readonly driver: MongoDbDriver,\n counterCollection?: string,\n ) {\n if (counterCollection) {\n this.counterCollection = counterCollection;\n }\n }\n\n /**\n * Generate the next ID for a table.\n *\n * Uses atomic findOneAndUpdate with aggregation pipeline to ensure uniqueness\n * even in concurrent scenarios. Automatically participates in active transactions.\n *\n * @param options - Configuration for ID generation\n * @returns The generated ID\n *\n * @example\n * ```typescript\n * // Simple usage\n * const id = await idGenerator.generateNextId({ table: \"users\" });\n *\n * // With custom initial ID\n * const id = await idGenerator.generateNextId({\n * table: \"products\",\n * initialId: 1000,\n * incrementIdBy: 1\n * });\n * ```\n */\n public async generateNextId(options: GenerateIdOptions): Promise<number> {\n const { table, initialId = 1, incrementIdBy = 1 } = options;\n\n // Get the MongoDB database instance\n const database = this.driver.getDatabase();\n const collection = database.collection(this.counterCollection);\n\n // Use atomic findOneAndUpdate with aggregation pipeline\n // The driver's withSession method will automatically attach the session if in a transaction\n const result = await collection.findOneAndUpdate(\n { collection: table },\n [\n {\n $set: {\n id: {\n $cond: {\n if: { $or: [{ $eq: [\"$id\", null] }, { $not: \"$id\" }] },\n then: initialId,\n else: { $add: [\"$id\", incrementIdBy] },\n },\n },\n collection: table,\n },\n },\n ],\n {\n upsert: true,\n returnDocument: \"after\",\n },\n );\n\n return result?.id ?? initialId;\n }\n\n /**\n * Get the last generated ID for a table.\n *\n * @param table - The table/collection name\n * @returns The last generated ID, or 0 if none exists\n *\n * @example\n * ```typescript\n * const lastId = await idGenerator.getLastId(\"users\");\n * console.log(`Last user ID: ${lastId}`);\n * ```\n */\n public async getLastId(table: string): Promise<number> {\n const query = this.driver.queryBuilder(this.counterCollection);\n const doc = (await query.where(\"collection\", table).first()) as Record<string, unknown> | null;\n return (doc?.id as number) ?? 0;\n }\n\n /**\n * Set the last ID for a table.\n *\n * Creates or updates the counter document for the specified table.\n * Useful for seeding or resetting ID sequences.\n *\n * @param table - The table/collection name\n * @param id - The ID to set as the last generated ID\n *\n * @example\n * ```typescript\n * // Reset user IDs to start from 1000\n * await idGenerator.setLastId(\"users\", 1000);\n * ```\n */\n public async setLastId(table: string, id: number): Promise<void> {\n await this.driver.update(\n this.counterCollection,\n { collection: table },\n { $set: { id, collection: table } },\n { upsert: true },\n );\n }\n}\n","import type { ClientSession, CreateIndexesOptions, Db, IndexDescription } from \"mongodb\";\nimport { databaseTransactionContext } from \"../../context/database-transaction-context\";\nimport type {\n ColumnDefinition,\n ForeignKeyDefinition,\n FullTextIndexOptions,\n GeoIndexOptions,\n IndexDefinition,\n MigrationDriverContract,\n TableIndexInformation,\n VectorIndexOptions,\n} from \"../../contracts/migration-driver.contract\";\nimport type { MigrationDefaults } from \"../../types\";\nimport type { MongoDbDriver } from \"./mongodb-driver\";\n\n/**\n * MongoDB-specific migration driver implementation.\n *\n * Key behaviors:\n * - Column operations are **no-ops** (MongoDB is schema-less)\n * - Index operations use native `createIndex()`\n * - Foreign keys are **no-ops** (MongoDB has no FK constraints)\n * - TTL indexes supported natively\n * - Vector indexes use Atlas Search (when available)\n * - Schema validation uses `collMod` command\n *\n * @example\n * ```typescript\n * const migrationDriver = new MongoMigrationDriver(mongoDriver);\n * await migrationDriver.createIndex(\"users\", {\n * columns: [\"email\"],\n * unique: true,\n * });\n * ```\n */\nexport class MongoMigrationDriver implements MigrationDriverContract {\n /** Active transaction session (if any) */\n private session?: ClientSession;\n\n /**\n * Create a new MongoDB migration driver.\n *\n * @param driver - The MongoDB driver instance\n */\n public constructor(public readonly driver: MongoDbDriver) {}\n\n /**\n * Get the MongoDB database instance.\n */\n private get db(): Db {\n return this.driver.getDatabase();\n }\n\n /**\n * Get session options for operations.\n */\n private get sessionOptions(): { session?: ClientSession } | undefined {\n const session = databaseTransactionContext.getSession<ClientSession>();\n return session ? { session } : undefined;\n }\n\n // ============================================================================\n // TABLE/COLLECTION OPERATIONS\n // ============================================================================\n\n /**\n * Create a new collection.\n *\n * MongoDB creates collections lazily on first insert, but this method\n * creates them explicitly for migrations that need to add indexes or\n * schema validation.\n */\n public async createTable(table: string): Promise<void> {\n try {\n await this.db.createCollection(table);\n } catch (error: any) {\n // Collection already exists - ignore\n if (error.codeName === \"NamespaceExists\") {\n return;\n }\n throw error;\n }\n }\n\n /**\n * Create table if not exists\n */\n public async createTableIfNotExists(table: string): Promise<void> {\n try {\n await this.db.createCollection(table);\n } catch (error: any) {\n // Collection already exists - ignore\n if (error.codeName === \"NamespaceExists\") {\n return;\n }\n throw error;\n }\n }\n\n /**\n * Drop an existing collection.\n *\n * @throws Error if collection doesn't exist\n */\n public async dropTable(table: string): Promise<void> {\n await this.db.dropCollection(table);\n }\n\n /**\n * Drop collection if it exists (no error if missing).\n */\n public async dropTableIfExists(table: string): Promise<void> {\n try {\n await this.db.dropCollection(table);\n } catch {\n // Collection doesn't exist - ignore\n }\n }\n\n /**\n * Rename a collection.\n */\n public async renameTable(from: string, to: string): Promise<void> {\n await this.db.renameCollection(from, to);\n }\n\n /**\n * Truncate a collection — remove all documents.\n *\n * @param table - Collection name\n */\n public async truncateTable(table: string): Promise<void> {\n await this.db.collection(table).deleteMany({});\n }\n\n /**\n * Check if a collection exists.\n */\n public async tableExists(table: string): Promise<boolean> {\n const collections = await this.db.listCollections({ name: table }).toArray();\n return collections.length > 0;\n }\n\n /**\n * List all columns in a collection.\n *\n * MongoDB is schema-less, so this returns an empty array.\n * For actual schema inspection, would need to sample documents.\n */\n public async listColumns(_table: string): Promise<ColumnDefinition[]> {\n // No-op: MongoDB is schema-less\n return [];\n }\n\n /**\n * List all collections in the current database.\n */\n public async listTables(): Promise<string[]> {\n const collections = await this.db.listCollections().toArray();\n return collections.map((col) => col.name);\n }\n\n /**\n * Ensure the migrations tracking collection exists.\n *\n * MongoDB creates collections lazily, but we can create explicitly\n * and add a unique index on the name field.\n *\n * @param tableName - Name of the migrations collection\n */\n public async ensureMigrationsTable(tableName: string): Promise<void> {\n // Create collection if not exists\n const exists = await this.tableExists(tableName);\n if (!exists) {\n await this.db.createCollection(tableName);\n }\n\n // Ensure unique index on name\n await this.db.collection(tableName).createIndex({ name: 1 }, { unique: true });\n }\n\n // ============================================================================\n // COLUMN OPERATIONS (No-ops for MongoDB)\n // ============================================================================\n\n /**\n * Add a column (no-op for MongoDB).\n *\n * MongoDB is schema-less, so columns don't need to be declared.\n */\n public async addColumn(_table: string, _column: ColumnDefinition): Promise<void> {\n // No-op: MongoDB is schema-less\n }\n\n /**\n * Drop a column by running $unset on all documents.\n *\n * This actually removes the field from all documents in the collection.\n */\n public async dropColumn(table: string, column: string): Promise<void> {\n const collection = this.db.collection(table);\n await collection.updateMany({}, { $unset: { [column]: \"\" } }, this.sessionOptions);\n }\n\n /**\n * Drop multiple columns by running $unset on all documents.\n */\n public async dropColumns(table: string, columns: string[]): Promise<void> {\n const collection = this.db.collection(table);\n const unsetFields: Record<string, string> = {};\n for (const column of columns) {\n unsetFields[column] = \"\";\n }\n await collection.updateMany({}, { $unset: unsetFields }, this.sessionOptions);\n }\n\n /**\n * Rename a column by running $rename on all documents.\n */\n public async renameColumn(table: string, from: string, to: string): Promise<void> {\n const collection = this.db.collection(table);\n await collection.updateMany({}, { $rename: { [from]: to } }, this.sessionOptions);\n }\n\n /**\n * Modify a column definition (no-op for MongoDB).\n *\n * MongoDB is schema-less, so column types don't need to be modified.\n */\n public async modifyColumn(_table: string, _column: ColumnDefinition): Promise<void> {\n // No-op: MongoDB is schema-less\n }\n\n /**\n * Create standard timestamp columns (created_at, updated_at).\n *\n * MongoDB implementation is a no-op since timestamps are handled\n * at the application level via Model hooks.\n *\n * @param _table - Collection name (unused)\n */\n public async createTimestampColumns(_table: string): Promise<void> {\n // No-op: MongoDB handles timestamps at application level\n }\n\n // ============================================================================\n // INDEX OPERATIONS\n // ============================================================================\n\n /**\n * Create an index on one or more columns.\n *\n * **Note**: Expression-based indexes, INCLUDE clause, and concurrent creation\n * are PostgreSQL-specific features and are silently ignored by MongoDB.\n */\n public async createIndex(table: string, index: IndexDefinition): Promise<void> {\n // Skip expression-based indexes (PostgreSQL-specific)\n if (index.expressions && index.expressions.length > 0) {\n // No-op: MongoDB doesn't support expression-based indexes\n return;\n }\n\n // Ignore include and concurrently options (PostgreSQL-specific)\n // MongoDB doesn't support covering indexes or concurrent creation\n\n const collection = this.db.collection(table);\n\n // Build index specification\n const indexSpec: IndexDescription[\"key\"] = {};\n for (let i = 0; i < index.columns.length; i++) {\n const column = index.columns[i];\n const direction = index.directions?.[i] === \"desc\" ? -1 : 1;\n indexSpec[column] = direction;\n }\n\n // Build index options\n const options: CreateIndexesOptions = {};\n if (index.name) {\n options.name = index.name;\n }\n if (index.unique) {\n options.unique = true;\n }\n if (index.sparse) {\n options.sparse = true;\n }\n if (index.where) {\n options.partialFilterExpression = index.where;\n }\n\n await collection.createIndex(indexSpec, options);\n }\n\n /**\n * Drop an index by name or columns.\n *\n * @param indexNameOrColumns - Index name (string) or columns array\n */\n public async dropIndex(table: string, indexNameOrColumns: string | string[]): Promise<void> {\n const collection = this.db.collection(table);\n\n if (!Array.isArray(indexNameOrColumns)) {\n indexNameOrColumns = [indexNameOrColumns];\n }\n\n // If columns array provided, generate MongoDB-style index name\n // MongoDB creates index names like: \"column1_1_column2_1\"\n const indexName = indexNameOrColumns.map((col) => `${col}_1`).join(\"_\");\n\n await collection.dropIndex(indexName);\n }\n\n /**\n * Create a unique index/constraint.\n */\n public async createUniqueIndex(table: string, columns: string[], name?: string): Promise<void> {\n await this.createIndex(table, {\n columns,\n unique: true,\n name,\n });\n }\n\n /**\n * Drop a unique index by finding its name from columns.\n */\n public async dropUniqueIndex(table: string, columns: string[]): Promise<void> {\n const collection = this.db.collection(table);\n const indexes = await collection.indexes();\n\n // Find the index that matches the columns\n for (const idx of indexes) {\n const indexKeys = Object.keys(idx.key || {});\n if (indexKeys.length === columns.length && indexKeys.every((key, i) => key === columns[i])) {\n if (idx.name && idx.name !== \"_id_\") {\n await collection.dropIndex(idx.name);\n return;\n }\n }\n }\n }\n\n // ============================================================================\n // SPECIALIZED INDEXES\n // ============================================================================\n\n /**\n * Create a full-text search index.\n *\n * MongoDB uses \"text\" index type for full-text search.\n */\n public async createFullTextIndex(\n table: string,\n columns: string[],\n options?: FullTextIndexOptions,\n ): Promise<void> {\n const collection = this.db.collection(table);\n\n // Build text index specification\n const indexSpec: Record<string, \"text\"> = {};\n for (const column of columns) {\n indexSpec[column] = \"text\";\n }\n\n // Build options\n const indexOptions: CreateIndexesOptions = {};\n if (options?.name) {\n indexOptions.name = options.name;\n }\n if (options?.language) {\n indexOptions.default_language = options.language;\n }\n if (options?.weights) {\n indexOptions.weights = options.weights;\n }\n\n await collection.createIndex(indexSpec, indexOptions);\n }\n\n /**\n * Drop a full-text search index.\n */\n public async dropFullTextIndex(table: string, name: string): Promise<void> {\n await this.dropIndex(table, name);\n }\n\n /**\n * Create a geo-spatial index.\n */\n public async createGeoIndex(\n table: string,\n column: string,\n options?: GeoIndexOptions,\n ): Promise<void> {\n const collection = this.db.collection(table);\n\n // Build geo index specification - MongoDB accepts string values for geo indexes\n const indexType = options?.type ?? \"2dsphere\";\n\n // Build options\n const indexOptions: CreateIndexesOptions = {};\n if (options?.name) {\n indexOptions.name = options.name;\n }\n if (options?.min !== undefined) {\n indexOptions.min = options.min;\n }\n if (options?.max !== undefined) {\n indexOptions.max = options.max;\n }\n\n await collection.createIndex({ [column]: indexType } as any, indexOptions);\n }\n\n /**\n * Drop a geo-spatial index.\n */\n public async dropGeoIndex(table: string, column: string): Promise<void> {\n const collection = this.db.collection(table);\n const indexes = await collection.indexes();\n\n // Find the geo index for this column\n for (const idx of indexes) {\n const key = idx.key || {};\n if (column in key && (key[column] === \"2dsphere\" || key[column] === \"2d\")) {\n if (idx.name && idx.name !== \"_id_\") {\n await collection.dropIndex(idx.name);\n return;\n }\n }\n }\n }\n\n /**\n * Create a vector search index for AI embeddings.\n *\n * Note: This requires MongoDB Atlas with Vector Search enabled.\n * For self-hosted MongoDB, this will create a regular index on the field.\n */\n public async createVectorIndex(\n table: string,\n column: string,\n options: VectorIndexOptions,\n ): Promise<void> {\n const collection = this.db.collection(table);\n\n // Try to create Atlas vector search index first\n try {\n // Check if we're on Atlas by looking for vectorSearch indexes\n const searchIndexes = await (collection as any).listSearchIndexes?.()?.toArray?.();\n if (Array.isArray(searchIndexes)) {\n // We're on Atlas - create a vector search index\n await (collection as any).createSearchIndex({\n name: options.name ?? `${column}_vector_idx`,\n definition: {\n mappings: {\n dynamic: false,\n fields: {\n [column]: {\n type: \"knnVector\",\n dimensions: options.dimensions,\n similarity: options.similarity ?? \"cosine\",\n },\n },\n },\n },\n });\n return;\n }\n } catch {\n // Not on Atlas or doesn't support search indexes\n }\n\n // Fallback: Create a regular index on the vector field\n // This won't provide vector search capabilities but ensures the field is indexed\n await collection.createIndex({ [column]: 1 }, { name: options.name ?? `${column}_vector_idx` });\n }\n\n /**\n * Drop a vector search index.\n */\n public async dropVectorIndex(table: string, column: string): Promise<void> {\n const collection = this.db.collection(table);\n\n // Try to drop Atlas search index first\n try {\n const searchIndexes = await (collection as any).listSearchIndexes?.()?.toArray?.();\n if (Array.isArray(searchIndexes)) {\n for (const idx of searchIndexes) {\n if (idx.name?.includes(column)) {\n await (collection as any).dropSearchIndex(idx.name);\n return;\n }\n }\n }\n } catch {\n // Not on Atlas\n }\n\n // Fallback: Try to drop regular index\n const indexName = `${column}_vector_idx`;\n try {\n await collection.dropIndex(indexName);\n } catch {\n // Index doesn't exist\n }\n }\n\n /**\n * Create a TTL (time-to-live) index for automatic document expiration.\n */\n public async createTTLIndex(\n table: string,\n column: string,\n expireAfterSeconds: number,\n ): Promise<void> {\n const collection = this.db.collection(table);\n await collection.createIndex({ [column]: 1 }, { expireAfterSeconds });\n }\n\n /**\n * Drop a TTL index.\n */\n public async dropTTLIndex(table: string, column: string): Promise<void> {\n const collection = this.db.collection(table);\n const indexes = await collection.indexes();\n\n // Find the TTL index for this column\n for (const idx of indexes) {\n const key = idx.key || {};\n if (column in key && idx.expireAfterSeconds !== undefined) {\n if (idx.name && idx.name !== \"_id_\") {\n await collection.dropIndex(idx.name);\n return;\n }\n }\n }\n }\n\n /**\n * List all indexes on a collection.\n *\n * @param table - Collection name\n * @returns Array of index metadata\n */\n public async listIndexes(table: string): Promise<TableIndexInformation[]> {\n const collection = this.db.collection(table);\n const indexes = await collection.indexes();\n\n return indexes.map((idx) => ({\n name: idx.name ?? \"\",\n columns: Object.keys(idx.key ?? {}),\n type: \"btree\",\n unique: idx.unique ?? false,\n partial: !!idx.partialFilterExpression,\n options: { sparse: idx.sparse, expireAfterSeconds: idx.expireAfterSeconds },\n }));\n }\n\n // ============================================================================\n // CONSTRAINTS (No-ops for MongoDB)\n // ============================================================================\n\n /**\n * Add a foreign key constraint (no-op for MongoDB).\n *\n * MongoDB doesn't support foreign key constraints.\n * Use application-level validation or DBRefs instead.\n */\n public async addForeignKey(_table: string, _foreignKey: ForeignKeyDefinition): Promise<void> {\n // No-op: MongoDB doesn't support foreign keys\n }\n\n /**\n * Drop a foreign key constraint (no-op for MongoDB).\n */\n public async dropForeignKey(_table: string, _name: string): Promise<void> {\n // No-op: MongoDB doesn't support foreign keys\n }\n\n /**\n * Add a primary key constraint (no-op for MongoDB).\n *\n * MongoDB always has _id as the primary key.\n */\n public async addPrimaryKey(_table: string, _columns: string[]): Promise<void> {\n // No-op: MongoDB always has _id as primary key\n }\n\n /**\n * Drop the primary key constraint (no-op for MongoDB).\n */\n public async dropPrimaryKey(_table: string): Promise<void> {\n // No-op: Cannot drop _id index in MongoDB\n }\n\n /**\n * Add a CHECK constraint (no-op for MongoDB).\n *\n * MongoDB doesn't support CHECK constraints.\n * Use schema validation instead.\n */\n public async addCheck(_table: string, _name: string, _expression: string): Promise<void> {\n // No-op: MongoDB doesn't support CHECK constraints\n }\n\n /**\n * Drop a CHECK constraint (no-op for MongoDB).\n */\n public async dropCheck(_table: string, _name: string): Promise<void> {\n // No-op: MongoDB doesn't support CHECK constraints\n }\n\n // ============================================================================\n // SCHEMA VALIDATION (NoSQL)\n // ============================================================================\n\n /**\n * Set JSON schema validation rules on a collection.\n *\n * Uses MongoDB's validator feature to enforce document structure.\n *\n * @example\n * ```typescript\n * await driver.setSchemaValidation(\"users\", {\n * bsonType: \"object\",\n * required: [\"name\", \"email\"],\n * properties: {\n * name: { bsonType: \"string\" },\n * email: { bsonType: \"string\" },\n * },\n * });\n * ```\n */\n public async setSchemaValidation(table: string, schema: object): Promise<void> {\n await this.db.command({\n collMod: table,\n validator: { $jsonSchema: schema },\n validationLevel: \"strict\",\n validationAction: \"error\",\n });\n }\n\n /**\n * Remove schema validation rules from a collection.\n */\n public async removeSchemaValidation(table: string): Promise<void> {\n await this.db.command({\n collMod: table,\n validator: {},\n validationLevel: \"off\",\n });\n }\n\n // ============================================================================\n // TRANSACTIONS\n // ============================================================================\n\n /**\n * Begin a database transaction.\n *\n * Uses the driver's transaction mechanism.\n */\n public async beginTransaction(): Promise<void> {\n const transaction = await this.driver.beginTransaction();\n this.session = transaction.context;\n }\n\n /**\n * Commit the current transaction.\n */\n public async commit(): Promise<void> {\n if (this.session) {\n await this.session.commitTransaction();\n await this.session.endSession();\n this.session = undefined;\n }\n }\n\n /**\n * Rollback the current transaction.\n */\n public async rollback(): Promise<void> {\n if (this.session) {\n await this.session.abortTransaction();\n await this.session.endSession();\n this.session = undefined;\n }\n }\n\n /**\n * MongoDB supports transactions (requires replica set).\n */\n public supportsTransactions(): boolean {\n return true;\n }\n\n /**\n * Get the default transactional behavior for MongoDB.\n *\n * MongoDB DDL operations (createCollection, createIndex, etc.) cannot\n * be wrapped in transactions, even with replica sets. Transactions only\n * work for document CRUD operations.\n *\n * @returns false (MongoDB DDL is not transactional)\n */\n public getDefaultTransactional(): boolean {\n return false;\n }\n\n // ============================================================================\n // DEFAULTS\n // ============================================================================\n\n /**\n * Get the default UUID generation expression for MongoDB.\n *\n * MongoDB does not use SQL-level UUID defaults — UUID generation\n * is handled at the application level. Always returns `undefined`.\n *\n * @param _migrationDefaults - Ignored (MongoDB handles UUIDs at app level)\n * @returns undefined\n */\n public getUuidDefault(_migrationDefaults?: MigrationDefaults): undefined {\n return undefined;\n }\n\n // ============================================================================\n // EXTENSIONS\n // ============================================================================\n\n /**\n * Check if a database extension is available (no-op for MongoDB).\n *\n * @param _extension - Extension name\n */\n public async isExtensionAvailable(_extension: string): Promise<boolean> {\n return true; // MongoDB doesn't use SQL extensions\n }\n\n /**\n * Get the official documentation or installation URL for a database extension.\n *\n * @param _extension - Extension name\n */\n public getExtensionDocsUrl(_extension: string): string | undefined {\n return undefined; // MongoDB doesn't use SQL extensions\n }\n\n // ============================================================================\n // RAW ACCESS\n // ============================================================================\n\n /**\n * Execute raw operations with direct database access.\n *\n * @param callback - Callback receiving the MongoDB Db instance\n * @returns Result from callback\n *\n * @example\n * ```typescript\n * await driver.raw(async (db) => {\n * await db.collection(\"users\").updateMany({}, { $set: { active: true } });\n * });\n * ```\n */\n public async raw<T>(callback: (connection: unknown) => Promise<T>): Promise<T> {\n return callback(this.db);\n }\n}\n","/**\n * Pure Query Builder Base Class\n *\n * Driver-agnostic operation recorder. All fluent methods push typed entries into\n * `operations[]`. No SQL, no driver references, no table property, no execution.\n *\n * ┌─────────────────────────────────────────────────┐\n * │ Usage contexts │\n * │ (a) Subclassed — PG / Mongo / MySQL / … │\n * │ (b) Instantiated directly (new QueryBuilder()) │\n * │ inside callbacks for: │\n * │ • nested where groups │\n * │ • joinWith constraints │\n * │ • whereExists / whereHas subqueries │\n * └─────────────────────────────────────────────────┘\n *\n * Design rules:\n * - `table` / alias are NOT here — the parser gets them from the executor.\n * - `opIndex` is protected so subclasses can rebuild after direct mutation.\n * - Op type names are stable — parsers switch on them; no renaming without\n * a parser update.\n * - OR-variants keep distinct op types (orWhere, orWhereColumn, …) so existing\n * parsers that switch on type need no changes.\n * - `joinWith` eagerly resolves callbacks → subOps at record time so the\n * driver executor receives a plain data structure, not a live function.\n *\n * @module cascade/query-builder\n */\n\nimport type {\n GroupByInput,\n HavingInput,\n JoinOptions,\n OrderDirection,\n RawExpression,\n WhereCallback,\n WhereObject,\n WhereOperator,\n} from \"../contracts/query-builder.contract\";\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\n/**\n * A single recorded query operation.\n * `type` is the discriminator; `data` carries all parameters.\n */\nexport type Op = {\n readonly type: string;\n readonly data: Record<string, unknown>;\n};\n\n/**\n * Constraint value accepted by `joinWith()`.\n *\n * - `string` → comma-separated column shorthand: `\"id,name,createdAt\"`\n * - `fn` → callback receives a bare QueryBuilder to record sub-ops\n *\n * @example\n * joinWith({ actions: \"id,status\" })\n * joinWith({ actions: q => q.where(\"status\", \"pending\").limit(5) })\n */\nexport type JoinWithConstraint = string | ((q: QueryBuilder) => void);\n\n// ============================================================================\n// QUERY BUILDER — CONCRETE, DIRECTLY INSTANTIABLE\n// ============================================================================\n\n/**\n * Pure, driver-agnostic query builder.\n *\n * Records operations in `operations[]`. Subclasses own execution, parsing, and\n * driver-specific clause generation. Safe to instantiate directly inside\n * callbacks where only operation recording is needed.\n *\n * @example\n * ```ts\n * // Driver subclass usage:\n * const users = await User.query()\n * .select([\"id\", \"name\"])\n * .where(\"status\", \"active\")\n * .where(q => q.where(\"role\", \"admin\").orWhere(\"role\", \"mod\"))\n * .orderBy(\"createdAt\", \"desc\")\n * .limit(10)\n * .get();\n *\n * // Direct instantiation (callback context — no driver needed):\n * joinWith({ actions: q => q.where(\"status\", \"pending\").limit(5) });\n * // The sub-QB's operations[] are captured and stored in the joinWith op data.\n * ```\n */\nexport class QueryBuilder<T = unknown> {\n // ════════════════════════════════════════════════════════\n // OPERATION STORE\n // ════════════════════════════════════════════════════════\n\n /** Flat, ordered list of recorded operations. Public for parser access. */\n public operations: Op[] = [];\n\n /**\n * type → ordered list of indices into `operations[]`.\n *\n * Protected (not private) so:\n * - `rebuildIndex()` can reset it after direct `operations[]` mutation.\n * - Subclasses can inspect it without unsafe casts.\n *\n * External consumers should use `getOps(type)` instead.\n */\n protected opIndex: Map<string, number[]> = new Map();\n\n // ════════════════════════════════════════════════════════\n // SCOPE STATE (injected by Model.query(), consumed before execution)\n // ════════════════════════════════════════════════════════\n\n /** Global scope definitions injected by Model.query(). Keyed by scope name. */\n public pendingGlobalScopes?: Map<string, any>;\n /** Local scope callbacks injected by Model.query(). Applied on demand via scope(). */\n public availableLocalScopes?: Map<string, (...args: any[]) => void>;\n /** Names of global scopes that have been intentionally disabled. */\n public disabledGlobalScopes: Set<string> = new Set();\n /** True once the driver subclass has applied pending scopes. */\n public scopesApplied = false;\n\n // ════════════════════════════════════════════════════════\n // RELATION STATE (consumed by driver subclass at execute time)\n // ════════════════════════════════════════════════════════\n\n /** Relations to eager-load via separate queries. */\n public eagerLoadRelations: Map<string, boolean | ((query: any) => void)> = new Map();\n /** Count expressions to emit per result row, keyed by output column alias. */\n public countRelations: Map<string, { relation: string; constraintOps?: Op[] }> = new Map();\n /** Relation definition map injected from the owning Model. */\n public relationDefinitions?: Record<string, any>;\n /** The Model class reference, required for relation resolution. */\n public modelClass?: any;\n\n // ════════════════════════════════════════════════════════\n // CORE INTERNALS\n // ════════════════════════════════════════════════════════\n\n /**\n * Append an operation to `operations[]` and update `opIndex`.\n * Every fluent method calls this.\n */\n protected addOperation(type: string, data: Record<string, unknown>): void {\n const idx = this.operations.length;\n this.operations.push({ type, data });\n const list = this.opIndex.get(type);\n if (list) {\n list.push(idx);\n } else {\n this.opIndex.set(type, [idx]);\n }\n }\n\n /**\n * Return all recorded operations of the specified types in original\n * insertion order.\n *\n * @example\n * builder.getOps(\"where\", \"orWhere\", \"whereIn\")\n */\n public getOps(...types: string[]): Op[] {\n if (types.length === 1) {\n return (this.opIndex.get(types[0]) ?? []).map((i) => this.operations[i]);\n }\n const result: Array<{ idx: number; op: Op }> = [];\n for (const type of types) {\n for (const idx of this.opIndex.get(type) ?? []) {\n result.push({ idx, op: this.operations[idx] });\n }\n }\n return result.sort((a, b) => a.idx - b.idx).map((r) => r.op);\n }\n\n /**\n * Rebuild `opIndex` from scratch.\n *\n * Call this after any direct mutation of `this.operations[]` (e.g. scope\n * injection, joinWith consumption in the executor, clone post-processing).\n */\n public rebuildIndex(): void {\n this.opIndex = new Map();\n for (let i = 0; i < this.operations.length; i++) {\n const type = this.operations[i].type;\n const list = this.opIndex.get(type);\n if (list) {\n list.push(i);\n } else {\n this.opIndex.set(type, [i]);\n }\n }\n }\n\n /**\n * Factory for sub-QueryBuilders used inside callbacks.\n *\n * Override in driver subclasses to return a driver-typed instance, so that\n * driver-specific methods (e.g. `whereArrayContains`) are available inside\n * nested `where(q => ...)` / `whereHas` / `joinWith` callbacks.\n *\n * @example\n * // In PostgresQueryBuilder:\n * protected override subQuery(): QueryBuilder {\n * return new PostgresQueryBuilder(\"__sub__\", this.dataSource);\n * }\n */\n protected subQuery(): QueryBuilder {\n return new QueryBuilder();\n }\n\n /**\n * Shallow-clone this builder — copies operations, opIndex, and all shared state.\n *\n * Subclasses MUST call `super.clone()` and then copy their own fields\n * (dataSource, joinRelations, …).\n */\n public clone(): this {\n const cloned = Object.create(Object.getPrototypeOf(this)) as this;\n cloned.operations = [...this.operations];\n cloned.opIndex = new Map(Array.from(this.opIndex.entries()).map(([k, v]) => [k, [...v]]));\n cloned.pendingGlobalScopes = this.pendingGlobalScopes;\n cloned.availableLocalScopes = this.availableLocalScopes;\n cloned.disabledGlobalScopes = new Set(this.disabledGlobalScopes);\n cloned.scopesApplied = this.scopesApplied;\n cloned.eagerLoadRelations = new Map(this.eagerLoadRelations);\n cloned.countRelations = new Map(this.countRelations);\n cloned.relationDefinitions = this.relationDefinitions;\n cloned.modelClass = this.modelClass;\n return cloned;\n }\n\n // ════════════════════════════════════════════════════════\n // SCOPES\n // ════════════════════════════════════════════════════════\n\n /** Disable one or more named global scopes for this query. */\n public withoutGlobalScope(...scopeNames: string[]): this {\n scopeNames.forEach((name) => this.disabledGlobalScopes.add(name));\n return this;\n }\n\n /** Disable ALL pending global scopes for this query. */\n public withoutGlobalScopes(): this {\n this.pendingGlobalScopes?.forEach((_, name) => this.disabledGlobalScopes.add(name));\n return this;\n }\n\n /**\n * Apply a registered local scope by name.\n * @throws if no local scopes are available or the named scope is not found\n */\n public scope(scopeName: string, ...args: unknown[]): this {\n if (!this.availableLocalScopes) {\n throw new Error(\"No local scopes available on this query builder.\");\n }\n const cb = this.availableLocalScopes.get(scopeName);\n if (!cb) throw new Error(`Local scope \"${scopeName}\" not found.`);\n cb(this, ...args);\n return this;\n }\n\n // ════════════════════════════════════════════════════════\n // WHERE CLAUSES — CORE\n // ════════════════════════════════════════════════════════\n\n /**\n * Add a WHERE clause (AND).\n *\n * @example\n * q.where(\"status\", \"active\")\n * q.where(\"age\", \">\", 18)\n * q.where({ role: \"admin\", active: true })\n * q.where(q => q.where(\"a\", 1).orWhere(\"b\", 2))\n */\n public where(field: string, value: unknown): this;\n public where(field: string, operator: WhereOperator, value: unknown): this;\n public where(conditions: WhereObject): this;\n public where(callback: WhereCallback<T>): this;\n public where(...args: unknown[]): this {\n if (args.length === 1 && typeof args[0] === \"function\") {\n const sub = this.subQuery();\n (args[0] as (q: QueryBuilder) => void)(sub);\n this.addOperation(\"where\", { nested: sub.operations });\n } else if (args.length === 1 && typeof args[0] === \"object\" && args[0] !== null) {\n for (const [key, value] of Object.entries(args[0] as WhereObject)) {\n this.addOperation(\"where\", { field: key, operator: \"=\", value });\n }\n } else if (args.length === 2) {\n this.addOperation(\"where\", { field: args[0], operator: \"=\", value: args[1] });\n } else {\n this.addOperation(\"where\", { field: args[0], operator: args[1], value: args[2] });\n }\n return this;\n }\n\n /**\n * Add an OR WHERE clause.\n *\n * @example\n * q.where(\"role\", \"admin\").orWhere(\"role\", \"mod\")\n */\n public orWhere(field: string, value: unknown): this;\n public orWhere(field: string, operator: WhereOperator, value: unknown): this;\n public orWhere(conditions: WhereObject): this;\n public orWhere(callback: WhereCallback<T>): this;\n public orWhere(...args: unknown[]): this {\n if (args.length === 1 && typeof args[0] === \"function\") {\n const sub = this.subQuery();\n (args[0] as (q: QueryBuilder) => void)(sub);\n this.addOperation(\"orWhere\", { nested: sub.operations });\n } else if (args.length === 1 && typeof args[0] === \"object\" && args[0] !== null) {\n for (const [key, value] of Object.entries(args[0] as WhereObject)) {\n this.addOperation(\"orWhere\", { field: key, operator: \"=\", value });\n }\n } else if (args.length === 2) {\n this.addOperation(\"orWhere\", { field: args[0], operator: \"=\", value: args[1] });\n } else {\n this.addOperation(\"orWhere\", { field: args[0], operator: args[1], value: args[2] });\n }\n return this;\n }\n\n /**\n * Raw WHERE expression in the target dialect (AND).\n *\n * @example\n * q.whereRaw(\"age > ? AND role = ?\", [18, \"admin\"]) // SQL\n * q.whereRaw({ $expr: { $gt: [\"$stock\", \"$reserved\"] } }) // MongoDB\n */\n public whereRaw(expression: RawExpression, bindings?: unknown[]): this {\n this.addOperation(\"whereRaw\", { expression, bindings: bindings ?? [] });\n return this;\n }\n\n /** Raw OR WHERE expression. */\n public orWhereRaw(expression: RawExpression, bindings?: unknown[]): this {\n this.addOperation(\"orWhereRaw\", { expression, bindings: bindings ?? [] });\n return this;\n }\n\n // ════════════════════════════════════════════════════════\n // WHERE CLAUSES — COLUMN COMPARISONS\n // ════════════════════════════════════════════════════════\n\n /**\n * Compare two columns directly (AND).\n * @example q.whereColumn(\"stock\", \">\", \"reserved\")\n */\n public whereColumn(first: string, operator: WhereOperator, second: string): this {\n this.addOperation(\"whereColumn\", { first, operator, second });\n return this;\n }\n\n /** Compare two columns directly (OR). */\n public orWhereColumn(first: string, operator: WhereOperator, second: string): this {\n this.addOperation(\"orWhereColumn\", { first, operator, second });\n return this;\n }\n\n /** Compare multiple column pairs in one call. */\n public whereColumns(\n comparisons: Array<[left: string, operator: WhereOperator, right: string]>,\n ): this {\n for (const [left, operator, right] of comparisons) {\n this.whereColumn(left, operator, right);\n }\n return this;\n }\n\n /**\n * Field value must fall between two other column values.\n * Stored as a `whereBetween` op with `useColumns: true` so the SQL parser\n * knows to quote the values as identifiers rather than bind them.\n */\n public whereBetweenColumns(field: string, lowerColumn: string, upperColumn: string): this {\n this.addOperation(\"whereBetween\", { field, lowerColumn, upperColumn, useColumns: true });\n return this;\n }\n\n // ════════════════════════════════════════════════════════\n // WHERE CLAUSES — STANDARD COMPARISON OPERATORS\n // ════════════════════════════════════════════════════════\n\n /** WHERE field IN values. */\n public whereIn(field: string, values: unknown[]): this {\n this.addOperation(\"whereIn\", { field, values });\n return this;\n }\n\n /** WHERE field NOT IN values. */\n public whereNotIn(field: string, values: unknown[]): this {\n this.addOperation(\"whereNotIn\", { field, values });\n return this;\n }\n\n /** WHERE field IS NULL. */\n public whereNull(field: string): this {\n this.addOperation(\"whereNull\", { field });\n return this;\n }\n\n /** WHERE field IS NOT NULL. */\n public whereNotNull(field: string): this {\n this.addOperation(\"whereNotNull\", { field });\n return this;\n }\n\n /** WHERE field BETWEEN low AND high. */\n public whereBetween(field: string, range: [unknown, unknown]): this {\n this.addOperation(\"whereBetween\", { field, range });\n return this;\n }\n\n /** WHERE field NOT BETWEEN low AND high. */\n public whereNotBetween(field: string, range: [unknown, unknown]): this {\n this.addOperation(\"whereNotBetween\", { field, range });\n return this;\n }\n\n // ════════════════════════════════════════════════════════\n // WHERE CLAUSES — PATTERN MATCHING\n // ════════════════════════════════════════════════════════\n\n /**\n * LIKE pattern match (AND).\n * @example q.whereLike(\"email\", \"%@gmail.com\")\n */\n public whereLike(field: string, pattern: RegExp | string): this {\n const patternStr = pattern instanceof RegExp ? pattern.source : pattern;\n this.addOperation(\"whereLike\", { field, pattern: patternStr });\n return this;\n }\n\n /** NOT LIKE pattern match. */\n public whereNotLike(field: string, pattern: RegExp | string): this {\n const patternStr = pattern instanceof RegExp ? pattern.source : pattern;\n this.addOperation(\"whereNotLike\", { field, pattern: patternStr });\n return this;\n }\n\n /** Starts with a prefix. */\n public whereStartsWith(field: string, value: string | number): this {\n return this.whereLike(field, `${value}%`);\n }\n\n /** Does NOT start with a prefix. */\n public whereNotStartsWith(field: string, value: string | number): this {\n return this.whereNotLike(field, `${value}%`);\n }\n\n /** Ends with a suffix. */\n public whereEndsWith(field: string, value: string | number): this {\n return this.whereLike(field, `%${value}`);\n }\n\n /** Does NOT end with a suffix. */\n public whereNotEndsWith(field: string, value: string | number): this {\n return this.whereNotLike(field, `%${value}`);\n }\n\n // ════════════════════════════════════════════════════════\n // WHERE CLAUSES — DATE/TIME PARTIALS\n // ════════════════════════════════════════════════════════\n\n /**\n * Match on date portion only (time ignored).\n * @example q.whereDate(\"createdAt\", \"2024-05-01\")\n */\n public whereDate(field: string, value: Date | string): this {\n this.addOperation(\"whereDate\", { field, value });\n return this;\n }\n\n /** Alias for whereDate. */\n public whereDateEquals(field: string, value: Date | string): this {\n return this.whereDate(field, value);\n }\n\n /** Field date is before value. */\n public whereDateBefore(field: string, value: Date | string): this {\n this.addOperation(\"whereDateBefore\", { field, value });\n return this;\n }\n\n /** Field date is after value. */\n public whereDateAfter(field: string, value: Date | string): this {\n this.addOperation(\"whereDateAfter\", { field, value });\n return this;\n }\n\n /** Field date is within a range [from, to]. */\n public whereDateBetween(field: string, range: [Date | string, Date | string]): this {\n this.addOperation(\"whereDateBetween\", { field, range });\n return this;\n }\n\n /** Field date is NOT within a range. */\n public whereDateNotBetween(field: string, range: [Date | string, Date | string]): this {\n this.addOperation(\"whereNotBetween\", { field, range });\n return this;\n }\n\n /**\n * Match on the time portion of a datetime field.\n * Emits a `whereRaw` op with a driver-agnostic marker; the driver parser\n * rewrites it to the appropriate SQL (`TIME(field) = ?`) or Mongo expression.\n */\n public whereTime(field: string, value: string): this {\n this.addOperation(\"whereRaw\", {\n expression: `TIME(${field}) = ?`,\n bindings: [value],\n });\n return this;\n }\n\n /**\n * Day-of-month from a date field (1–31).\n * Uses a `whereRaw` op so SQL parsers get the `EXTRACT` expression directly.\n * MongoDB drivers override to emit `$dayOfMonth`.\n */\n public whereDay(field: string, value: number): this {\n this.addOperation(\"whereRaw\", {\n expression: `EXTRACT(DAY FROM ${field}) = ?`,\n bindings: [value],\n });\n return this;\n }\n\n /** Month extracted from a date field (1–12). */\n public whereMonth(field: string, value: number): this {\n this.addOperation(\"whereRaw\", {\n expression: `EXTRACT(MONTH FROM ${field}) = ?`,\n bindings: [value],\n });\n return this;\n }\n\n /** Year extracted from a date field. */\n public whereYear(field: string, value: number): this {\n this.addOperation(\"whereRaw\", {\n expression: `EXTRACT(YEAR FROM ${field}) = ?`,\n bindings: [value],\n });\n return this;\n }\n\n // ════════════════════════════════════════════════════════\n // WHERE CLAUSES — JSON / STRUCTURED DATA\n // ════════════════════════════════════════════════════════\n\n /**\n * JSON/array path contains the given value.\n * @example q.whereJsonContains(\"tags\", \"typescript\")\n */\n public whereJsonContains(path: string, value: unknown): this {\n this.addOperation(\"whereJsonContains\", { path, value });\n return this;\n }\n\n /** JSON/array path does NOT contain the value. */\n public whereJsonDoesntContain(path: string, value: unknown): this {\n this.addOperation(\"whereJsonDoesntContain\", { path, value });\n return this;\n }\n\n /**\n * JSON path key exists.\n * Uses a `whereRaw` so existing SQL parsers get `IS NOT NULL` immediately.\n */\n public whereJsonContainsKey(path: string): this {\n this.addOperation(\"whereRaw\", { expression: `${path} IS NOT NULL`, bindings: [] });\n return this;\n }\n\n /**\n * Constrain the length of a JSON array at a path.\n * @example q.whereJsonLength(\"tags\", \">\", 3)\n */\n public whereJsonLength(path: string, operator: WhereOperator, value: number): this {\n this.addOperation(\"whereRaw\", {\n expression: `jsonb_array_length(${path}) ${operator} ?`,\n bindings: [value],\n });\n return this;\n }\n\n /** JSON path must resolve to an array. */\n public whereJsonIsArray(path: string): this {\n this.addOperation(\"whereRaw\", {\n expression: `jsonb_typeof(${path}) = 'array'`,\n bindings: [],\n });\n return this;\n }\n\n /** JSON path must resolve to an object. */\n public whereJsonIsObject(path: string): this {\n this.addOperation(\"whereRaw\", {\n expression: `jsonb_typeof(${path}) = 'object'`,\n bindings: [],\n });\n return this;\n }\n\n /**\n * Constrain the number of elements in an array field.\n * @example q.whereArrayLength(\"roles\", \">=\", 2)\n */\n public whereArrayLength(field: string, operator: WhereOperator, value: number): this {\n this.addOperation(\"whereRaw\", {\n expression: `array_length(${field}, 1) ${operator} ?`,\n bindings: [value],\n });\n return this;\n }\n\n // ════════════════════════════════════════════════════════\n // WHERE CLAUSES — CONVENIENCE SHORTCUTS\n // ════════════════════════════════════════════════════════\n\n /** WHERE id = value. */\n public whereId(value: string | number): this {\n return this.where(\"id\", value);\n }\n\n /** WHERE id IN values. */\n public whereIds(values: Array<string | number>): this {\n return this.whereIn(\"id\", values);\n }\n\n /** WHERE uuid = value. */\n public whereUuid(value: string): this {\n return this.where(\"uuid\", value);\n }\n\n /** WHERE ulid = value. */\n public whereUlid(value: string): this {\n return this.where(\"ulid\", value);\n }\n\n /**\n * Full-text search across one or more fields.\n * @example q.whereFullText([\"title\", \"body\"], \"typescript\")\n */\n public whereFullText(fields: string | string[], query: string): this {\n this.addOperation(\"whereFullText\", {\n fields: Array.isArray(fields) ? fields : [fields],\n query,\n });\n return this;\n }\n\n /** Full-text search (OR). */\n public orWhereFullText(fields: string | string[], query: string): this {\n return this.whereFullText(fields, query);\n }\n\n /** Alias for whereFullText with a single field. */\n public whereSearch(field: string, query: string): this {\n return this.whereFullText([field], query);\n }\n\n /**\n * Text search with optional extra equality filters.\n * MongoDB-style convenience shorthand.\n */\n public textSearch(query: string, filters?: WhereObject): this {\n if (filters) {\n for (const [key, value] of Object.entries(filters)) this.where(key, value as never);\n }\n return this;\n }\n\n // ════════════════════════════════════════════════════════\n // WHERE CLAUSES — EXISTENCE / SUBQUERIES\n // ════════════════════════════════════════════════════════\n\n /**\n * WHERE EXISTS (subquery callback) or field IS NOT NULL (string).\n *\n * @example\n * q.whereExists(sub => sub.where(\"userId\", \"users.id\"))\n * q.whereExists(\"optionalField\")\n */\n public whereExists(field: string): this;\n public whereExists(callback: WhereCallback<T>): this;\n public whereExists(param: string | WhereCallback<T>): this {\n if (typeof param === \"function\") {\n const sub = this.subQuery();\n param(sub as any);\n this.addOperation(\"whereExists\", { subquery: sub.operations });\n } else {\n this.addOperation(\"whereNotNull\", { field: param });\n }\n return this;\n }\n\n /**\n * WHERE NOT EXISTS (subquery callback) or field IS NULL (string).\n */\n public whereNotExists(field: string): this;\n public whereNotExists(callback: WhereCallback<T>): this;\n public whereNotExists(param: string | WhereCallback<T>): this {\n if (typeof param === \"function\") {\n const sub = this.subQuery();\n param(sub as any);\n this.addOperation(\"whereNotExists\", { subquery: sub.operations });\n } else {\n this.addOperation(\"whereNull\", { field: param });\n }\n return this;\n }\n\n /**\n * Constrain an array/collection field by element count.\n *\n * @example\n * q.whereSize(\"tags\", 3) // exactly 3\n * q.whereSize(\"tags\", \">=\", 1) // at least 1\n */\n public whereSize(field: string, size: number): this;\n public whereSize(field: string, operator: WhereOperator, size: number): this;\n public whereSize(field: string, ...args: unknown[]): this {\n const operator = args.length === 2 ? (args[0] as WhereOperator) : \"=\";\n const size = (args.length === 2 ? args[1] : args[0]) as number;\n return this.whereArrayLength(field, operator, size);\n }\n\n /**\n * AND NOT wrapper — negate a nested group.\n * @example q.whereNot(q => q.where(\"status\", \"banned\").where(\"role\", \"user\"))\n */\n public whereNot(callback: WhereCallback<T>): this {\n const sub = this.subQuery();\n callback(sub as any);\n this.addOperation(\"whereNot\", { nested: sub.operations });\n return this;\n }\n\n /** OR NOT wrapper. */\n public orWhereNot(callback: WhereCallback<T>): this {\n const sub = this.subQuery();\n callback(sub as any);\n this.addOperation(\"orWhereNot\", { nested: sub.operations });\n return this;\n }\n\n // ════════════════════════════════════════════════════════\n // JOINS — STANDARD SQL-STYLE\n // Note: Op type names match parser switch cases exactly.\n // join / innerJoin → INNER JOIN\n // leftJoin → LEFT JOIN\n // rightJoin → RIGHT JOIN\n // fullJoin → FULL OUTER JOIN\n // crossJoin → CROSS JOIN\n // joinRaw → raw expression\n // ════════════════════════════════════════════════════════\n\n /**\n * INNER JOIN.\n * @example q.join(\"categories\", \"posts.categoryId\", \"categories.id\")\n */\n public join(table: string, localField: string, foreignField: string): this;\n public join(options: JoinOptions): this;\n public join(...args: unknown[]): this {\n if (args.length === 3) {\n this.addOperation(\"join\", { table: args[0], localField: args[1], foreignField: args[2] });\n } else {\n this.addOperation(\"join\", args[0] as Record<string, unknown>);\n }\n return this;\n }\n\n /** LEFT JOIN. */\n public leftJoin(table: string, localField: string, foreignField: string): this;\n public leftJoin(options: JoinOptions): this;\n public leftJoin(...args: unknown[]): this {\n if (args.length === 3) {\n this.addOperation(\"leftJoin\", { table: args[0], localField: args[1], foreignField: args[2] });\n } else {\n this.addOperation(\"leftJoin\", args[0] as Record<string, unknown>);\n }\n return this;\n }\n\n /** RIGHT JOIN. */\n public rightJoin(table: string, localField: string, foreignField: string): this;\n public rightJoin(options: JoinOptions): this;\n public rightJoin(...args: unknown[]): this {\n if (args.length === 3) {\n this.addOperation(\"rightJoin\", {\n table: args[0],\n localField: args[1],\n foreignField: args[2],\n });\n } else {\n this.addOperation(\"rightJoin\", args[0] as Record<string, unknown>);\n }\n return this;\n }\n\n /** INNER JOIN (alias for join). */\n public innerJoin(table: string, localField: string, foreignField: string): this;\n public innerJoin(options: JoinOptions): this;\n public innerJoin(...args: unknown[]): this {\n if (args.length === 3) {\n this.addOperation(\"innerJoin\", {\n table: args[0],\n localField: args[1],\n foreignField: args[2],\n });\n } else {\n this.addOperation(\"innerJoin\", args[0] as Record<string, unknown>);\n }\n return this;\n }\n\n /** FULL OUTER JOIN. */\n public fullJoin(table: string, localField: string, foreignField: string): this;\n public fullJoin(options: JoinOptions): this;\n public fullJoin(...args: unknown[]): this {\n if (args.length === 3) {\n this.addOperation(\"fullJoin\", { table: args[0], localField: args[1], foreignField: args[2] });\n } else {\n this.addOperation(\"fullJoin\", args[0] as Record<string, unknown>);\n }\n return this;\n }\n\n /** CROSS JOIN. */\n public crossJoin(table: string): this {\n this.addOperation(\"crossJoin\", { table });\n return this;\n }\n\n /** Raw JOIN expression. Driver responsible for handling. */\n public joinRaw(expression: RawExpression, bindings?: unknown[]): this {\n this.addOperation(\"joinRaw\", { expression, bindings: bindings ?? [] });\n return this;\n }\n\n // ════════════════════════════════════════════════════════\n // RELATION EAGER LOADING — JOIN-BASED (joinWith)\n // ════════════════════════════════════════════════════════\n\n /**\n * Eager-load named relations via a single JOIN / $lookup query.\n *\n * Constraints are eagerly resolved at call time:\n * - Callbacks are invoked immediately → `subOps` stored in op data.\n * - Column shorthands are parsed into a `columns[]` array.\n *\n * The driver executor reads the `joinWith` op and uses the resolved data\n * alongside its own relation definition map to emit the appropriate SQL JOIN\n * or MongoDB $lookup stage.\n *\n * Supported arg forms (may be mixed):\n * - `\"author\"` / `[\"author\", \"category\"]` — no constraint\n * - `{ author: \"id,name\" }` — column shorthand\n * - `{ actions: q => q.where(\"status\",\"pending\").limit(5) }` — callback\n *\n * @example\n * Post.joinWith(\"author\", \"category\")\n * ChatMessage.joinWith({ actions: q => q.where(\"status\", \"pending\").limit(5) })\n * ChatMessage.joinWith({ org: \"id,name\", actions: q => q.orderBy(\"sort_order\") })\n */\n public joinWith(...args: unknown[]): this {\n const resolved: Record<string, { columns?: string[]; subOps?: Op[] }> = {};\n\n for (const arg of args) {\n if (typeof arg === \"string\") {\n resolved[arg] = {};\n } else if (Array.isArray(arg)) {\n for (const rel of arg as string[]) resolved[rel] = {};\n } else if (typeof arg === \"object\" && arg !== null) {\n for (const [rel, constraint] of Object.entries(arg as Record<string, JoinWithConstraint>)) {\n if (typeof constraint === \"function\") {\n const sub = this.subQuery();\n constraint(sub);\n resolved[rel] = { subOps: sub.operations };\n } else if (typeof constraint === \"string\" && constraint !== \"\") {\n resolved[rel] = {\n columns: constraint\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean),\n };\n } else {\n resolved[rel] = {};\n }\n }\n }\n }\n\n this.addOperation(\"joinWith\", { resolved });\n return this;\n }\n\n // ════════════════════════════════════════════════════════\n // RELATION EAGER LOADING — SEPARATE QUERIES (with)\n // ════════════════════════════════════════════════════════\n\n /**\n * Eager-load relations via separate queries (N+1 avoided by batching).\n *\n * @example\n * q.with(\"posts\")\n * q.with(\"posts\", q => q.where(\"published\", true))\n * q.with({ posts: true, comments: q => q.limit(5) })\n */\n public with(\n ...args: (string | Record<string, boolean | ((q: any) => void)> | ((q: any) => void))[]\n ): this {\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (typeof arg === \"string\") {\n const next = args[i + 1];\n if (typeof next === \"function\") {\n this.eagerLoadRelations.set(arg, next as (q: any) => void);\n i++;\n } else {\n this.eagerLoadRelations.set(arg, true);\n }\n } else if (typeof arg === \"object\" && arg !== null) {\n for (const [key, value] of Object.entries(\n arg as Record<string, boolean | ((q: any) => void)>,\n )) {\n this.eagerLoadRelations.set(key, value);\n }\n }\n }\n return this;\n }\n\n /**\n * Register one or more relation counts to emit alongside each result row.\n *\n * Accepts:\n * - Bare relation names (variadic strings or array): `withCount(\"posts\", \"comments\")`\n * - Alias shorthand: `withCount(\"posts as totalPosts\")`\n * - Object form for per-relation constraints / aliases:\n * `withCount({ posts: true, \"posts as approved\": (q) => q.where(\"approved\", true) })`\n *\n * Each entry is stored in `countRelations` keyed by its output column alias\n * (default `${relationName}Count`). The driver subclass consumes the map at\n * execute time to emit count expressions.\n *\n * @example\n * ```typescript\n * await User.query().withCount(\"posts\").get(); // postsCount\n * await User.query().withCount(\"posts as totalPosts\").get(); // totalPosts\n * await User.query()\n * .withCount({\n * posts: true,\n * \"posts as published\": (q) => q.where(\"isPublished\", true),\n * comments: \"commentTotal\",\n * })\n * .get();\n * ```\n */\n public withCount(...args: unknown[]): this {\n for (const arg of args) {\n if (typeof arg === \"string\") {\n this.recordCountEntry(arg);\n continue;\n }\n\n if (Array.isArray(arg)) {\n for (const spec of arg as string[]) {\n this.recordCountEntry(spec);\n }\n continue;\n }\n\n if (typeof arg === \"object\" && arg !== null) {\n const entries = Object.entries(\n arg as Record<string, true | string | ((query: any) => void)>,\n );\n\n for (const [key, value] of entries) {\n if (value === true) {\n this.recordCountEntry(key);\n } else if (typeof value === \"string\") {\n this.recordCountEntry(`${key} as ${value}`);\n } else if (typeof value === \"function\") {\n this.recordCountEntry(key, value);\n }\n }\n }\n }\n\n return this;\n }\n\n /**\n * Parse a count spec (\"relation\" or \"relation as alias\") into its relation\n * name and output alias, optionally capturing a constraint callback's\n * operations via a sub-builder. Stored in `countRelations` keyed by alias.\n */\n protected recordCountEntry(spec: string, constraint?: (query: any) => void): void {\n const { relation, alias } = this.parseCountSpec(spec);\n\n let constraintOps: Op[] | undefined;\n\n if (constraint) {\n const sub = this.subQuery();\n constraint(sub);\n constraintOps = sub.operations;\n }\n\n this.countRelations.set(alias, { relation, constraintOps });\n }\n\n /**\n * Split a `\"<relation>\"` or `\"<relation> as <alias>\"` spec. Returns the\n * resolved relation name and the output column alias (defaulting to\n * `${relation}Count` when no `as` is present).\n */\n protected parseCountSpec(spec: string): { relation: string; alias: string } {\n const trimmed = spec.trim();\n const match = /^(.+?)\\s+as\\s+(.+)$/i.exec(trimmed);\n\n if (!match) {\n return { relation: trimmed, alias: `${trimmed}Count` };\n }\n\n return { relation: match[1].trim(), alias: match[2].trim() };\n }\n\n /**\n * Filter to rows that have at least one related record.\n * @example q.has(\"comments\")\n * @example q.has(\"comments\", \">=\", 3)\n */\n public has(relation: string, operator?: WhereOperator, count?: number): this {\n this.addOperation(\"has\", { relation, operator: operator ?? \">=\", count: count ?? 1 });\n return this;\n }\n\n /**\n * Filter to rows with related records matching a sub-query (AND).\n * @example q.whereHas(\"comments\", q => q.where(\"approved\", true))\n */\n public whereHas(relation: string, callback: (q: any) => void): this {\n const sub = this.subQuery();\n callback(sub);\n this.addOperation(\"whereHas\", { relation, subquery: sub.operations });\n return this;\n }\n\n /** Same as whereHas but OR-joined. */\n public orWhereHas(relation: string, callback: (q: any) => void): this {\n const sub = this.subQuery();\n callback(sub);\n this.addOperation(\"orWhereHas\", { relation, subquery: sub.operations });\n return this;\n }\n\n /** Filter to rows with NO related records. */\n public doesntHave(relation: string): this {\n this.addOperation(\"doesntHave\", { relation });\n return this;\n }\n\n /** Filter to rows with NO related records matching conditions. */\n public whereDoesntHave(relation: string, callback: (q: any) => void): this {\n const sub = this.subQuery();\n callback(sub);\n this.addOperation(\"whereDoesntHave\", { relation, subquery: sub.operations });\n return this;\n }\n\n // ════════════════════════════════════════════════════════\n // SELECT / PROJECTION\n // ════════════════════════════════════════════════════════\n\n /**\n * Select specific columns.\n *\n * @example\n * q.select([\"id\", \"name\"])\n * q.select(\"id\", \"name\")\n * q.select({ name: 1, password: 0 }) // MongoDB-style projection\n */\n public select(fields: string[]): this;\n public select(fields: Record<string, 0 | 1 | boolean>): this;\n public select(...fields: Array<string | string[]>): this;\n public select(...args: unknown[]): this {\n if (args.length === 1 && Array.isArray(args[0])) {\n this.addOperation(\"select\", { fields: args[0] });\n } else if (args.length === 1 && typeof args[0] === \"object\" && !Array.isArray(args[0])) {\n this.addOperation(\"select\", { fields: args[0] as Record<string, unknown> });\n } else {\n this.addOperation(\"select\", { fields: (args as Array<string | string[]>).flat() });\n }\n return this;\n }\n\n /** Select a field under an alias. @example q.selectAs(\"fullName\", \"name\") */\n public selectAs(field: string, alias: string): this {\n this.addOperation(\"select\", { fields: { [field]: alias } });\n return this;\n }\n\n /**\n * Raw SELECT expression.\n * @example q.selectRaw(\"COUNT(*) AS total\")\n */\n public selectRaw(expression: RawExpression, bindings?: unknown[]): this {\n this.addOperation(\"selectRaw\", { expression, bindings: bindings ?? [] });\n return this;\n }\n\n /** Multiple raw SELECT expressions in one call. */\n public selectRawMany(\n definitions: Array<{ alias: string; expression: RawExpression; bindings?: unknown[] }>,\n ): this {\n for (const def of definitions) {\n this.selectRaw({ [def.alias]: def.expression }, def.bindings);\n }\n return this;\n }\n\n /** Subquery as a named projected field. */\n public selectSub(expression: RawExpression, alias: string): this {\n this.addOperation(\"selectRaw\", { expression: { [alias]: expression } });\n return this;\n }\n\n /** Alias for selectSub. */\n public addSelectSub(expression: RawExpression, alias: string): this {\n return this.selectSub(expression, alias);\n }\n\n /**\n * Aggregate function as a projected field.\n * @example q.selectAggregate(\"price\", \"sum\", \"totalRevenue\")\n */\n public selectAggregate(\n field: string,\n aggregate: \"sum\" | \"avg\" | \"min\" | \"max\" | \"count\" | \"first\" | \"last\",\n alias: string,\n ): this {\n return this.selectRaw({ [alias]: `${aggregate.toUpperCase()}(${field})` });\n }\n\n /** Existence check as a projected boolean field. */\n public selectExists(field: string, alias: string): this {\n return this.selectRaw({ [alias]: `${field} IS NOT NULL` });\n }\n\n /** COUNT as a projected field. */\n public selectCount(field: string, alias: string): this {\n return this.selectAggregate(field, \"count\", alias);\n }\n\n /**\n * CASE / switch expression.\n * @example q.selectCase([{ when: \"status = 1\", then: \"'active'\" }], \"'inactive'\", \"statusLabel\")\n */\n public selectCase(\n cases: Array<{ when: RawExpression; then: RawExpression | unknown }>,\n otherwise: RawExpression | unknown,\n alias: string,\n ): this {\n const caseExpr = cases.map((c) => `WHEN ${c.when} THEN ${c.then}`).join(\" \");\n return this.selectRaw({ [alias]: `CASE ${caseExpr} ELSE ${otherwise} END` });\n }\n\n /** IF/ELSE conditional field. */\n public selectWhen(\n condition: RawExpression,\n thenValue: RawExpression | unknown,\n elseValue: RawExpression | unknown,\n alias: string,\n ): this {\n return this.selectRaw({\n [alias]: `CASE WHEN ${condition} THEN ${thenValue} ELSE ${elseValue} END`,\n });\n }\n\n /**\n * Driver-native projection manipulation.\n * No-op in base — override in driver subclasses.\n */\n public selectDriverProjection(_callback: (projection: Record<string, unknown>) => void): this {\n return this;\n }\n\n /** JSON path extraction as a projected field. */\n public selectJson(path: string, alias?: string): this {\n const parts = path.split(\"->\");\n const column = parts[0];\n const jsonPath = parts.slice(1).join(\"->\");\n const expr = jsonPath ? `${column}->>'${jsonPath}'` : column;\n return alias ? this.selectAs(expr, alias) : this.selectRaw(expr);\n }\n\n /** JSON extraction via raw expression. */\n public selectJsonRaw(_path: string, expression: RawExpression, alias: string): this {\n return this.selectRaw({ [alias]: expression });\n }\n\n /** Exclude a JSON path from projection. */\n public deselectJson(path: string): this {\n return this.deselect([path]);\n }\n\n /** String concatenation as a projected field. */\n public selectConcat(fields: Array<string | RawExpression>, alias: string): this {\n return this.selectRaw({ [alias]: fields.join(\" || \") });\n }\n\n /** COALESCE (first non-null) as a projected field. */\n public selectCoalesce(fields: Array<string | RawExpression>, alias: string): this {\n return this.selectRaw({ [alias]: `COALESCE(${fields.join(\", \")})` });\n }\n\n /** Window function expression. */\n public selectWindow(spec: RawExpression): this {\n this.addOperation(\"selectRaw\", { expression: spec });\n return this;\n }\n\n /** Exclude specific columns from results. */\n public deselect(fields: string[]): this {\n this.addOperation(\"deselect\", { fields });\n return this;\n }\n\n /**\n * Remove all select operations (resets to wildcard).\n * Uses `rebuildIndex()` — no unsafe casts.\n */\n public clearSelect(): this {\n this.operations = this.operations.filter(\n (op) => !op.type.startsWith(\"select\") && op.type !== \"deselect\",\n );\n this.rebuildIndex();\n return this;\n }\n\n /** Alias for clearSelect. */\n public selectAll(): this {\n return this.clearSelect();\n }\n\n /** Alias for clearSelect. */\n public selectDefault(): this {\n return this.clearSelect();\n }\n\n /** Append additional fields to existing selection. */\n public addSelect(fields: string[]): this {\n this.addOperation(\"select\", { fields, add: true });\n return this;\n }\n\n /**\n * Record a DISTINCT flag (fluent — does not execute).\n * Subclasses expose a separate async `distinct(field)` execution method.\n */\n public distinctValues(fields?: string | string[]): this {\n const fieldList = fields ? (Array.isArray(fields) ? fields : [fields]) : [];\n this.addOperation(\"distinct\", { fields: fieldList });\n return this;\n }\n\n // ════════════════════════════════════════════════════════\n // ORDERING\n // ════════════════════════════════════════════════════════\n\n /**\n * ORDER BY a column.\n *\n * @example\n * q.orderBy(\"createdAt\", \"desc\")\n * q.orderBy({ name: \"asc\", age: \"desc\" })\n */\n public orderBy(field: string, direction?: OrderDirection): this;\n public orderBy(fields: Record<string, OrderDirection>): this;\n public orderBy(...args: unknown[]): this {\n if (typeof args[0] === \"string\") {\n this.addOperation(\"orderBy\", {\n field: args[0],\n direction: (args[1] as OrderDirection) ?? \"asc\",\n });\n } else {\n for (const [field, direction] of Object.entries(args[0] as Record<string, OrderDirection>)) {\n this.addOperation(\"orderBy\", { field, direction });\n }\n }\n return this;\n }\n\n /** ORDER BY descending shorthand. */\n public orderByDesc(field: string): this {\n return this.orderBy(field, \"desc\");\n }\n\n /**\n * Raw ORDER BY expression.\n * @example q.orderByRaw(\"RANDOM()\")\n * @example q.orderByRaw({ $meta: \"textScore\" })\n */\n public orderByRaw(expression: RawExpression, bindings?: unknown[]): this {\n this.addOperation(\"orderByRaw\", { expression, bindings: bindings ?? [] });\n return this;\n }\n\n /**\n * Random order. Maps to `RANDOM()` in SQL or `$sample` in MongoDB.\n * @param limit - Optional limit (required for MongoDB $sample)\n */\n public orderByRandom(limit?: number): this {\n this.addOperation(\"orderByRaw\", { expression: \"RANDOM()\" });\n if (limit !== undefined) this.limit(limit);\n return this;\n }\n\n /** Order ascending by a date column (oldest first). */\n public oldest(column = \"createdAt\"): this {\n return this.orderBy(column, \"asc\");\n }\n\n // ════════════════════════════════════════════════════════\n // LIMIT / OFFSET\n // ════════════════════════════════════════════════════════\n\n /** Limit number of results. */\n public limit(value: number): this {\n this.addOperation(\"limit\", { value });\n return this;\n }\n\n /** Skip N results (OFFSET). */\n public skip(value: number): this {\n this.addOperation(\"offset\", { value });\n return this;\n }\n\n /** Alias for skip. */\n public offset(value: number): this {\n return this.skip(value);\n }\n\n /** Alias for limit. */\n public take(value: number): this {\n return this.limit(value);\n }\n\n // ════════════════════════════════════════════════════════\n // GROUPING / AGGREGATION\n // ════════════════════════════════════════════════════════\n\n /**\n * GROUP BY clause.\n * @example q.groupBy(\"status\")\n * @example q.groupBy([\"year\", \"month\"])\n */\n public groupBy(input: GroupByInput): this {\n const fields = Array.isArray(input) ? input : [input];\n this.addOperation(\"groupBy\", { fields });\n return this;\n }\n\n /** Raw GROUP BY expression. */\n public groupByRaw(expression: RawExpression, bindings?: unknown[]): this {\n this.addOperation(\"groupBy\", { expression, bindings: bindings ?? [] });\n return this;\n }\n\n /**\n * HAVING clause (post-group filter).\n *\n * @example\n * q.having(\"total\", \">\", 100)\n * q.having([\"total\", \">\", 100])\n * q.having({ total: 100 })\n */\n public having(field: string, value: unknown): this;\n public having(field: string, operator: WhereOperator, value: unknown): this;\n public having(condition: HavingInput): this;\n public having(...args: unknown[]): this {\n if (args.length === 1) {\n const input = args[0] as HavingInput;\n if (Array.isArray(input)) {\n if (input.length === 2) {\n this.addOperation(\"having\", { field: input[0], operator: \"=\", value: input[1] });\n } else {\n this.addOperation(\"having\", { field: input[0], operator: input[1], value: input[2] });\n }\n } else {\n for (const [key, value] of Object.entries(input as Record<string, unknown>)) {\n this.addOperation(\"having\", { field: key, operator: \"=\", value });\n }\n }\n } else if (args.length === 2) {\n this.addOperation(\"having\", { field: args[0], operator: \"=\", value: args[1] });\n } else {\n this.addOperation(\"having\", { field: args[0], operator: args[1], value: args[2] });\n }\n return this;\n }\n\n /** Raw HAVING expression. */\n public havingRaw(expression: RawExpression, bindings?: unknown[]): this {\n this.addOperation(\"havingRaw\", { expression, bindings: bindings ?? [] });\n return this;\n }\n\n // ════════════════════════════════════════════════════════\n // UTILITY / CONTROL FLOW\n // ════════════════════════════════════════════════════════\n\n /**\n * Side-effect tap — executes callback synchronously and returns `this`.\n * @example q.where(...).tap(q => console.log(q.operations.length)).limit(10)\n */\n public tap(callback: (builder: this) => void): this {\n callback(this);\n return this;\n }\n\n /**\n * Conditionally apply query modifications.\n *\n * @example\n * q.when(userId, (q, id) => q.where(\"userId\", id))\n * q.when(isAdmin, q => q.withoutGlobalScopes(), q => q.scope(\"active\"))\n */\n public when<V>(\n condition: V | boolean,\n callback: (builder: this, value: V) => void,\n otherwise?: (builder: this) => void,\n ): this {\n if (condition) {\n callback(this, condition as V);\n } else if (otherwise) {\n otherwise(this);\n }\n return this;\n }\n}\n","import type { Operation, PipelineStage } from \"./types\";\n\n/**\n * Helper class for constructing MongoDB aggregation pipeline operations.\n *\n * This class encapsulates the logic for creating operation objects that will be\n * converted to MongoDB aggregation stages by the query parser. It provides a\n * clean abstraction over the low-level operation structure, making the query\n * builder code more maintainable and testable.\n *\n * Each operation consists of:\n * - **stage**: The MongoDB aggregation stage name (e.g., \"$match\", \"$project\")\n * - **type**: An internal identifier for the operation type\n * - **data**: The data associated with the operation\n * - **mergeable**: Whether this operation can be merged with adjacent similar operations\n *\n * @internal This class is for internal use within the MongoDB driver\n *\n * @example\n * ```typescript\n * const operations: Operation[] = [];\n * const helper = new MongoQueryOperations(operations);\n *\n * // Add a match operation\n * helper.addMatchOperation(\"whereIn\", { field: \"status\", values: [\"active\", \"pending\"] });\n *\n * // Add a project operation\n * helper.addProjectOperation(\"select\", { fields: [\"name\", \"email\"] });\n *\n * // Operations array is now populated\n * console.log(operations);\n * // [\n * // { stage: \"$match\", mergeable: true, type: \"whereIn\", data: {...} },\n * // { stage: \"$project\", mergeable: true, type: \"select\", data: {...} }\n * // ]\n * ```\n */\nexport class MongoQueryOperations {\n /**\n * Creates a new operations helper.\n *\n * The helper maintains a reference to the operations array and populates it\n * as methods are called. This allows the query builder to maintain a single\n * ordered list of operations that will be converted to a MongoDB aggregation\n * pipeline.\n *\n * @param operations - Reference to the operations array to populate\n *\n * @example\n * ```typescript\n * const operations: Operation[] = [];\n * const helper = new MongoQueryOperations(operations);\n * ```\n */\n public constructor(private operations: Operation[]) {}\n\n public setOperations(operations: Operation[]): void {\n this.operations = operations;\n }\n\n /**\n * Adds a $match stage operation to the pipeline.\n *\n * Match operations filter documents in the aggregation pipeline, similar to\n * the WHERE clause in SQL. Multiple match operations can be merged together\n * by the parser for optimization.\n *\n * @param type - The operation type identifier (e.g., \"where\", \"whereIn\", \"whereLike\")\n * @param data - The operation data data containing filter criteria\n * @param mergeable - Whether this operation can be merged with adjacent match operations (default: true)\n *\n * @example\n * ```typescript\n * // Simple where operation\n * helper.addMatchOperation(\"where\", { field: \"age\", operator: \">\", value: 18 });\n *\n * // WhereIn operation\n * helper.addMatchOperation(\"whereIn\", { field: \"status\", values: [\"active\", \"pending\"] });\n *\n * // Non-mergeable match (e.g., after a group stage)\n * helper.addMatchOperation(\"having\", { field: \"count\", operator: \">\", value: 5 }, false);\n * ```\n */\n public addMatchOperation(type: string, data: Record<string, unknown>, mergeable = true): void {\n this.operations.push({\n stage: \"$match\",\n mergeable,\n type,\n data,\n });\n }\n\n /**\n * Adds a $project stage operation to the pipeline.\n *\n * Project operations control which fields are included or excluded in the\n * output documents, similar to the SELECT clause in SQL. They can also be\n * used to compute new fields or reshape documents.\n *\n * @param type - The operation type identifier (e.g., \"select\", \"deselect\", \"selectRaw\")\n * @param data - The operation data data containing projection specifications\n * @param mergeable - Whether this operation can be merged with adjacent project operations (default: true)\n *\n * @example\n * ```typescript\n * // Select specific fields\n * helper.addProjectOperation(\"select\", { fields: [\"name\", \"email\", \"age\"] });\n *\n * // Deselect fields\n * helper.addProjectOperation(\"deselect\", { fields: [\"password\", \"secret\"] });\n *\n * // Computed field\n * helper.addProjectOperation(\"selectRaw\", {\n * expression: { fullName: { $concat: [\"$firstName\", \" \", \"$lastName\"] } }\n * });\n * ```\n */\n public addProjectOperation(\n type: string,\n data: Record<string, unknown>,\n mergeable = true,\n ): void {\n this.operations.push({\n stage: \"$project\",\n mergeable,\n type,\n data,\n });\n }\n\n /**\n * Adds a $sort stage operation to the pipeline.\n *\n * Sort operations order the documents in the pipeline, similar to the ORDER BY\n * clause in SQL. Multiple sort operations can be merged to create compound\n * sorting.\n *\n * @param type - The operation type identifier (e.g., \"orderBy\", \"orderByRandom\")\n * @param data - The operation data data containing sort specifications\n * @param mergeable - Whether this operation can be merged with adjacent sort operations (default: true)\n *\n * @example\n * ```typescript\n * // Order by a single field\n * helper.addSortOperation(\"orderBy\", { field: \"createdAt\", direction: \"desc\" });\n *\n * // Random ordering (not mergeable)\n * helper.addSortOperation(\"orderByRandom\", {limit: 1000}, false);\n *\n * // Order by raw expression\n * helper.addSortOperation(\"orderByRaw\", {\n * expression: { score: -1, name: 1 }\n * });\n * ```\n */\n public addSortOperation(type: string, data: Record<string, unknown>, mergeable = true): void {\n this.operations.push({\n stage: \"$sort\",\n mergeable,\n type,\n data,\n });\n }\n\n /**\n * Adds a $group stage operation to the pipeline.\n *\n * Group operations aggregate documents by specified fields and compute\n * aggregate values, similar to the GROUP BY clause in SQL. Group operations\n * are typically not mergeable as they represent distinct aggregation boundaries.\n *\n * @param type - The operation type identifier (e.g., \"groupBy\", \"distinct\")\n * @param data - The operation data data containing grouping specifications\n * @param mergeable - Whether this operation can be merged with adjacent group operations (default: false)\n *\n * @example\n * ```typescript\n * // Group by a single field\n * helper.addGroupOperation(\"groupBy\", { fields: \"category\" });\n *\n * // Group by multiple fields\n * helper.addGroupOperation(\"groupBy\", {\n * fields: { category: \"$category\", status: \"$status\" }\n * });\n *\n * // Distinct operation (special case of grouping)\n * helper.addGroupOperation(\"distinct\", { fields: [\"email\"] });\n * ```\n */\n public addGroupOperation(\n type: string,\n data: Record<string, unknown>,\n mergeable = false,\n ): void {\n this.operations.push({\n stage: \"$group\",\n mergeable,\n type,\n data,\n });\n }\n\n /**\n * Adds a $lookup stage operation to the pipeline.\n *\n * Lookup operations perform left outer joins with other collections, similar\n * to JOIN in SQL. Lookup operations are never mergeable as each represents a\n * distinct join operation.\n *\n * @param type - The operation type identifier (typically \"join\")\n * @param data - The operation data data containing join specifications\n *\n * @example\n * ```typescript\n * // Simple lookup\n * helper.addLookupOperation(\"join\", {\n * table: \"orders\",\n * localField: \"id\",\n * foreignField: \"userId\",\n * alias: \"userOrders\"\n * });\n *\n * // Lookup with pipeline\n * helper.addLookupOperation(\"join\", {\n * table: \"products\",\n * pipeline: [\n * { $match: { inStock: true } },\n * { $sort: { price: 1 } }\n * ],\n * alias: \"availableProducts\"\n * });\n * ```\n */\n public addLookupOperation(type: string, data: Record<string, unknown>): void {\n this.operations.push({\n stage: \"$lookup\",\n mergeable: false,\n type,\n data,\n });\n }\n\n /**\n * Adds a generic stage operation to the pipeline.\n *\n * This method provides flexibility to add any MongoDB aggregation stage,\n * including less common stages like $facet, $bucket, $setWindowFields, etc.\n * Use this for operations that don't fit into the standard categories.\n *\n * @param stage - The MongoDB aggregation stage name (e.g., \"$limit\", \"$skip\", \"$unwind\")\n * @param type - The operation type identifier\n * @param data - The operation data data\n * @param mergeable - Whether this operation can be merged with adjacent operations (default: false)\n *\n * @example\n * ```typescript\n * // Add a limit operation\n * helper.addOperation(\"$limit\", \"limit\", { value: 10 });\n *\n * // Add a skip operation\n * helper.addOperation(\"$skip\", \"skip\", { value: 20 });\n *\n * // Add an unwind operation\n * helper.addOperation(\"$unwind\", \"unwind\", { path: \"$tags\" });\n *\n * // Add a window function\n * helper.addOperation(\"$setWindowFields\", \"selectWindow\", {\n * spec: {\n * partitionBy: \"$category\",\n * sortBy: { price: 1 },\n * output: { rank: { $rank: {} } }\n * }\n * });\n * ```\n */\n public addOperation(\n stage: PipelineStage,\n type: string,\n data: Record<string, unknown>,\n mergeable = false,\n ): void {\n this.operations.push({\n stage,\n mergeable,\n type,\n data,\n });\n }\n}\n","import { colors } from \"@mongez/copper\";\nimport type { Collection } from \"mongodb\";\nimport type { GroupByInput, RawExpression, WhereOperator } from \"../../contracts\";\nimport {\n isAggregateExpression,\n type AggregateExpression,\n} from \"../../expressions/aggregate-expressions\";\nimport type { MongoQueryBuilder } from \"./mongodb-query-builder\";\nimport type { Operation, PipelineStage } from \"./types\";\n\n/**\n * Options for configuring the MongoDB query parser.\n */\nexport type MongoQueryParserOptions = {\n /** The MongoDB collection being queried */\n collection: Collection;\n /** The ordered list of operations to parse */\n operations: Operation[];\n /** Factory method for creating sub-builders (used for callbacks) */\n createSubBuilder: () => MongoQueryBuilder;\n};\n\n/**\n * Parses query builder operations into MongoDB aggregation pipeline.\n *\n * This parser is responsible for converting the abstract operations collected\n * by the query builder into a concrete MongoDB aggregation pipeline. It handles\n * intelligent grouping of mergeable operations (like multiple where clauses)\n * into single pipeline stages for optimal performance.\n */\nexport class MongoQueryParser {\n /**\n * The MongoDB collection being queried.\n */\n private readonly collection: Collection;\n\n /**\n * The ordered list of operations to parse.\n */\n private readonly operations: Operation[];\n\n /**\n * Factory for creating sub-builders (used when resolving callbacks).\n */\n private readonly createSubBuilder: () => MongoQueryBuilder;\n\n /**\n * Track group field names for automatic _id renaming.\n * Maps pipeline index to field names.\n */\n private readonly groupFieldNames = new Map<number, string | string[]>();\n\n /**\n * Create a new MongoDB query parser.\n *\n * @param options - Configuration options for the parser\n */\n public constructor(options: MongoQueryParserOptions) {\n this.collection = options.collection;\n this.operations = options.operations;\n this.createSubBuilder = options.createSubBuilder;\n }\n\n /**\n * Parse the operations into a MongoDB aggregation pipeline.\n *\n * This method intelligently groups mergeable operations (e.g., multiple where\n * clauses) into single pipeline stages while maintaining the correct execution\n * order for non-mergeable operations.\n *\n * @returns The MongoDB aggregation pipeline\n *\n * @example\n * ```typescript\n * const parser = new MongoQueryParser({ collection, operations });\n * const pipeline = parser.parse();\n * // [\n * // { $match: { status: 'active', age: { $gt: 18 } } },\n * // { $sort: { createdAt: -1 } },\n * // { $limit: 10 }\n * // ]\n * ```\n */\n public parse(): any[] {\n const pipeline: any[] = [];\n let currentStage: PipelineStage | null = null;\n let currentBuffer: Operation[] = [];\n\n for (const op of this.operations) {\n if (op.mergeable && op.stage === currentStage) {\n // Same mergeable stage, add to buffer\n currentBuffer.push(op);\n } else {\n // Different stage or non-mergeable, flush buffer\n if (currentBuffer.length > 0) {\n const builtStage = this.buildStage(currentStage!, currentBuffer);\n if (builtStage) {\n const stageIndex = pipeline.length;\n pipeline.push(builtStage);\n // Track field names for group stages with aggregates\n this.trackGroupFieldNames(currentStage!, currentBuffer, stageIndex);\n }\n currentBuffer = [];\n }\n\n if (op.mergeable) {\n // Start new buffer\n currentStage = op.stage;\n currentBuffer.push(op);\n } else {\n // Non-mergeable, add directly\n const builtStage = this.buildStage(op.stage, [op]);\n if (builtStage) {\n const stageIndex = pipeline.length;\n pipeline.push(builtStage);\n // Track field names for group stages with aggregates\n this.trackGroupFieldNames(op.stage, [op], stageIndex);\n }\n currentStage = null;\n }\n }\n }\n\n // Flush remaining buffer\n if (currentBuffer.length > 0) {\n const builtStage = this.buildStage(currentStage!, currentBuffer);\n if (builtStage) {\n const stageIndex = pipeline.length;\n pipeline.push(builtStage);\n // Track field names for group stages with aggregates\n this.trackGroupFieldNames(currentStage!, currentBuffer, stageIndex);\n }\n }\n\n // Post-process: Rename _id to actual field names after $group stages with aggregates\n return this.postProcessGroupStages(pipeline);\n }\n\n /**\n * Track field names for group stages that need _id renaming.\n */\n private trackGroupFieldNames(\n stage: PipelineStage,\n operations: Operation[],\n stageIndex: number,\n ): void {\n if (stage === \"$group\") {\n const op = operations[0];\n if (op.type === \"groupByWithAggregates\" && op.data.fields) {\n const fieldNames = this.extractGroupFieldNames(op.data.fields);\n if (fieldNames) {\n this.groupFieldNames.set(stageIndex, fieldNames);\n }\n }\n }\n }\n\n /**\n * Post-process pipeline to rename _id fields after $group stages.\n *\n * This automatically renames MongoDB's `_id` field to the actual field name(s)\n * used for grouping, making the results more intuitive.\n *\n * @param pipeline - The aggregation pipeline\n * @returns The processed pipeline\n */\n private postProcessGroupStages(pipeline: any[]): any[] {\n const processed: any[] = [];\n\n for (let i = 0; i < pipeline.length; i++) {\n const stage = pipeline[i];\n\n // Check if this is a $group stage that needs _id renaming\n if (stage.$group && this.groupFieldNames.has(i)) {\n const fieldNames = this.groupFieldNames.get(i)!;\n\n // Add the $group stage\n processed.push(stage);\n\n // Add a $project stage to rename _id\n const projection: Record<string, unknown> = {};\n\n if (typeof fieldNames === \"string\") {\n // Single field: rename _id to field name\n projection[fieldNames] = \"$_id\";\n } else if (Array.isArray(fieldNames) && fieldNames.length > 0) {\n // Multiple fields: _id is an object, spread it\n for (const fieldName of fieldNames) {\n projection[fieldName] = `$_id.${fieldName}`;\n }\n }\n\n // Include all aggregate fields\n const aggregateFields = Object.keys(stage.$group).filter((key) => key !== \"_id\");\n for (const field of aggregateFields) {\n projection[field] = 1;\n }\n\n if (Object.keys(projection).length > 0) {\n // now unselect the _id field\n projection._id = 0;\n processed.push({ $project: projection });\n }\n } else {\n // Regular stage, add as-is\n processed.push(stage);\n }\n }\n\n return processed;\n }\n\n /**\n * Convert the parsed pipeline to a pretty-printed string for debugging.\n *\n * This method formats the MongoDB aggregation pipeline in a human-readable\n * way, making it easier to understand and debug complex queries.\n *\n * @returns A formatted string representation of the pipeline\n *\n * @example\n * ```typescript\n * const parser = new MongoQueryParser({ collection, operations });\n * console.log(parser.toPrettyString());\n * // Output:\n * // MongoDB Aggregation Pipeline:\n * // ════════════════════════════\n * // Stage 1: $match\n * // status: \"active\"\n * // age: { $gt: 18 }\n * //\n * // Stage 2: $sort\n * // createdAt: -1\n * ```\n */\n public toPrettyString(): string {\n const pipeline = this.parse();\n\n if (pipeline.length === 0) {\n return \"MongoDB Aggregation Pipeline: (empty)\";\n }\n\n let output = \"MongoDB Aggregation Pipeline:\\n\";\n output += \"═\".repeat(50) + \"\\n\";\n\n pipeline.forEach((stage, index) => {\n const stageName = Object.keys(stage)[0];\n const stageData = stage[stageName];\n\n if (index > 0) {\n output += \"\\n\";\n }\n\n output += `Stage ${index + 1}: ${colors.redBright(stageName)}\\n`;\n output += this.formatStageData(stageData, 2);\n });\n\n return output;\n }\n\n /**\n * Format stage data with proper indentation.\n *\n * @param data - The stage data to format\n * @param indent - The indentation level\n * @returns Formatted string\n */\n private formatStageData(data: any, indent: number = 0): string {\n const spaces = \" \".repeat(indent);\n\n if (typeof data !== \"object\" || data === null) {\n return `${spaces}${JSON.stringify(data)}\\n`;\n }\n\n if (Array.isArray(data)) {\n if (data.length === 0) return `${spaces}[]`;\n\n let result = \"\";\n data.forEach((item, index) => {\n result += `${spaces}[${colors.magenta(index)}]:\\n`;\n result += this.formatStageData(item, indent + 2);\n });\n return result;\n }\n\n let result = \"\";\n Object.entries(data).forEach(([key, value]) => {\n const isOperator = key.startsWith(\"$\");\n const coloredKey = isOperator ? colors.magentaBright(key) : colors.blue(key);\n\n if (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\n result += `${spaces}${coloredKey}:\\n`;\n result += this.formatStageData(value, indent + 2);\n } else if (Array.isArray(value)) {\n result += `${spaces}${coloredKey}:\\n`;\n result += this.formatStageData(value, indent + 2);\n } else {\n const formattedValue =\n typeof value === \"number\"\n ? colors.yellowBright(value)\n : typeof value === \"boolean\"\n ? colors.cyanBright(value.toString())\n : typeof value === \"string\"\n ? colors.greenBright(JSON.stringify(value))\n : colors.greenBright(String(value));\n result += `${spaces}${coloredKey}: ${formattedValue}\\n`;\n }\n });\n\n return result.endsWith(\"\\n\") ? result : `${result}\\n`;\n }\n\n /**\n * Build a single pipeline stage from a group of operations.\n *\n * @param stage - The pipeline stage type\n * @param operations - The operations to build the stage from\n * @returns The built pipeline stage or null if no stage should be added\n */\n private buildStage(stage: PipelineStage, operations: Operation[]): any {\n switch (stage) {\n case \"$match\":\n return this.buildMatchStage(operations);\n case \"$project\":\n return this.buildProjectStage(operations);\n case \"$sort\":\n return this.buildSortStage(operations);\n case \"$group\":\n return this.buildGroupStage(operations);\n case \"$lookup\":\n return this.buildLookupStage(operations);\n case \"$limit\":\n return { $limit: operations[0].data.value };\n case \"$skip\":\n return { $skip: operations[0].data.value };\n case \"$setWindowFields\":\n return {\n $setWindowFields: operations[0].data.spec,\n };\n default:\n return null;\n }\n }\n\n /**\n * Build a $match stage from where operations.\n *\n * Query building strategy:\n * - Top-level where() + orWhere() = Pure OR\n * - Use callbacks for AND + OR grouping\n *\n * @param operations - The where operations\n * @returns The $match stage or null\n */\n private buildMatchStage(operations: Operation[]): any {\n const andFilter: Record<string, any> = {};\n const orClauses: any[] = [];\n const pendingSimpleWhere: any[] = [];\n let topLevelOrMode = false;\n\n const pushOr = (clause: any): void => {\n if (!clause) {\n return;\n }\n\n if (this.isPureOrCondition(clause)) {\n orClauses.push(...clause.$or);\n return;\n }\n\n if (Array.isArray(clause)) {\n orClauses.push(...clause);\n return;\n }\n\n orClauses.push(clause);\n };\n\n const mergeAnd = (condition: any): void => {\n if (!condition) {\n return;\n }\n\n Object.entries(condition).forEach(([key, value]) => {\n if (key === \"$or\") {\n pushOr(value);\n return;\n }\n\n if (\n value &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n andFilter[key] &&\n typeof andFilter[key] === \"object\" &&\n !Array.isArray(andFilter[key])\n ) {\n andFilter[key] = { ...andFilter[key], ...value };\n } else {\n andFilter[key] = value;\n }\n });\n };\n\n const queueSimpleWhere = (condition: any): void => {\n if (!condition) {\n return;\n }\n if (topLevelOrMode) {\n pushOr(condition);\n } else {\n pendingSimpleWhere.push(condition);\n }\n };\n\n const enterTopLevelOrMode = (): void => {\n if (topLevelOrMode) {\n return;\n }\n topLevelOrMode = true;\n while (pendingSimpleWhere.length > 0) {\n const condition = pendingSimpleWhere.shift();\n if (condition) {\n pushOr(condition);\n }\n }\n };\n\n const flushPendingSimpleWhere = (): void => {\n if (pendingSimpleWhere.length === 0) {\n return;\n }\n if (topLevelOrMode) {\n pendingSimpleWhere.forEach(pushOr);\n } else {\n pendingSimpleWhere.forEach(mergeAnd);\n }\n pendingSimpleWhere.length = 0;\n };\n\n for (const op of operations) {\n if (op.type === \"where:callback\" || op.type === \"orWhere:callback\") {\n flushPendingSimpleWhere();\n const callbackCondition = this.buildCallbackCondition(op.data);\n if (!callbackCondition) {\n continue;\n }\n\n const treatAsOr =\n op.type === \"orWhere:callback\" ||\n (topLevelOrMode && !this.isPureOrCondition(callbackCondition)) ||\n this.isPureOrCondition(callbackCondition);\n\n if (treatAsOr) {\n if (op.type === \"orWhere:callback\") {\n enterTopLevelOrMode();\n }\n pushOr(callbackCondition);\n } else {\n mergeAnd(callbackCondition);\n }\n continue;\n }\n\n if (op.type === \"where:object\") {\n queueSimpleWhere(op.data);\n continue;\n }\n\n if (\n op.type === \"where:not\" ||\n op.type === \"orWhere:not\" ||\n op.type === \"where:exists\" ||\n op.type === \"where:notExists\"\n ) {\n const negated = op.type === \"where:not\" || op.type === \"where:notExists\";\n const nested = this.buildCallbackCondition(op.data.callback);\n if (nested) {\n const condition = negated ? { $nor: [nested] } : nested;\n if (op.type.startsWith(\"orWhere\")) {\n enterTopLevelOrMode();\n pushOr(condition);\n } else {\n queueSimpleWhere(condition);\n }\n }\n continue;\n }\n\n if (op.type === \"orWhere:object\") {\n enterTopLevelOrMode();\n pushOr(op.data);\n continue;\n }\n\n const condition = this.buildWhereCondition(op);\n if (!condition) {\n continue;\n }\n\n if (op.type.startsWith(\"orWhere\")) {\n enterTopLevelOrMode();\n pushOr(condition);\n } else {\n queueSimpleWhere(condition);\n }\n }\n\n flushPendingSimpleWhere();\n\n const hasAnd = Object.keys(andFilter).length > 0;\n const hasOr = orClauses.length > 0;\n\n if (!hasAnd && !hasOr) {\n return null;\n }\n\n const match: any = {};\n if (hasAnd) {\n Object.assign(match, andFilter);\n }\n if (hasOr) {\n match.$or = orClauses;\n }\n\n return { $match: match };\n }\n\n private isPureOrCondition(condition: any): condition is { $or: any[] } {\n return (\n condition &&\n typeof condition === \"object\" &&\n !Array.isArray(condition) &&\n Object.keys(condition).length === 1 &&\n Array.isArray((condition as any).$or)\n );\n }\n\n /**\n * Build a condition from a callback-based where clause.\n * Creates a sub-builder, executes the callback, and extracts the conditions.\n * If callback has orWhere, all conditions become OR.\n *\n * @param callback - The callback function\n * @returns The built condition or null\n */\n private buildCallbackCondition(callback: any): any {\n // Create a temporary sub-builder\n const subBuilder = this.createSubBuilder();\n\n // Execute the callback with the sub-builder\n callback(subBuilder);\n\n // Extract only match operations from the sub-builder\n const matchOps = subBuilder.operations.filter((op: Operation) => op.stage === \"$match\");\n\n if (matchOps.length === 0) {\n return null;\n }\n\n const andFilter: Record<string, any> = {};\n const orClauses: any[] = [];\n const hasInternalOr = matchOps.some((op) => op.type.startsWith(\"orWhere\"));\n\n const pushOr = (clause: any): void => {\n if (!clause) {\n return;\n }\n if (this.isPureOrCondition(clause)) {\n orClauses.push(...clause.$or);\n return;\n }\n orClauses.push(clause);\n };\n\n if (hasInternalOr) {\n for (const op of matchOps) {\n if (op.type === \"where:callback\" || op.type === \"orWhere:callback\") {\n const nestedCondition = this.buildCallbackCondition(op.data);\n if (nestedCondition) {\n pushOr(nestedCondition);\n }\n continue;\n }\n\n if (op.type === \"where:object\" || op.type === \"orWhere:object\") {\n pushOr(op.data);\n continue;\n }\n\n const condition = this.buildWhereCondition(op);\n if (condition) {\n pushOr(condition);\n }\n }\n\n return orClauses.length > 0 ? { $or: orClauses } : null;\n }\n\n for (const op of matchOps) {\n if (op.type === \"where:callback\") {\n const nestedCondition = this.buildCallbackCondition(op.data);\n if (nestedCondition) {\n Object.assign(andFilter, nestedCondition);\n }\n } else if (op.type === \"where:object\") {\n Object.assign(andFilter, op.data);\n } else {\n const condition = this.buildWhereCondition(op);\n if (condition) {\n Object.assign(andFilter, condition);\n }\n }\n }\n\n return Object.keys(andFilter).length > 0 ? andFilter : null;\n }\n\n /**\n * Build a MongoDB filter condition from a where operation.\n *\n * @param op - The operation to build\n * @returns The MongoDB filter condition\n */\n private buildWhereCondition(op: Operation): any {\n const { field, operator, value } = op.data;\n\n switch (op.type) {\n case \"where\":\n case \"orWhere\":\n return this.buildOperatorCondition(field, operator, value);\n\n case \"whereIn\":\n return { [field]: { $in: value || op.data.values } };\n\n case \"whereNotIn\":\n return { [field]: { $nin: value || op.data.values } };\n\n case \"whereNull\":\n return { [field]: null };\n\n case \"whereNotNull\":\n return { [field]: { $ne: null } };\n\n case \"whereBetween\":\n return {\n [field]: {\n $gte: op.data.range[0],\n $lte: op.data.range[1],\n },\n };\n\n case \"whereNotBetween\":\n return {\n [field]: {\n $not: {\n $gte: op.data.range[0],\n $lte: op.data.range[1],\n },\n },\n };\n\n case \"whereLike\": {\n const pattern =\n typeof op.data.pattern === \"string\" ? op.data.pattern : op.data.pattern.source;\n return { [field]: { $regex: pattern, $options: \"i\" } };\n }\n\n case \"whereNotLike\": {\n const notPattern =\n typeof op.data.pattern === \"string\" ? op.data.pattern : op.data.pattern.source;\n return { [field]: { $not: { $regex: notPattern, $options: \"i\" } } };\n }\n\n case \"whereStartsWith\":\n return { [field]: { $regex: `^${op.data.value}`, $options: \"i\" } };\n\n case \"whereNotStartsWith\":\n return {\n [field]: { $not: { $regex: `^${op.data.value}`, $options: \"i\" } },\n };\n\n case \"whereEndsWith\":\n return { [field]: { $regex: `${op.data.value}$`, $options: \"i\" } };\n\n case \"whereNotEndsWith\":\n return {\n [field]: { $not: { $regex: `${op.data.value}$`, $options: \"i\" } },\n };\n\n case \"whereExists\":\n return { [field]: { $exists: true } };\n\n case \"whereNotExists\":\n return { [field]: { $exists: false } };\n\n case \"whereSize\":\n if (op.data.operator === \"=\") {\n return { [field]: { $size: op.data.size } };\n } else {\n const mongoOp = this.getMongoOperator(op.data.operator);\n return {\n $expr: {\n [mongoOp]: [{ $size: `$${field}` }, op.data.size],\n },\n };\n }\n\n case \"textSearch\":\n return {\n $text: { $search: op.data.query },\n ...(op.data.filters || {}),\n };\n\n case \"whereRaw\":\n case \"orWhereRaw\":\n return this.resolveRawExpression(\n op.data.expression as RawExpression,\n op.data.bindings,\n );\n\n case \"whereColumn\":\n case \"orWhereColumn\":\n return this.buildColumnComparison(op.data.first, op.data.operator, op.data.second);\n\n case \"whereBetweenColumns\":\n return this.buildBetweenColumnsCondition(\n op.data.field,\n op.data.lowerColumn,\n op.data.upperColumn,\n );\n\n case \"whereDate\":\n case \"whereDateEquals\":\n return this.buildDateEqualityCondition(op.data.field, op.data.value);\n\n case \"whereDateBefore\":\n return this.buildDateBeforeCondition(op.data.field, op.data.value);\n\n case \"whereDateAfter\":\n return this.buildDateAfterCondition(op.data.field, op.data.value);\n\n case \"whereTime\":\n return this.buildTimeCondition(op.data.field, op.data.value);\n\n case \"whereDay\":\n return this.buildDatePartCondition(op.data.field, \"$dayOfMonth\", op.data.value);\n\n case \"whereMonth\":\n return this.buildDatePartCondition(op.data.field, \"$month\", op.data.value);\n\n case \"whereYear\":\n return this.buildDatePartCondition(op.data.field, \"$year\", op.data.value);\n\n case \"whereJsonContains\":\n return this.buildJsonContainsCondition(op.data.path, op.data.value);\n\n case \"whereJsonDoesntContain\":\n return this.buildJsonDoesntContainCondition(op.data.path, op.data.value);\n\n case \"whereJsonContainsKey\":\n return this.buildJsonContainsKeyCondition(op.data.path);\n\n case \"whereJsonLength\":\n return this.buildJsonLengthCondition(\n op.data.path,\n op.data.operator,\n op.data.value,\n );\n\n case \"whereJsonIsArray\":\n return this.buildJsonTypeCondition(op.data.path, \"array\");\n\n case \"whereJsonIsObject\":\n return this.buildJsonTypeCondition(op.data.path, \"object\");\n\n case \"whereArrayLength\":\n return this.buildArrayLengthCondition(\n op.data.field,\n op.data.operator,\n op.data.value,\n );\n\n case \"whereFullText\":\n case \"orWhereFullText\":\n return { $text: { $search: op.data.query } };\n\n case \"whereSearch\":\n return {\n [op.data.field]: {\n $regex: op.data.query,\n $options: \"i\",\n },\n };\n\n case \"where:not\":\n case \"orWhere:not\": {\n const nestedNot = this.buildCallbackCondition(op.data.callback);\n return nestedNot ? { $nor: [nestedNot] } : null;\n }\n\n case \"where:exists\":\n return this.buildCallbackCondition(op.data.callback);\n\n case \"where:notExists\": {\n const nestedExists = this.buildCallbackCondition(op.data.callback);\n return nestedExists ? { $nor: [nestedExists] } : null;\n }\n\n case \"whereArrayContains\":\n if (op.data.key) {\n return {\n [field]: {\n $elemMatch: { [op.data.key]: op.data.value },\n },\n };\n } else {\n return { [field]: op.data.value };\n }\n\n default:\n return null;\n }\n }\n\n /**\n * Build a condition based on the operator.\n *\n * @param field - The field name\n * @param operator - The comparison operator\n * @param value - The value to compare\n * @returns The MongoDB filter condition\n */\n private buildOperatorCondition(field: string, operator: string, value: unknown): any {\n switch (operator) {\n case \"=\":\n return { [field]: value };\n case \"!=\":\n return { [field]: { $ne: value } };\n case \">\":\n return { [field]: { $gt: value } };\n case \">=\":\n return { [field]: { $gte: value } };\n case \"<\":\n return { [field]: { $lt: value } };\n case \"<=\":\n return { [field]: { $lte: value } };\n default:\n return { [field]: value };\n }\n }\n\n /**\n * Get MongoDB operator from comparison operator.\n *\n * @param operator - The comparison operator\n * @returns The MongoDB operator\n */\n private getMongoOperator(operator: string): string {\n const map: Record<string, string> = {\n \"=\": \"$eq\",\n \"!=\": \"$ne\",\n \">\": \"$gt\",\n \">=\": \"$gte\",\n \"<\": \"$lt\",\n \"<=\": \"$lte\",\n };\n return map[operator] || \"$eq\";\n }\n\n private resolveRawExpression(expression: RawExpression, bindings?: unknown[]): any {\n if (typeof expression === \"string\") {\n const bound = this.bindRawString(expression, bindings);\n return { $where: bound };\n }\n\n if (typeof expression === \"object\" && expression !== null) {\n return expression;\n }\n\n return null;\n }\n\n private bindRawString(expression: string, bindings?: unknown[]): string {\n if (!bindings || bindings.length === 0) {\n return expression;\n }\n\n let index = 0;\n return expression.replace(/\\?/g, () => {\n const value = bindings[index++];\n return value === undefined ? \"?\" : JSON.stringify(value);\n });\n }\n\n private buildColumnComparison(first: string, operator: WhereOperator, second: string): any {\n const mongoOperator = this.getMongoOperator(operator);\n return {\n $expr: {\n [mongoOperator]: [this.wrapColumn(first), this.wrapColumn(second)],\n },\n };\n }\n\n private buildBetweenColumnsCondition(field: string, lower: string, upper: string): any {\n return {\n $expr: {\n $and: [\n { $gte: [this.wrapColumn(field), this.wrapColumn(lower)] },\n { $lte: [this.wrapColumn(field), this.wrapColumn(upper)] },\n ],\n },\n };\n }\n\n private wrapColumn(column: string): string {\n return column.startsWith(\"$\") ? column : `$${column}`;\n }\n\n private buildDateEqualityCondition(field: string, value: Date | string): any {\n const target = this.normalizeDateInput(value);\n const start = this.startOfDay(target);\n const end = this.endOfDay(target);\n return { [field]: { $gte: start, $lte: end } };\n }\n\n private buildDateBeforeCondition(field: string, value: Date | string): any {\n const target = this.startOfDay(this.normalizeDateInput(value));\n return { [field]: { $lt: target } };\n }\n\n private buildDateAfterCondition(field: string, value: Date | string): any {\n const target = this.endOfDay(this.normalizeDateInput(value));\n return { [field]: { $gt: target } };\n }\n\n private buildTimeCondition(field: string, value: string): any {\n return {\n $expr: {\n $eq: [\n {\n $dateToString: {\n format: \"%H:%M\",\n date: `$${field}`,\n },\n },\n value,\n ],\n },\n };\n }\n\n private buildDatePartCondition(\n field: string,\n operator: \"$dayOfMonth\" | \"$month\" | \"$year\",\n value: number,\n ): any {\n return {\n $expr: {\n $eq: [\n {\n [operator]: `$${field}`,\n },\n value,\n ],\n },\n };\n }\n\n private buildJsonContainsCondition(path: string, value: unknown): any {\n const fieldPath = this.normalizePath(path);\n if (Array.isArray(value)) {\n return { [fieldPath]: { $all: value } };\n }\n return { [fieldPath]: value };\n }\n\n private buildJsonDoesntContainCondition(path: string, value: unknown): any {\n const fieldPath = this.normalizePath(path);\n const values = Array.isArray(value) ? value : [value];\n return { [fieldPath]: { $nin: values } };\n }\n\n private buildJsonContainsKeyCondition(path: string): any {\n return {\n [this.normalizePath(path)]: { $exists: true },\n };\n }\n\n private buildJsonLengthCondition(path: string, operator: WhereOperator, value: number): any {\n const mongoOperator = this.getMongoOperator(operator);\n return {\n $expr: {\n [mongoOperator]: [{ $size: { $ifNull: [`$${this.normalizePath(path)}`, []] } }, value],\n },\n };\n }\n\n private buildJsonTypeCondition(path: string, type: string): any {\n return {\n $expr: {\n $eq: [{ $type: `$${this.normalizePath(path)}` }, type],\n },\n };\n }\n\n private buildArrayLengthCondition(field: string, operator: WhereOperator, value: number): any {\n const mongoOperator = this.getMongoOperator(operator);\n return {\n $expr: {\n [mongoOperator]: [{ $size: { $ifNull: [`$${field}`, []] } }, value],\n },\n };\n }\n\n private normalizeDateInput(value: Date | string): Date {\n if (value instanceof Date) {\n return value;\n }\n const parsed = new Date(value);\n if (Number.isNaN(parsed.getTime())) {\n throw new Error(`Invalid date value: ${value}`);\n }\n return parsed;\n }\n\n private startOfDay(date: Date): Date {\n const copy = new Date(date);\n copy.setHours(0, 0, 0, 0);\n return copy;\n }\n\n private endOfDay(date: Date): Date {\n const copy = new Date(date);\n copy.setHours(23, 59, 59, 999);\n return copy;\n }\n\n private normalizePath(path: string): string {\n return path.replace(/->/g, \".\");\n }\n\n private applyProjectionFields(\n projection: Record<string, unknown>,\n fields: string[],\n value: 0 | 1,\n ): void {\n for (const field of fields) {\n projection[field] = value;\n }\n }\n\n /**\n * Apply projection object with aliases and inclusion/exclusion.\n * @param projection - The projection object to modify\n * @param projectionObj - The projection specification\n */\n private applyProjectionObject(\n projection: Record<string, unknown>,\n projectionObj: Record<string, unknown>,\n ): void {\n for (const [field, value] of Object.entries(projectionObj)) {\n // Handle boolean values (true = 1, false = 0)\n if (typeof value === \"boolean\") {\n projection[field] = value ? 1 : 0;\n continue;\n }\n\n // Handle numeric values (0 or 1)\n if (typeof value === \"number\") {\n projection[field] = value;\n continue;\n }\n\n // Handle string values (aliases)\n if (typeof value === \"string\") {\n // Alias: project the field with a new name\n projection[value] = `$${field}`;\n continue;\n }\n\n // Handle complex expressions (objects)\n if (typeof value === \"object\" && value !== null) {\n projection[field] = value;\n continue;\n }\n\n // Default: include the field\n projection[field] = 1;\n }\n }\n\n private applyRawProjection(\n projection: Record<string, unknown>,\n expression: RawExpression,\n bindings?: unknown[],\n ): void {\n const resolved = this.resolveProjectionExpression(expression, bindings);\n if (!resolved) {\n return;\n }\n\n if (typeof resolved === \"object\" && resolved !== null && !Array.isArray(resolved)) {\n Object.assign(projection, resolved as Record<string, unknown>);\n }\n }\n\n private resolveProjectionExpression(\n expression: RawExpression | unknown,\n bindings?: unknown[],\n ): any {\n if (typeof expression === \"string\") {\n const source =\n bindings && expression.includes(\"?\")\n ? this.bindRawString(expression, bindings)\n : expression;\n if (source.startsWith(\":\")) {\n return source.slice(1);\n }\n return this.normalizeFieldReference(source);\n }\n\n if (typeof expression === \"object\" && expression !== null && !(expression instanceof Date)) {\n return expression;\n }\n\n if (typeof expression === \"number\" || typeof expression === \"boolean\") {\n return expression;\n }\n\n return expression;\n }\n\n private normalizeFieldReference(value: string | RawExpression): any {\n if (typeof value === \"string\") {\n if (value.startsWith(\":\")) {\n return value.slice(1);\n }\n // If already a field reference, return as-is\n if (value.startsWith(\"$\")) {\n return value;\n }\n // Check if it's a string literal (contains spaces or special chars)\n // Field paths are typically: alphanumeric, underscore, dot only\n if (!/^[a-zA-Z0-9_.]+$/.test(value)) {\n return value; // Return as literal\n }\n // Otherwise, treat as field reference\n return `$${value}`;\n }\n return value;\n }\n\n private buildAggregateProjection(field: string, aggregate: string): any {\n if (aggregate === \"count\") {\n return this.buildArraySizeExpression(field);\n }\n\n const map: Record<string, string> = {\n sum: \"$sum\",\n avg: \"$avg\",\n min: \"$min\",\n max: \"$max\",\n first: \"$first\",\n last: \"$last\",\n };\n\n const operator = map[aggregate];\n if (!operator) {\n return null;\n }\n\n return {\n [operator]: this.normalizeFieldReference(field),\n };\n }\n\n private buildExistsProjection(field: string): any {\n return {\n $ne: [{ $type: `$${field}` }, \"missing\"],\n };\n }\n\n private buildArraySizeExpression(field: string): any {\n return {\n $size: { $ifNull: [`$${field}`, []] },\n };\n }\n\n private buildCaseExpression(\n cases: Array<{ when: RawExpression; then: RawExpression | unknown }>,\n otherwise: RawExpression | unknown,\n ): any {\n return {\n $switch: {\n branches: cases.map((item) => ({\n case: this.resolveProjectionExpression(item.when),\n then: this.resolveLiteralOrExpression(item.then),\n })),\n default: this.resolveLiteralOrExpression(otherwise),\n },\n };\n }\n\n private buildCondExpression(\n condition: RawExpression,\n thenValue: RawExpression | unknown,\n elseValue: RawExpression | unknown,\n ): any {\n return {\n $cond: [\n this.resolveProjectionExpression(condition),\n this.resolveLiteralOrExpression(thenValue),\n this.resolveLiteralOrExpression(elseValue),\n ],\n };\n }\n\n /**\n * Resolve a value as a literal (if it's a plain string) or as an expression.\n * Used for `then`/`default` values in CASE/WHEN expressions.\n */\n private resolveLiteralOrExpression(value: RawExpression | unknown): any {\n // If it's a string that starts with $, treat as field reference\n if (typeof value === \"string\" && value.startsWith(\"$\")) {\n return value;\n }\n // If it's a plain string (not starting with $), treat as literal\n if (typeof value === \"string\") {\n return value;\n }\n // For objects (expressions), numbers, booleans, etc., use normal resolution\n return this.resolveProjectionExpression(value);\n }\n\n private inferJsonAlias(path: string): string {\n const normalized = this.normalizePath(path);\n const segments = normalized.split(\".\");\n return segments[segments.length - 1];\n }\n\n private buildConcatExpression(values: Array<string | RawExpression>): any {\n return {\n $concat: values.map((value) => this.normalizeFieldReference(value)),\n };\n }\n\n private buildCoalesceExpression(values: Array<string | RawExpression>): any {\n if (values.length === 0) {\n return null;\n }\n\n let expression = this.normalizeFieldReference(values[values.length - 1]);\n\n for (let index = values.length - 2; index >= 0; index--) {\n expression = {\n $ifNull: [this.normalizeFieldReference(values[index]), expression],\n };\n }\n\n return expression;\n }\n\n /**\n * Build a $project stage from select operations.\n *\n * @param operations - The select operations\n * @returns The $project stage or null\n */\n private buildProjectStage(operations: Operation[]): any {\n if (operations.length === 0) {\n return null;\n }\n\n const projection: Record<string, unknown> = {};\n const driverCallbacks: Array<(projection: Record<string, unknown>) => void> = [];\n\n for (const op of operations) {\n switch (op.type) {\n case \"select\":\n // Handle new projection format with aliases\n if (op.data.projection) {\n this.applyProjectionObject(projection, op.data.projection);\n } else if (op.data.fields) {\n this.applyProjectionFields(projection, op.data.fields, 1);\n }\n break;\n\n case \"deselect\":\n this.applyProjectionFields(projection, op.data.fields, 0);\n break;\n\n case \"addSelect\":\n this.applyProjectionFields(projection, op.data.fields, 1);\n break;\n\n case \"selectRaw\":\n this.applyRawProjection(projection, op.data.expression, op.data.bindings);\n break;\n\n case \"selectSub\":\n case \"addSelectSub\": {\n const expr = this.resolveProjectionExpression(op.data.expression, op.data.bindings);\n if (expr !== undefined) {\n projection[op.data.alias] = expr;\n }\n break;\n }\n\n case \"selectAggregate\":\n projection[op.data.alias] = this.buildAggregateProjection(\n op.data.field,\n op.data.aggregate,\n );\n break;\n\n case \"selectExists\":\n projection[op.data.alias] = this.buildExistsProjection(op.data.field);\n break;\n\n case \"selectCount\":\n projection[op.data.alias] = this.buildArraySizeExpression(op.data.field);\n break;\n\n case \"selectCase\":\n projection[op.data.alias] = this.buildCaseExpression(\n op.data.cases,\n op.data.otherwise,\n );\n break;\n\n case \"selectWhen\":\n projection[op.data.alias] = this.buildCondExpression(\n op.data.condition,\n op.data.thenValue,\n op.data.elseValue,\n );\n break;\n\n case \"selectDriverProjection\":\n driverCallbacks.push(op.data.callback);\n break;\n\n case \"selectJson\": {\n const alias = op.data.alias ?? this.inferJsonAlias(op.data.path);\n projection[alias] = this.normalizeFieldReference(\n `$${this.normalizePath(op.data.path)}`,\n );\n break;\n }\n\n case \"selectJsonRaw\": {\n projection[op.data.alias] = this.resolveProjectionExpression(op.data.expression);\n break;\n }\n\n case \"deselectJson\":\n projection[this.normalizePath(op.data.path)] = 0;\n break;\n\n case \"selectConcat\":\n projection[op.data.alias] = this.buildConcatExpression(op.data.fields);\n break;\n\n case \"selectCoalesce\":\n projection[op.data.alias] = this.buildCoalesceExpression(op.data.fields);\n break;\n\n default:\n break;\n }\n }\n\n for (const callback of driverCallbacks) {\n callback(projection);\n }\n\n return Object.keys(projection).length > 0 ? { $project: projection } : null;\n }\n\n /**\n * Build a $sort stage from order operations.\n *\n * @param operations - The order operations\n * @returns The $sort stage or null\n */\n private buildSortStage(operations: Operation[]): any {\n const sort: any = {};\n\n for (const op of operations) {\n switch (op.type) {\n case \"orderBy\":\n sort[op.data.field] = op.data.direction === \"asc\" ? 1 : -1;\n break;\n\n case \"orderByRandom\":\n return { $sample: { size: op.data.limit } };\n\n case \"orderByRaw\":\n // TODO: Handle raw expressions\n break;\n }\n }\n\n return Object.keys(sort).length > 0 ? { $sort: sort } : null;\n }\n\n /**\n * Build a $group stage from group operations.\n *\n * @param operations - The group operations\n * @returns The $group stage or null\n */\n private buildGroupStage(operations: Operation[]): any {\n const op = operations[0];\n\n switch (op.type) {\n case \"groupBy\": {\n const stage = this.buildGroupByStage(op.data.fields);\n if (stage) {\n return stage;\n }\n break;\n }\n case \"groupByWithAggregates\": {\n const stage = this.buildGroupByWithAggregatesStage(\n op.data.fields,\n op.data.aggregates,\n );\n if (stage) {\n return stage;\n }\n break;\n }\n case \"groupByRaw\": {\n const expression = op.data.expression;\n if (expression && typeof expression === \"object\") {\n return { $group: expression };\n }\n // If expression is not an object, it might be a string or other type\n // In that case, we should still return it as a $group stage\n if (expression) {\n return { $group: { _id: expression } };\n }\n break;\n }\n case \"distinct\": {\n const stage = this.buildGroupByStage(op.data.fields);\n if (stage) {\n return stage;\n }\n break;\n }\n default:\n break;\n }\n\n return null;\n }\n\n private buildGroupByStage(fields: GroupByInput): any {\n const groupId = this.buildGroupId(fields);\n if (!groupId) {\n return null;\n }\n\n return { $group: { _id: groupId } };\n }\n\n /**\n * Build a $group stage with aggregates from group operations.\n *\n * @param fields - Fields to group by\n * @param aggregates - Aggregate operations (abstract or raw)\n * @returns The $group stage or null\n */\n private buildGroupByWithAggregatesStage(\n fields: GroupByInput,\n aggregates: Record<string, RawExpression>,\n ): any {\n const groupId = this.buildGroupId(fields);\n if (!groupId) {\n return null;\n }\n\n const groupStage: Record<string, unknown> = {\n _id: groupId,\n };\n\n // Translate each aggregate expression\n for (const [alias, expression] of Object.entries(aggregates)) {\n if (isAggregateExpression(expression)) {\n // Translate abstract expression to MongoDB format\n groupStage[alias] = this.translateAggregateExpression(expression);\n } else {\n // Use raw expression as-is (already in MongoDB format)\n groupStage[alias] = expression;\n }\n }\n\n return { $group: groupStage };\n }\n\n /**\n * Extract field names from GroupByInput for renaming _id.\n *\n * @param fields - The grouping fields\n * @returns Field name(s) to use for renaming _id\n */\n private extractGroupFieldNames(fields: GroupByInput): string | string[] | null {\n if (typeof fields === \"string\") {\n return fields;\n }\n\n if (Array.isArray(fields)) {\n const allStrings = fields.every((field) => typeof field === \"string\");\n if (allStrings) {\n return fields as string[];\n }\n // For complex arrays, return null (don't rename)\n return null;\n }\n\n if (typeof fields === \"object\" && fields !== null) {\n // For object syntax, use the keys as field names\n return Object.keys(fields);\n }\n\n return null;\n }\n\n /**\n * Translate an abstract aggregate expression to MongoDB format.\n *\n * @param expr - Abstract aggregate expression\n * @returns MongoDB aggregation expression\n */\n private translateAggregateExpression(expr: AggregateExpression): Record<string, unknown> {\n switch (expr.__agg) {\n case \"count\":\n return { $sum: 1 };\n\n case \"sum\":\n if (!expr.__field) {\n throw new Error(\"Sum aggregate requires a field name\");\n }\n return { $sum: `$${expr.__field}` };\n\n case \"avg\":\n if (!expr.__field) {\n throw new Error(\"Average aggregate requires a field name\");\n }\n return { $avg: `$${expr.__field}` };\n\n case \"min\":\n if (!expr.__field) {\n throw new Error(\"Min aggregate requires a field name\");\n }\n return { $min: `$${expr.__field}` };\n\n case \"max\":\n if (!expr.__field) {\n throw new Error(\"Max aggregate requires a field name\");\n }\n return { $max: `$${expr.__field}` };\n\n case \"first\":\n if (!expr.__field) {\n throw new Error(\"First aggregate requires a field name\");\n }\n return { $first: `$${expr.__field}` };\n\n case \"last\":\n if (!expr.__field) {\n throw new Error(\"Last aggregate requires a field name\");\n }\n return { $last: `$${expr.__field}` };\n\n case \"distinct\":\n if (!expr.__field) {\n throw new Error(\"Distinct aggregate requires a field name\");\n }\n return { $distinct: `$${expr.__field}` };\n\n case \"floor\":\n if (!expr.__field) {\n throw new Error(\"Floor aggregate requires a field name\");\n }\n\n return { $floor: `$${expr.__field}` };\n\n default:\n throw new Error(`Unknown aggregate function: ${expr.__agg}`);\n }\n }\n\n private buildGroupId(fields: GroupByInput): any {\n if (!fields) {\n return null;\n }\n\n if (typeof fields === \"string\") {\n return `$${fields}`;\n }\n\n if (Array.isArray(fields)) {\n if (fields.length === 0) {\n return null;\n }\n\n const allStrings = fields.every((field) => typeof field === \"string\");\n if (allStrings) {\n const result: Record<string, string> = {};\n for (const field of fields as string[]) {\n result[field] = `$${field}`;\n }\n return result;\n }\n\n // Array of objects - merge them to build complex _id structures\n return (fields as Record<string, unknown>[]).reduce((acc, item) => ({ ...acc, ...item }), {});\n }\n\n if (typeof fields === \"object\") {\n const normalized: Record<string, unknown> = {};\n Object.entries(fields).forEach(([key, value]) => {\n if (typeof value === \"string\" && !value.startsWith(\"$\")) {\n normalized[key] = `$${value}`;\n } else {\n normalized[key] = value;\n }\n });\n return normalized;\n }\n\n return null;\n }\n\n /**\n * Build a $lookup stage from join operations.\n *\n * @param operations - The join operations\n * @returns The $lookup stage or null\n */\n private buildLookupStage(operations: Operation[]): any {\n const op = operations[0];\n const options = op.data;\n\n return {\n $lookup: {\n from: options.table,\n localField: options.localField,\n foreignField: options.foreignField,\n as: options.alias || options.table,\n },\n };\n }\n}\n","/* eslint-disable no-case-declarations */\r\nimport { GenericObject, get } from \"@mongez/reinforcements\";\r\nimport type { AggregateOptions, ClientSession, Collection } from \"mongodb\";\r\nimport { databaseTransactionContext } from \"../../context/database-transaction-context\";\r\nimport type {\r\n CursorPaginationOptions,\r\n CursorPaginationResult,\r\n DriverQuery,\r\n GroupByInput,\r\n HavingInput,\r\n JoinOptions,\r\n OrderDirection,\r\n PaginationOptions,\r\n PaginationResult,\r\n QueryBuilderContract,\r\n RawExpression,\r\n WhereCallback,\r\n WhereObject,\r\n WhereOperator,\r\n} from \"../../contracts\";\r\nimport { type DataSource } from \"../../data-source/data-source\";\r\nimport { dataSourceRegistry } from \"../../data-source/data-source-registry\";\r\nimport { QueryBuilder } from \"../../query-builder/query-builder\";\r\nimport { type MongoDbDriver } from \"./mongodb-driver\";\r\nimport { MongoQueryOperations } from \"./mongodb-query-operations\";\r\nimport { MongoQueryParser } from \"./mongodb-query-parser\";\r\nimport type { Operation } from \"./types\";\r\n\r\n/**\r\n * MongoDB-specific query builder implementation using aggregation pipeline.\r\n */\r\nexport class MongoQueryBuilder<T = unknown>\r\n extends QueryBuilder<T>\r\n implements QueryBuilderContract<T>\r\n{\r\n /**\r\n * Ordered list of operations to be converted to MongoDB aggregation pipeline.\r\n * Public to allow parser access. Uses MongoDB's own Operation type.\r\n *\r\n * NOTE: This shadows the base `operations: Op[]` field intentionally — the Mongo\r\n * Operation type carries an extra `stage` discriminator used by the pipeline assembler.\r\n */\r\n public override operations: Operation[] = [];\r\n\r\n /**\r\n * Data source instance\r\n */\r\n public readonly dataSource: DataSource;\r\n\r\n /**\r\n * Lazy-loaded operations helper for constructing pipeline operations.\r\n */\r\n protected _operationsHelper?: MongoQueryOperations;\r\n\r\n public hydrateCallback?: (data: any, index: number) => any;\r\n\r\n private fetchingCallback?: (query: this) => void | Promise<void>;\r\n private hydratingCallback?: (records: any[], context: any) => void | Promise<void>;\r\n private fetchedCallback?: (records: any[], context: any) => void | Promise<void>;\r\n\r\n // scopesApplied, pendingGlobalScopes, availableLocalScopes, disabledGlobalScopes\r\n // are inherited from QueryBuilder base class.\r\n\r\n /**\r\n * Create a new query builder for the given collection.\r\n * @param collection - The MongoDB collection to query\r\n */\r\n public constructor(\r\n public readonly table: string,\r\n dataSource?: DataSource,\r\n ) {\r\n super();\r\n this.dataSource = dataSource || dataSourceRegistry.get()!;\r\n // TODO: Trigger the fetching event\r\n }\r\n\r\n /**\r\n * Gets the operations helper instance, creating it if needed.\r\n * @returns The operations helper instance\r\n */\r\n protected get operationsHelper(): MongoQueryOperations {\r\n if (!this._operationsHelper) {\r\n this._operationsHelper = new MongoQueryOperations(this.operations);\r\n }\r\n return this._operationsHelper;\r\n }\r\n\r\n /**\r\n * Get collection instance\r\n */\r\n public get collection(): Collection {\r\n const driver = this.dataSource.driver as MongoDbDriver;\r\n\r\n return driver.database!.collection(this.table);\r\n }\r\n\r\n /**\r\n * Add hydrate callback function\r\n */\r\n public hydrate(callback: (data: any, index: number) => any): this {\r\n this.hydrateCallback = callback;\r\n return this;\r\n }\r\n\r\n /**\r\n * Register a callback to be invoked before query execution\r\n * @returns Unsubscribe function to remove the callback\r\n */\r\n public onFetching(callback: (query: this) => void | Promise<void>): () => void {\r\n this.fetchingCallback = callback;\r\n return () => {\r\n this.fetchingCallback = undefined;\r\n };\r\n }\r\n\r\n /**\r\n * Register a callback to be invoked after records are fetched but before hydration\r\n * @returns Unsubscribe function to remove the callback\r\n */\r\n public onHydrating(callback: (records: any[], context: any) => void | Promise<void>): () => void {\r\n this.hydratingCallback = callback;\r\n return () => {\r\n this.hydratingCallback = undefined;\r\n };\r\n }\r\n\r\n /**\r\n * Register a callback to be invoked after records are fetched and hydrated\r\n * @returns Unsubscribe function to remove the callback\r\n */\r\n public onFetched(callback: (records: any[], context: any) => void | Promise<void>): () => void {\r\n this.fetchedCallback = callback;\r\n return () => {\r\n this.fetchedCallback = undefined;\r\n };\r\n }\r\n\r\n /**\r\n * Disable one or more global scopes for this query\r\n */\r\n public withoutGlobalScope(...scopeNames: string[]): this {\r\n scopeNames.forEach((name) => this.disabledGlobalScopes.add(name));\r\n return this;\r\n }\r\n\r\n /**\r\n * Disable all global scopes for this query\r\n */\r\n public withoutGlobalScopes(): this {\r\n if (this.pendingGlobalScopes) {\r\n this.pendingGlobalScopes.forEach((_, name) => {\r\n this.disabledGlobalScopes.add(name);\r\n });\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Apply a local scope to this query\r\n */\r\n public scope(scopeName: string, ...args: any[]): this {\r\n if (!this.availableLocalScopes) {\r\n throw new Error(`No local scopes available`);\r\n }\r\n\r\n const scopeCallback = this.availableLocalScopes.get(scopeName);\r\n if (!scopeCallback) {\r\n throw new Error(`Local scope \"${scopeName}\" not found`);\r\n }\r\n\r\n // Apply scope immediately (not deferred)\r\n scopeCallback(this, ...args);\r\n return this;\r\n }\r\n\r\n /**\r\n * Apply pending global scopes before query execution\r\n */\r\n private applyPendingScopes(): void {\r\n if (!this.pendingGlobalScopes || this.scopesApplied) {\r\n return;\r\n }\r\n\r\n const beforeOps: any[] = [];\r\n const afterOps: any[] = [];\r\n\r\n for (const [name, { callback, timing }] of this.pendingGlobalScopes) {\r\n // Skip disabled scopes\r\n if (this.disabledGlobalScopes.has(name)) {\r\n continue;\r\n }\r\n\r\n // Create temporary query builder to capture operations\r\n const tempBuilder = new MongoQueryBuilder(this.table, this.dataSource);\r\n callback(tempBuilder);\r\n\r\n // Collect operations based on timing\r\n if (timing === \"before\") {\r\n beforeOps.push(...tempBuilder.operations);\r\n } else {\r\n afterOps.push(...tempBuilder.operations);\r\n }\r\n }\r\n\r\n // Apply: before scopes + user operations + after scopes\r\n this.operations = [...beforeOps, ...this.operations, ...afterOps];\r\n this.scopesApplied = true;\r\n }\r\n\r\n // ============================================================================\r\n // WHERE CLAUSES - BASIC\r\n // ============================================================================\r\n\r\n /**\r\n * Adds a WHERE clause to filter documents. Supports equality, operators, objects, or callbacks.\r\n * @param field - Field name, or conditions object, or callback\r\n * @param operator - Comparison operator\r\n * @param value - Value to compare\r\n */\r\n public where(field: string, value: unknown): this;\r\n public where(field: string, operator: WhereOperator, value: unknown): this;\r\n public where(conditions: WhereObject): this;\r\n public where(callback: WhereCallback<T>): this;\r\n public where(...args: any[]): this {\r\n this.addWhereClause(\"where\", args);\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds an OR WHERE clause. Works like where() but uses OR logic.\r\n * @param field - Field name, or conditions object, or callback\r\n * @param operator - Comparison operator\r\n * @param value - Value to compare\r\n */\r\n public orWhere(field: string, value: unknown): this;\r\n public orWhere(field: string, operator: WhereOperator, value: unknown): this;\r\n public orWhere(conditions: WhereObject): this;\r\n public orWhere(callback: WhereCallback<T>): this;\r\n public orWhere(...args: any[]): this {\r\n this.addWhereClause(\"orWhere\", args);\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a raw WHERE clause using MongoDB's native query syntax.\r\n * @param expression - Raw MongoDB expression\r\n * @param bindings - Optional parameter bindings for string expressions\r\n */\r\n public whereRaw(expression: RawExpression, bindings?: unknown[]): this {\r\n return this.addRawWhere(\"whereRaw\", expression, bindings);\r\n }\r\n\r\n /**\r\n * Adds a raw OR WHERE clause using MongoDB's native query syntax.\r\n * @param expression - Raw MongoDB expression\r\n * @param bindings - Optional parameter bindings\r\n */\r\n public orWhereRaw(expression: RawExpression, bindings?: unknown[]): this {\r\n return this.addRawWhere(\"orWhereRaw\", expression, bindings);\r\n }\r\n\r\n // ============================================================================\r\n // WHERE CLAUSES - COLUMN COMPARISONS\r\n // ============================================================================\r\n\r\n /**\r\n * Adds a WHERE clause comparing two columns/fields directly.\r\n * @param first - The first field name\r\n * @param operator - The comparison operator\r\n * @param second - The second field name\r\n */\r\n public whereColumn(first: string, operator: WhereOperator, second: string): this {\r\n this.operationsHelper.addMatchOperation(\"whereColumn\", {\r\n first,\r\n operator,\r\n second,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds an OR WHERE clause comparing two columns/fields directly.\r\n * @param first - The first field name\r\n * @param operator - The comparison operator\r\n * @param second - The second field name\r\n */\r\n public orWhereColumn(first: string, operator: WhereOperator, second: string): this {\r\n this.operationsHelper.addMatchOperation(\"orWhereColumn\", {\r\n first,\r\n operator,\r\n second,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds multiple column comparison clauses at once.\r\n * @param comparisons - Array of tuples [leftField, operator, rightField]\r\n */\r\n public whereColumns(\r\n comparisons: Array<[left: string, operator: WhereOperator, right: string]>,\r\n ): this {\r\n for (const [left, operator, right] of comparisons) {\r\n this.whereColumn(left, operator, right);\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a field's value falls between two other fields.\r\n * @param field - The field to check\r\n * @param lowerColumn - The field defining the lower bound\r\n * @param upperColumn - The field defining the upper bound\r\n */\r\n public whereBetweenColumns(field: string, lowerColumn: string, upperColumn: string): this {\r\n this.operationsHelper.addMatchOperation(\"whereBetweenColumns\", {\r\n field,\r\n lowerColumn,\r\n upperColumn,\r\n });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // WHERE CLAUSES - DATE OPERATIONS\r\n // ============================================================================\r\n\r\n /**\r\n * Filters documents where a date field matches the given date (ignoring time).\r\n * @param field - The date field name\r\n * @param value - The date to match\r\n */\r\n public whereDate(field: string, value: Date | string): this {\r\n this.operationsHelper.addMatchOperation(\"whereDate\", { field, value });\r\n return this;\r\n }\r\n\r\n /**\r\n * Alias for `whereDate()`. Filters by exact date match (ignoring time).\r\n * @param field - The date field name\r\n * @param value - The date to match\r\n */\r\n public whereDateEquals(field: string, value: Date | string): this {\r\n this.operationsHelper.addMatchOperation(\"whereDateEquals\", {\r\n field,\r\n value,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a date field is before the given date.\r\n * @param field - The date field name\r\n * @param value - The cutoff date\r\n */\r\n public whereDateBefore(field: string, value: Date | string): this {\r\n this.operationsHelper.addMatchOperation(\"whereDateBefore\", {\r\n field,\r\n value,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a date field is after the given date.\r\n * @param field - The date field name\r\n * @param value - The cutoff date\r\n */\r\n public whereDateAfter(field: string, value: Date | string): this {\r\n this.operationsHelper.addMatchOperation(\"whereDateAfter\", { field, value });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a time field matches the given time (HH:MM:SS format).\r\n * @param field - The time/datetime field name\r\n * @param value - The time string in HH:MM:SS format\r\n */\r\n public whereTime(field: string, value: string): this {\r\n this.operationsHelper.addMatchOperation(\"whereTime\", { field, value });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where the day of the month matches the given value (1-31).\r\n * @param field - The date field name\r\n * @param value - The day of the month\r\n */\r\n public whereDay(field: string, value: number): this {\r\n this.operationsHelper.addMatchOperation(\"whereDay\", { field, value });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where the month matches the given value (1-12).\r\n * @param field - The date field name\r\n * @param value - The month number\r\n */\r\n public whereMonth(field: string, value: number): this {\r\n this.operationsHelper.addMatchOperation(\"whereMonth\", { field, value });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where the year matches the given value.\r\n * @param field - The date field name\r\n * @param value - The year\r\n */\r\n public whereYear(field: string, value: number): this {\r\n this.operationsHelper.addMatchOperation(\"whereYear\", { field, value });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // WHERE CLAUSES - JSON OPERATIONS\r\n // ============================================================================\r\n\r\n /**\r\n * Filters documents where a JSON field contains the specified value.\r\n * @param path - The JSON path to check\r\n * @param value - The value to search for\r\n */\r\n public whereJsonContains(path: string, value: unknown): this {\r\n this.operationsHelper.addMatchOperation(\"whereJsonContains\", {\r\n path,\r\n value,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a JSON field does NOT contain the specified value.\r\n * @param path - The JSON path to check\r\n * @param value - The value to exclude\r\n */\r\n public whereJsonDoesntContain(path: string, value: unknown): this {\r\n this.operationsHelper.addMatchOperation(\"whereJsonDoesntContain\", {\r\n path,\r\n value,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a JSON field contains a specific key.\r\n * @param path - The JSON path to check for key existence\r\n */\r\n public whereJsonContainsKey(path: string): this {\r\n this.operationsHelper.addMatchOperation(\"whereJsonContainsKey\", { path });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a JSON array or string has a specific length.\r\n * @param path - The JSON path to check\r\n * @param operator - The comparison operator\r\n * @param value - The length value to compare against\r\n */\r\n public whereJsonLength(path: string, operator: WhereOperator, value: number): this {\r\n this.operationsHelper.addMatchOperation(\"whereJsonLength\", {\r\n path,\r\n operator,\r\n value,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a JSON field is an array.\r\n * @param path - The JSON path to check\r\n */\r\n public whereJsonIsArray(path: string): this {\r\n this.operationsHelper.addMatchOperation(\"whereJsonIsArray\", { path });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a JSON field is an object.\r\n * @param path - The JSON path to check\r\n */\r\n public whereJsonIsObject(path: string): this {\r\n this.operationsHelper.addMatchOperation(\"whereJsonIsObject\", { path });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where an array field has a specific length.\r\n * @param field - The array field name\r\n * @param operator - The comparison operator\r\n * @param value - The length value to compare against\r\n */\r\n public whereArrayLength(field: string, operator: WhereOperator, value: number): this {\r\n this.operationsHelper.addMatchOperation(\"whereArrayLength\", {\r\n field,\r\n operator,\r\n value,\r\n });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // WHERE CLAUSES - CONVENIENCE METHODS\r\n // ============================================================================\r\n\r\n /**\r\n * Filters documents by ID (convenience method for `where(\"id\", value)`).\r\n * @param value - The ID value to match\r\n */\r\n public whereId(value: string | number): this {\r\n return this.where(\"id\", value);\r\n }\r\n\r\n /**\r\n * Filters documents by multiple IDs (convenience method for `whereIn(\"id\", values)`).\r\n * @param values - Array of ID values to match\r\n */\r\n public whereIds(values: Array<string | number>): this {\r\n return this.whereIn(\"id\", values);\r\n }\r\n\r\n /**\r\n * Filters documents by UUID (convenience method for `where(\"uuid\", value)`).\r\n * @param value - The UUID string to match\r\n */\r\n public whereUuid(value: string): this {\r\n return this.where(\"uuid\", value);\r\n }\r\n\r\n /**\r\n * Filters documents by ULID (convenience method for `where(\"ulid\", value)`).\r\n * @param value - The ULID string to match\r\n */\r\n public whereUlid(value: string): this {\r\n return this.where(\"ulid\", value);\r\n }\r\n\r\n /**\r\n * Performs full-text search on one or more fields.\r\n * @param fields - Field name or array of field names to search\r\n * @param query - The search query string\r\n */\r\n public whereFullText(fields: string | string[], query: string): this {\r\n const filters = typeof fields === \"string\" ? { fields: [fields] } : { fields: fields ?? [] };\r\n this.operationsHelper.addMatchOperation(\"whereFullText\", {\r\n fields: filters.fields,\r\n query,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Performs full-text search with OR logic.\r\n * @param fields - Field name or array of field names to search\r\n * @param query - The search query string\r\n */\r\n public orWhereFullText(fields: string | string[], query: string): this {\r\n const filters = typeof fields === \"string\" ? { fields: [fields] } : { fields: fields ?? [] };\r\n this.operationsHelper.addMatchOperation(\"orWhereFullText\", {\r\n fields: filters.fields,\r\n query,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Alias for `whereFullText()` with a single field.\r\n * @param field - The field name to search\r\n * @param query - The search query string\r\n */\r\n public whereSearch(field: string, query: string): this {\r\n return this.whereFullText(field, query);\r\n }\r\n\r\n /**\r\n * Negates a set of conditions using a callback.\r\n * @param callback - Callback function defining conditions to negate\r\n */\r\n public whereNot(callback: WhereCallback<T>): this {\r\n this.operationsHelper.addMatchOperation(\"where:not\", { callback });\r\n return this;\r\n }\r\n\r\n /**\r\n * Negates a set of conditions with OR logic.\r\n * @param callback - Callback function defining conditions to negate\r\n */\r\n public orWhereNot(callback: WhereCallback<T>): this {\r\n this.operationsHelper.addMatchOperation(\"orWhere:not\", { callback });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // WHERE CLAUSES - COMPARISON OPERATORS\r\n // ============================================================================\r\n\r\n /**\r\n * Filters documents where a field's value matches any value in the given array.\r\n * @param field - The field name to check\r\n * @param values - Array of values to match against\r\n */\r\n public whereIn(field: string, values: unknown[]): this {\r\n this.operationsHelper.addMatchOperation(\"whereIn\", { field, values });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a field's value does NOT match any value in the array.\r\n * @param field - The field name to check\r\n * @param values - Array of values to exclude\r\n */\r\n public whereNotIn(field: string, values: unknown[]): this {\r\n this.operationsHelper.addMatchOperation(\"whereNotIn\", { field, values });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a field's value is null or undefined.\r\n * @param field - The field name to check\r\n */\r\n public whereNull(field: string): this {\r\n this.operationsHelper.addMatchOperation(\"whereNull\", { field });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a field's value is NOT null or undefined.\r\n * @param field - The field name to check\r\n */\r\n public whereNotNull(field: string): this {\r\n this.operationsHelper.addMatchOperation(\"whereNotNull\", { field });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a field's value falls within the given range (inclusive).\r\n * @param field - The field name to check\r\n * @param range - Tuple of [min, max] values\r\n */\r\n public whereBetween(field: string, range: [unknown, unknown]): this {\r\n this.operationsHelper.addMatchOperation(\"whereBetween\", { field, range });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a field's value is NOT within the given range.\r\n * @param field - The field name to check\r\n * @param range - Tuple of [min, max] values to exclude\r\n */\r\n public whereNotBetween(field: string, range: [unknown, unknown]): this {\r\n this.operationsHelper.addMatchOperation(\"whereNotBetween\", {\r\n field,\r\n range,\r\n });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // WHERE CLAUSES - PATTERN MATCHING\r\n // ============================================================================\r\n\r\n /**\r\n * Filters documents where a field matches the given pattern (case-insensitive).\r\n * @param field - The field name to search\r\n * @param pattern - The pattern to match\r\n */\r\n public whereLike(field: string, pattern: RegExp | string): this {\r\n this.operationsHelper.addMatchOperation(\"whereLike\", { field, pattern });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a field does NOT match the given pattern.\r\n * @param field - The field name to search\r\n * @param pattern - The pattern to exclude\r\n */\r\n public whereNotLike(field: string, pattern: RegExp | string): this {\r\n this.operationsHelper.addMatchOperation(\"whereNotLike\", { field, pattern });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a field's value starts with the given prefix.\r\n * @param field - The field name to check\r\n * @param value - The prefix to match\r\n */\r\n public whereStartsWith(field: string, value: string | number): this {\r\n this.operationsHelper.addMatchOperation(\"whereStartsWith\", {\r\n field,\r\n value,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a field's value does NOT start with the given prefix.\r\n * @param field - The field name to check\r\n * @param value - The prefix to exclude\r\n */\r\n public whereNotStartsWith(field: string, value: string | number): this {\r\n this.operationsHelper.addMatchOperation(\"whereNotStartsWith\", {\r\n field,\r\n value,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a field's value ends with the given suffix.\r\n * @param field - The field name to check\r\n * @param value - The suffix to match\r\n */\r\n public whereEndsWith(field: string, value: string | number): this {\r\n this.operationsHelper.addMatchOperation(\"whereEndsWith\", { field, value });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a field's value does NOT end with the given suffix.\r\n * @param field - The field name to check\r\n * @param value - The suffix to exclude\r\n */\r\n public whereNotEndsWith(field: string, value: string | number): this {\r\n this.operationsHelper.addMatchOperation(\"whereNotEndsWith\", {\r\n field,\r\n value,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a date field falls within the given date range.\r\n * @param field - The date field name\r\n * @param range - Tuple of [startDate, endDate]\r\n */\r\n public whereDateBetween(field: string, range: [Date, Date]): this {\r\n this.operationsHelper.addMatchOperation(\"whereDateBetween\", {\r\n field,\r\n range,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a date field is NOT within the given date range.\r\n * @param field - The date field name\r\n * @param range - Tuple of [startDate, endDate] to exclude\r\n */\r\n public whereDateNotBetween(field: string, range: [Date, Date]): this {\r\n this.operationsHelper.addMatchOperation(\"whereDateNotBetween\", {\r\n field,\r\n range,\r\n });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // WHERE CLAUSES - EXISTENCE CHECKS\r\n // ============================================================================\r\n\r\n /**\r\n * Filters documents where a field exists (has any value including null).\r\n * @param field - The field name to check for existence\r\n * @param callback - Optional callback for subquery existence\r\n */\r\n public whereExists(field: string): this;\r\n public whereExists(callback: WhereCallback<T>): this;\r\n public whereExists(param: string | WhereCallback<T>): this {\r\n if (typeof param === \"function\") {\r\n this.operationsHelper.addMatchOperation(\"where:exists\", {\r\n callback: param,\r\n });\r\n return this;\r\n }\r\n\r\n this.operationsHelper.addMatchOperation(\"whereExists\", { field: param });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where a field does NOT exist in the document.\r\n * @param field - The field name to check for absence\r\n * @param callback - Optional callback for subquery non-existence\r\n */\r\n public whereNotExists(field: string): this;\r\n public whereNotExists(callback: WhereCallback<T>): this;\r\n public whereNotExists(param: string | WhereCallback<T>): this {\r\n if (typeof param === \"function\") {\r\n this.operationsHelper.addMatchOperation(\"where:notExists\", {\r\n callback: param,\r\n });\r\n return this;\r\n }\r\n\r\n this.operationsHelper.addMatchOperation(\"whereNotExists\", {\r\n field: param,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where an array field has a specific size.\r\n * @param field - The array field name\r\n * @param size - The exact size to match\r\n * @param operator - Optional comparison operator\r\n */\r\n public whereSize(field: string, size: number): this;\r\n public whereSize(field: string, operator: \">\" | \">=\" | \"=\" | \"<\" | \"<=\", size: number): this;\r\n public whereSize(field: string, ...args: any[]): this {\r\n if (args.length === 1) {\r\n this.operationsHelper.addMatchOperation(\"whereSize\", {\r\n field,\r\n operator: \"=\",\r\n size: args[0],\r\n });\r\n } else {\r\n this.operationsHelper.addMatchOperation(\"whereSize\", {\r\n field,\r\n operator: args[0],\r\n size: args[1],\r\n });\r\n }\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // WHERE CLAUSES - FULL-TEXT SEARCH\r\n // ============================================================================\r\n\r\n /**\r\n * Performs a full-text search on the specified fields.\r\n * @param query - The search query string\r\n * @param filters - Optional additional filter conditions\r\n */\r\n public textSearch(query: string, filters?: WhereObject): this {\r\n this.operationsHelper.addMatchOperation(\"textSearch\", { query, filters });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // WHERE CLAUSES - ARRAY OPERATIONS\r\n // ============================================================================\r\n\r\n /**\r\n * Filters documents where an array field contains the given value.\r\n * @param field - The array field name\r\n * @param value - The value to search for in the array\r\n * @param key - Optional key to check within array objects\r\n */\r\n public whereArrayContains(field: string, value: unknown, key?: string): this {\r\n this.operationsHelper.addMatchOperation(\"whereArrayContains\", {\r\n field,\r\n value,\r\n key,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where an array field does NOT contain the given value.\r\n * @param field - The array field name\r\n * @param value - The value to exclude from the array\r\n * @param key - Optional key to check within array objects\r\n */\r\n public whereArrayNotContains(field: string, value: unknown, key?: string): this {\r\n this.operationsHelper.addMatchOperation(\"whereArrayNotContains\", {\r\n field,\r\n value,\r\n key,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where an array field contains the value OR is empty.\r\n * @param field - The array field name\r\n * @param value - The value to search for\r\n * @param key - Optional key to check within array objects\r\n */\r\n public whereArrayHasOrEmpty(field: string, value: unknown, key?: string): this {\r\n this.operationsHelper.addMatchOperation(\"whereArrayHasOrEmpty\", {\r\n field,\r\n value,\r\n key,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters documents where an array field does NOT contain the value AND is not empty.\r\n * @param field - The array field name\r\n * @param value - The value to exclude\r\n * @param key - Optional key to check within array objects\r\n */\r\n public whereArrayNotHaveOrEmpty(field: string, value: unknown, key?: string): this {\r\n this.operationsHelper.addMatchOperation(\"whereArrayNotHaveOrEmpty\", {\r\n field,\r\n value,\r\n key,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Internal helper for processing where clause arguments.\r\n * @param prefix - The operation prefix\r\n * @param args - The arguments passed to where/orWhere\r\n */\r\n protected addWhereClause(prefix: \"where\" | \"orWhere\", args: any[]): void {\r\n if (args.length === 1) {\r\n if (typeof args[0] === \"function\") {\r\n // Callback-based where\r\n this.operationsHelper.addMatchOperation(`${prefix}:callback`, args[0]);\r\n } else {\r\n // Object-based where\r\n this.operationsHelper.addMatchOperation(`${prefix}:object`, args[0]);\r\n }\r\n } else if (args.length === 2) {\r\n // Simple equality: where(field, value)\r\n this.operationsHelper.addMatchOperation(prefix, {\r\n field: args[0],\r\n operator: \"=\",\r\n value: args[1],\r\n });\r\n } else if (args.length === 3) {\r\n // With operator: where(field, operator, value)\r\n this.operationsHelper.addMatchOperation(prefix, {\r\n field: args[0],\r\n operator: args[1],\r\n value: args[2],\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Internal helper for adding raw where clauses.\r\n * @param type - The operation type\r\n * @param expression - The raw expression in MongoDB query language\r\n * @param bindings - Optional bindings for the expression\r\n */\r\n protected addRawWhere(\r\n type: \"whereRaw\" | \"orWhereRaw\",\r\n expression: RawExpression,\r\n bindings?: unknown[],\r\n ): this {\r\n this.operationsHelper.addMatchOperation(type, { expression, bindings });\r\n return this;\r\n }\r\n\r\n /**\r\n * Normalizes select field arguments into a structured format.\r\n * @param args - The arguments to normalize\r\n * @returns Normalized selection object with fields and aliases\r\n */\r\n protected normalizeSelectFields(args: any[]): {\r\n fields?: string[];\r\n projection?: Record<string, unknown>;\r\n } {\r\n // Single argument cases\r\n if (args.length === 1) {\r\n const arg = args[0];\r\n\r\n // Object format: { field: 1, field2: 0, field3: \"alias\", field4: true }\r\n if (typeof arg === \"object\" && !Array.isArray(arg)) {\r\n return { projection: arg };\r\n }\r\n\r\n // Array format: [\"field1\", \"field2\"]\r\n if (Array.isArray(arg)) {\r\n return { fields: arg };\r\n }\r\n\r\n // Single string: \"field\"\r\n if (typeof arg === \"string\") {\r\n return { fields: [arg] };\r\n }\r\n }\r\n\r\n // Multiple string arguments: select(\"field1\", \"field2\", \"field3\")\r\n return { fields: args.filter((arg) => typeof arg === \"string\") };\r\n }\r\n\r\n // ============================================================================\r\n // SELECT / PROJECTION\r\n // ============================================================================\r\n\r\n /**\r\n * Specifies which fields to include in the query results.\r\n * Supports arrays, multiple args, or object with aliases/inclusion/exclusion.\r\n * @param fields - Field names, array, or projection object\r\n */\r\n public select(fields: string[]): this;\r\n public select(fields: Record<string, 0 | 1 | boolean | string>): this;\r\n public select(...fields: string[]): this;\r\n public select(...args: any): this {\r\n const normalized = this.normalizeSelectFields(args);\r\n this.operationsHelper.addProjectOperation(\"select\", normalized);\r\n return this;\r\n }\r\n\r\n /**\r\n * Selects a field with an alias.\r\n * @param field - The field to select\r\n * @param alias - The alias name for the field\r\n * @returns The query builder instance\r\n */\r\n public selectAs(field: string, alias: string): this {\r\n return this.select({ [field]: alias });\r\n }\r\n\r\n /**\r\n * Adds a computed field using a raw MongoDB expression.\r\n * @param expression - The raw MongoDB expression\r\n * @param bindings - Optional parameter bindings for string expressions\r\n */\r\n public selectRaw(expression: RawExpression, bindings?: unknown[]): this {\r\n this.operationsHelper.addProjectOperation(\"selectRaw\", {\r\n expression,\r\n bindings,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds multiple computed fields using raw MongoDB expressions.\r\n * @param definitions - Array of field definitions with alias, expression, and optional bindings\r\n */\r\n public selectRawMany(\r\n definitions: Array<{\r\n alias: string;\r\n expression: RawExpression;\r\n bindings?: unknown[];\r\n }>,\r\n ): this {\r\n for (const definition of definitions) {\r\n this.selectRaw({ [definition.alias]: definition.expression }, definition.bindings);\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a subquery as a computed field.\r\n * @param expression - The subquery expression\r\n * @param alias - The alias for the computed field\r\n */\r\n public selectSub(expression: RawExpression, alias: string): this {\r\n this.operationsHelper.addProjectOperation(\"selectSub\", {\r\n expression,\r\n alias,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds an additional subquery field to existing selections.\r\n * @param expression - The subquery expression\r\n * @param alias - The alias for the computed field\r\n */\r\n public addSelectSub(expression: RawExpression, alias: string): this {\r\n this.operationsHelper.addProjectOperation(\"addSelectSub\", {\r\n expression,\r\n alias,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds an aggregate value as a computed field.\r\n * @param field - The field to aggregate\r\n * @param aggregate - The aggregate function to apply\r\n * @param alias - The alias for the computed field\r\n */\r\n public selectAggregate(\r\n field: string,\r\n aggregate: \"sum\" | \"avg\" | \"min\" | \"max\" | \"count\" | \"first\" | \"last\",\r\n alias: string,\r\n ): this {\r\n this.operationsHelper.addProjectOperation(\"selectAggregate\", {\r\n field,\r\n aggregate,\r\n alias,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a boolean field indicating whether a related document exists.\r\n * @param field - The field to check for existence\r\n * @param alias - The alias for the boolean field\r\n */\r\n public selectExists(field: string, alias: string): this {\r\n this.operationsHelper.addProjectOperation(\"selectExists\", {\r\n field,\r\n alias,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a count field for a related collection.\r\n * @param field - The field to count\r\n * @param alias - The alias for the count field\r\n */\r\n public selectCount(field: string, alias: string): this {\r\n this.operationsHelper.addProjectOperation(\"selectCount\", { field, alias });\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a CASE-like conditional field using multiple conditions.\r\n * @param cases - Array of when/then pairs\r\n * @param otherwise - Default value if no conditions match\r\n * @param alias - The alias for the computed field\r\n */\r\n public selectCase(\r\n cases: Array<{ when: RawExpression; then: RawExpression | unknown }>,\r\n otherwise: RawExpression | unknown,\r\n alias: string,\r\n ): this {\r\n this.operationsHelper.addProjectOperation(\"selectCase\", {\r\n cases,\r\n otherwise,\r\n alias,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a simple conditional field (if/else).\r\n * @param condition - The condition to evaluate\r\n * @param thenValue - Value if condition is true\r\n * @param elseValue - Value if condition is false\r\n * @param alias - The alias for the computed field\r\n */\r\n public selectWhen(\r\n condition: RawExpression,\r\n thenValue: RawExpression | unknown,\r\n elseValue: RawExpression | unknown,\r\n alias: string,\r\n ): this {\r\n this.operationsHelper.addProjectOperation(\"selectWhen\", {\r\n condition,\r\n thenValue,\r\n elseValue,\r\n alias,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Allows direct manipulation of the MongoDB projection object.\r\n * @param callback - Function that receives and modifies the projection object\r\n */\r\n public selectDriverProjection(callback: (projection: Record<string, unknown>) => void): this {\r\n this.operationsHelper.addProjectOperation(\"selectDriverProjection\", {\r\n callback,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Extracts a JSON field from a document.\r\n * @param path - The JSON path to extract\r\n * @param alias - Optional alias for the extracted field\r\n */\r\n public selectJson(path: string, alias?: string): this {\r\n this.operationsHelper.addProjectOperation(\"selectJson\", { path, alias });\r\n return this;\r\n }\r\n\r\n /**\r\n * Extracts a JSON field using a raw MongoDB expression.\r\n * @param path - The JSON path\r\n * @param expression - The raw expression for extraction\r\n * @param alias - The alias for the extracted field\r\n */\r\n public selectJsonRaw(path: string, expression: RawExpression, alias: string): this {\r\n this.operationsHelper.addProjectOperation(\"selectJsonRaw\", {\r\n path,\r\n expression,\r\n alias,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Excludes a JSON path from the results.\r\n * @param path - The JSON path to exclude\r\n */\r\n public deselectJson(path: string): this {\r\n this.operationsHelper.addProjectOperation(\"deselectJson\", { path });\r\n return this;\r\n }\r\n\r\n /**\r\n * Concatenates multiple fields into a single string field.\r\n * @param fields - Array of fields or expressions to concatenate\r\n * @param alias - The alias for the concatenated field\r\n */\r\n public selectConcat(fields: Array<string | RawExpression>, alias: string): this {\r\n this.operationsHelper.addProjectOperation(\"selectConcat\", {\r\n fields,\r\n alias,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Returns the first non-null value from a list of fields.\r\n * @param fields - Array of fields to check\r\n * @param alias - The alias for the coalesced field\r\n */\r\n public selectCoalesce(fields: Array<string | RawExpression>, alias: string): this {\r\n this.operationsHelper.addProjectOperation(\"selectCoalesce\", {\r\n fields,\r\n alias,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds window function operations to the query.\r\n * @param spec - The window function specification\r\n */\r\n public selectWindow(spec: RawExpression): this {\r\n this.operationsHelper.addOperation(\"$setWindowFields\", \"selectWindow\", { spec }, false);\r\n return this;\r\n }\r\n\r\n /**\r\n * Excludes specific fields from the query results.\r\n * @param fields - Field names to exclude\r\n */\r\n public deselect(fields: string[]): this;\r\n public deselect(...fields: Array<string | string[]>): this;\r\n public deselect(...args: Array<string | string[]>): this {\r\n const fields = this.normalizeSelectFields(args);\r\n this.operationsHelper.addProjectOperation(\"deselect\", { fields });\r\n return this;\r\n }\r\n\r\n /**\r\n * Returns only distinct values for the specified fields.\r\n * @param fields - Optional field names to use for distinctness\r\n */\r\n public distinctValues(fields?: string | string[]): this {\r\n this.operationsHelper.addGroupOperation(\"distinct\", { fields }, false);\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds additional fields to an existing selection.\r\n * @param fields - Additional field names to include\r\n */\r\n public addSelect(fields: string[]): this;\r\n public addSelect(...fields: Array<string | string[]>): this;\r\n public addSelect(...args: Array<string | string[]>): this {\r\n const fields = this.normalizeSelectFields(args);\r\n this.operationsHelper.addProjectOperation(\"addSelect\", { fields });\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes all field selection restrictions.\r\n */\r\n public clearSelect(): this {\r\n this.operations = this.operations.filter((op) => op.stage !== \"$project\");\r\n return this;\r\n }\r\n\r\n /**\r\n * Alias for `clearSelect()`. Removes all field restrictions.\r\n */\r\n public selectAll(): this {\r\n return this.clearSelect();\r\n }\r\n\r\n /**\r\n * Alias for `clearSelect()`. Resets to default field selection.\r\n */\r\n public selectDefault(): this {\r\n return this.clearSelect();\r\n }\r\n\r\n // ============================================================================\r\n // ORDERING\r\n // ============================================================================\r\n\r\n /**\r\n * Orders the query results by a specific field or multiple fields.\r\n *\r\n * @param field - The field name to sort by, or an object with multiple fields\r\n * @param direction - The sort direction (only used when field is a string)\r\n *\r\n * @example\r\n * ```typescript\r\n * // Single field\r\n * query.orderBy(\"createdAt\", \"desc\");\r\n *\r\n * // Multiple fields\r\n * query.orderBy({ id: \"asc\", age: \"desc\", createdAt: \"desc\" });\r\n * ```\r\n */\r\n public orderBy(field: string, direction?: OrderDirection): this;\r\n public orderBy(fields: Record<string, OrderDirection>): this;\r\n public orderBy(\r\n fieldOrFields: string | Record<string, OrderDirection>,\r\n direction: OrderDirection = \"asc\",\r\n ): this {\r\n if (typeof fieldOrFields === \"string\") {\r\n // Single field\r\n this.operationsHelper.addSortOperation(\"orderBy\", {\r\n field: fieldOrFields,\r\n direction,\r\n });\r\n } else {\r\n // Multiple fields - add each as a separate operation (they'll be merged)\r\n for (const [field, dir] of Object.entries(fieldOrFields)) {\r\n this.operationsHelper.addSortOperation(\"orderBy\", {\r\n field,\r\n direction: dir,\r\n });\r\n }\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Orders the query results by a field in descending order.\r\n * @param field - The field name to sort by\r\n */\r\n public orderByDesc(field: string): this {\r\n return this.orderBy(field, \"desc\");\r\n }\r\n\r\n /**\r\n * Orders the query results using a raw MongoDB sort expression.\r\n * @param expression - The raw MongoDB sort expression\r\n * @param bindings - Optional parameter bindings\r\n */\r\n public orderByRaw(expression: RawExpression, bindings?: unknown[]): this {\r\n this.operationsHelper.addSortOperation(\"orderByRaw\", {\r\n expression,\r\n bindings,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Orders the query results randomly.\r\n */\r\n public orderByRandom(limit: number = 1000): this {\r\n this.operationsHelper.addSortOperation(\"orderByRandom\", { limit }, false);\r\n return this;\r\n }\r\n\r\n /**\r\n * Orders results by a date field in descending order (newest first).\r\n * @param column - The date column to sort by\r\n */\r\n public latest(column: string = \"createdAt\"): Promise<T[]> {\r\n return this.orderBy(column, \"desc\").get();\r\n }\r\n\r\n /**\r\n * Orders results by a date field in ascending order (oldest first).\r\n * @param column - The date column to sort by\r\n */\r\n public oldest(column: string = \"createdAt\"): this {\r\n return this.orderBy(column, \"asc\");\r\n }\r\n\r\n // ============================================================================\r\n // LIMITING / PAGINATION\r\n // ============================================================================\r\n\r\n /**\r\n * Limits the number of documents returned by the query.\r\n * @param value - The maximum number of documents to return\r\n */\r\n public limit(value: number): this {\r\n this.operationsHelper.addOperation(\"$limit\", \"limit\", { value }, false);\r\n return this;\r\n }\r\n\r\n /**\r\n * Skips a specified number of documents in the query results.\r\n * @param value - The number of documents to skip\r\n */\r\n public skip(value: number): this {\r\n this.operationsHelper.addOperation(\"$skip\", \"skip\", { value }, false);\r\n return this;\r\n }\r\n\r\n /**\r\n * Alias for `skip()`. Skips a specified number of documents.\r\n * @param value - The number of documents to skip\r\n */\r\n public offset(value: number): this {\r\n return this.skip(value);\r\n }\r\n\r\n /**\r\n * Alias for `limit()`. Limits the number of documents returned.\r\n * @param value - The maximum number of documents to return\r\n */\r\n public take(value: number): this {\r\n return this.limit(value);\r\n }\r\n\r\n /**\r\n * Applies cursor-based filtering for pagination.\r\n * @param after - Cursor value for forward pagination\r\n * @param before - Cursor value for backward pagination\r\n */\r\n public cursor(after?: unknown, before?: unknown): this {\r\n this.operationsHelper.addMatchOperation(\"cursor\", { after, before });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // GROUPING / AGGREGATION\r\n // ============================================================================\r\n\r\n /**\r\n * Groups documents by one or more fields.\r\n *\r\n * @param fields - Field(s) to group by\r\n * @param aggregates - Optional aggregate operations to perform\r\n *\r\n * @example\r\n * ```typescript\r\n * import { $agg } from '@warlock.js/cascade';\r\n *\r\n * // Simple grouping\r\n * query.groupBy(\"type\");\r\n *\r\n * // Grouping with aggregates\r\n * query.groupBy(\"type\", {\r\n * count: $agg.count(),\r\n * total: $agg.sum(\"duration\")\r\n * });\r\n * ```\r\n */\r\n public groupBy(fields: GroupByInput): this;\r\n public groupBy(fields: GroupByInput, aggregates: Record<string, RawExpression>): this;\r\n public groupBy(fields: GroupByInput, aggregates?: Record<string, RawExpression>): this {\r\n if (aggregates) {\r\n this.operationsHelper.addGroupOperation(\r\n \"groupByWithAggregates\",\r\n { fields, aggregates },\r\n false,\r\n );\r\n } else {\r\n this.operationsHelper.addGroupOperation(\"groupBy\", { fields }, false);\r\n }\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Groups documents using a raw MongoDB expression.\r\n * @param expression - The raw grouping expression\r\n * @param bindings - Optional parameter bindings\r\n */\r\n public groupByRaw(expression: RawExpression, bindings?: unknown[]): this {\r\n this.operationsHelper.addGroupOperation(\"groupByRaw\", { expression, bindings }, false);\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters grouped results based on aggregate conditions.\r\n * @param field - The aggregate field to filter on\r\n * @param value - The value to compare against\r\n * @param operator - The comparison operator\r\n * @param condition - A condition object for complex filters\r\n */\r\n public having(field: string, value: unknown): this;\r\n public having(field: string, operator: WhereOperator, value: unknown): this;\r\n public having(condition: HavingInput): this;\r\n public having(...args: any[]): this {\r\n if (args.length === 1) {\r\n this.operationsHelper.addMatchOperation(\"having:condition\", args[0], false);\r\n } else if (args.length === 2) {\r\n this.operationsHelper.addMatchOperation(\r\n \"having\",\r\n { field: args[0], operator: \"=\", value: args[1] },\r\n false,\r\n );\r\n } else {\r\n this.operationsHelper.addMatchOperation(\r\n \"having\",\r\n { field: args[0], operator: args[1], value: args[2] },\r\n false,\r\n );\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Filters grouped results using a raw MongoDB expression.\r\n * @param expression - The raw having expression\r\n * @param bindings - Optional parameter bindings\r\n */\r\n public havingRaw(expression: RawExpression, bindings?: unknown[]): this {\r\n this.operationsHelper.addMatchOperation(\"havingRaw\", { expression, bindings }, false);\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // JOINS\r\n // ============================================================================\r\n\r\n /**\r\n * Performs a join with another collection using MongoDB's $lookup.\r\n *\r\n * @param table - Target collection name\r\n * @param localField - Field from the input documents\r\n * @param foreignField - Field from the documents of the \"from\" collection\r\n */\r\n public join(table: string, localField: string, foreignField: string): this;\r\n /**\r\n * Performs a join with another collection using MongoDB's $lookup.\r\n *\r\n * @param options - Join configuration including table, fields, and optional pipeline\r\n */\r\n public join(options: JoinOptions): this;\r\n public join(\r\n tableOrOptions: string | JoinOptions,\r\n localField?: string,\r\n foreignField?: string,\r\n ): this {\r\n const options: JoinOptions =\r\n typeof tableOrOptions === \"string\"\r\n ? {\r\n table: tableOrOptions,\r\n localField: localField!,\r\n foreignField: foreignField!,\r\n type: \"left\", // MongoDB $lookup is inherently a left outer join\r\n }\r\n : tableOrOptions;\r\n\r\n this.operationsHelper.addLookupOperation(\"join\", options);\r\n return this;\r\n }\r\n\r\n /**\r\n * Performs a left outer join with another collection.\r\n * In MongoDB, this is the standard $lookup behavior.\r\n *\r\n * @param table - Target collection name\r\n * @param localField - Field from the input documents\r\n * @param foreignField - Field from the documents of the \"from\" collection\r\n */\r\n public leftJoin(table: string, localField: string, foreignField: string): this;\r\n /**\r\n * Performs a left outer join with another collection.\r\n *\r\n * @param options - Join configuration\r\n */\r\n public leftJoin(options: JoinOptions): this;\r\n public leftJoin(\r\n tableOrOptions: string | JoinOptions,\r\n localField?: string,\r\n foreignField?: string,\r\n ): this {\r\n const options: JoinOptions =\r\n typeof tableOrOptions === \"string\"\r\n ? {\r\n table: tableOrOptions,\r\n localField: localField!,\r\n foreignField: foreignField!,\r\n type: \"left\",\r\n }\r\n : { ...tableOrOptions, type: \"left\" };\r\n\r\n this.operationsHelper.addLookupOperation(\"join\", options);\r\n return this;\r\n }\r\n\r\n /**\r\n * Performs a right outer join with another collection.\r\n *\r\n * Note: MongoDB doesn't natively support right joins. This is implemented\r\n * as a regular left join with a warning. For true right join semantics,\r\n * consider reversing the collections in your query.\r\n *\r\n * @param table - Target collection name\r\n * @param localField - Field from the input documents\r\n * @param foreignField - Field from the documents of the \"from\" collection\r\n */\r\n public rightJoin(table: string, localField: string, foreignField: string): this;\r\n /**\r\n * Performs a right outer join with another collection.\r\n *\r\n * @param options - Join configuration\r\n */\r\n public rightJoin(options: JoinOptions): this;\r\n public rightJoin(\r\n tableOrOptions: string | JoinOptions,\r\n localField?: string,\r\n foreignField?: string,\r\n ): this {\r\n // MongoDB $lookup is always a left join from the perspective of the input collection\r\n // Right join semantics would require reversing the query direction\r\n const options: JoinOptions =\r\n typeof tableOrOptions === \"string\"\r\n ? {\r\n table: tableOrOptions,\r\n localField: localField!,\r\n foreignField: foreignField!,\r\n type: \"right\",\r\n }\r\n : { ...tableOrOptions, type: \"right\" };\r\n\r\n this.operationsHelper.addLookupOperation(\"join\", options);\r\n return this;\r\n }\r\n\r\n /**\r\n * Performs an inner join with another collection.\r\n *\r\n * This adds a $lookup followed by a $match to filter out documents\r\n * where the joined array is empty.\r\n *\r\n * @param table - Target collection name\r\n * @param localField - Field from the input documents\r\n * @param foreignField - Field from the documents of the \"from\" collection\r\n */\r\n public innerJoin(table: string, localField: string, foreignField: string): this;\r\n /**\r\n * Performs an inner join with another collection.\r\n *\r\n * @param options - Join configuration\r\n */\r\n public innerJoin(options: JoinOptions): this;\r\n public innerJoin(\r\n tableOrOptions: string | JoinOptions,\r\n localField?: string,\r\n foreignField?: string,\r\n ): this {\r\n const options: JoinOptions =\r\n typeof tableOrOptions === \"string\"\r\n ? {\r\n table: tableOrOptions,\r\n localField: localField!,\r\n foreignField: foreignField!,\r\n type: \"inner\",\r\n }\r\n : { ...tableOrOptions, type: \"inner\" };\r\n\r\n this.operationsHelper.addLookupOperation(\"join\", options);\r\n return this;\r\n }\r\n\r\n /**\r\n * Performs a full outer join with another collection.\r\n *\r\n * Note: MongoDB doesn't natively support full outer joins. This is implemented\r\n * as a regular left join. For true full outer join semantics, you would need\r\n * to use $unionWith and additional aggregation logic.\r\n *\r\n * @param table - Target collection name\r\n * @param localField - Field from the input documents\r\n * @param foreignField - Field from the documents of the \"from\" collection\r\n */\r\n public fullJoin(table: string, localField: string, foreignField: string): this;\r\n /**\r\n * Performs a full outer join with another collection.\r\n *\r\n * @param options - Join configuration\r\n */\r\n public fullJoin(options: JoinOptions): this;\r\n public fullJoin(\r\n tableOrOptions: string | JoinOptions,\r\n localField?: string,\r\n foreignField?: string,\r\n ): this {\r\n const options: JoinOptions =\r\n typeof tableOrOptions === \"string\"\r\n ? {\r\n table: tableOrOptions,\r\n localField: localField!,\r\n foreignField: foreignField!,\r\n type: \"full\",\r\n }\r\n : { ...tableOrOptions, type: \"full\" };\r\n\r\n this.operationsHelper.addLookupOperation(\"join\", options);\r\n return this;\r\n }\r\n\r\n /**\r\n * Performs a cross join with another collection.\r\n *\r\n * This creates a cartesian product by using $lookup with empty matching criteria.\r\n *\r\n * @param table - Target collection name\r\n */\r\n public crossJoin(table: string): this {\r\n // Cross join: match every document in the foreign collection\r\n this.operationsHelper.addLookupOperation(\"join\", {\r\n table,\r\n localField: \"_crossJoinDummy\",\r\n foreignField: \"_crossJoinDummy\",\r\n type: \"cross\",\r\n pipeline: [{ $match: {} }], // Match all documents\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Performs a raw join using a custom aggregation pipeline.\r\n *\r\n * This allows full control over the $lookup stage for complex join scenarios.\r\n *\r\n * @param expression - Raw expression (typically a $lookup stage or pipeline)\r\n * @param _bindings - Optional bindings (not used in MongoDB but kept for API consistency)\r\n */\r\n public joinRaw(expression: RawExpression, _bindings?: unknown[]): this {\r\n // For MongoDB, expression should be a $lookup stage object or a simple string\r\n // describing the join. We add it as a raw operation.\r\n this.operationsHelper.addMatchOperation(\"raw\", { builder: () => expression }, false);\r\n return this;\r\n }\r\n\r\n /**\r\n * Allows direct manipulation of the native MongoDB query.\r\n * @param builder - Function that receives and modifies the native query\r\n */\r\n public raw(builder: (native: unknown) => unknown): this {\r\n this.operationsHelper.addMatchOperation(\"raw\", { builder }, false);\r\n return this;\r\n }\r\n\r\n /**\r\n * Extends the query builder with driver-specific functionality.\r\n * @param extension - The extension name\r\n * @param _args - Extension-specific arguments\r\n * @returns The extension's return value\r\n */\r\n public extend<R>(extension: string, ..._args: unknown[]): R {\r\n // Driver-specific extensions can be added here\r\n throw new Error(`Extension '${extension}' is not supported by MongoQueryBuilder`);\r\n }\r\n\r\n /**\r\n * Creates a deep copy of the query builder.\r\n * @returns A new query builder instance with copied operations\r\n */\r\n public clone(): this {\r\n const cloned = new MongoQueryBuilder<T>(this.table, this.dataSource) as this;\r\n cloned.operations = [...this.operations];\r\n cloned.hydrateCallback = this.hydrateCallback?.bind(cloned);\r\n cloned.fetchingCallback = this.fetchingCallback?.bind(cloned);\r\n cloned.hydratingCallback = this.hydratingCallback?.bind(cloned);\r\n cloned.fetchedCallback = this.fetchedCallback?.bind(cloned);\r\n\r\n // Copy scope state\r\n cloned.pendingGlobalScopes = this.pendingGlobalScopes;\r\n cloned.availableLocalScopes = this.availableLocalScopes;\r\n cloned.disabledGlobalScopes = new Set(this.disabledGlobalScopes);\r\n cloned.scopesApplied = this.scopesApplied;\r\n\r\n (cloned as any).__operationsHelper = (this as any).__operationsHelper;\r\n return cloned;\r\n }\r\n\r\n /**\r\n * Executes a callback with the query builder without breaking the chain.\r\n * @param callback - Function to execute with the builder\r\n */\r\n public tap(callback: (builder: this) => void): this {\r\n callback(this);\r\n return this;\r\n }\r\n\r\n /**\r\n * Conditionally applies query modifications based on a condition.\r\n * @param condition - The condition to evaluate\r\n * @param callback - Function to execute if condition is true\r\n * @param otherwise - Optional function to execute if condition is false\r\n *\r\n * @example\r\n * query.when(searchTerm, (q, term) => q.whereLike('name', term))\r\n */\r\n public when<V>(\r\n condition: V | boolean,\r\n callback: (builder: this, value: V) => void,\r\n otherwise?: (builder: this) => void,\r\n ): this {\r\n if (condition) {\r\n callback(this, condition as V);\r\n } else if (otherwise) {\r\n otherwise(this);\r\n }\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // EXECUTION METHODS\r\n // ============================================================================\r\n\r\n /**\r\n * Executes the query and returns all matching documents.\r\n * @returns an array of matching documents\r\n */\r\n public async get<Output = T>(): Promise<Output[]> {\r\n const startTime = Date.now();\r\n\r\n // Emit onFetching event\r\n if (this.fetchingCallback) {\r\n await this.fetchingCallback(this);\r\n }\r\n\r\n // Execute query and get raw records\r\n const rawRecords = await this.execute<Output>();\r\n\r\n // Emit onHydrating event\r\n if (this.hydratingCallback) {\r\n await this.hydratingCallback(rawRecords, {\r\n query: this,\r\n hydrateCallback: this.hydrateCallback,\r\n });\r\n }\r\n\r\n // Hydrate records\r\n const hydratedRecords = this.hydrateCallback\r\n ? rawRecords.map(this.hydrateCallback)\r\n : rawRecords;\r\n\r\n // Emit onFetched event\r\n if (this.fetchedCallback) {\r\n await this.fetchedCallback(hydratedRecords, {\r\n query: this,\r\n rawRecords,\r\n duration: Date.now() - startTime,\r\n });\r\n }\r\n\r\n return hydratedRecords;\r\n }\r\n\r\n /**\r\n * Execute the query and get first result\r\n * This is different than `first` as first adds a `limit = 1` to the pipeline\r\n */\r\n public async getFirst<Output = T>(): Promise<Output | null> {\r\n return (await this.get<Output>())?.[0] ?? null;\r\n }\r\n\r\n /**\r\n * Executes the query and returns the first matching document.\r\n * @returns the first document or null\r\n */\r\n public async first<Output = T>(): Promise<Output | null> {\r\n const results = await this.limit(1).get<Output>();\r\n return results.length > 0 ? results[0] : null;\r\n }\r\n\r\n /**\r\n * Executes the query and returns the first matching document, throwing if none found.\r\n * @returns the first document\r\n */\r\n public async firstOrFail<Output = T>(): Promise<Output> {\r\n const result = await this.first<Output>();\r\n if (!result) {\r\n throw new Error(\"No records found matching the query\");\r\n }\r\n return result;\r\n }\r\n\r\n /**\r\n * Find a document by its primary key (id field).\r\n */\r\n public async find<Output = T>(id: number | string): Promise<Output | null> {\r\n return this.where(\"id\", id).first<Output>();\r\n }\r\n\r\n /**\r\n * Configures the query to retrieve the last matching document.\r\n */\r\n public last<Output = T>(field: string = \"createdAt\"): Promise<Output | null> {\r\n this.orderBy(field, \"desc\");\r\n return this.first<Output>();\r\n }\r\n\r\n /**\r\n * Counts the number of documents matching the query.\r\n * @returns the count of matching documents\r\n */\r\n public async count(): Promise<number> {\r\n const pipeline = this.buildPipeline();\r\n pipeline.push({ $count: \"total\" });\r\n\r\n const results = await this.execute<{ total: number }>(pipeline);\r\n\r\n return results.length > 0 ? results[0].total : 0;\r\n }\r\n\r\n /**\r\n * Calculates the sum of a numeric field across matching documents.\r\n * @param field - The numeric field to sum\r\n * @returns the sum value\r\n */\r\n public async sum(field: string): Promise<number> {\r\n this.groupByRaw({\r\n _id: null,\r\n total: { $sum: `$${field}` },\r\n });\r\n\r\n // make sure to clear the data map callback\r\n this.hydrateCallback = undefined;\r\n\r\n const result = await this.getFirst<{ total: number }>();\r\n\r\n return result?.total ?? 0;\r\n }\r\n\r\n /**\r\n * Calculates the average value of a numeric field across matching documents.\r\n * @param field - The numeric field to average\r\n * @returns the average value\r\n */\r\n public async avg(field: string): Promise<number> {\r\n this.groupByRaw({\r\n _id: null,\r\n average: { $avg: `$${field}` },\r\n });\r\n\r\n // make sure to clear the data map callback\r\n this.hydrateCallback = undefined;\r\n\r\n return (await this.getFirst<{ average: number }>())?.average ?? 0;\r\n }\r\n\r\n /**\r\n * Finds the minimum value of a field across matching documents.\r\n * @param field - The field to find the minimum of\r\n * @returns the minimum value\r\n */\r\n public async min(field: string): Promise<number> {\r\n this.groupByRaw({\r\n _id: null,\r\n minimum: { $min: `$${field}` },\r\n });\r\n\r\n // make sure to clear the data map callback\r\n this.hydrateCallback = undefined;\r\n\r\n return (await this.getFirst<{ minimum: number }>())?.minimum ?? 0;\r\n }\r\n\r\n /**\r\n * Finds the maximum value of a field across matching documents.\r\n * @param field - The field to find the maximum of\r\n * @returns the maximum value\r\n */\r\n public async max(field: string): Promise<number> {\r\n this.groupByRaw({\r\n _id: null,\r\n maximum: { $max: `$${field}` },\r\n });\r\n\r\n // make sure to clear the data map callback\r\n this.hydrateCallback = undefined;\r\n\r\n return (await this.getFirst<{ maximum: number }>())?.maximum ?? 0;\r\n }\r\n\r\n /**\r\n * Returns an array of distinct values for a field, respecting query filters.\r\n * @param field - The field to get distinct values from\r\n * @returns an array of distinct values\r\n */\r\n public async distinct<T = unknown>(field: string, ignoreNull = true): Promise<T[]> {\r\n if (ignoreNull) {\r\n this.whereNotNull(field);\r\n }\r\n\r\n this.groupBy(field);\r\n\r\n // make sure to clear the data map callback\r\n this.hydrateCallback = undefined;\r\n\r\n const results = await this.get<{ _id: T }>();\r\n return results.map((doc) => doc._id);\r\n }\r\n\r\n /**\r\n * Count distinct values for a field, respecting query filters.\r\n * @param field - The field to count distinct values for\r\n * @returns the count of distinct values\r\n */\r\n public async countDistinct(field: string, ignoreNull = true): Promise<number> {\r\n if (ignoreNull) {\r\n this.whereNotNull(field);\r\n }\r\n\r\n return await this.groupBy(field).count();\r\n }\r\n\r\n /**\r\n * Extracts a single field value from each matching document.\r\n * @param field - The field to extract\r\n * @returns an array of field values\r\n */\r\n public async pluck<T = unknown>(field: string): Promise<T[]> {\r\n // make sure to clear the data map callback\r\n this.hydrateCallback = undefined;\r\n\r\n // Use object aliasing: { [field]: \"value\" } to project field as \"value\"\r\n const results = await this.selectAs(field, \"value\").get<{\r\n value: T;\r\n }>();\r\n\r\n return results.map((doc) => doc.value).filter((value) => value !== undefined);\r\n }\r\n\r\n /**\r\n * Gets the value of a single field from the first matching document.\r\n * @param field - The field to extract\r\n * @returns the field value or null\r\n */\r\n public async value<T = unknown>(field: string): Promise<T | null> {\r\n // make sure to clear the data map callback\r\n this.hydrateCallback = undefined;\r\n\r\n const result = await this.selectAs(field, \"value\").first<{ value: T }>();\r\n return result?.value ?? null;\r\n }\r\n\r\n /**\r\n * Checks if any documents match the query.\r\n * @param filter - Optional filter to apply to the query\r\n * @returns true if documents exist, false otherwise\r\n */\r\n public async exists(filter?: GenericObject): Promise<boolean> {\r\n if (filter) {\r\n this.where(filter);\r\n }\r\n\r\n const count = await this.limit(1).count();\r\n return count > 0;\r\n }\r\n\r\n /**\r\n * Checks if no documents match the query.\r\n * @param filter - Optional filter to apply to the query\r\n * @returns true if no documents exist, false otherwise\r\n */\r\n public async notExists(filter?: GenericObject): Promise<boolean> {\r\n return !(await this.exists(filter));\r\n }\r\n\r\n /**\r\n * Increments a numeric field by the specified amount for first matching document.\r\n * @param field - The field to increment\r\n * @param amount - The amount to increment by (default: 1)\r\n * @returns the new value\r\n */\r\n public async increment(field: string, amount: number = 1): Promise<number> {\r\n const filter = this.buildFilter();\r\n\r\n const result = await this.collection.findOneAndUpdate(\r\n filter,\r\n {\r\n $inc: { [field]: amount },\r\n },\r\n {\r\n returnDocument: \"after\",\r\n },\r\n );\r\n\r\n return get(result, field, 0);\r\n }\r\n\r\n /**\r\n * Decrements a numeric field by the specified amount.\r\n * @param field - The field to decrement\r\n * @param amount - The amount to decrement by\r\n * @returns the new value\r\n */\r\n public async decrement(field: string, amount: number = 1): Promise<number> {\r\n return this.increment(field, -amount);\r\n }\r\n\r\n /**\r\n * Increments a numeric field by the specified amount for all matching documents.\r\n * @param field - The field to increment\r\n * @param amount - The amount to increment by (default: 1)\r\n * @returns the number of documents modified\r\n */\r\n public async incrementMany(field: string, amount: number = 1): Promise<number> {\r\n const filter = this.buildFilter();\r\n\r\n const result = await this.dataSource.driver.updateMany(this.table, filter, {\r\n $inc: { [field]: amount },\r\n });\r\n\r\n return result.modifiedCount;\r\n }\r\n\r\n /**\r\n * Decrements a numeric field by the specified amount for all matching documents.\r\n * @param field - The field to decrement\r\n * @param amount - The amount to decrement by (default: 1)\r\n * @returns the number of documents modified\r\n */\r\n public async decrementMany(field: string, amount: number = 1): Promise<number> {\r\n return this.incrementMany(field, -amount);\r\n }\r\n\r\n /**\r\n * Delete all documents matching the query.\r\n */\r\n public async delete(): Promise<number> {\r\n const filter = this.buildFilter();\r\n return await this.dataSource.driver.deleteMany(this.table, filter);\r\n }\r\n\r\n /**\r\n * Delete a single document matching the query.\r\n */\r\n public async deleteOne(): Promise<number> {\r\n const filter = this.buildFilter();\r\n return await this.dataSource.driver.delete(this.table, filter);\r\n }\r\n\r\n /**\r\n * Update the given fields for all documents matching the query.\r\n */\r\n public async update(fields: Record<string, unknown>): Promise<number> {\r\n const filter = this.buildFilter();\r\n const result = await this.dataSource.driver.updateMany(this.table, filter, {\r\n $set: fields,\r\n });\r\n return result.modifiedCount;\r\n }\r\n\r\n /**\r\n * Unset the given fields from all documents matching the query.\r\n */\r\n public async unset(...fields: string[]): Promise<number> {\r\n const filter = this.buildFilter();\r\n const result = await this.dataSource.driver.updateMany(this.table, filter, {\r\n $unset: fields.reduce(\r\n (acc, field) => {\r\n acc[field] = 1;\r\n return acc;\r\n },\r\n {} as Record<string, 1 | true>,\r\n ),\r\n });\r\n return result.modifiedCount;\r\n }\r\n\r\n // ============================================================================\r\n // CHUNKING / PAGINATION\r\n // ============================================================================\r\n\r\n /**\r\n * Processes query results in chunks, executing a callback for each chunk.\r\n * @param size - The number of documents per chunk\r\n * @param callback - Function to execute for each chunk\r\n * @returns void\r\n */\r\n public async chunk(\r\n size: number,\r\n callback: (rows: T[], chunkIndex: number) => Promise<boolean | void> | boolean | void,\r\n ): Promise<void> {\r\n let chunkIndex = 0;\r\n let hasMore = true;\r\n\r\n while (hasMore) {\r\n const chunk = await this.clone()\r\n .skip(chunkIndex * size)\r\n .limit(size)\r\n .get();\r\n\r\n if (chunk.length === 0) {\r\n break;\r\n }\r\n\r\n const shouldContinue = await callback(chunk, chunkIndex);\r\n\r\n if (shouldContinue === false) {\r\n break;\r\n }\r\n\r\n hasMore = chunk.length === size;\r\n chunkIndex++;\r\n }\r\n }\r\n\r\n /**\r\n * Executes the query with traditional page-based pagination.\r\n * @param options - Pagination options\r\n * @returns pagination result with data and metadata\r\n */\r\n public async paginate(options?: PaginationOptions): Promise<PaginationResult<T>> {\r\n const page = options?.page ?? 1;\r\n const limit = options?.limit ?? 10;\r\n const skip = (page - 1) * limit;\r\n\r\n const [data, total] = await Promise.all([\r\n this.clone().skip(skip).limit(limit).get(),\r\n this.count(),\r\n ]);\r\n\r\n return {\r\n data,\r\n pagination: {\r\n total,\r\n page,\r\n limit,\r\n pages: Math.ceil(total / limit),\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Executes the query with cursor-based pagination supporting both directions.\r\n * @param options - Cursor pagination options\r\n * @returns cursor pagination result with data and cursor info\r\n */\r\n public async cursorPaginate(\r\n options?: CursorPaginationOptions,\r\n ): Promise<CursorPaginationResult<T>> {\r\n const limit = options?.limit ?? 10;\r\n const cursor = options?.cursor;\r\n const column = options?.column ?? \"id\";\r\n const direction = options?.direction ?? \"next\";\r\n\r\n // Apply cursor filter\r\n if (cursor) {\r\n const operator = direction === \"next\" ? \">\" : \"<\";\r\n this.where(column, operator, cursor);\r\n }\r\n\r\n // Apply sorting\r\n const sortOrder = direction === \"next\" ? \"asc\" : \"desc\";\r\n this.orderBy(column, sortOrder);\r\n\r\n this.orderBy(\"_id\", sortOrder); // Always sort by _id to ensure consistent order\r\n\r\n // Fetch one extra to detect if there are more results\r\n const results = await this.limit(limit + 1).get<T>();\r\n\r\n const hasMore = results.length > limit;\r\n let data = hasMore ? results.slice(0, limit) : results;\r\n\r\n // Reverse results if fetching previous page to keep natural order\r\n if (direction === \"prev\") {\r\n data = data.reverse();\r\n }\r\n\r\n // Determine cursors based on actual data\r\n let nextCursor: unknown | undefined;\r\n let prevCursor: unknown | undefined;\r\n let hasPrev = false;\r\n\r\n if (data.length > 0) {\r\n const firstItem = (data[0] as any)[column];\r\n const lastItem = (data[data.length - 1] as any)[column];\r\n\r\n if (direction === \"next\") {\r\n // Forward pagination\r\n nextCursor = hasMore ? lastItem : undefined;\r\n\r\n // Check if there's a previous page\r\n if (cursor) {\r\n hasPrev = true;\r\n prevCursor = firstItem;\r\n }\r\n } else {\r\n // Backward pagination\r\n prevCursor = hasMore ? firstItem : undefined;\r\n hasPrev = hasMore;\r\n\r\n // Check if there's a next page\r\n if (cursor) {\r\n nextCursor = lastItem;\r\n }\r\n }\r\n }\r\n\r\n return {\r\n data,\r\n pagination: {\r\n hasMore,\r\n hasPrev,\r\n nextCursor,\r\n prevCursor,\r\n },\r\n };\r\n }\r\n\r\n // ============================================================================\r\n // INSPECTION / DEBUGGING\r\n // ============================================================================\r\n\r\n /**\r\n * Returns the MongoDB aggregation pipeline that will be executed.\r\n */\r\n public parse(): DriverQuery {\r\n return { pipeline: this.buildPipeline() };\r\n }\r\n\r\n /**\r\n * Returns a formatted string representation of the query pipeline.\r\n * @returns A formatted string representation of the pipeline\r\n */\r\n public pretty() {\r\n return this.getParser().toPrettyString();\r\n }\r\n\r\n /**\r\n * Returns the MongoDB query execution plan.\r\n * @returns MongoDB's explain output\r\n */\r\n public async explain(): Promise<unknown> {\r\n // TODO: Trigger the explaining event\r\n const pipeline = this.buildPipeline();\r\n const session = databaseTransactionContext.getSession();\r\n const options = session ? { session, explain: true } : { explain: true };\r\n\r\n return this.collection.aggregate(pipeline, options as any).toArray();\r\n }\r\n\r\n // ============================================================================\r\n // INTERNAL PIPELINE BUILDING\r\n // ============================================================================\r\n\r\n /**\r\n * Get query parser instance\r\n */\r\n protected getParser(): MongoQueryParser {\r\n this.applyPendingScopes();\r\n\r\n return new MongoQueryParser({\r\n collection: this.collection,\r\n operations: this.operations,\r\n createSubBuilder: () => new MongoQueryBuilder(this.table, this.dataSource),\r\n });\r\n }\r\n\r\n /**\r\n * Build the MongoDB aggregation pipeline from the operations list.\r\n * @returns The MongoDB aggregation pipeline\r\n */\r\n protected buildPipeline() {\r\n const parser = this.getParser();\r\n\r\n return parser.parse();\r\n }\r\n\r\n /**\r\n * Build a MongoDB filter object from the query's where clauses.\r\n * Used for update operations like increment/decrement.\r\n * @returns The MongoDB filter object\r\n */\r\n protected buildFilter(): Record<string, unknown> {\r\n // Get all match operations\r\n const matchOperations = this.operations.filter((op) => op.stage === \"$match\");\r\n\r\n if (matchOperations.length === 0) {\r\n return {}; // No filters, match all documents\r\n }\r\n\r\n // Build the pipeline and extract the first $match stage\r\n const pipeline = this.buildPipeline();\r\n const matchStage = pipeline.find((stage) => stage.$match);\r\n\r\n if (matchStage && matchStage.$match) {\r\n return matchStage.$match;\r\n }\r\n\r\n return {};\r\n }\r\n\r\n /**\r\n * Execute the aggregate command\r\n */\r\n protected async execute<T extends any = any>(pipeline?: any[]): Promise<T[]> {\r\n const aggregationPipeline = pipeline || this.buildPipeline();\r\n const session = databaseTransactionContext.getSession() as ClientSession | undefined;\r\n const options: AggregateOptions = { session };\r\n\r\n // TODO: Trigger the executing event\r\n const results = (await this.collection\r\n .aggregate(aggregationPipeline, options)\r\n .toArray()) as T[];\r\n\r\n // TODO: Trigger the fetched event\r\n\r\n // we need to cleanup the operations list\r\n this.operations = [];\r\n this.operationsHelper.setOperations(this.operations);\r\n\r\n return results;\r\n }\r\n\r\n // ============================================================================\r\n // RELATIONS / EAGER LOADING (Stubs)\r\n // ============================================================================\r\n\r\n /**\r\n * Relations to eagerly load.\r\n */\r\n public eagerLoadRelations: Map<string, boolean | ((query: QueryBuilderContract) => void)> =\r\n new Map();\r\n\r\n /**\r\n * Relations to load via $lookup (single query).\r\n */\r\n public joinRelations: Map<string, { alias: string; type: \"belongsTo\" | \"hasOne\" | \"hasMany\" }> =\r\n new Map();\r\n\r\n /**\r\n * Relation definitions from the model.\r\n */\r\n declare public relationDefinitions?: Record<string, any>;\r\n\r\n /**\r\n * Model class reference.\r\n */\r\n declare public modelClass?: any;\r\n\r\n /**\r\n * Load relations using MongoDB $lookup in a single aggregation query.\r\n *\r\n * Unlike `with()` which uses separate queries, `joinWith()` uses\r\n * $lookup to fetch related data in a single aggregation pipeline.\r\n *\r\n * @param relations - Relation names to load via $lookup\r\n * @returns This builder for chaining\r\n */\r\n public joinWith(...relations: string[]): this {\r\n for (const relation of relations) {\r\n const def = this.relationDefinitions?.[relation];\r\n if (def) {\r\n this.joinRelations.set(relation, {\r\n alias: `_rel_${relation}`,\r\n type: def.type,\r\n });\r\n }\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Eagerly load one or more relations.\r\n *\r\n * Supported patterns:\r\n * - `with(\"posts\")` - Load relation\r\n * - `with(\"posts\", \"comments\")` - Load multiple relations\r\n * - `with(\"posts\", callback)` - Load relation with constraint\r\n * - `with({ posts: true, comments: callback })` - Object configuration\r\n *\r\n * @param args - Relation name(s), callbacks, or configuration object\r\n */\r\n public with(\r\n ...args: (\r\n | string\r\n | Record<string, boolean | ((query: QueryBuilderContract) => void)>\r\n | ((query: QueryBuilderContract) => void)\r\n )[]\r\n ): this {\r\n for (let i = 0; i < args.length; i++) {\r\n const arg = args[i];\r\n\r\n if (typeof arg === \"string\") {\r\n // Check if next argument is a callback for this relation\r\n const nextArg = args[i + 1];\r\n if (typeof nextArg === \"function\") {\r\n this.eagerLoadRelations.set(arg, nextArg);\r\n i++; // Skip the callback in next iteration\r\n } else {\r\n this.eagerLoadRelations.set(arg, true);\r\n }\r\n } else if (typeof arg === \"object\" && arg !== null) {\r\n for (const [key, value] of Object.entries(arg)) {\r\n this.eagerLoadRelations.set(key, value);\r\n }\r\n }\r\n // Functions not preceded by a string are ignored (invalid usage)\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Filter results to only those that have related models.\r\n * @param relation - Relation name\r\n * @param operator - Optional comparison operator\r\n * @param count - Optional count to compare against\r\n */\r\n public has(relation: string, operator?: string, count?: number): this {\r\n // TODO: Implement has() using $lookup and $match\r\n this.operationsHelper.addMatchOperation(\"has\", { relation, operator, count });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filter results that have related models matching specific conditions.\r\n * @param relation - Relation name\r\n * @param callback - Callback to define conditions\r\n */\r\n public whereHas(relation: string, callback: (query: QueryBuilderContract) => void): this {\r\n // TODO: Implement whereHas() using $lookup with pipeline\r\n this.operationsHelper.addMatchOperation(\"whereHas\", { relation, callback });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filter results that don't have any related models.\r\n * @param relation - Relation name\r\n */\r\n public doesntHave(relation: string): this {\r\n // TODO: Implement doesntHave() using $lookup and $match\r\n this.operationsHelper.addMatchOperation(\"doesntHave\", { relation });\r\n return this;\r\n }\r\n\r\n /**\r\n * Filter results that don't have related models matching specific conditions.\r\n * @param relation - Relation name\r\n * @param callback - Callback to define conditions\r\n */\r\n public whereDoesntHave(relation: string, callback: (query: QueryBuilderContract) => void): this {\r\n // TODO: Implement whereDoesntHave() using $lookup with pipeline\r\n this.operationsHelper.addMatchOperation(\"whereDoesntHave\", { relation, callback });\r\n return this;\r\n }\r\n\r\n /**\r\n * Nearest-neighbour vector similarity search via MongoDB Atlas $vectorSearch.\r\n *\r\n * Adds two pipeline stages:\r\n * 1. `$vectorSearch` — runs the ANN search using the Atlas vector index.\r\n * Must be the first stage in the pipeline. Limit is embedded here.\r\n * 2. `$addFields` — exposes `{ $meta: \"vectorSearchScore\" }` under `alias`\r\n * so callers can filter by minimum score after `.get()`.\r\n *\r\n * **Prerequisites:**\r\n * - MongoDB Atlas cluster (local/Community MongoDB does NOT support $vectorSearch)\r\n * - A vector search index on the collection, e.g.:\r\n * `{ \"fields\": [{ \"type\": \"vector\", \"path\": \"embedding\", \"numDimensions\": 1536, \"similarity\": \"cosine\" }] }`\r\n * - The index name convention used here is `\"${column}_index\"` (override via `alias` if needed).\r\n *\r\n * @param column - Vector column name (e.g. `\"embedding\"`)\r\n * @param embedding - Query embedding as a plain number array\r\n * @param alias - Score alias added to each result row (default: `\"score\"`)\r\n *\r\n * @example\r\n * ```typescript\r\n * const results = await Vector.query()\r\n * .where({ organization_id: \"org-123\" })\r\n * .similarTo(\"embedding\", queryEmbedding)\r\n * .limit(5)\r\n * .get<VectorRow & { score: number }>();\r\n * ```\r\n */\r\n public similarTo(column: string, embedding: number[], alias = \"score\"): this {\r\n // Grab the limit op recorded so far (default to 10 if not set yet)\r\n const limitOp = this.operations.find((op) => op.type === \"limit\");\r\n const limit = (limitOp?.data?.value as number) ?? 10;\r\n\r\n // Stage 1: $vectorSearch — ANN search via Atlas vector index\r\n this.operationsHelper.addOperation(\r\n \"$vectorSearch\",\r\n \"vectorSearch\",\r\n {\r\n index: `${column}_index`,\r\n path: column,\r\n queryVector: embedding,\r\n numCandidates: limit * 10, // Atlas recommendation: 10–20x the limit\r\n limit,\r\n },\r\n false, // Not mergeable — must stay as its own stage\r\n );\r\n\r\n // Stage 2: $addFields — expose vectorSearchScore as the score alias\r\n this.operationsHelper.addOperation(\r\n \"$addFields\",\r\n \"vectorSearchScore\",\r\n { [alias]: { $meta: \"vectorSearchScore\" } },\r\n false,\r\n );\r\n\r\n return this;\r\n }\r\n}\r\n","/**\n * MongoDB-specific sync adapter implementation.\n *\n * @module cascade-next/drivers/mongodb/mongodb-sync-adapter\n */\n\nimport type { SyncAdapterContract, SyncInstruction } from \"../../contracts/sync-adapter.contract\";\nimport type { MongoDbDriver } from \"./mongodb-driver\";\n\n/**\n * MongoDB implementation of the sync adapter.\n * Handles array updates using positional operators and arrayFilters.\n * Automatically participates in active transactions via the driver's session context.\n */\nexport class MongoSyncAdapter implements SyncAdapterContract {\n private readonly driver: MongoDbDriver;\n\n /**\n * Creates a new MongoDB sync adapter.\n *\n * @param driver - The MongoDB driver instance (provides session-aware operations)\n */\n public constructor(driver: MongoDbDriver) {\n this.driver = driver;\n }\n\n /**\n * Executes a batch of sync instructions.\n *\n * @param instructions - Array of sync instructions\n * @returns Total number of documents affected\n */\n public async executeBatch(instructions: SyncInstruction[]): Promise<number> {\n let totalAffected = 0;\n\n for (const instruction of instructions) {\n const affected = instruction.isArrayUpdate\n ? await this.executeArrayUpdate(instruction)\n : await this.executeOne(instruction);\n\n totalAffected += affected;\n }\n\n return totalAffected;\n }\n\n /**\n * Executes a single sync instruction.\n * Uses the driver's updateMany to automatically participate in active transactions.\n *\n * @param instruction - The sync instruction\n * @returns Number of documents affected\n */\n public async executeOne(instruction: SyncInstruction): Promise<number> {\n const result = await this.driver.updateMany(\n instruction.targetTable,\n instruction.filter,\n instruction.update,\n );\n\n return result.modifiedCount;\n }\n\n /**\n * Executes an array update using MongoDB positional operators.\n * Uses the driver's updateMany to automatically participate in active transactions.\n *\n * @param instruction - The sync instruction with array info\n * @returns Number of documents affected\n */\n public async executeArrayUpdate(instruction: SyncInstruction): Promise<number> {\n if (!instruction.arrayField || !instruction.identifierField) {\n throw new Error(\"Array update requires arrayField and identifierField to be specified\");\n }\n\n // Strategy 1: Try positional operator $ (simpler, faster)\n // Works when filter already identifies the array element\n if (this.canUsePositionalOperator(instruction)) {\n const result = await this.driver.updateMany(\n instruction.targetTable,\n instruction.filter,\n instruction.update,\n );\n return result.modifiedCount;\n }\n\n // Strategy 2: Use arrayFilters (more flexible)\n // Works for any array update scenario\n return await this.executeWithArrayFilters(instruction);\n }\n\n /**\n * Checks if positional operator $ can be used.\n * Requires filter to already match the array element.\n *\n * @param instruction - The sync instruction\n * @returns True if positional operator can be used\n */\n private canUsePositionalOperator(instruction: SyncInstruction): boolean {\n // Check if filter already includes array element match\n const arrayElementFilter = `${instruction.arrayField}.${instruction.identifierField}`;\n return arrayElementFilter in instruction.filter;\n }\n\n /**\n * Executes array update using arrayFilters.\n * Uses the driver's updateMany with arrayFilters option to participate in transactions.\n *\n * @param instruction - The sync instruction\n * @returns Number of documents affected\n */\n private async executeWithArrayFilters(instruction: SyncInstruction): Promise<number> {\n // Build arrayFilters to match array elements\n const arrayFilters = [\n {\n [`elem.${instruction.identifierField}`]: instruction.identifierValue,\n },\n ];\n\n // Transform update to use array filter placeholder\n const transformedUpdate = this.transformUpdateForArrayFilters(\n instruction.update,\n instruction.arrayField!,\n );\n\n // Build optimized filter to reduce documents scanned\n const optimizedFilter = this.buildOptimizedFilter(\n instruction.filter,\n instruction.arrayField!,\n instruction.identifierField!,\n );\n\n // Use driver's updateMany (session-aware) with arrayFilters\n const result = await this.driver.updateMany(\n instruction.targetTable,\n optimizedFilter,\n transformedUpdate,\n { arrayFilters },\n );\n\n return result.modifiedCount;\n }\n\n /**\n * Builds an optimized filter to reduce the number of documents scanned.\n * Adds array existence check when filter doesn't already match array elements.\n *\n * @param originalFilter - The original filter from the instruction\n * @param arrayField - The array field path\n * @param identifierField - The identifier field within array elements\n * @returns Optimized filter\n */\n private buildOptimizedFilter(\n originalFilter: Record<string, unknown>,\n arrayField: string,\n identifierField: string,\n ): Record<string, unknown> {\n // If filter already has array element match, use it as-is\n const arrayElementFilter = `${arrayField}.${identifierField}`;\n if (arrayElementFilter in originalFilter) {\n return originalFilter;\n }\n\n // Otherwise, add array existence check to avoid full collection scan\n return {\n ...originalFilter,\n [arrayField]: { $exists: true, $ne: [] }, // Array exists and not empty\n };\n }\n\n /**\n * Transforms update operation to use arrayFilters placeholder.\n *\n * @param update - Original update operation\n * @param arrayField - Array field path\n * @returns Transformed update operation\n */\n private transformUpdateForArrayFilters(\n update: Record<string, unknown>,\n arrayField: string,\n ): Record<string, unknown> {\n const transformed: Record<string, unknown> = {};\n\n for (const [operator, fields] of Object.entries(update)) {\n if (typeof fields === \"object\" && fields !== null) {\n const transformedFields: Record<string, unknown> = {};\n\n for (const [field, value] of Object.entries(fields)) {\n // Replace positional $ with arrayFilters placeholder $[elem]\n const transformedField = field.replace(`${arrayField}.$`, `${arrayField}.$[elem]`);\n transformedFields[transformedField] = value;\n }\n\n transformed[operator] = transformedFields;\n }\n }\n\n return transformed;\n }\n}\n","import { colors } from \"@mongez/copper\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport type {\r\n BulkWriteOptions,\r\n ClientSession,\r\n Db,\r\n DeleteOptions,\r\n FindOneAndDeleteOptions,\r\n FindOneAndUpdateOptions,\r\n InsertManyResult,\r\n InsertOneOptions,\r\n MongoClient,\r\n MongoClientOptions,\r\n TransactionOptions,\r\n UpdateFilter,\r\n UpdateOptions,\r\n} from \"mongodb\";\r\nimport { EventEmitter } from \"node:events\";\r\nimport { databaseTransactionContext } from \"../../context/database-transaction-context\";\r\nimport type {\r\n DriverBlueprintContract,\r\n DriverContract,\r\n DriverEvent,\r\n DriverEventListener,\r\n DriverTransactionContract,\r\n IdGeneratorContract,\r\n InsertResult,\r\n MigrationDriverContract,\r\n QueryBuilderContract,\r\n SyncAdapterContract,\r\n TransactionContext,\r\n UpdateOperations,\r\n UpdateResult,\r\n} from \"../../contracts\";\r\nimport { dataSourceRegistry } from \"../../data-source/data-source-registry\";\r\nimport { DatabaseDirtyTracker } from \"../../database-dirty-tracker\";\r\nimport { TransactionRollbackError } from \"../../errors/transaction-rollback.error\";\r\nimport { type SQLSerializer } from \"../../migration/sql-serializer\";\r\nimport type { ModelDefaults } from \"../../types\";\r\nimport { isValidDateValue } from \"../../utils/is-valid-date-value\";\r\nimport { MongoDBBlueprint } from \"./mongodb-blueprint\";\r\nimport { MongoIdGenerator } from \"./mongodb-id-generator\";\r\nimport { MongoMigrationDriver } from \"./mongodb-migration-driver\";\r\nimport { MongoQueryBuilder } from \"./mongodb-query-builder\";\r\nimport { MongoSyncAdapter } from \"./mongodb-sync-adapter\";\r\nimport type { MongoDriverOptions } from \"./types\";\r\n\r\nconst DEFAULT_TRANSACTION_OPTIONS: TransactionOptions = {\r\n readPreference: \"primary\",\r\n readConcern: { level: \"local\" },\r\n writeConcern: { w: \"majority\" },\r\n};\r\n\r\n// ============================================================\r\n// Lazy-loaded MongoDB SDK Types\r\n// ============================================================\r\n\r\n/**\r\n * Cached MongoDB module (loaded once, reused)\r\n */\r\nlet MongoDBClient: typeof import(\"mongodb\");\r\n\r\nlet ObjectId: typeof import(\"mongodb\").ObjectId;\r\n\r\nlet isModuleExists: boolean | null = null;\r\n\r\nlet loadingPromise: Promise<any>;\r\n\r\n/**\r\n * Installation instructions for MongoDB package\r\n */\r\nconst MONGODB_INSTALL_INSTRUCTIONS = `\r\nMongoDB driver requires the mongodb package.\r\nInstall it with:\r\n\r\n npm install mongodb\r\n\r\nOr with your preferred package manager:\r\n\r\n pnpm add mongodb\r\n yarn add mongodb\r\n`.trim();\r\n\r\n/**\r\n * Load MongoDB module\r\n */\r\nasync function loadMongoDB() {\r\n try {\r\n loadingPromise = import(\"mongodb\");\r\n MongoDBClient = await loadingPromise;\r\n ObjectId = MongoDBClient.ObjectId;\r\n isModuleExists = true;\r\n } catch {\r\n isModuleExists = false;\r\n }\r\n}\r\n\r\nloadMongoDB();\r\n\r\nexport function isMongoDBDriverLoaded() {\r\n return isModuleExists;\r\n}\r\n\r\nasync function assertModuleIsLoaded() {\r\n if (isModuleExists === false) {\r\n throw new Error(MONGODB_INSTALL_INSTRUCTIONS);\r\n }\r\n\r\n if (isModuleExists === null) {\r\n await loadingPromise;\r\n\r\n return await assertModuleIsLoaded();\r\n }\r\n}\r\n\r\n/**\r\n * MongoDB driver implementation that fulfils the Cascade driver contract.\r\n *\r\n * It encapsulates the native Mongo client, exposes lifecycle events, and\r\n * provides helpers for CRUD, transactions, atomic updates, and sync adapters.\r\n */\r\nexport class MongoDbDriver implements DriverContract {\r\n private readonly events = new EventEmitter();\r\n public client?: MongoClient;\r\n public database?: Db;\r\n private connected = false;\r\n private syncAdapterInstance?: MongoSyncAdapter;\r\n private migrationDriverInstance?: MigrationDriverContract;\r\n private readonly transactionOptions: TransactionOptions;\r\n private idGeneratorInstance?: IdGeneratorContract;\r\n private _blueprint?: DriverBlueprintContract;\r\n\r\n public get blueprint(): DriverBlueprintContract {\r\n if (!this._blueprint) {\r\n this._blueprint = new MongoDBBlueprint(this.database!);\r\n }\r\n\r\n return this._blueprint!;\r\n }\r\n\r\n /**\r\n * The name of this driver.\r\n */\r\n public readonly name = \"mongodb\";\r\n\r\n /**\r\n * Current database name\r\n */\r\n protected _databaseName?: string;\r\n\r\n /**\r\n * MongoDB driver model defaults.\r\n *\r\n * MongoDB follows NoSQL conventions:\r\n * - camelCase naming for fields (createdAt, updatedAt, deletedAt)\r\n * - Manual ID generation (auto-increment id field separate from _id)\r\n * - Timestamps enabled by default\r\n * - Trash delete strategy with per-collection trash tables\r\n */\r\n public readonly modelDefaults: Partial<ModelDefaults> = {\r\n namingConvention: \"camelCase\",\r\n createdAtColumn: \"createdAt\",\r\n updatedAtColumn: \"updatedAt\",\r\n deletedAtColumn: \"deletedAt\",\r\n timestamps: true,\r\n autoGenerateId: true, // MongoDB needs manual ID generation\r\n strictMode: \"strip\",\r\n deleteStrategy: \"trash\",\r\n trashTable: (table) => `${table}Trash`, // Per-collection trash (usersTrash, productsTrash)\r\n };\r\n\r\n /**\r\n * Create a new MongoDB driver using the supplied connection options.\r\n *\r\n * @param config - Connection configuration\r\n * @param driverOptions - Driver-specific options\r\n */\r\n public constructor(\r\n private readonly config: {\r\n database: string;\r\n uri?: string;\r\n host?: string;\r\n port?: number;\r\n username?: string;\r\n password?: string;\r\n authSource?: string;\r\n logging?: boolean;\r\n clientOptions?: MongoClientOptions;\r\n },\r\n private readonly driverOptions?: MongoDriverOptions,\r\n ) {\r\n this.transactionOptions = {\r\n ...DEFAULT_TRANSACTION_OPTIONS,\r\n ...driverOptions?.transactionOptions,\r\n };\r\n }\r\n\r\n /**\r\n * Get data base name\r\n */\r\n public get databaseName(): string | undefined {\r\n if (!this._databaseName) {\r\n this.resolveDatabaseName();\r\n }\r\n\r\n return this._databaseName;\r\n }\r\n\r\n /**\r\n * Resolve database name either from config or uri\r\n */\r\n private resolveDatabaseName() {\r\n if (this.config.database) {\r\n this._databaseName = this.config.database;\r\n } else if (this.config.uri) {\r\n this._databaseName = this.config.uri.split(\"/\").pop()?.split(\"?\")?.[0];\r\n }\r\n }\r\n\r\n /**\r\n * Indicates whether the driver currently maintains an active connection.\r\n */\r\n public get isConnected(): boolean {\r\n return this.connected;\r\n }\r\n\r\n /**\r\n * Get the MongoDB database instance.\r\n *\r\n * @returns The MongoDB Db instance\r\n * @throws {Error} If not connected\r\n *\r\n * @example\r\n * ```typescript\r\n * const db = driver.getDatabase();\r\n * const collection = db.collection(\"users\");\r\n * ```\r\n */\r\n public getDatabase(): Db {\r\n if (!this.database) {\r\n throw new Error(\r\n \"Database not available. Ensure the driver is connected before accessing the database.\",\r\n );\r\n }\r\n return this.database;\r\n }\r\n\r\n /**\r\n * Get the ID generator instance for this driver.\r\n *\r\n * Creates a MongoIdGenerator on first access if autoGenerateId is enabled.\r\n *\r\n * @returns The ID generator instance, or undefined if disabled\r\n *\r\n * @example\r\n * ```typescript\r\n * const idGenerator = driver.getIdGenerator();\r\n * if (idGenerator) {\r\n * const id = await idGenerator.generateNextId({ table: \"users\" });\r\n * }\r\n * ```\r\n */\r\n public getIdGenerator(): IdGeneratorContract | undefined {\r\n // Return undefined if ID generation is disabled\r\n if (this.driverOptions?.autoGenerateId === false) {\r\n return undefined;\r\n }\r\n\r\n // Create ID generator lazily on first access\r\n if (!this.idGeneratorInstance) {\r\n this.idGeneratorInstance = new MongoIdGenerator(this, this.driverOptions?.counterCollection);\r\n }\r\n\r\n return this.idGeneratorInstance;\r\n }\r\n\r\n /**\r\n * Establish a MongoDB connection using the configured options.\r\n * Throws if the connection attempt fails.\r\n */\r\n public async connect(): Promise<void> {\r\n if (this.connected) {\r\n return;\r\n }\r\n\r\n await assertModuleIsLoaded();\r\n\r\n const uri = this.resolveUri();\r\n\r\n const { MongoClient, ObjectId: ObjectIdMongoDB } = MongoDBClient;\r\n\r\n ObjectId = ObjectIdMongoDB;\r\n\r\n const client = new MongoClient(uri, this.buildClientOptions());\r\n\r\n try {\r\n log.info(\r\n \"database.mongodb\",\r\n \"connection\",\r\n `Connecting to database ${colors.bold(colors.yellowBright(this.databaseName))}`,\r\n );\r\n await client.connect();\r\n this.client = client;\r\n this.database = client.db(this.databaseName);\r\n\r\n this.connected = true;\r\n log.success(\"database.mongodb\", \"connection\", \"Connected to database\");\r\n\r\n client.on(\"close\", () => {\r\n if (this.connected) {\r\n this.connected = false;\r\n this.emit(\"disconnected\");\r\n log.warn(\"database.mongodb\", \"connection\", \"Disconnected from database\");\r\n }\r\n });\r\n\r\n if (this.config.logging) {\r\n const ignoredCommands = [\"isMaster\", \"hello\", \"ping\", \"saslStart\", \"saslContinue\"];\r\n\r\n client.on(\"commandStarted\", (event: any) => {\r\n if (ignoredCommands.includes(event.commandName)) return;\r\n\r\n let cmdStr = JSON.stringify(event.command);\r\n if (cmdStr.length > 300) {\r\n cmdStr = cmdStr.substring(0, 300) + \"...\";\r\n }\r\n\r\n log.info({\r\n module: \"database.mongodb\",\r\n action: \"query.executing\",\r\n message: `[${event.commandName}] ${cmdStr}`,\r\n context: { command: event.command },\r\n });\r\n });\r\n\r\n client.on(\"commandSucceeded\", (event: any) => {\r\n if (ignoredCommands.includes(event.commandName)) return;\r\n\r\n log.success({\r\n module: \"database.mongodb\",\r\n action: \"query.executed\",\r\n message: `[${event.duration.toFixed(2)}ms] [${event.commandName}]`,\r\n });\r\n });\r\n\r\n client.on(\"commandFailed\", (event: any) => {\r\n if (ignoredCommands.includes(event.commandName)) return;\r\n\r\n log.error({\r\n module: \"database.mongodb\",\r\n action: \"query.error\",\r\n message: `[${event.duration.toFixed(2)}ms] [${event.commandName}]`,\r\n context: { failure: event.failure },\r\n });\r\n });\r\n }\r\n\r\n this.emit(\"connected\");\r\n } catch (error: any) {\r\n await client.close().catch(() => undefined);\r\n this.emit(\"disconnected\");\r\n // Boot-time database connection failure is unrecoverable in every\r\n // realistic caller (app boot, CLI migrations, workers) — `fatal` makes\r\n // \"page on fatal only\" alerting clean. Per-query failures stay at error.\r\n log.fatal(\r\n \"database.mongodb\",\r\n \"connection\",\r\n `Failed to connect to database: ${error.message}`,\r\n );\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Close the underlying MongoDB connection.\r\n */\r\n public async disconnect(): Promise<void> {\r\n if (!this.client) {\r\n return;\r\n }\r\n\r\n try {\r\n await this.client.close();\r\n } finally {\r\n this.connected = false;\r\n this.emit(\"disconnected\");\r\n }\r\n }\r\n\r\n /**\r\n * Subscribe to driver lifecycle events.\r\n */\r\n public on(event: DriverEvent, listener: DriverEventListener): void {\r\n this.events.on(event, listener);\r\n }\r\n\r\n /**\r\n * Insert a single document into the given collection.\r\n */\r\n public async insert(\r\n table: string,\r\n document: Record<string, unknown>,\r\n options?: Record<string, unknown>,\r\n ): Promise<InsertResult> {\r\n const collection = this.getDatabaseInstance().collection(table);\r\n const mongoOptions = this.withSession<InsertOneOptions>(options);\r\n const result = await collection.insertOne(document, mongoOptions);\r\n\r\n return {\r\n document: {\r\n ...document,\r\n _id: result.insertedId,\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Insert multiple documents into the given collection.\r\n */\r\n public async insertMany(\r\n table: string,\r\n documents: Record<string, unknown>[],\r\n options?: Record<string, unknown>,\r\n ): Promise<InsertResult[]> {\r\n const collection = this.getDatabaseInstance().collection(table);\r\n const mongoOptions = this.withSession<BulkWriteOptions>(options);\r\n const result: InsertManyResult<Record<string, unknown>> = await collection.insertMany(\r\n documents,\r\n mongoOptions,\r\n );\r\n\r\n return documents.map((document, index) => {\r\n const insertedId = result.insertedIds[index as unknown as keyof typeof result.insertedIds];\r\n\r\n return {\r\n document: {\r\n ...document,\r\n _id: insertedId,\r\n },\r\n };\r\n });\r\n }\r\n\r\n /**\r\n * Update a single document that matches the provided filter.\r\n */\r\n public async update(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n update: Record<string, unknown>,\r\n options?: Record<string, unknown>,\r\n ): Promise<UpdateResult> {\r\n const collection = this.getDatabaseInstance().collection(table);\r\n const mongoOptions = this.withSession<UpdateOptions>(options);\r\n const result = await collection.updateOne(\r\n filter,\r\n update as UpdateFilter<Record<string, unknown>>,\r\n mongoOptions,\r\n );\r\n\r\n return { modifiedCount: result.modifiedCount };\r\n }\r\n\r\n /**\r\n * Replace a single document that matches the provided filter.\r\n */\r\n public async replace<T = unknown>(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n document: Record<string, unknown>,\r\n options?: Record<string, unknown>,\r\n ): Promise<T | null> {\r\n const collection = this.getDatabaseInstance().collection(table);\r\n const result = await collection.findOneAndReplace(filter, document as Record<string, unknown>);\r\n\r\n return result?.value as T | null;\r\n }\r\n\r\n /**\r\n * Find one and update a single document that matches the provided filter and return the updated document\r\n */\r\n public async findOneAndUpdate<T = unknown>(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n update: UpdateOperations,\r\n options?: Record<string, unknown>,\r\n ): Promise<T | null> {\r\n const collection = this.getDatabaseInstance().collection(table);\r\n const mongoOptions = this.withSession<FindOneAndUpdateOptions>(options);\r\n const result = await collection.findOneAndUpdate(filter, update as Record<string, unknown>, {\r\n returnDocument: \"after\",\r\n ...mongoOptions,\r\n });\r\n\r\n return result as T | null;\r\n }\r\n\r\n /**\r\n * Upsert (insert or update) a single document.\r\n *\r\n * Uses MongoDB's findOneAndUpdate with upsert option.\r\n *\r\n * @param table - Target collection name\r\n * @param filter - Filter conditions to find existing document\r\n * @param document - Document data to insert or update\r\n * @param options - Optional upsert options\r\n * @returns The upserted document\r\n */\r\n public async upsert<T = unknown>(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n document: Record<string, unknown>,\r\n options?: Record<string, unknown>,\r\n ): Promise<T> {\r\n const collection = this.getDatabaseInstance().collection(table);\r\n const mongoOptions = this.withSession<FindOneAndUpdateOptions>(options);\r\n\r\n // Use $set to update all fields from document\r\n const update = { $set: document };\r\n\r\n const result = await collection.findOneAndUpdate(filter, update, {\r\n upsert: true,\r\n returnDocument: \"after\",\r\n ...mongoOptions,\r\n });\r\n\r\n return result as T;\r\n }\r\n\r\n /**\r\n * Find one and delete a single document that matches the provided filter and return the deleted document.\r\n *\r\n * @param table - Target collection name\r\n * @param filter - Filter conditions\r\n * @param options - Optional delete options\r\n * @returns The deleted document or null if not found\r\n */\r\n public async findOneAndDelete<T = unknown>(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n options?: Record<string, unknown>,\r\n ): Promise<T | null> {\r\n const collection = this.getDatabaseInstance().collection(table);\r\n const mongoOptions = this.withSession<FindOneAndDeleteOptions>(options);\r\n\r\n const result = await collection.findOneAndDelete(filter, mongoOptions || {});\r\n\r\n return result as T | null;\r\n }\r\n\r\n /**\r\n * Update multiple documents that match the provided filter.\r\n */\r\n public async updateMany(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n update: UpdateOperations,\r\n options?: Record<string, unknown>,\r\n ): Promise<UpdateResult> {\r\n const collection = this.getDatabaseInstance().collection(table);\r\n const mongoOptions = this.withSession<UpdateOptions>(options);\r\n const result = await collection.updateMany(\r\n filter,\r\n update as UpdateFilter<Record<string, unknown>>,\r\n mongoOptions,\r\n );\r\n\r\n return { modifiedCount: result.modifiedCount };\r\n }\r\n\r\n /**\r\n * Delete a single document that matches the provided filter.\r\n */\r\n public async delete(\r\n table: string,\r\n filter: Record<string, unknown> = {},\r\n options?: Record<string, unknown>,\r\n ): Promise<number> {\r\n const collection = this.getDatabaseInstance().collection(table);\r\n const mongoOptions = this.withSession<DeleteOptions>(options);\r\n const result = await collection.deleteOne(filter, mongoOptions);\r\n\r\n return result.deletedCount > 0 ? 1 : 0;\r\n }\r\n\r\n /**\r\n * Delete documents that match the provided filter.\r\n */\r\n public async deleteMany(\r\n table: string,\r\n filter: Record<string, unknown> = {},\r\n options?: Record<string, unknown>,\r\n ): Promise<number> {\r\n const collection = this.getDatabaseInstance().collection(table);\r\n const mongoOptions = this.withSession<DeleteOptions>(options);\r\n\r\n const result = await collection.deleteMany(filter, mongoOptions);\r\n\r\n return result.deletedCount ?? 0;\r\n }\r\n\r\n /**\r\n * Remove all records from a collection.\r\n *\r\n * This uses deleteMany with an empty filter to remove all documents.\r\n * For very large collections, consider using the migration driver's\r\n * dropTable + createTable approach for better performance.\r\n */\r\n public async truncateTable(table: string, options?: Record<string, unknown>): Promise<number> {\r\n const collection = this.getDatabaseInstance().collection(table);\r\n const mongoOptions = this.withSession<DeleteOptions>(options);\r\n const result = await collection.deleteMany({}, mongoOptions);\r\n\r\n return result.deletedCount ?? 0;\r\n }\r\n\r\n /**\r\n * Serialize the given data\r\n */\r\n public serialize(data: Record<string, unknown>): Record<string, unknown> {\r\n const serialized: Record<string, unknown> = {};\r\n\r\n for (const [key, value] of Object.entries(data)) {\r\n if (value === undefined) {\r\n continue; // Skip undefined values\r\n }\r\n\r\n if (value instanceof ObjectId) {\r\n serialized[key] = value.toString();\r\n } else if (value instanceof Date) {\r\n serialized[key] = value.toISOString();\r\n } else if (typeof value === \"bigint\") {\r\n serialized[key] = value.toString();\r\n } else if (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\r\n // Nested objects will be stored as JSONB\r\n serialized[key] = value;\r\n } else {\r\n serialized[key] = value;\r\n }\r\n }\r\n\r\n return serialized;\r\n }\r\n\r\n /**\r\n * Get the dirty tracker for this driver.\r\n */\r\n public getDirtyTracker(data: Record<string, unknown>): DatabaseDirtyTracker {\r\n return new DatabaseDirtyTracker(data);\r\n }\r\n\r\n /**\r\n * Deserialize the given data\r\n */\r\n public deserialize(data: Record<string, unknown>): Record<string, unknown> {\r\n if (data._id && typeof data._id === \"string\") {\r\n data._id = new ObjectId(data._id);\r\n }\r\n\r\n for (const [key, value] of Object.entries(data)) {\r\n // Only re-inflate strings — Mongo driver already returns Date objects from DB reads\r\n if (typeof value === \"string\" && isValidDateValue(value)) {\r\n data[key] = new Date(value);\r\n }\r\n }\r\n\r\n return data;\r\n }\r\n\r\n /**\r\n * Provide a Mongo-backed query builder instance for the given collection.\r\n */\r\n public queryBuilder<T = unknown>(table: string): QueryBuilderContract<T> {\r\n return new MongoQueryBuilder(table, dataSourceRegistry.get());\r\n }\r\n\r\n /**\r\n * Begin a MongoDB transaction, returning commit/rollback helpers.\r\n */\r\n public async beginTransaction(): Promise<DriverTransactionContract<ClientSession>> {\r\n const client = this.getClientInstance();\r\n const session = client.startSession();\r\n\r\n await session.startTransaction(this.transactionOptions);\r\n databaseTransactionContext.enter({ session });\r\n let finished = false;\r\n\r\n const finalize = async (operation: () => Promise<void>): Promise<void> => {\r\n if (finished) return;\r\n\r\n try {\r\n await operation();\r\n } finally {\r\n finished = true;\r\n databaseTransactionContext.exit();\r\n await session.endSession().catch(() => undefined);\r\n }\r\n };\r\n\r\n return {\r\n context: session,\r\n commit: async () => {\r\n await finalize(async () => {\r\n try {\r\n await session.commitTransaction();\r\n } catch (error) {\r\n await session.abortTransaction().catch(() => undefined);\r\n throw error;\r\n }\r\n });\r\n },\r\n rollback: async () => {\r\n await finalize(async () => {\r\n await session.abortTransaction();\r\n });\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Execute a function within a transaction scope (recommended pattern).\r\n *\r\n * Automatically commits on success, rolls back on any error, and guarantees\r\n * resource cleanup. This is the recommended way to use transactions.\r\n *\r\n * **MongoDB Requirements:**\r\n * - Requires MongoDB 4.0+ with replica set or sharded cluster\r\n * - Standalone MongoDB instances do not support transactions\r\n *\r\n * @param fn - Async function to execute within transaction\r\n * @param options - Transaction options (read preference, write concern, etc.)\r\n * @returns The return value of the callback function\r\n * @throws {Error} If transaction fails, is explicitly rolled back, or replica set not configured\r\n */\r\n public async transaction<T>(\r\n fn: (ctx: TransactionContext) => Promise<T>,\r\n options?: Record<string, unknown>,\r\n ): Promise<T> {\r\n // Prevent nested transaction() calls\r\n if (databaseTransactionContext.hasActiveTransaction()) {\r\n throw new Error(\r\n \"Nested transaction() calls are not supported. \" +\r\n \"Use beginTransaction() with savepoints for advanced transaction patterns.\",\r\n );\r\n }\r\n\r\n // Check if MongoDB is running as a replica set (required for transactions)\r\n await this.ensureReplicaSetAvailable();\r\n\r\n const client = this.getClientInstance();\r\n const session = client.startSession();\r\n\r\n try {\r\n await session.startTransaction({\r\n ...this.transactionOptions,\r\n ...(options as TransactionOptions),\r\n });\r\n\r\n // Set transaction context for queries within callback\r\n databaseTransactionContext.enter({ session });\r\n\r\n try {\r\n // Create transaction context with rollback method\r\n const ctx: TransactionContext = {\r\n rollback(reason?: string): never {\r\n throw new TransactionRollbackError(reason);\r\n },\r\n };\r\n\r\n // Execute callback\r\n const result = await fn(ctx);\r\n\r\n // Auto-commit on success\r\n await session.commitTransaction();\r\n\r\n return result;\r\n } catch (error) {\r\n // Auto-rollback on any error (including explicit rollback)\r\n await session.abortTransaction().catch(() => undefined);\r\n throw error;\r\n } finally {\r\n // Guaranteed context cleanup\r\n databaseTransactionContext.exit();\r\n }\r\n } finally {\r\n // Guaranteed session cleanup\r\n await session.endSession().catch(() => undefined);\r\n }\r\n }\r\n\r\n /**\r\n * Execute atomic operations (typically $inc/$set style updates) against documents.\r\n *\r\n * Uses `updateMany` so callers can atomically modify any set of documents.\r\n */\r\n public async atomic(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n operations: Record<string, unknown>,\r\n options?: Record<string, unknown>,\r\n ): Promise<UpdateResult> {\r\n const collection = this.getDatabaseInstance().collection(table);\r\n const mongoOptions = this.withSession<UpdateOptions>(options);\r\n const result = await collection.updateMany(\r\n filter,\r\n operations as UpdateFilter<Record<string, unknown>>,\r\n mongoOptions,\r\n );\r\n\r\n return { modifiedCount: result.modifiedCount };\r\n }\r\n\r\n /**\r\n * Lazily create (and cache) the Mongo sync adapter.\r\n * The adapter uses this driver instance to ensure all operations\r\n * participate in active transactions via the session context.\r\n */\r\n public syncAdapter(): SyncAdapterContract {\r\n if (!this.syncAdapterInstance) {\r\n this.syncAdapterInstance = new MongoSyncAdapter(this);\r\n }\r\n\r\n return this.syncAdapterInstance;\r\n }\r\n\r\n /**\r\n * Lazily create (and cache) the Mongo migration driver.\r\n * The migration driver handles schema operations like indexes, collections, etc.\r\n */\r\n public migrationDriver(): MigrationDriverContract {\r\n if (!this.migrationDriverInstance) {\r\n this.migrationDriverInstance = new MongoMigrationDriver(this);\r\n }\r\n\r\n return this.migrationDriverInstance!;\r\n }\r\n\r\n /**\r\n * Expose the underlying Mongo client for advanced consumers.\r\n */\r\n public getClient<Client = MongoClient>(): Client {\r\n return this.getClientInstance() as Client;\r\n }\r\n\r\n /**\r\n * Retrieve the active Mongo client, throwing if the driver is disconnected.\r\n */\r\n private getClientInstance(): MongoClient {\r\n if (!this.client) {\r\n throw new Error(\"Mongo driver is not connected.\");\r\n }\r\n\r\n return this.client;\r\n }\r\n\r\n /**\r\n * Retrieve the active Mongo database, throwing if the driver is disconnected.\r\n * @private\r\n */\r\n private getDatabaseInstance(): Db {\r\n if (!this.database) {\r\n throw new Error(\"Mongo driver is not connected to a database.\");\r\n }\r\n\r\n return this.database;\r\n }\r\n\r\n /**\r\n * Resolve the Mongo connection string based on provided options.\r\n */\r\n private resolveUri(): string {\r\n if (this.config.uri) {\r\n return this.config.uri;\r\n }\r\n\r\n const host = this.config.host ?? \"localhost\";\r\n const port = this.config.port ?? 27017;\r\n\r\n return `mongodb://${host}:${port}`;\r\n }\r\n\r\n /**\r\n * Build the Mongo client options derived from the driver configuration.\r\n */\r\n private buildClientOptions(): MongoClientOptions {\r\n const baseOptions: MongoClientOptions = {\r\n ...(this.config.clientOptions ?? {}),\r\n };\r\n\r\n if (this.config.logging) {\r\n baseOptions.monitorCommands = true;\r\n }\r\n\r\n if (this.config.username && !baseOptions.auth) {\r\n baseOptions.auth = {\r\n username: this.config.username,\r\n password: this.config.password,\r\n };\r\n }\r\n\r\n if (this.config.authSource && !baseOptions.authSource) {\r\n baseOptions.authSource = this.config.authSource;\r\n }\r\n\r\n return baseOptions;\r\n }\r\n\r\n /**\r\n * Emit a driver lifecycle event.\r\n */\r\n private emit(event: DriverEvent, ...args: unknown[]): void {\r\n this.events.emit(event, ...args);\r\n }\r\n\r\n /**\r\n * Ensure MongoDB is running as a replica set (required for transactions).\r\n *\r\n * @throws {Error} If MongoDB is running as a standalone instance\r\n */\r\n private async ensureReplicaSetAvailable(): Promise<void> {\r\n try {\r\n const admin = this.database!.admin();\r\n const status = await admin.serverStatus();\r\n\r\n if (!status.repl) {\r\n throw new Error(\r\n \"MongoDB transactions require a replica set or sharded cluster. \" +\r\n \"Standalone MongoDB instances do not support transactions.\\n\\n\" +\r\n \"For local development:\\n\" +\r\n \" - Run MongoDB with --replSet flag: mongod --replSet rs0\\n\" +\r\n \" - Or use Docker with replica set configuration\\n\" +\r\n \" - Or use MongoDB Atlas (cloud) which provides replica sets by default\",\r\n );\r\n }\r\n } catch (error: any) {\r\n if (error.message?.includes(\"replica set\")) {\r\n throw error;\r\n }\r\n throw new Error(`Failed to check MongoDB replica set status: ${error.message}`);\r\n }\r\n }\r\n\r\n /**\r\n * Attach the active transaction session (when available) to Mongo options.\r\n */\r\n private withSession<TOptions extends { session?: ClientSession }>(\r\n options?: Record<string, unknown>,\r\n ): TOptions | undefined {\r\n const session = databaseTransactionContext.getSession<ClientSession>();\r\n\r\n if (!session) {\r\n return options as TOptions | undefined;\r\n }\r\n\r\n const baseOptions = options ? ({ ...options } as TOptions) : ({} as TOptions);\r\n\r\n baseOptions.session = session;\r\n\r\n return baseOptions;\r\n }\r\n\r\n // ============================================================\r\n // SQL Compatibility Operations (Not supported in MongoDB)\r\n // ============================================================\r\n\r\n /**\r\n * Return a SQL serializer for this driver's dialect.\r\n * Not supported for MongoDB.\r\n */\r\n public getSQLSerializer(): SQLSerializer {\r\n throw new Error(\"MongoDB driver does not support SQL serialization.\");\r\n }\r\n\r\n /**\r\n * Execute a raw SQL query.\r\n * Not supported for MongoDB.\r\n */\r\n public async query<T = unknown>(_sql: string, _params?: unknown[]): Promise<any> {\r\n throw new Error(\"MongoDB driver does not support raw SQL queries.\");\r\n }\r\n\r\n // ============================================================\r\n // Database Lifecycle Operations\r\n // ============================================================\r\n\r\n /**\r\n * Create a new database.\r\n *\r\n * In MongoDB, databases are created automatically when data is first written.\r\n * This method creates an empty collection to ensure the database exists.\r\n *\r\n * @param name - Database name to create\r\n * @returns true if created, false if already exists\r\n */\r\n public async createDatabase(name: string): Promise<boolean> {\r\n const client = this.getClientInstance();\r\n\r\n // Check if database already exists\r\n if (await this.databaseExists(name)) {\r\n return false;\r\n }\r\n\r\n try {\r\n // MongoDB creates databases on first write, so create a system collection\r\n const db = client.db(name);\r\n await db.createCollection(\"__init__\");\r\n // Drop the temp collection\r\n await db.collection(\"__init__\").drop();\r\n\r\n log.success(\"database\", \"lifecycle\", `Created database ${name}`);\r\n return true;\r\n } catch (error) {\r\n log.error(\"database\", \"lifecycle\", `Failed to create database ${name}: ${error}`);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Drop a database.\r\n *\r\n * @param name - Database name to drop\r\n * @returns true if dropped, false if didn't exist\r\n */\r\n public async dropDatabase(name: string): Promise<boolean> {\r\n const client = this.getClientInstance();\r\n\r\n // Check if database exists\r\n if (!(await this.databaseExists(name))) {\r\n return false;\r\n }\r\n\r\n try {\r\n await client.db(name).dropDatabase();\r\n log.success(\"database\", \"lifecycle\", `Dropped database ${name}`);\r\n return true;\r\n } catch (error) {\r\n log.error(\"database\", \"lifecycle\", `Failed to drop database ${name}: ${error}`);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Check if a database exists.\r\n *\r\n * @param name - Database name to check\r\n * @returns true if database exists\r\n */\r\n public async databaseExists(name: string): Promise<boolean> {\r\n const client = this.getClientInstance();\r\n\r\n const result = await client.db(\"admin\").admin().listDatabases();\r\n return result.databases.some((db) => db.name === name);\r\n }\r\n\r\n /**\r\n * List all databases.\r\n *\r\n * @returns Array of database names\r\n */\r\n public async listDatabases(): Promise<string[]> {\r\n const client = this.getClientInstance();\r\n\r\n const result = await client.db(\"admin\").admin().listDatabases();\r\n return result.databases\r\n .map((db) => db.name)\r\n .filter((name) => ![\"admin\", \"local\", \"config\"].includes(name));\r\n }\r\n\r\n // ============================================================\r\n // Table/Collection Management Operations\r\n // ============================================================\r\n\r\n /**\r\n * Drop a collection.\r\n *\r\n * @param name - Collection name to drop\r\n * @throws Error if collection doesn't exist\r\n */\r\n public async dropTable(name: string): Promise<void> {\r\n const db = this.getDatabaseInstance();\r\n await db.collection(name).drop();\r\n log.success(\"database\", \"collection\", `Dropped collection ${name}`);\r\n }\r\n\r\n /**\r\n * Drop a collection if it exists.\r\n *\r\n * @param name - Collection name to drop\r\n */\r\n public async dropTableIfExists(name: string): Promise<void> {\r\n if (await this.blueprint.tableExists(name)) {\r\n await this.dropTable(name);\r\n }\r\n }\r\n\r\n /**\r\n * Drop all collections in the current database.\r\n *\r\n * Useful for `migrate:fresh` command.\r\n */\r\n public async dropAllTables(): Promise<void> {\r\n const collections = await this.blueprint.listTables();\r\n\r\n if (collections.length === 0) {\r\n return;\r\n }\r\n\r\n const db = this.getDatabaseInstance();\r\n\r\n for (const collection of collections) {\r\n await db.collection(collection).drop();\r\n }\r\n\r\n log.success(\"database\", \"collection\", `Dropped ${collections.length} collections`);\r\n }\r\n}\r\n","/**\n * PostgreSQL Blueprint\n *\n * Implements the DriverBlueprintContract for querying PostgreSQL\n * information schema metadata.\n *\n * @module cascade/drivers/postgres\n */\n\nimport type {\n DriverBlueprintContract,\n TableIndexInformation,\n} from \"../../contracts/driver-blueprint.contract\";\nimport type { PostgresDriver } from \"./postgres-driver\";\n\n/**\n * PostgreSQL Blueprint.\n *\n * Provides methods for introspecting the database schema\n * via PostgreSQL's information_schema and pg_catalog.\n *\n * @example\n * ```typescript\n * const blueprint = driver.blueprint;\n *\n * // Get all tables\n * const tables = await blueprint.listTables();\n *\n * // Get columns for a table\n * const columns = await blueprint.listColumns('users');\n * ```\n */\nexport class PostgresBlueprint implements DriverBlueprintContract {\n /**\n * Create a new blueprint.\n *\n * @param driver - The PostgreSQL driver instance\n */\n public constructor(private readonly driver: PostgresDriver) {}\n\n /**\n * Get all table names in the database.\n *\n * @returns Array of table names\n */\n public async listTables(): Promise<string[]> {\n const result = await this.driver.query<{ table_name: string }>(\n `SELECT table_name \n FROM information_schema.tables \n WHERE table_schema = 'public' \n AND table_type = 'BASE TABLE'\n ORDER BY table_name`,\n );\n\n return result.rows.map((row) => row.table_name);\n }\n\n /**\n * Get all indexes for a table.\n *\n * @param table - Table name\n * @returns Array of index information\n */\n public async listIndexes(table: string): Promise<TableIndexInformation[]> {\n const result = await this.driver.query<{\n indexname: string;\n indexdef: string;\n }>(\n `SELECT indexname, indexdef\n FROM pg_indexes\n WHERE schemaname = 'public'\n AND tablename = $1`,\n [table],\n );\n\n return result.rows.map((row) => {\n const isUnique = row.indexdef.includes(\"UNIQUE\");\n const isPrimary = row.indexname.endsWith(\"_pkey\");\n\n // Extract columns from indexdef\n const columnsMatch = row.indexdef.match(/\\(([^)]+)\\)/);\n const columns = columnsMatch\n ? columnsMatch[1].split(\",\").map((c) => c.trim().replace(/\"/g, \"\"))\n : [];\n\n // Determine index type\n let type = \"btree\"; // default\n if (row.indexdef.includes(\"USING GIN\")) type = \"gin\";\n else if (row.indexdef.includes(\"USING GIST\")) type = \"gist\";\n else if (row.indexdef.includes(\"USING HASH\")) type = \"hash\";\n else if (row.indexdef.includes(\"USING ivfflat\")) type = \"ivfflat\";\n\n // Check for partial index\n const isPartial = row.indexdef.includes(\"WHERE\");\n\n return {\n name: row.indexname,\n columns,\n type,\n unique: isUnique || isPrimary,\n partial: isPartial,\n options: {\n primary: isPrimary,\n definition: row.indexdef,\n },\n };\n });\n }\n\n /**\n * Get all column names for a table.\n *\n * @param table - Table name\n * @returns Array of column names\n */\n public async listColumns(table: string): Promise<string[]> {\n const result = await this.driver.query<{ column_name: string }>(\n `SELECT column_name\n FROM information_schema.columns\n WHERE table_schema = 'public'\n AND table_name = $1\n ORDER BY ordinal_position`,\n [table],\n );\n\n return result.rows.map((row) => row.column_name);\n }\n\n /**\n * Check if a table exists.\n *\n * @param table - Table name\n * @returns Whether the table exists\n */\n public async tableExists(table: string): Promise<boolean> {\n const result = await this.driver.query<{ exists: boolean }>(\n `SELECT EXISTS (\n SELECT FROM information_schema.tables \n WHERE table_schema = 'public' \n AND table_name = $1\n )`,\n [table],\n );\n\n return result.rows[0]?.exists ?? false;\n }\n}\n","/**\n * PostgreSQL Dialect Implementation\n *\n * Implements the SqlDialectContract for PostgreSQL-specific SQL syntax.\n * Handles parameter placeholders ($1, $2), identifier quoting, and\n * PostgreSQL-specific features like JSONB operators.\n *\n * @module cascade/drivers/postgres\n */\n\nimport type { AggregateExpression } from \"../../expressions\";\nimport type { SqlDialectContract } from \"../sql/sql-dialect.contract\";\n\n/**\n * PostgreSQL-specific SQL dialect implementation.\n *\n * Provides PostgreSQL syntax for:\n * - Parameter placeholders ($1, $2, $3...)\n * - Identifier quoting with double quotes\n * - JSONB operators (->, ->>, @>)\n * - ILIKE for case-insensitive matching\n * - RETURNING clause support\n *\n * @example\n * ```typescript\n * const dialect = new PostgresDialect();\n *\n * dialect.placeholder(1); // \"$1\"\n * dialect.quoteIdentifier('user'); // '\"user\"'\n * dialect.jsonExtract('data', 'name'); // \"data\"->>'name'\n * ```\n */\nexport class PostgresDialect implements SqlDialectContract {\n /**\n * Dialect name identifier.\n */\n public readonly name = \"postgres\" as const;\n\n /**\n * PostgreSQL supports the RETURNING clause for INSERT/UPDATE/DELETE.\n */\n public readonly supportsReturning = true;\n\n /**\n * PostgreSQL uses ON CONFLICT for upsert operations.\n */\n public readonly upsertKeyword = \"ON CONFLICT\" as const;\n\n /**\n * Generate a PostgreSQL parameter placeholder.\n *\n * PostgreSQL uses numbered placeholders: $1, $2, $3, etc.\n *\n * @param index - The 1-based parameter index\n * @returns The placeholder string (e.g., \"$1\")\n */\n public placeholder(index: number): string {\n return `$${index}`;\n }\n\n /**\n * Quote an identifier using PostgreSQL's double-quote syntax.\n *\n * Handles escaping of embedded double quotes by doubling them.\n * This is necessary for reserved words and special characters.\n *\n * @param identifier - The identifier (table/column name) to quote\n * @returns The quoted identifier (e.g., '\"user\"')\n */\n public quoteIdentifier(identifier: string): string {\n // Split on dots for qualified names (schema.table.column)\n const parts = identifier.split(\".\");\n return parts.map((part) => `\"${part.replace(/\"/g, '\"\"')}\"`).join(\".\");\n }\n\n /**\n * Convert a boolean to PostgreSQL literal.\n *\n * @param value - The boolean value\n * @returns \"TRUE\" or \"FALSE\"\n */\n public booleanLiteral(value: boolean): string {\n return value ? \"TRUE\" : \"FALSE\";\n }\n\n /**\n * Build LIMIT/OFFSET clause for PostgreSQL.\n *\n * @param limit - Maximum rows to return\n * @param offset - Rows to skip\n * @returns The SQL clause (e.g., \"LIMIT 10 OFFSET 20\")\n */\n public limitOffset(limit?: number, offset?: number): string {\n const parts: string[] = [];\n\n if (limit !== undefined) {\n parts.push(`LIMIT ${limit}`);\n }\n\n if (offset !== undefined) {\n parts.push(`OFFSET ${offset}`);\n }\n\n return parts.join(\" \");\n }\n\n /**\n * Build a JSON path extraction expression for PostgreSQL.\n *\n * Uses the ->> operator for text extraction from JSONB columns.\n * Supports nested paths using chained operators.\n *\n * @param column - The JSONB column name\n * @param path - The path to extract (dot notation: \"user.name\")\n * @returns The SQL expression (e.g., \"data\"->>'user'->>'name')\n */\n public jsonExtract(column: string, path: string): string {\n const quotedColumn = this.quoteIdentifier(column);\n const pathParts = path.split(\".\");\n\n if (pathParts.length === 1) {\n return `${quotedColumn}->>'${pathParts[0]}'`;\n }\n\n // For nested paths: data->'user'->>'name' (last one gets text extraction)\n const jsonPath = pathParts\n .slice(0, -1)\n .map((p) => `'${p}'`)\n .join(\"->\");\n const lastKey = pathParts[pathParts.length - 1];\n\n return `${quotedColumn}->${jsonPath}->>'${lastKey}'`;\n }\n\n /**\n * Build a JSON contains expression for PostgreSQL.\n *\n * Uses the @> containment operator for JSONB columns.\n *\n * @param column - The JSONB column name\n * @param value - The value to check for\n * @param path - Optional path within the JSON\n * @returns The SQL expression\n */\n public jsonContains(column: string, value: unknown, path?: string): string {\n const quotedColumn = this.quoteIdentifier(column);\n\n if (path) {\n // Check if a specific path contains the value\n const jsonValue = JSON.stringify({ [path]: value });\n return `${quotedColumn} @> '${jsonValue}'::jsonb`;\n }\n\n // Check if the column contains the value (for arrays or objects)\n const jsonValue = JSON.stringify(value);\n return `${quotedColumn} @> '${jsonValue}'::jsonb`;\n }\n\n /**\n * Build a LIKE pattern expression for PostgreSQL.\n *\n * Uses ILIKE for case-insensitive matching, LIKE for case-sensitive.\n *\n * @param pattern - The pattern to match\n * @param caseInsensitive - Whether to use case-insensitive matching\n * @returns Object with operator and pattern\n */\n public likePattern(\n pattern: string,\n caseInsensitive = true,\n ): { operator: string; pattern: string } {\n // Escape special characters in the pattern (%, _, \\)\n const escapedPattern = pattern.replace(/\\\\/g, \"\\\\\\\\\").replace(/%/g, \"\\\\%\").replace(/_/g, \"\\\\_\");\n\n return {\n operator: caseInsensitive ? \"ILIKE\" : \"LIKE\",\n pattern: escapedPattern,\n };\n }\n\n /**\n * Build an array contains expression for PostgreSQL.\n *\n * Uses ANY() for checking if a value is in an array column.\n *\n * @param column - The array column name\n * @param paramIndex - The parameter index\n * @returns The SQL expression\n */\n public arrayContains(column: string, paramIndex: number): string {\n return `${this.placeholder(paramIndex)} = ANY(${this.quoteIdentifier(column)})`;\n }\n\n /**\n * Get the PostgreSQL SQL type for an abstract type.\n *\n * @param type - The abstract type name\n * @param options - Type-specific options\n * @returns The PostgreSQL type string\n */\n public getSqlType(\n type: string,\n options?: { length?: number; precision?: number; scale?: number; dimensions?: number },\n ): string {\n switch (type) {\n case \"string\":\n return options?.length ? `VARCHAR(${options.length})` : \"TEXT\";\n case \"char\":\n return `CHAR(${options?.length ?? 1})`;\n case \"text\":\n return \"TEXT\";\n case \"mediumText\":\n case \"longText\":\n return \"TEXT\"; // PostgreSQL doesn't distinguish text sizes\n case \"integer\":\n return \"INTEGER\";\n case \"smallInteger\":\n return \"SMALLINT\";\n case \"tinyInteger\":\n return \"SMALLINT\"; // PostgreSQL doesn't have TINYINT\n case \"bigInteger\":\n return \"BIGINT\";\n case \"float\":\n return \"REAL\";\n case \"double\":\n return \"DOUBLE PRECISION\";\n case \"decimal\":\n if (options?.precision !== undefined) {\n const scale = options.scale ?? 0;\n return `DECIMAL(${options.precision}, ${scale})`;\n }\n return \"DECIMAL\";\n case \"boolean\":\n return \"BOOLEAN\";\n case \"date\":\n return \"DATE\";\n case \"dateTime\":\n return \"TIMESTAMP\";\n case \"timestamp\":\n return \"TIMESTAMPTZ\"; // With timezone\n case \"time\":\n return \"TIME\";\n case \"year\":\n return \"SMALLINT\"; // PostgreSQL doesn't have YEAR type\n case \"json\":\n return \"JSONB\"; // Prefer JSONB for indexing and operators\n case \"binary\":\n return \"BYTEA\";\n case \"uuid\":\n return \"UUID\";\n case \"ulid\":\n return \"CHAR(26)\"; // ULIDs are 26 characters\n case \"ipAddress\":\n return \"INET\";\n case \"macAddress\":\n return \"MACADDR\";\n case \"point\":\n return \"POINT\";\n case \"polygon\":\n return \"POLYGON\";\n case \"lineString\":\n return \"PATH\";\n case \"geometry\":\n return \"GEOMETRY\"; // Requires PostGIS\n case \"vector\":\n return options?.dimensions ? `VECTOR(${options.dimensions})` : \"VECTOR\"; // Requires pgvector\n case \"enum\":\n return \"TEXT\"; // PostgreSQL enums need CREATE TYPE first\n case \"set\":\n return \"TEXT[]\"; // Use array for set-like behavior\n // PostgreSQL native array types\n case \"arrayInt\":\n return \"INTEGER[]\";\n case \"arrayBigInt\":\n return \"BIGINT[]\";\n case \"arrayFloat\":\n return \"REAL[]\";\n case \"arrayDecimal\":\n if (options?.precision !== undefined) {\n const scale = options.scale ?? 0;\n return `DECIMAL(${options.precision}, ${scale})[]`;\n }\n return \"DECIMAL[]\";\n case \"arrayBoolean\":\n return \"BOOLEAN[]\";\n case \"arrayText\":\n return \"TEXT[]\";\n case \"arrayDate\":\n return \"DATE[]\";\n case \"arrayTimestamp\":\n return \"TIMESTAMPTZ[]\";\n case \"arrayUuid\":\n return \"UUID[]\";\n case \"arrayJson\":\n return \"JSONB[]\";\n default:\n return type.toUpperCase();\n }\n }\n\n /**\n * Translate a database-agnostic aggregate expression to PostgreSQL SQL.\n *\n * The five scalar aggregates map to their ANSI SQL function. `distinct`,\n * `floor`, `first` and `last` are MongoDB-only for v1 — none has a\n * single-scalar `GROUP BY` equivalent on PostgreSQL, so they throw instead\n * of emitting a silently-different semantic (the footgun this guards).\n *\n * @param expression - The abstract aggregate (`$agg.*`) to translate\n * @returns The SQL fragment (e.g. `SUM(\"amount\")`, `COUNT(*)`)\n */\n public aggregateToSql(expression: AggregateExpression): string {\n const column = expression.__field === null ? \"*\" : this.quoteIdentifier(expression.__field);\n\n switch (expression.__agg) {\n case \"count\":\n return \"COUNT(*)\";\n case \"sum\":\n return `SUM(${column})`;\n case \"avg\":\n return `AVG(${column})`;\n case \"min\":\n return `MIN(${column})`;\n case \"max\":\n return `MAX(${column})`;\n default:\n throw new Error(\n `$agg.${expression.__agg} is MongoDB-only and not supported on a ` +\n `PostgreSQL groupBy. Use selectRaw / havingRaw with the equivalent ` +\n `SQL (window function / DISTINCT / FLOOR) if you need it here.`,\n );\n }\n }\n}\n","import { DatabaseDirtyTracker } from \"./database-dirty-tracker\";\n\n/**\n * A dirty tracker designed for SQL databases where nested objects shouldn't be flattened.\n * Since SQL drivers (like Postgres) replace the entire JSON column when updated,\n * we keep the object intact instead of using dot-notation keys.\n */\nexport class SqlDatabaseDirtyTracker extends DatabaseDirtyTracker {\n /**\n * Overrides the default flattening behavior to keep the raw data structure.\n */\n protected override flattenData(data: Record<string, unknown>): Record<string, unknown> {\n // Return a shallow copy of the data without flattening nested objects\n return { ...data };\n }\n}\n","/**\r\n * PostgreSQL Migration Driver\r\n *\r\n * Implements the MigrationDriverContract for PostgreSQL DDL operations.\r\n * Provides methods for creating/dropping tables, columns, indexes,\r\n * and constraints.\r\n *\r\n * @module cascade/drivers/postgres\r\n */\r\n\r\nimport { databaseTransactionContext } from \"../../context/database-transaction-context\";\r\nimport type {\r\n ColumnDefinition,\r\n ColumnType,\r\n ForeignKeyDefinition,\r\n FullTextIndexOptions,\r\n GeoIndexOptions,\r\n IndexDefinition,\r\n MigrationDriverContract,\r\n TableIndexInformation,\r\n VectorIndexOptions,\r\n} from \"../../contracts/migration-driver.contract\";\r\nimport type { MigrationDefaults, UuidStrategy } from \"../../types\";\r\nimport type { PostgresDriver } from \"./postgres-driver\";\r\n\r\n/**\r\n * PostgreSQL Migration Driver.\r\n *\r\n * Handles database schema operations for PostgreSQL including:\r\n * - Table creation and deletion\r\n * - Column management\r\n * - Index creation (B-tree, GIN, GiST, etc.)\r\n * - Constraint management (foreign keys, unique, etc.)\r\n *\r\n * @example\r\n * ```typescript\r\n * const migrationDriver = driver.migrationDriver();\r\n *\r\n * // Create a table\r\n * await migrationDriver.createTable('users');\r\n *\r\n * // Add columns\r\n * await migrationDriver.addColumn('users', {\r\n * name: 'email',\r\n * type: 'string',\r\n * length: 255,\r\n * nullable: false\r\n * });\r\n *\r\n * // Create unique index\r\n * await migrationDriver.createUniqueIndex('users', ['email']);\r\n * ```\r\n */\r\nexport class PostgresMigrationDriver implements MigrationDriverContract {\r\n /**\r\n * Active transaction client (if any).\r\n */\r\n private get transactionClient(): unknown {\r\n return databaseTransactionContext.getSession();\r\n }\r\n\r\n /**\r\n * Create a new migration driver.\r\n *\r\n * @param driver - The PostgreSQL driver instance\r\n */\r\n public constructor(public readonly driver: PostgresDriver) {}\r\n\r\n // ============================================================================\r\n // TABLE OPERATIONS\r\n // ============================================================================\r\n\r\n /**\r\n * Create a new table with a default id column.\r\n *\r\n * @param table - Table name\r\n */\r\n public async createTable(table: string): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n // Create empty table - columns are added via addColumn operations\r\n await this.execute(`CREATE TABLE ${quotedTable} ()`);\r\n }\r\n\r\n /**\r\n * Create table if it doesn't exist.\r\n *\r\n * @param table - Table name\r\n */\r\n public async createTableIfNotExists(table: string): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n // Create empty table if not exists - columns are added via addColumn operations\r\n await this.execute(`CREATE TABLE IF NOT EXISTS ${quotedTable} ()`);\r\n }\r\n\r\n /**\r\n * Drop an existing table.\r\n *\r\n * @param table - Table name\r\n */\r\n public async dropTable(table: string): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n await this.execute(`DROP TABLE ${quotedTable} CASCADE`);\r\n }\r\n\r\n /**\r\n * Drop table if it exists.\r\n *\r\n * @param table - Table name\r\n */\r\n public async dropTableIfExists(table: string): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n await this.execute(`DROP TABLE IF EXISTS ${quotedTable} CASCADE`);\r\n }\r\n\r\n /**\r\n * Rename a table.\r\n *\r\n * @param from - Current table name\r\n * @param to - New table name\r\n */\r\n public async renameTable(from: string, to: string): Promise<void> {\r\n const quotedFrom = this.driver.dialect.quoteIdentifier(from);\r\n const quotedTo = this.driver.dialect.quoteIdentifier(to);\r\n await this.execute(`ALTER TABLE ${quotedFrom} RENAME TO ${quotedTo}`);\r\n }\r\n\r\n /**\r\n * Truncate a table — remove all rows efficiently.\r\n *\r\n * @param table - Table name\r\n */\r\n public async truncateTable(table: string): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n await this.execute(`TRUNCATE TABLE ${quotedTable}`);\r\n }\r\n\r\n /**\r\n * Check if a table exists.\r\n *\r\n * @param table - Table name\r\n * @returns Whether the table exists\r\n */\r\n public async tableExists(table: string): Promise<boolean> {\r\n const result = await this.driver.query<{ exists: boolean }>(\r\n `SELECT EXISTS (\r\n SELECT FROM information_schema.tables\r\n WHERE table_schema = 'public'\r\n AND table_name = $1\r\n )`,\r\n [table],\r\n );\r\n return result.rows[0]?.exists ?? false;\r\n }\r\n\r\n /**\r\n * List all columns in a table.\r\n *\r\n * @param table - Table name\r\n * @returns Array of column definitions\r\n */\r\n public async listColumns(table: string): Promise<ColumnDefinition[]> {\r\n const result = await this.driver.query<{\r\n column_name: string;\r\n data_type: string;\r\n character_maximum_length: number | null;\r\n numeric_precision: number | null;\r\n numeric_scale: number | null;\r\n is_nullable: string;\r\n column_default: string | null;\r\n }>(\r\n `SELECT\r\n column_name,\r\n data_type,\r\n character_maximum_length,\r\n numeric_precision,\r\n numeric_scale,\r\n is_nullable,\r\n column_default\r\n FROM information_schema.columns\r\n WHERE table_schema = 'public'\r\n AND table_name = $1\r\n ORDER BY ordinal_position`,\r\n [table],\r\n );\r\n\r\n return result.rows.map((row) => ({\r\n name: row.column_name,\r\n type: this.mapPostgresTypeToColumnType(row.data_type),\r\n length: row.character_maximum_length ?? undefined,\r\n precision: row.numeric_precision ?? undefined,\r\n scale: row.numeric_scale ?? undefined,\r\n nullable: row.is_nullable === \"YES\",\r\n defaultValue: row.column_default ?? undefined,\r\n }));\r\n }\r\n\r\n /**\r\n * List all tables in the current database.\r\n *\r\n * @returns Array of table names\r\n */\r\n public async listTables(): Promise<string[]> {\r\n const result = await this.driver.query<{ table_name: string }>(\r\n `SELECT table_name\r\n FROM information_schema.tables\r\n WHERE table_schema = 'public'\r\n ORDER BY table_name`,\r\n );\r\n\r\n return result.rows.map((row) => row.table_name);\r\n }\r\n\r\n /**\r\n * Ensure the migrations tracking table exists.\r\n *\r\n * Creates the table with proper schema if it doesn't exist.\r\n *\r\n * @param tableName - Name of the migrations table\r\n */\r\n public async ensureMigrationsTable(tableName: string): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(tableName);\r\n\r\n await this.execute(`\r\n CREATE TABLE IF NOT EXISTS ${quotedTable} (\r\n \"id\" SERIAL PRIMARY KEY,\r\n \"name\" VARCHAR(255) NOT NULL UNIQUE,\r\n \"batch\" INTEGER NOT NULL,\r\n \"executedAt\" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),\r\n \"createdAt\" TIMESTAMP WITH TIME ZONE\r\n )\r\n `);\r\n }\r\n\r\n // ============================================================================\r\n // COLUMN OPERATIONS\r\n // ============================================================================\r\n\r\n /**\r\n * Add a column to an existing table.\r\n *\r\n * @param table - Table name\r\n * @param column - Column definition\r\n */\r\n public async addColumn(table: string, column: ColumnDefinition): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const quotedColumn = this.driver.dialect.quoteIdentifier(column.name);\r\n\r\n // For auto-increment integers, use SERIAL/BIGSERIAL instead of INTEGER/BIGINT\r\n let sqlType: string;\r\n if (column.autoIncrement) {\r\n if (column.type === \"bigInteger\") {\r\n sqlType = \"BIGSERIAL\";\r\n } else {\r\n sqlType = \"SERIAL\";\r\n }\r\n } else {\r\n sqlType = this.driver.dialect.getSqlType(column.type, {\r\n length: column.length,\r\n precision: column.precision,\r\n scale: column.scale,\r\n dimensions: column.dimensions,\r\n });\r\n }\r\n\r\n let sql = `ALTER TABLE ${quotedTable} ADD COLUMN ${quotedColumn} ${sqlType}`;\r\n\r\n // Handle generated columns\r\n if (column.generated) {\r\n sql += ` GENERATED ALWAYS AS (${column.generated.expression})`;\r\n if (column.generated.stored) {\r\n sql += \" STORED\";\r\n }\r\n // PostgreSQL only supports STORED, not VIRTUAL\r\n // If virtual is requested, it's simply ignored (PostgreSQL doesn't support it)\r\n } else {\r\n // SERIAL/BIGSERIAL are always NOT NULL, so skip for those\r\n if (!column.autoIncrement && column.nullable === false) {\r\n sql += \" NOT NULL\";\r\n }\r\n\r\n if (column.defaultValue !== undefined) {\r\n // Check for special CURRENT_TIMESTAMP marker\r\n if (\r\n typeof column.defaultValue === \"object\" &&\r\n column.defaultValue !== null &&\r\n (column.defaultValue as any).__type === \"CURRENT_TIMESTAMP\"\r\n ) {\r\n sql += \" DEFAULT NOW()\";\r\n } else if (column.isRawDefault === false) {\r\n // Explicit string literal - escape it properly\r\n const escaped = String(column.defaultValue).replace(/'/g, \"''\");\r\n sql += ` DEFAULT '${escaped}'`;\r\n } else if (typeof column.defaultValue === \"boolean\") {\r\n // Boolean values\r\n sql += ` DEFAULT ${column.defaultValue ? \"TRUE\" : \"FALSE\"}`;\r\n } else if (typeof column.defaultValue === \"number\") {\r\n // Numeric values\r\n sql += ` DEFAULT ${column.defaultValue}`;\r\n } else {\r\n // Raw SQL expression (default behavior when isRawDefault is true or undefined)\r\n sql += ` DEFAULT ${column.defaultValue}`;\r\n }\r\n }\r\n\r\n // Handle primary key\r\n if (column.primary) {\r\n sql += \" PRIMARY KEY\";\r\n }\r\n\r\n // Handle unique constraint\r\n if (column.unique) {\r\n sql += \" UNIQUE\";\r\n }\r\n }\r\n\r\n await this.execute(sql);\r\n }\r\n\r\n /**\r\n * Drop a column from a table.\r\n *\r\n * @param table - Table name\r\n * @param column - Column name\r\n */\r\n public async dropColumn(table: string, column: string): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const quotedColumn = this.driver.dialect.quoteIdentifier(column);\r\n await this.execute(`ALTER TABLE ${quotedTable} DROP COLUMN ${quotedColumn}`);\r\n }\r\n\r\n /**\r\n * Drop multiple columns from a table.\r\n *\r\n * @param table - Table name\r\n * @param columns - Column names\r\n */\r\n public async dropColumns(table: string, columns: string[]): Promise<void> {\r\n for (const column of columns) {\r\n await this.dropColumn(table, column);\r\n }\r\n }\r\n\r\n /**\r\n * Rename a column.\r\n *\r\n * @param table - Table name\r\n * @param from - Current column name\r\n * @param to - New column name\r\n */\r\n public async renameColumn(table: string, from: string, to: string): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const quotedFrom = this.driver.dialect.quoteIdentifier(from);\r\n const quotedTo = this.driver.dialect.quoteIdentifier(to);\r\n await this.execute(`ALTER TABLE ${quotedTable} RENAME COLUMN ${quotedFrom} TO ${quotedTo}`);\r\n }\r\n\r\n /**\r\n * Modify an existing column.\r\n *\r\n * @param table - Table name\r\n * @param column - New column definition\r\n */\r\n public async modifyColumn(table: string, column: ColumnDefinition): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const quotedColumn = this.driver.dialect.quoteIdentifier(column.name);\r\n const sqlType = this.driver.dialect.getSqlType(column.type, {\r\n length: column.length,\r\n precision: column.precision,\r\n scale: column.scale,\r\n dimensions: column.dimensions,\r\n });\r\n\r\n // PostgreSQL requires separate ALTER statements for type and nullability\r\n await this.execute(`ALTER TABLE ${quotedTable} ALTER COLUMN ${quotedColumn} TYPE ${sqlType}`);\r\n\r\n if (column.nullable === false) {\r\n await this.execute(`ALTER TABLE ${quotedTable} ALTER COLUMN ${quotedColumn} SET NOT NULL`);\r\n } else if (column.nullable === true) {\r\n await this.execute(`ALTER TABLE ${quotedTable} ALTER COLUMN ${quotedColumn} DROP NOT NULL`);\r\n }\r\n\r\n if (column.defaultValue !== undefined) {\r\n let defaultVal: string;\r\n\r\n // Check for special CURRENT_TIMESTAMP marker\r\n if (\r\n typeof column.defaultValue === \"object\" &&\r\n column.defaultValue !== null &&\r\n (column.defaultValue as any).__type === \"CURRENT_TIMESTAMP\"\r\n ) {\r\n defaultVal = \"NOW()\";\r\n } else if (typeof column.defaultValue === \"string\") {\r\n defaultVal = `'${column.defaultValue}'`;\r\n } else {\r\n defaultVal = String(column.defaultValue);\r\n }\r\n\r\n await this.execute(\r\n `ALTER TABLE ${quotedTable} ALTER COLUMN ${quotedColumn} SET DEFAULT ${defaultVal}`,\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Create standard timestamp columns (created_at, updated_at).\r\n *\r\n * PostgreSQL implementation creates TIMESTAMPTZ columns with NOW() defaults.\r\n *\r\n * @param table - Table name\r\n */\r\n public async createTimestampColumns(table: string): Promise<void> {\r\n await this.addColumn(table, {\r\n name: \"created_at\",\r\n type: \"timestamp\",\r\n nullable: false,\r\n defaultValue: \"NOW()\",\r\n isRawDefault: true,\r\n });\r\n\r\n await this.addColumn(table, {\r\n name: \"updated_at\",\r\n type: \"timestamp\",\r\n nullable: false,\r\n defaultValue: \"NOW()\",\r\n isRawDefault: true,\r\n });\r\n }\r\n\r\n // ============================================================================\r\n // INDEX OPERATIONS\r\n // ============================================================================\r\n\r\n /**\r\n * Create an index on one or more columns.\r\n *\r\n * Supports:\r\n * - Regular column indexes\r\n * - Expression-based indexes (e.g., `lower(email)`)\r\n * - Covering indexes (INCLUDE clause)\r\n * - Concurrent index creation (CONCURRENTLY keyword)\r\n *\r\n * @param table - Table name\r\n * @param index - Index definition\r\n */\r\n public async createIndex(table: string, index: IndexDefinition): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const indexName = index.name ?? `idx_${table}_${index.columns.join(\"_\")}`;\r\n const quotedIndexName = this.driver.dialect.quoteIdentifier(indexName);\r\n const uniqueKeyword = index.unique ? \"UNIQUE \" : \"\";\r\n const concurrentlyKeyword = index.concurrently ? \"CONCURRENTLY \" : \"\";\r\n\r\n let columnsPart: string;\r\n\r\n // Handle expression-based indexes\r\n if (index.expressions && index.expressions.length > 0) {\r\n // Wrap each expression in parentheses\r\n columnsPart = index.expressions.map((expr) => `(${expr})`).join(\", \");\r\n } else {\r\n // Regular column indexes\r\n const columns = index.columns.map((col, i) => {\r\n const quotedCol = this.driver.dialect.quoteIdentifier(col);\r\n const direction = index.directions?.[i]?.toUpperCase() ?? \"\";\r\n return direction ? `${quotedCol} ${direction}` : quotedCol;\r\n });\r\n columnsPart = columns.join(\", \");\r\n }\r\n\r\n let sql = `CREATE ${uniqueKeyword}INDEX ${concurrentlyKeyword}${quotedIndexName} ON ${quotedTable} (${columnsPart})`;\r\n\r\n // Add INCLUDE clause for covering indexes\r\n if (index.include && index.include.length > 0) {\r\n const includeCols = index.include\r\n .map((col) => this.driver.dialect.quoteIdentifier(col))\r\n .join(\", \");\r\n sql += ` INCLUDE (${includeCols})`;\r\n }\r\n\r\n // Add partial index condition\r\n if (index.where && Object.keys(index.where).length > 0) {\r\n const conditions = Object.entries(index.where)\r\n .map(([key, value]) => {\r\n const quotedKey = this.driver.dialect.quoteIdentifier(key);\r\n return typeof value === \"string\"\r\n ? `${quotedKey} = '${value}'`\r\n : `${quotedKey} = ${value}`;\r\n })\r\n .join(\" AND \");\r\n sql += ` WHERE ${conditions}`;\r\n }\r\n\r\n await this.execute(sql);\r\n }\r\n\r\n /**\r\n * Drop an index.\r\n *\r\n * @param table - Table name\r\n * @param indexNameOrColumns - Index name or columns\r\n */\r\n public async dropIndex(table: string, indexNameOrColumns: string | string[]): Promise<void> {\r\n let indexName: string;\r\n\r\n if (typeof indexNameOrColumns === \"string\") {\r\n indexName = indexNameOrColumns;\r\n } else {\r\n indexName = `idx_${table}_${indexNameOrColumns.join(\"_\")}`;\r\n }\r\n\r\n const quotedIndexName = this.driver.dialect.quoteIdentifier(indexName);\r\n await this.execute(`DROP INDEX IF EXISTS ${quotedIndexName}`);\r\n }\r\n\r\n /**\r\n * Create a unique index.\r\n *\r\n * @param table - Table name\r\n * @param columns - Columns to include\r\n * @param name - Optional index name\r\n */\r\n public async createUniqueIndex(table: string, columns: string[], name?: string): Promise<void> {\r\n await this.createIndex(table, { columns, unique: true, name });\r\n }\r\n\r\n /**\r\n * Drop a unique index.\r\n *\r\n * @param table - Table name\r\n * @param columns - Columns in the index\r\n */\r\n public async dropUniqueIndex(table: string, columns: string[]): Promise<void> {\r\n await this.dropIndex(table, columns);\r\n }\r\n\r\n // ============================================================================\r\n // SPECIALIZED INDEXES\r\n // ============================================================================\r\n\r\n /**\r\n * Create a full-text search index using GIN.\r\n *\r\n * @param table - Table name\r\n * @param columns - Columns to index\r\n * @param options - Full-text options\r\n */\r\n public async createFullTextIndex(\r\n table: string,\r\n columns: string[],\r\n options?: FullTextIndexOptions,\r\n ): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const indexName = options?.name ?? `idx_${table}_fulltext_${columns.join(\"_\")}`;\r\n const quotedIndexName = this.driver.dialect.quoteIdentifier(indexName);\r\n const language = options?.language ?? \"english\";\r\n\r\n const tsvectors = columns.map((col) => {\r\n const weight = options?.weights?.[col] ?? \"A\";\r\n return `setweight(to_tsvector('${language}', COALESCE(${this.driver.dialect.quoteIdentifier(col)}, '')), '${weight}')`;\r\n });\r\n\r\n await this.execute(\r\n `CREATE INDEX ${quotedIndexName} ON ${quotedTable} USING GIN ((${tsvectors.join(\" || \")}))`,\r\n );\r\n }\r\n\r\n /**\r\n * Drop a full-text search index.\r\n *\r\n * @param table - Table name\r\n * @param name - Index name\r\n */\r\n public async dropFullTextIndex(table: string, name: string): Promise<void> {\r\n await this.dropIndex(table, name);\r\n }\r\n\r\n /**\r\n * Create a geo-spatial index using GiST.\r\n *\r\n * @param table - Table name\r\n * @param column - Geo column\r\n * @param options - Geo index options\r\n */\r\n public async createGeoIndex(\r\n table: string,\r\n column: string,\r\n options?: GeoIndexOptions,\r\n ): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const quotedColumn = this.driver.dialect.quoteIdentifier(column);\r\n const indexName = options?.name ?? `idx_${table}_geo_${column}`;\r\n const quotedIndexName = this.driver.dialect.quoteIdentifier(indexName);\r\n\r\n await this.execute(\r\n `CREATE INDEX ${quotedIndexName} ON ${quotedTable} USING GIST (${quotedColumn})`,\r\n );\r\n }\r\n\r\n /**\r\n * Drop a geo-spatial index.\r\n *\r\n * @param table - Table name\r\n * @param column - Geo column\r\n */\r\n public async dropGeoIndex(table: string, column: string): Promise<void> {\r\n await this.dropIndex(table, `idx_${table}_geo_${column}`);\r\n }\r\n\r\n /**\r\n * Create a vector search index (requires pgvector extension).\r\n *\r\n * @param table - Table name\r\n * @param column - Vector column\r\n * @param options - Vector index options\r\n */\r\n public async createVectorIndex(\r\n table: string,\r\n column: string,\r\n options: VectorIndexOptions,\r\n ): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const quotedColumn = this.driver.dialect.quoteIdentifier(column);\r\n const indexName = options.name ?? `idx_${table}_vector_${column}`;\r\n const quotedIndexName = this.driver.dialect.quoteIdentifier(indexName);\r\n\r\n // Map similarity to pgvector operator class\r\n const opClass =\r\n options.similarity === \"euclidean\"\r\n ? \"vector_l2_ops\"\r\n : options.similarity === \"dotProduct\"\r\n ? \"vector_ip_ops\"\r\n : \"vector_cosine_ops\";\r\n\r\n const lists = options.lists ?? 100;\r\n\r\n await this.execute(\r\n `CREATE INDEX ${quotedIndexName} ON ${quotedTable} USING ivfflat (${quotedColumn} ${opClass}) WITH (lists = ${lists})`,\r\n );\r\n }\r\n\r\n /**\r\n * Drop a vector search index.\r\n *\r\n * @param table - Table name\r\n * @param column - Vector column\r\n */\r\n public async dropVectorIndex(table: string, column: string): Promise<void> {\r\n await this.dropIndex(table, `idx_${table}_vector_${column}`);\r\n }\r\n\r\n /**\r\n * Create a TTL index (not natively supported in PostgreSQL).\r\n *\r\n * Note: PostgreSQL doesn't have native TTL indexes like MongoDB.\r\n * This creates a partial index and requires a scheduled job for cleanup.\r\n *\r\n * @param table - Table name\r\n * @param column - Date column\r\n * @param expireAfterSeconds - Expiration time in seconds\r\n */\r\n public async createTTLIndex(\r\n table: string,\r\n column: string,\r\n expireAfterSeconds: number,\r\n ): Promise<void> {\r\n // Create a partial index for expired rows (for efficient cleanup queries)\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const quotedColumn = this.driver.dialect.quoteIdentifier(column);\r\n const indexName = `idx_${table}_ttl_${column}`;\r\n const quotedIndexName = this.driver.dialect.quoteIdentifier(indexName);\r\n\r\n await this.execute(\r\n `CREATE INDEX ${quotedIndexName} ON ${quotedTable} (${quotedColumn}) WHERE ${quotedColumn} < NOW() - INTERVAL '${expireAfterSeconds} seconds'`,\r\n );\r\n\r\n // Note: User must set up a scheduled job (pg_cron, etc.) to:\r\n // DELETE FROM table WHERE column < NOW() - INTERVAL 'X seconds'\r\n }\r\n\r\n /**\r\n * Drop a TTL index.\r\n *\r\n * @param table - Table name\r\n * @param column - Column with TTL index\r\n */\r\n public async dropTTLIndex(table: string, column: string): Promise<void> {\r\n await this.dropIndex(table, `idx_${table}_ttl_${column}`);\r\n }\r\n\r\n /**\r\n * List all indexes on a table.\r\n *\r\n * @param table - Table name\r\n * @returns Array of index metadata\r\n */\r\n public async listIndexes(table: string): Promise<TableIndexInformation[]> {\r\n const result = await this.driver.query<{ indexname: string; indexdef: string }>(\r\n `SELECT indexname, indexdef FROM pg_indexes WHERE schemaname = 'public' AND tablename = $1`,\r\n [table],\r\n );\r\n\r\n return result.rows.map((row) => {\r\n const isUnique = row.indexdef.includes(\"UNIQUE\");\r\n const isPrimary = row.indexname.endsWith(\"_pkey\");\r\n const columnsMatch = row.indexdef.match(/\\(([^)]+)\\)/);\r\n const columns = columnsMatch\r\n ? columnsMatch[1].split(\",\").map((c) => c.trim().replace(/\"/g, \"\"))\r\n : [];\r\n\r\n let type = \"btree\";\r\n if (row.indexdef.includes(\"USING GIN\")) type = \"gin\";\r\n else if (row.indexdef.includes(\"USING GIST\")) type = \"gist\";\r\n else if (row.indexdef.includes(\"USING HASH\")) type = \"hash\";\r\n else if (row.indexdef.includes(\"USING ivfflat\")) type = \"ivfflat\";\r\n\r\n return {\r\n name: row.indexname,\r\n columns,\r\n type,\r\n unique: isUnique || isPrimary,\r\n partial: row.indexdef.includes(\"WHERE\"),\r\n options: { primary: isPrimary, definition: row.indexdef },\r\n };\r\n });\r\n }\r\n\r\n // ============================================================================\r\n // EXTENSIONS\r\n // ============================================================================\r\n\r\n /**\r\n * Check if a PostgreSQL extension is available on the database server.\r\n *\r\n * @param extension - Extension name (e.g., \"vector\")\r\n */\r\n public async isExtensionAvailable(extension: string): Promise<boolean> {\r\n try {\r\n const result = await this.driver.query<{ name: string }>(\r\n `SELECT name FROM pg_available_extensions WHERE name = $1`,\r\n [extension],\r\n );\r\n\r\n return result?.rows?.length > 0;\r\n } catch {\r\n // If we can't check (e.g., permissions issue or pg_available_extensions not accessible),\r\n // we return true to avoid false positives. Execution will just proceed and fail naturally if it's missing.\r\n return true;\r\n }\r\n }\r\n\r\n /**\r\n * Get the official documentation or installation URL for a PostgreSQL extension.\r\n *\r\n * @param extension - Extension name\r\n */\r\n public getExtensionDocsUrl(extension: string): string | undefined {\r\n const guideUrls: Record<string, string> = {\r\n vector: \"https://github.com/pgvector/pgvector#installation\",\r\n postgis: \"https://postgis.net/documentation/getting_started/\",\r\n pg_trgm: \"https://www.postgresql.org/docs/current/pgtrgm.html\",\r\n uuid_ossp: \"https://www.postgresql.org/docs/current/uuid-ossp.html\",\r\n };\r\n\r\n return guideUrls[extension] ?? `https://www.postgresql.org/docs/current/${extension}.html`;\r\n }\r\n\r\n // ============================================================================\r\n // CONSTRAINTS\r\n // ============================================================================\r\n\r\n /**\r\n * Add a foreign key constraint.\r\n *\r\n * @param table - Table name\r\n * @param foreignKey - Foreign key definition\r\n */\r\n public async addForeignKey(table: string, foreignKey: ForeignKeyDefinition): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const quotedColumn = this.driver.dialect.quoteIdentifier(foreignKey.column);\r\n const quotedRefTable = this.driver.dialect.quoteIdentifier(foreignKey.referencesTable);\r\n const quotedRefColumn = this.driver.dialect.quoteIdentifier(foreignKey.referencesColumn);\r\n\r\n const constraintName =\r\n foreignKey.name ?? `fk_${table}_${foreignKey.column}_${foreignKey.referencesTable}`;\r\n const quotedConstraint = this.driver.dialect.quoteIdentifier(constraintName);\r\n\r\n let sql = `ALTER TABLE ${quotedTable} ADD CONSTRAINT ${quotedConstraint} FOREIGN KEY (${quotedColumn}) REFERENCES ${quotedRefTable} (${quotedRefColumn})`;\r\n\r\n if (foreignKey.onDelete) {\r\n sql += ` ON DELETE ${this.mapForeignKeyAction(foreignKey.onDelete)}`;\r\n }\r\n\r\n if (foreignKey.onUpdate) {\r\n sql += ` ON UPDATE ${this.mapForeignKeyAction(foreignKey.onUpdate)}`;\r\n }\r\n\r\n await this.execute(sql);\r\n }\r\n\r\n /**\r\n * Drop a foreign key constraint.\r\n *\r\n * @param table - Table name\r\n * @param name - Constraint name\r\n */\r\n public async dropForeignKey(table: string, name: string): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const quotedConstraint = this.driver.dialect.quoteIdentifier(name);\r\n await this.execute(`ALTER TABLE ${quotedTable} DROP CONSTRAINT ${quotedConstraint}`);\r\n }\r\n\r\n /**\r\n * Add a primary key constraint.\r\n *\r\n * @param table - Table name\r\n * @param columns - Primary key columns\r\n */\r\n public async addPrimaryKey(table: string, columns: string[]): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const quotedColumns = columns.map((c) => this.driver.dialect.quoteIdentifier(c)).join(\", \");\r\n const constraintName = `pk_${table}`;\r\n const quotedConstraint = this.driver.dialect.quoteIdentifier(constraintName);\r\n\r\n await this.execute(\r\n `ALTER TABLE ${quotedTable} ADD CONSTRAINT ${quotedConstraint} PRIMARY KEY (${quotedColumns})`,\r\n );\r\n }\r\n\r\n /**\r\n * Drop the primary key constraint.\r\n *\r\n * @param table - Table name\r\n */\r\n public async dropPrimaryKey(table: string): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const constraintName = `pk_${table}`;\r\n const quotedConstraint = this.driver.dialect.quoteIdentifier(constraintName);\r\n\r\n await this.execute(`ALTER TABLE ${quotedTable} DROP CONSTRAINT ${quotedConstraint}`);\r\n }\r\n\r\n /**\r\n * Add a CHECK constraint.\r\n *\r\n * @param table - Table name\r\n * @param name - Constraint name\r\n * @param expression - SQL CHECK expression\r\n */\r\n public async addCheck(table: string, name: string, expression: string): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const quotedName = this.driver.dialect.quoteIdentifier(name);\r\n const sql = `ALTER TABLE ${quotedTable} ADD CONSTRAINT ${quotedName} CHECK (${expression})`;\r\n await this.execute(sql);\r\n }\r\n\r\n /**\r\n * Drop a CHECK constraint.\r\n *\r\n * @param table - Table name\r\n * @param name - Constraint name\r\n */\r\n public async dropCheck(table: string, name: string): Promise<void> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const quotedName = this.driver.dialect.quoteIdentifier(name);\r\n await this.execute(`ALTER TABLE ${quotedTable} DROP CONSTRAINT ${quotedName}`);\r\n }\r\n\r\n // ============================================================================\r\n // SCHEMA VALIDATION (NOT APPLICABLE FOR PostgreSQL)\r\n // ============================================================================\r\n\r\n /**\r\n * Set schema validation (no-op for PostgreSQL).\r\n *\r\n * PostgreSQL uses column constraints instead.\r\n */\r\n public async setSchemaValidation(_table: string, _schema: object): Promise<void> {\r\n // No-op: PostgreSQL doesn't have MongoDB-style schema validation\r\n // Use CHECK constraints instead\r\n }\r\n\r\n /**\r\n * Remove schema validation (no-op for PostgreSQL).\r\n */\r\n public async removeSchemaValidation(_table: string): Promise<void> {\r\n // No-op\r\n }\r\n\r\n // ============================================================================\r\n // TRANSACTIONS\r\n // ============================================================================\r\n\r\n /**\r\n * Begin a transaction.\r\n */\r\n public async beginTransaction(): Promise<void> {\r\n await this.execute(\"BEGIN\");\r\n }\r\n\r\n /**\r\n * Commit the current transaction.\r\n */\r\n public async commit(): Promise<void> {\r\n await this.execute(\"COMMIT\");\r\n }\r\n\r\n /**\r\n * Rollback the current transaction.\r\n */\r\n public async rollback(): Promise<void> {\r\n await this.execute(\"ROLLBACK\");\r\n }\r\n\r\n /**\r\n * Whether transactions are supported.\r\n */\r\n public supportsTransactions(): boolean {\r\n return true;\r\n }\r\n\r\n /**\r\n * Get the default transactional behavior for PostgreSQL.\r\n *\r\n * PostgreSQL supports transactional DDL operations, so migrations\r\n * are wrapped in transactions by default for atomicity and safety.\r\n *\r\n * @returns true (PostgreSQL DDL is transactional)\r\n */\r\n public getDefaultTransactional(): boolean {\r\n return true;\r\n }\r\n\r\n // ============================================================================\r\n // DEFAULTS\r\n // ============================================================================\r\n\r\n /**\r\n * Get the default UUID generation expression for PostgreSQL.\r\n *\r\n * Resolution order:\r\n * 1. `migrationDefaults.uuidExpression` → raw expression (escape hatch)\r\n * 2. `migrationDefaults.uuidStrategy` → mapped to PG function\r\n * 3. Fallback → `gen_random_uuid()` (v4, PG 13+)\r\n *\r\n * @param migrationDefaults - Optional overrides from DataSource config\r\n * @returns PostgreSQL SQL expression for UUID generation\r\n *\r\n * @example\r\n * ```typescript\r\n * driver.getUuidDefault(); // \"gen_random_uuid()\"\r\n * driver.getUuidDefault({ uuidStrategy: \"v7\" }); // \"uuidv7()\"\r\n * driver.getUuidDefault({ uuidExpression: \"uuid_generate_v1mc()\" }); // \"uuid_generate_v1mc()\"\r\n * ```\r\n */\r\n public getUuidDefault(migrationDefaults?: MigrationDefaults): string {\r\n // Escape hatch: raw expression takes highest precedence\r\n if (migrationDefaults?.uuidExpression) {\r\n return migrationDefaults.uuidExpression;\r\n }\r\n\r\n const strategy = migrationDefaults?.uuidStrategy ?? \"v4\";\r\n\r\n const strategyMap: Record<UuidStrategy, string> = {\r\n v4: \"gen_random_uuid()\",\r\n v7: \"uuidv7()\",\r\n };\r\n\r\n return strategyMap[strategy];\r\n }\r\n\r\n // ============================================================================\r\n // RAW ACCESS\r\n // ============================================================================\r\n\r\n /**\r\n * Execute raw operations with direct driver access.\r\n *\r\n * @param callback - Callback receiving the driver\r\n */\r\n public async raw<T>(callback: (connection: unknown) => Promise<T>): Promise<T> {\r\n return callback(this.driver);\r\n }\r\n\r\n // ============================================================================\r\n // HELPERS\r\n // ============================================================================\r\n\r\n /**\r\n * Execute a SQL statement.\r\n *\r\n * @param sql - SQL to execute\r\n * @param params - Query parameters\r\n */\r\n private async execute(sql: string, params: unknown[] = []): Promise<void> {\r\n await this.driver.query(sql, params);\r\n }\r\n\r\n /**\r\n * Map foreign key action to PostgreSQL syntax.\r\n */\r\n private mapForeignKeyAction(action: \"cascade\" | \"restrict\" | \"setNull\" | \"noAction\"): string {\r\n const mapping: Record<string, string> = {\r\n cascade: \"CASCADE\",\r\n restrict: \"RESTRICT\",\r\n setNull: \"SET NULL\",\r\n noAction: \"NO ACTION\",\r\n };\r\n return mapping[action] ?? \"NO ACTION\";\r\n }\r\n\r\n /**\r\n * Map PostgreSQL data type to ColumnType.\r\n */\r\n private mapPostgresTypeToColumnType(pgType: string): ColumnType {\r\n const typeMap: Record<string, ColumnType> = {\r\n \"character varying\": \"string\",\r\n varchar: \"string\",\r\n character: \"char\",\r\n char: \"char\",\r\n text: \"text\",\r\n integer: \"integer\",\r\n int: \"integer\",\r\n smallint: \"smallInteger\",\r\n bigint: \"bigInteger\",\r\n real: \"float\",\r\n \"double precision\": \"double\",\r\n numeric: \"decimal\",\r\n decimal: \"decimal\",\r\n boolean: \"boolean\",\r\n date: \"date\",\r\n timestamp: \"dateTime\",\r\n \"timestamp without time zone\": \"dateTime\",\r\n \"timestamp with time zone\": \"timestamp\",\r\n time: \"time\",\r\n \"time without time zone\": \"time\",\r\n json: \"json\",\r\n jsonb: \"json\",\r\n bytea: \"binary\",\r\n uuid: \"uuid\",\r\n inet: \"ipAddress\",\r\n macaddr: \"macAddress\",\r\n point: \"point\",\r\n polygon: \"polygon\",\r\n line: \"lineString\",\r\n geometry: \"geometry\",\r\n // PostgreSQL array types\r\n \"integer[]\": \"arrayInt\",\r\n \"int[]\": \"arrayInt\",\r\n \"bigint[]\": \"arrayBigInt\",\r\n \"real[]\": \"arrayFloat\",\r\n \"decimal[]\": \"arrayDecimal\",\r\n \"numeric[]\": \"arrayDecimal\",\r\n \"boolean[]\": \"arrayBoolean\",\r\n \"text[]\": \"arrayText\",\r\n \"date[]\": \"arrayDate\",\r\n \"timestamp with time zone[]\": \"arrayTimestamp\",\r\n \"timestamptz[]\": \"arrayTimestamp\",\r\n \"uuid[]\": \"arrayUuid\",\r\n \"jsonb[]\": \"arrayJson\",\r\n \"json[]\": \"arrayJson\",\r\n };\r\n\r\n return typeMap[pgType.toLowerCase()] ?? \"string\";\r\n }\r\n}\r\n","/**\n * PostgreSQL Query Parser\n *\n * Translates Cascade query operations into PostgreSQL SQL queries.\n * Mirrors the MongoQueryParser pattern but generates SQL instead\n * of MongoDB aggregation pipelines.\n *\n * @module cascade/drivers/postgres\n */\n\nimport type {\n DriverQuery,\n JoinOptions,\n WhereOperator,\n} from \"../../contracts/query-builder.contract\";\nimport type { SqlDialectContract } from \"../sql/sql-dialect.contract\";\n\nimport { PostgresDialect } from \"./postgres-dialect\";\n\n/**\n * Operation types supported by the query parser.\n */\nexport type PostgresOperationType =\n // WHERE operations\n | \"where\"\n | \"orWhere\"\n | \"whereRaw\"\n | \"orWhereRaw\"\n | \"whereIn\"\n | \"whereNotIn\"\n | \"whereNull\"\n | \"whereNotNull\"\n | \"whereBetween\"\n | \"whereNotBetween\"\n | \"whereLike\"\n | \"whereNotLike\"\n | \"whereColumn\"\n | \"orWhereColumn\"\n | \"whereExists\"\n | \"whereNotExists\"\n | \"whereDate\"\n | \"whereDateBefore\"\n | \"whereDateAfter\"\n | \"whereDateBetween\"\n | \"whereJsonContains\"\n | \"whereJsonDoesntContain\"\n | \"whereFullText\"\n // SELECT operations\n | \"select\"\n | \"selectRaw\"\n | \"deselect\"\n // JOIN operations\n | \"join\"\n | \"leftJoin\"\n | \"rightJoin\"\n | \"innerJoin\"\n | \"fullJoin\"\n | \"crossJoin\"\n | \"joinRaw\"\n // ORDER operations\n | \"orderBy\"\n | \"orderByRaw\"\n // GROUP operations\n | \"groupBy\"\n | \"having\"\n | \"havingRaw\"\n // LIMIT operations\n | \"limit\"\n | \"offset\"\n // RELATION operations\n | \"has\"\n | \"whereHas\"\n | \"doesntHave\"\n | \"whereDoesntHave\"\n // joinWith operations\n | \"selectRelatedColumns\"\n // Other\n | \"distinct\";\n\n/**\n * Internal operation representation.\n */\nexport type PostgresParserOperation = {\n /** Operation type */\n readonly type: PostgresOperationType;\n /** Operation data/parameters */\n readonly data: Record<string, unknown>;\n};\n\n/**\n * Parser configuration options.\n */\nexport type PostgresParserOptions = {\n /** Target table name */\n readonly table: string;\n /** Table alias (optional) */\n readonly alias?: string;\n /** Operations to parse */\n readonly operations: PostgresParserOperation[];\n /** SQL dialect for syntax generation */\n readonly dialect?: SqlDialectContract;\n /** Factory for creating sub-parsers (for nested queries) */\n readonly createSubParser?: (table: string) => PostgresQueryParser;\n};\n\n/**\n * PostgreSQL Query Parser.\n *\n * Converts a list of query operations into a SQL query string with parameters.\n * Handles SELECT, WHERE, JOIN, ORDER BY, GROUP BY, LIMIT/OFFSET clauses.\n *\n * @example\n * ```typescript\n * const parser = new PostgresQueryParser({\n * table: 'users',\n * operations: [\n * { type: 'where', data: { field: 'name', operator: '=', value: 'Alice' } },\n * { type: 'orderBy', data: { field: 'createdAt', direction: 'desc' } },\n * { type: 'limit', data: { value: 10 } }\n * ]\n * });\n *\n * const { sql, params } = parser.parse();\n * // sql: 'SELECT * FROM \"users\" WHERE \"name\" = $1 ORDER BY \"createdAt\" DESC LIMIT 10'\n * // params: ['Alice']\n * ```\n */\nexport class PostgresQueryParser {\n /**\n * Target table name.\n */\n private readonly table: string;\n\n /**\n * Table alias.\n */\n private readonly alias?: string;\n\n /**\n * Operations to process.\n */\n private readonly operations: PostgresParserOperation[];\n\n /**\n * SQL dialect for syntax.\n */\n private readonly dialect: SqlDialectContract;\n\n /**\n * Current parameter index (1-based for PostgreSQL).\n */\n private paramIndex = 1;\n\n /**\n * Collected parameters.\n */\n private readonly params: unknown[] = [];\n\n /**\n * SELECT columns.\n */\n public selectColumns: string[] = [];\n\n /**\n * Deselected (excluded) columns.\n */\n private deselectColumns: string[] = [];\n\n /**\n * Raw SELECT expressions.\n */\n private selectRaw: string[] = [];\n\n /**\n * WHERE clauses.\n */\n public whereClauses: string[] = [];\n\n /**\n * JOIN clauses.\n */\n private joinClauses: string[] = [];\n\n /**\n * ORDER BY clauses.\n */\n public orderClauses: string[] = [];\n\n /**\n * GROUP BY columns.\n */\n private groupColumns: string[] = [];\n\n /**\n * HAVING clauses.\n */\n private havingClauses: string[] = [];\n\n /**\n * LIMIT value.\n */\n public limitValue?: number;\n\n /**\n * OFFSET value.\n */\n public offsetValue?: number;\n\n /**\n * DISTINCT flag.\n */\n private isDistinct = false;\n\n /**\n * Whether the query has any JOIN operations (pre-scanned before processing).\n * Used by qualifyColumn() to decide whether to prefix columns with the main table.\n */\n private hasJoins = false;\n\n /**\n * Tracked joined tables (for table reference detection).\n */\n private readonly joinedTables = new Set<string>();\n\n /**\n * Create a new query parser.\n *\n * @param options - Parser configuration\n */\n public constructor(options: PostgresParserOptions) {\n this.table = options.table;\n this.alias = options.alias;\n this.operations = options.operations;\n this.dialect = options.dialect ?? new PostgresDialect();\n }\n\n /**\n * Parse all operations and build the SQL query.\n *\n * @returns DriverQuery with `query` (SQL string) and `bindings` (parameter values)\n */\n public parse(): DriverQuery {\n // Pre-scan for any join operations so qualifyColumn() can prefix columns\n // correctly even when WHERE clauses appear before JOINs in the operations list.\n const JOIN_TYPES = new Set([\n \"join\",\n \"leftJoin\",\n \"rightJoin\",\n \"innerJoin\",\n \"fullJoin\",\n \"crossJoin\",\n \"joinRaw\",\n ]);\n\n this.hasJoins = false;\n\n // First pass: locate all joins and populate joinedTables for accurate JSON path detection\n for (const operation of this.operations) {\n if (JOIN_TYPES.has(operation.type)) {\n this.hasJoins = true;\n const data = operation.data as any;\n const joinTable = data.table as string;\n const alias = data.alias as string;\n\n if (joinTable) this.joinedTables.add(joinTable);\n if (alias) this.joinedTables.add(alias);\n }\n }\n\n // Process each operation\n for (const operation of this.operations) {\n this.processOperation(operation);\n }\n\n // Build the final SQL query\n const query = this.buildSql();\n\n return { query, bindings: this.params };\n }\n\n /**\n * Get a formatted string representation of the query.\n *\n * @returns Formatted SQL with bindings\n */\n public toPrettyString(): string {\n const { query = \"\", bindings } = this.parse();\n return `${query}\\n-- Bindings: ${JSON.stringify(bindings ?? [])}`;\n }\n\n /**\n * Process a single operation.\n *\n * @param operation - The operation to process\n */\n private processOperation(operation: PostgresParserOperation): void {\n const { type, data } = operation;\n\n switch (type) {\n // WHERE operations\n case \"where\":\n this.processWhere(data, \"AND\");\n break;\n case \"orWhere\":\n this.processWhere(data, \"OR\");\n break;\n case \"whereRaw\":\n this.processWhereRaw(data, \"AND\");\n break;\n case \"orWhereRaw\":\n this.processWhereRaw(data, \"OR\");\n break;\n case \"whereIn\":\n this.processWhereIn(data, false);\n break;\n case \"whereNotIn\":\n this.processWhereIn(data, true);\n break;\n case \"whereNull\":\n this.processWhereNull(data, false);\n break;\n case \"whereNotNull\":\n this.processWhereNull(data, true);\n break;\n case \"whereBetween\":\n this.processWhereBetween(data, false);\n break;\n case \"whereNotBetween\":\n this.processWhereBetween(data, true);\n break;\n case \"whereLike\":\n this.processWhereLike(data, false);\n break;\n case \"whereNotLike\":\n this.processWhereLike(data, true);\n break;\n case \"whereColumn\":\n this.processWhereColumn(data, \"AND\");\n break;\n case \"orWhereColumn\":\n this.processWhereColumn(data, \"OR\");\n break;\n case \"whereJsonContains\":\n this.processWhereJsonContains(data, false);\n break;\n case \"whereJsonDoesntContain\":\n this.processWhereJsonContains(data, true);\n break;\n case \"whereFullText\":\n this.processWhereFullText(data);\n break;\n\n // SELECT operations\n case \"select\":\n this.processSelect(data);\n break;\n case \"selectRaw\":\n this.processSelectRaw(data);\n break;\n case \"deselect\":\n this.processDeselect(data);\n break;\n\n // JOIN operations\n case \"join\":\n case \"innerJoin\":\n this.processJoin(data, \"INNER\");\n break;\n case \"leftJoin\":\n this.processJoin(data, \"LEFT\");\n break;\n case \"rightJoin\":\n this.processJoin(data, \"RIGHT\");\n break;\n case \"fullJoin\":\n this.processJoin(data, \"FULL OUTER\");\n break;\n case \"crossJoin\":\n this.processCrossJoin(data);\n break;\n case \"joinRaw\":\n this.processJoinRaw(data);\n break;\n\n // ORDER operations\n case \"orderBy\":\n this.processOrderBy(data);\n break;\n case \"orderByRaw\":\n this.processOrderByRaw(data);\n break;\n\n // GROUP operations\n case \"groupBy\":\n this.processGroupBy(data);\n break;\n case \"having\":\n this.processHaving(data);\n break;\n case \"havingRaw\":\n this.processHavingRaw(data);\n break;\n\n // LIMIT operations\n case \"limit\":\n this.limitValue = data.value as number;\n break;\n case \"offset\":\n this.offsetValue = data.value as number;\n break;\n\n // Other\n case \"distinct\":\n this.isDistinct = true;\n break;\n\n // joinWith select related columns\n case \"selectRelatedColumns\":\n this.processSelectRelatedColumns(data);\n break;\n\n default:\n // Unknown operation - ignore or throw\n break;\n }\n }\n\n /**\n * Build the final SQL query from collected clauses.\n *\n * @returns Complete SQL query string\n */\n private buildSql(): string {\n const parts: string[] = [];\n\n // SELECT clause\n parts.push(this.buildSelectClause());\n\n // FROM clause\n const quotedTable = this.dialect.quoteIdentifier(this.table);\n const fromClause = this.alias\n ? `FROM ${quotedTable} AS ${this.dialect.quoteIdentifier(this.alias)}`\n : `FROM ${quotedTable}`;\n parts.push(fromClause);\n\n // JOIN clauses\n if (this.joinClauses.length > 0) {\n parts.push(this.joinClauses.join(\" \"));\n }\n\n // WHERE clause\n if (this.whereClauses.length > 0) {\n parts.push(`WHERE ${this.whereClauses.join(\" \")}`);\n }\n\n // GROUP BY clause\n if (this.groupColumns.length > 0) {\n const quotedCols = this.groupColumns.map((c) => this.dialect.quoteIdentifier(c));\n parts.push(`GROUP BY ${quotedCols.join(\", \")}`);\n }\n\n // HAVING clause\n if (this.havingClauses.length > 0) {\n parts.push(`HAVING ${this.havingClauses.join(\" AND \")}`);\n }\n\n // ORDER BY clause\n if (this.orderClauses.length > 0) {\n parts.push(`ORDER BY ${this.orderClauses.join(\", \")}`);\n }\n\n // LIMIT/OFFSET\n const limitOffset = this.dialect.limitOffset(this.limitValue, this.offsetValue);\n if (limitOffset) {\n parts.push(limitOffset);\n }\n\n return parts.join(\" \");\n }\n\n /**\n * Build the SELECT clause.\n *\n * @returns SELECT clause string\n */\n private buildSelectClause(): string {\n const distinct = this.isDistinct ? \"DISTINCT \" : \"\";\n\n // If no specific columns, select all — qualify with main table when joins present\n if (this.selectColumns.length === 0 && this.selectRaw.length === 0) {\n return this.hasJoins\n ? `SELECT ${distinct}${this.dialect.quoteIdentifier(this.table)}.*`\n : `SELECT ${distinct}*`;\n }\n\n const columns: string[] = [];\n\n // Add selected columns — prefix with main table when joins present to avoid ambiguity\n for (const col of this.selectColumns) {\n if (!this.deselectColumns.includes(col)) {\n columns.push(this.parseColumnIdentifier(col, this.table, this.alias));\n }\n }\n\n // Add raw expressions\n columns.push(...this.selectRaw);\n\n return `SELECT ${distinct}${columns.join(\", \")}`;\n }\n\n /**\n * Add a placeholder and parameter.\n *\n * @param value - Parameter value\n * @returns Placeholder string ($1, $2, etc.)\n */\n private addParam(value: unknown): string {\n this.params.push(value);\n return this.dialect.placeholder(this.paramIndex++);\n }\n\n /**\n * Absorb a sub-parser's params into this parser, returning a rewriter\n * function that translates the sub-parser's `$N` placeholders into freshly\n * numbered placeholders in this parser's namespace.\n *\n * Required whenever sub-parser SQL fragments (e.g. WHERE clauses produced\n * for a `joinWith` constraint) are spliced into the outer query — without\n * the rewrite the embedded `$N` references point at parameters this\n * parser has no knowledge of, leaving them dangling in the final SQL.\n *\n * The sub-parser's `params[i]` corresponds to its `$(i+1)` placeholder\n * (its `paramIndex` always starts at 1), so we map sequentially.\n *\n * @example\n * const renumber = this.absorbSubParserParams(subParser);\n * const fragment = renumber(subParser.whereClauses.join(\" \"));\n */\n private absorbSubParserParams(subParser: PostgresQueryParser): (sql: string) => string {\n if (subParser.params.length === 0) {\n return (sql) => sql;\n }\n\n const oldToNew = new Map<string, string>();\n\n for (let index = 0; index < subParser.params.length; index++) {\n const newPlaceholder = this.addParam(subParser.params[index]);\n oldToNew.set(`$${index + 1}`, newPlaceholder);\n }\n\n return (sql) => sql.replace(/\\$\\d+/g, (match) => oldToNew.get(match) ?? match);\n }\n\n /**\n * Process a basic WHERE operation.\n *\n * Delegates to specialised processors for operators that require more than a\n * single placeholder (between, in, like-variants, exists, etc.).\n */\n private processWhere(data: Record<string, unknown>, boolean: \"AND\" | \"OR\"): void {\n const field = data.field as string;\n const operator = (data.operator as WhereOperator) ?? \"=\";\n const value = data.value;\n\n // Delegate to specialised processors for operators that need it\n switch (operator) {\n case \"between\":\n return this.processWhereBetween({ field, range: value as [unknown, unknown] }, false);\n case \"notBetween\":\n return this.processWhereBetween({ field, range: value as [unknown, unknown] }, true);\n case \"in\":\n return this.processWhereIn({ field, values: value as unknown[] }, false);\n case \"notIn\":\n return this.processWhereIn({ field, values: value as unknown[] }, true);\n case \"like\":\n case \"ilike\":\n case \"startsWith\":\n case \"endsWith\":\n return this.processWhereLike({ field, pattern: value as string }, false);\n case \"notLike\":\n case \"notStartsWith\":\n case \"notEndsWith\":\n return this.processWhereLike({ field, pattern: value as string }, true);\n case \"exists\":\n // EXISTS expects value to be a raw sub-query string\n return this.addWhereClause(`EXISTS (${value})`, boolean);\n }\n\n const quotedField = this.parseColumnIdentifier(field, this.table, this.alias);\n\n if (value === null) {\n const nullOperator = operator === \"!=\" ? \"IS NOT NULL\" : \"IS NULL\";\n return this.addWhereClause(`${quotedField} ${nullOperator}`, boolean);\n }\n\n // Simple single-value operator — fall through to generic path\n const placeholder = this.addParam(value);\n this.addWhereClause(`${quotedField} ${this.mapOperator(operator)} ${placeholder}`, boolean);\n }\n\n /**\n * Process a raw WHERE operation.\n */\n private processWhereRaw(data: Record<string, unknown>, boolean: \"AND\" | \"OR\"): void {\n const expression = data.expression as string;\n const bindings = (data.bindings as unknown[]) ?? [];\n\n // Replace ? placeholders with $n\n let processed = expression;\n for (const binding of bindings) {\n processed = processed.replace(\"?\", this.addParam(binding));\n }\n\n this.addWhereClause(processed, boolean);\n }\n\n /**\n * Process WHERE IN / NOT IN.\n */\n private processWhereIn(data: Record<string, unknown>, negate: boolean): void {\n const field = data.field as string;\n const values = data.values as unknown[];\n\n const quotedField = this.parseColumnIdentifier(field, this.table, this.alias);\n const operator = negate ? \"!= ALL\" : \"= ANY\";\n const placeholder = this.addParam(values);\n\n this.addWhereClause(`${quotedField} ${operator}(${placeholder})`, \"AND\");\n }\n\n /**\n * Process WHERE NULL / NOT NULL.\n */\n private processWhereNull(data: Record<string, unknown>, negate: boolean): void {\n const field = data.field as string;\n const quotedField = this.parseColumnIdentifier(field, this.table, this.alias);\n const clause = negate ? `${quotedField} IS NOT NULL` : `${quotedField} IS NULL`;\n this.addWhereClause(clause, \"AND\");\n }\n\n /**\n * Process WHERE BETWEEN / NOT BETWEEN.\n */\n private processWhereBetween(data: Record<string, unknown>, negate: boolean): void {\n const field = data.field as string;\n const range = data.range as [unknown, unknown];\n\n const quotedField = this.parseColumnIdentifier(field, this.table, this.alias);\n const placeholder1 = this.addParam(range[0]);\n const placeholder2 = this.addParam(range[1]);\n const keyword = negate ? \"NOT BETWEEN\" : \"BETWEEN\";\n\n this.addWhereClause(`${quotedField} ${keyword} ${placeholder1} AND ${placeholder2}`, \"AND\");\n }\n\n /**\n * Process WHERE LIKE / NOT LIKE.\n */\n private processWhereLike(data: Record<string, unknown>, negate: boolean): void {\n const field = data.field as string;\n const pattern = data.pattern as string;\n\n const quotedField = this.parseColumnIdentifier(field, this.table, this.alias);\n const { operator } = this.dialect.likePattern(pattern, true);\n const placeholder = this.addParam(pattern);\n const keyword = negate ? `NOT ${operator}` : operator;\n\n this.addWhereClause(`${quotedField} ${keyword} ${placeholder}`, \"AND\");\n }\n\n /**\n * Process WHERE column comparison.\n */\n private processWhereColumn(data: Record<string, unknown>, boolean: \"AND\" | \"OR\"): void {\n const first = data.first as string;\n const operator = (data.operator as string) ?? \"=\";\n const second = data.second as string;\n\n // Both sides may need qualification if unambiguous table is unclear\n const quotedFirst = this.parseColumnIdentifier(first, this.table, this.alias);\n const quotedSecond = this.parseColumnIdentifier(second, this.table, this.alias);\n\n this.addWhereClause(`${quotedFirst} ${operator} ${quotedSecond}`, boolean);\n }\n\n /**\n * Process WHERE JSON contains.\n */\n private processWhereJsonContains(data: Record<string, unknown>, negate: boolean): void {\n const path = data.path as string;\n const value = data.value;\n\n const quotedPath = this.parseColumnIdentifier(path, this.table, this.alias);\n const jsonValue = JSON.stringify(value);\n const operator = negate ? \"NOT @>\" : \"@>\";\n\n this.addWhereClause(`${quotedPath} ${operator} '${jsonValue}'::jsonb`, \"AND\");\n }\n\n /**\n * Process full-text search WHERE.\n */\n private processWhereFullText(data: Record<string, unknown>): void {\n const fields = data.fields as string[];\n const query = data.query as string;\n\n // Build tsvector from fields\n const tsVectors = fields\n .map((f) => `to_tsvector('english', ${this.dialect.quoteIdentifier(f)})`)\n .join(\" || \");\n\n const placeholder = this.addParam(query);\n this.addWhereClause(`(${tsVectors}) @@ plainto_tsquery('english', ${placeholder})`, \"AND\");\n }\n\n /**\n * Process SELECT operation.\n */\n private processSelect(data: Record<string, unknown>): void {\n const fields = data.fields as string[] | Record<string, string>;\n\n if (Array.isArray(fields)) {\n this.selectColumns.push(...fields);\n } else {\n // Handle aliases: { field: 'alias' }\n for (const [field, alias] of Object.entries(fields)) {\n const quotedField = this.dialect.quoteIdentifier(field);\n const quotedAlias = this.dialect.quoteIdentifier(alias);\n this.selectRaw.push(`${quotedField} AS ${quotedAlias}`);\n }\n }\n }\n\n /**\n * Process raw SELECT expression.\n */\n private processSelectRaw(data: Record<string, unknown>): void {\n const expression = data.expression as string | Record<string, unknown>;\n const bindings = (data.bindings as unknown[]) ?? [];\n\n if (typeof expression === \"string\") {\n // Replace ? placeholders with $n positional params (same as processWhereRaw)\n let processed = expression;\n for (const binding of bindings) {\n processed = processed.replace(\"?\", this.addParam(binding));\n }\n this.selectRaw.push(processed);\n } else {\n // Handle object expressions (for compatibility)\n for (const [alias, expr] of Object.entries(expression)) {\n this.selectRaw.push(`${expr} AS ${this.dialect.quoteIdentifier(alias)}`);\n }\n }\n }\n\n /**\n * Process DESELECT operation.\n */\n private processDeselect(data: Record<string, unknown>): void {\n const fields = data.fields as string[];\n this.deselectColumns.push(...fields);\n }\n\n /**\n * Process SELECT for related columns (joinWith).\n *\n * - hasOne / belongsTo → LEFT JOIN + row_to_json (single object)\n * - hasMany → correlated subquery with json_agg (array, no row explosion)\n *\n * @example hasMany correlated subquery:\n * (SELECT json_agg(row_to_json(a.*))\n * FROM \"chat_message_actions\" a\n * WHERE a.\"chat_message_id\" = \"chat_messages\".\"id\") AS \"actions\"\n *\n * @example hasOne/belongsTo row_to_json:\n * row_to_json(\"organizationAiModel\".*) AS \"organizationAiModel\"\n */\n private processSelectRelatedColumns(data: Record<string, unknown>): void {\n const alias = data.alias as string;\n const select = data.select as string[] | undefined;\n const relationType = data.type as string | undefined;\n const constraintOps = data.constraintOps as PostgresParserOperation[] | undefined;\n const quotedAlias = this.dialect.quoteIdentifier(alias);\n const quotedTable = this.dialect.quoteIdentifier(this.table);\n\n const hasExplicitSelect = this.selectColumns.length > 0;\n if (!hasExplicitSelect && !this.selectRaw.includes(`${quotedTable}.*`)) {\n this.selectRaw.unshift(`${quotedTable}.*`);\n }\n\n if (relationType === \"hasMany\") {\n // Correlated subquery — no JOIN, no row explosion, returns a JSON array.\n const relatedTable = data.table as string;\n const foreignKey = data.foreignKey as string;\n const localKey = data.localKey as string;\n const quotedRelatedTable = this.dialect.quoteIdentifier(relatedTable);\n const quotedForeignKey = this.dialect.quoteIdentifier(foreignKey);\n const quotedLocalKey = this.dialect.quoteIdentifier(localKey);\n const quotedMainTable = this.dialect.quoteIdentifier(this.table);\n\n let innerSelect: string;\n if (select && select.length > 0) {\n // Pick specific columns: json_agg(json_build_object('id', a.\"id\", ...))\n const fields = select\n .map((col) => `'${col}', a.${this.dialect.quoteIdentifier(col)}`)\n .join(\", \");\n innerSelect = `json_agg(json_build_object(${fields}))`;\n } else {\n innerSelect = `json_agg(row_to_json(a.*))`;\n }\n\n // Build the base FK condition\n const fkCondition = `a.${quotedForeignKey} = ${quotedMainTable}.${quotedLocalKey}`;\n\n // Merge constraint ops (where / order / limit) from a sub-parser.\n // The sub-parser numbers its own placeholders starting at $1; we must\n // absorb its params into this parser and renumber the embedded SQL,\n // otherwise $N references in the merged clauses dangle.\n let extraWhere = \"\";\n let orderBy = \"\";\n let limitClause = \"\";\n\n if (constraintOps && constraintOps.length > 0) {\n const subParser = new PostgresQueryParser({\n table: relatedTable,\n alias: \"a\",\n operations: constraintOps,\n });\n subParser.parse();\n\n const renumber = this.absorbSubParserParams(subParser);\n\n if (subParser.whereClauses.length > 0) {\n extraWhere = ` AND ${renumber(subParser.whereClauses.join(\" \"))}`;\n }\n if (subParser.orderClauses.length > 0) {\n orderBy = ` ORDER BY ${renumber(subParser.orderClauses.join(\", \"))}`;\n }\n if (subParser.limitValue !== undefined) {\n limitClause = ` LIMIT ${subParser.limitValue}`;\n }\n }\n\n // Wrap with ORDER/LIMIT only when constraints are present (json_agg ignores ORDER)\n const innerQuery =\n orderBy || limitClause\n ? `SELECT row_to_json(sub.*) FROM (SELECT * FROM ${quotedRelatedTable} a WHERE ${fkCondition}${extraWhere}${orderBy}${limitClause}) sub`\n : `SELECT ${innerSelect.replace(\"json_agg(\", \"\").replace(/\\)$/, \"\")} FROM ${quotedRelatedTable} a WHERE ${fkCondition}${extraWhere}`;\n\n const aggregated =\n orderBy || limitClause\n ? `(SELECT json_agg(row_to_json(sub.*)) FROM (SELECT * FROM ${quotedRelatedTable} a WHERE ${fkCondition}${extraWhere}${orderBy}${limitClause}) sub) AS ${quotedAlias}`\n : `(SELECT ${innerSelect} FROM ${quotedRelatedTable} a WHERE ${fkCondition}${extraWhere}) AS ${quotedAlias}`;\n\n this.selectRaw.push(aggregated);\n } else {\n // hasOne / belongsTo — single object via LEFT JOIN + row_to_json.\n // If constraint provides an explicit select list, prefer it over data.select\n let effectiveSelect = select;\n if (constraintOps && constraintOps.length > 0) {\n const subParser = new PostgresQueryParser({\n table: (data.table as string) ?? alias,\n alias,\n operations: constraintOps,\n });\n subParser.parse();\n if (subParser.selectColumns.length > 0) {\n effectiveSelect = subParser.selectColumns;\n }\n }\n\n if (effectiveSelect && effectiveSelect.length > 0) {\n const selectedColumns = effectiveSelect\n .map((col) => `${quotedAlias}.${this.dialect.quoteIdentifier(col)}`)\n .join(\", \");\n this.selectRaw.push(\n `row_to_json((SELECT d FROM (SELECT ${selectedColumns}) d)) AS ${quotedAlias}`,\n );\n } else {\n this.selectRaw.push(`row_to_json(${quotedAlias}.*) AS ${quotedAlias}`);\n }\n }\n }\n\n /**\n * Process JOIN operation with smart field detection.\n *\n * Handles both regular columns and JSONB nested paths:\n * - \"id\" → \"table\".\"id\" (auto-prefixed)\n * - \"users.id\" → \"users\".\"id\" (explicit table)\n * - \"createdBy.id\" → \"table\".\"createdBy\"->>'id' (JSONB path)\n * - \"posts.createdBy.id\" → \"posts\".\"createdBy\"->>'id' (JSONB with table)\n */\n private processJoin(data: Record<string, unknown>, type: string): void {\n const options = data as unknown as\n | JoinOptions\n | { table: string; localField: string; foreignField: string };\n\n const joinTable = \"table\" in options ? options.table : \"\";\n const localField = \"localField\" in options ? options.localField : \"\";\n const foreignField = \"foreignField\" in options ? options.foreignField : \"\";\n const alias = \"alias\" in options ? options.alias : undefined;\n const constraintOps = (data.constraintOps as PostgresParserOperation[] | undefined) ?? [];\n\n const quotedTable = this.dialect.quoteIdentifier(joinTable);\n const tableRef = alias\n ? `${quotedTable} AS ${this.dialect.quoteIdentifier(alias)}`\n : quotedTable;\n const tableAlias = alias ?? joinTable;\n\n // Track the joined table for reference detection\n this.joinedTables.add(joinTable);\n if (alias) {\n this.joinedTables.add(alias);\n }\n\n // Parse local field (belongs to main table)\n const quotedLocal = this.parseColumnIdentifier(localField!, this.table, this.alias);\n\n // Parse foreign field (belongs to join table)\n const quotedForeign = this.parseColumnIdentifier(foreignField!, joinTable, tableAlias);\n\n // Build the basic ON condition. For hasOne/belongsTo joinWith with a\n // constraint callback, append the constraint's where-clauses to the ON\n // clause (preserves LEFT JOIN semantics — main rows stay even when no\n // related row passes the constraint). orderBy/limit on the constraint\n // are silently dropped — they have no meaning on a single-row LEFT JOIN.\n let onClause = `${quotedLocal} = ${quotedForeign}`;\n\n if (constraintOps.length > 0) {\n const whereOps = constraintOps.filter(\n (op) => op.type.startsWith(\"where\") || op.type.startsWith(\"orWhere\"),\n );\n\n if (whereOps.length > 0) {\n const subParser = new PostgresQueryParser({\n table: joinTable,\n alias: tableAlias,\n operations: whereOps,\n });\n subParser.parse();\n\n if (subParser.whereClauses.length > 0) {\n const renumber = this.absorbSubParserParams(subParser);\n onClause = `${onClause} AND ${renumber(subParser.whereClauses.join(\" \"))}`;\n }\n }\n }\n\n this.joinClauses.push(`${type} JOIN ${tableRef} ON ${onClause}`);\n }\n\n /**\n * Parse a column identifier with smart detection for table prefixes and JSONB paths.\n *\n * Supports an optional explicit cast suffix using PostgreSQL's `::type` syntax,\n * which is the only way to coerce a JSONB-extracted value (always returned as\n * `text`) into another type. The parser does NOT infer casts from key names —\n * coercion is always opt-in by the caller.\n *\n * @param field - The field string. Examples:\n * - \"id\" → `\"table\".\"id\"`\n * - \"users.id\" → `\"users\".\"id\"`\n * - \"createdBy.id\" → `\"table\".\"createdBy\"->>'id'`\n * - \"createdBy.id::int\" → `(\"table\".\"createdBy\"->>'id')::int`\n * - \"meta.score::numeric\" → `(\"table\".\"meta\"->>'score')::numeric`\n * - \"posts.createdBy.id::uuid\" → `(\"posts\".\"createdBy\"->>'id')::uuid`\n * @param defaultTable - Default table to use if no prefix\n * @param tableAlias - Table alias to use if provided\n * @returns Properly quoted SQL expression\n */\n private parseColumnIdentifier(field: string, defaultTable: string, tableAlias?: string): string {\n if (!field) return \"\";\n\n // Extract optional explicit cast suffix: \"createdBy.id::int\" → path \"createdBy.id\", cast \"int\"\n let cast: string | undefined;\n const castIndex = field.indexOf(\"::\");\n if (castIndex !== -1) {\n cast = field.slice(castIndex + 2).trim();\n field = field.slice(0, castIndex);\n }\n\n const effectiveTable = tableAlias ?? defaultTable;\n const parts = field.split(\".\");\n\n let expression: string;\n\n if (parts.length === 1) {\n // Single part: just a column name, prefix with default table\n expression = `${this.dialect.quoteIdentifier(effectiveTable)}.${this.dialect.quoteIdentifier(field)}`;\n } else if (parts.length === 2) {\n // Two parts: could be \"table.column\" or \"jsonbColumn.key\"\n const [first, second] = parts;\n\n if (this.isTableReference(first)) {\n // It's table.column - regular column reference\n expression = `${this.dialect.quoteIdentifier(first)}.${this.dialect.quoteIdentifier(second)}`;\n } else {\n // It's jsonbColumn.key - JSONB path\n expression = this.buildJsonbPath(effectiveTable, first, [second]);\n }\n } else {\n // Three or more parts: \"table.jsonbColumn.key...\" or \"jsonbColumn.key1.key2...\"\n const [first, second, ...rest] = parts;\n\n if (this.isTableReference(first)) {\n // First part is table: \"posts.createdBy.id\" → table is \"posts\", JSONB is \"createdBy.id\"\n expression = this.buildJsonbPath(first, second, rest);\n } else {\n // No table prefix: \"createdBy.address.city\" → use default table\n expression = this.buildJsonbPath(effectiveTable, first, [second, ...rest]);\n }\n }\n\n return cast ? `(${expression})::${cast}` : expression;\n }\n\n /**\n * Check if a string is a table reference (main table or join table).\n */\n private isTableReference(name: string): boolean {\n if (name === this.table || name === this.alias) {\n return true;\n }\n\n if (this.joinedTables.has(name)) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Build a JSONB path expression.\n *\n * @param table - Table name\n * @param column - JSONB column name\n * @param path - Array of nested keys\n * @returns PostgreSQL JSONB path expression\n *\n * Returns the raw JSONB path expression — extracted values are always `text`\n * (`->>` returns text). Callers that need a different type must request an\n * explicit cast via the `::type` suffix in `parseColumnIdentifier`.\n *\n * @example\n * buildJsonbPath(\"posts\", \"createdBy\", [\"id\"])\n * // Returns: \"posts\".\"createdBy\"->>'id'\n *\n * buildJsonbPath(\"posts\", \"createdBy\", [\"address\", \"city\"])\n * // Returns: \"posts\".\"createdBy\"->'address'->>'city'\n */\n private buildJsonbPath(table: string, column: string, path: string[]): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n const quotedColumn = this.dialect.quoteIdentifier(column);\n\n if (path.length === 0) {\n return `${quotedTable}.${quotedColumn}`;\n }\n\n // Build JSONB path: use -> for intermediate keys, ->> for final key (returns text)\n let expression = `${quotedTable}.${quotedColumn}`;\n\n for (let i = 0; i < path.length; i++) {\n const isLast = i === path.length - 1;\n const operator = isLast ? \"->>\" : \"->\";\n expression += `${operator}'${path[i]}'`;\n }\n\n return expression;\n }\n\n /**\n * Process CROSS JOIN operation.\n */\n private processCrossJoin(data: Record<string, unknown>): void {\n const table = data.table as string;\n const quotedTable = this.dialect.quoteIdentifier(table);\n this.joinClauses.push(`CROSS JOIN ${quotedTable}`);\n }\n\n /**\n * Process raw JOIN expression.\n */\n private processJoinRaw(data: Record<string, unknown>): void {\n const expression = data.expression as string;\n const bindings = (data.bindings as unknown[]) ?? [];\n\n let processed = expression;\n for (const binding of bindings) {\n processed = processed.replace(\"?\", this.addParam(binding));\n }\n\n this.joinClauses.push(processed);\n }\n\n /**\n * Process ORDER BY operation.\n */\n private processOrderBy(data: Record<string, unknown>): void {\n const field = data.field as string;\n const direction = ((data.direction as string) ?? \"asc\").toUpperCase();\n\n const quotedField = this.parseColumnIdentifier(field, this.table, this.alias);\n this.orderClauses.push(`${quotedField} ${direction}`);\n }\n\n /**\n * Process raw ORDER BY expression.\n */\n private processOrderByRaw(data: Record<string, unknown>): void {\n const expression = data.expression as string;\n const bindings = (data.bindings as unknown[]) ?? [];\n\n // Replace ? placeholders with $n positional params (same as processWhereRaw)\n let processed = expression;\n for (const binding of bindings) {\n processed = processed.replace(\"?\", this.addParam(binding));\n }\n this.orderClauses.push(processed);\n }\n\n /**\n * Process GROUP BY operation.\n */\n private processGroupBy(data: Record<string, unknown>): void {\n const fields = data.fields as string | string[];\n const columns = Array.isArray(fields) ? fields : [fields];\n this.groupColumns.push(...columns);\n }\n\n /**\n * Process HAVING operation.\n */\n private processHaving(data: Record<string, unknown>): void {\n const field = data.field as string;\n const operator = (data.operator as string) ?? \"=\";\n const value = data.value;\n\n const quotedField = this.dialect.quoteIdentifier(field);\n const placeholder = this.addParam(value);\n\n this.havingClauses.push(`${quotedField} ${operator} ${placeholder}`);\n }\n\n /**\n * Process a raw HAVING expression, threading `?` placeholders into\n * positional params the same way `processWhereRaw` / `processSelectRaw` do.\n * Without this, bindings on a `havingRaw` op are silently dropped.\n */\n private processHavingRaw(data: Record<string, unknown>): void {\n let expression = data.expression as string;\n const bindings = (data.bindings as unknown[]) ?? [];\n\n for (const binding of bindings) {\n expression = expression.replace(\"?\", this.addParam(binding));\n }\n\n this.havingClauses.push(expression);\n }\n\n /**\n * Add a WHERE clause with boolean operator.\n */\n private addWhereClause(clause: string, boolean: \"AND\" | \"OR\"): void {\n if (this.whereClauses.length === 0) {\n this.whereClauses.push(clause);\n } else {\n this.whereClauses.push(`${boolean} ${clause}`);\n }\n }\n\n /**\n * Map simple Cascade operators to their SQL equivalents.\n *\n * Complex operators (between, in, like-variants, exists) are handled by\n * dedicated processors and should never reach this method.\n */\n private mapOperator(operator: WhereOperator): string {\n const mapping: Record<string, string> = {\n \"=\": \"=\",\n \"!=\": \"!=\",\n \"<>\": \"<>\",\n \">\": \">\",\n \">=\": \">=\",\n \"<\": \"<\",\n \"<=\": \"<=\",\n like: \"LIKE\",\n notlike: \"NOT LIKE\",\n ilike: \"ILIKE\",\n };\n\n return mapping[operator.toLowerCase()] ?? operator;\n }\n}\n","/**\n * PostgreSQL Query Builder\n *\n * Extends the pure QueryBuilder base with PostgreSQL-specific execution,\n * SQL generation, relation hydration, and scope management.\n *\n * @module cascade/drivers/postgres\n */\n\nimport type { GenericObject } from \"@mongez/reinforcements\";\nimport type {\n ChunkCallback,\n CursorPaginationOptions,\n CursorPaginationResult,\n DriverQuery,\n GroupByInput,\n PaginationOptions,\n PaginationResult,\n QueryBuilderContract,\n RawExpression,\n} from \"../../contracts/query-builder.contract\";\nimport type { DataSource } from \"../../data-source/data-source\";\nimport { dataSourceRegistry } from \"../../data-source/data-source-registry\";\nimport { isAggregateExpression } from \"../../expressions\";\nimport type { GlobalScopeDefinition } from \"../../model/model\";\nimport { resolveModelClass, tryResolveModelClass, type ModelRef } from \"../../model/register-model\";\nimport { QueryBuilder, type Op } from \"../../query-builder/query-builder\";\nimport {\n inferBelongsToForeignKey,\n inferHasForeignKey,\n inferPivotKey,\n inferPivotTable,\n} from \"../../relations/key-conventions\";\nimport { attachLoadedRelation, RelationLoader } from \"../../relations/relation-loader\";\nimport type { PostgresDriver } from \"./postgres-driver\";\nimport { PostgresQueryParser, type PostgresParserOperation } from \"./postgres-query-parser\";\n\n// ============================================================================\n// HELPER\n// ============================================================================\n\n/**\n * Cast an Op[] to PostgresParserOperation[] — the shapes are compatible since\n * both have `type: string` and `data: Record<string, unknown>`.\n */\nfunction toParserOps(ops: Op[]): PostgresParserOperation[] {\n return ops as unknown as PostgresParserOperation[];\n}\n\n// ============================================================================\n// JOIN RELATIONS MAP TYPE\n// ============================================================================\n\ntype JoinRelationConfig = {\n alias: string;\n type: \"belongsTo\" | \"hasOne\" | \"hasMany\";\n model?: ModelRef;\n localKey?: string;\n foreignKey?: string;\n ownerKey?: string;\n parentPath?: string | null;\n relationName?: string;\n parentModel?: ModelRef;\n select?: string[];\n /** Operations recorded by a joinWith constraint callback. */\n constraintOps?: Op[];\n};\n\n// ============================================================================\n// POSTGRES QUERY BUILDER\n// ============================================================================\n\n/**\n * PostgreSQL Query Builder.\n *\n * Collects query operations (via the base class) and delegates SQL generation\n * to `PostgresQueryParser`. Owns execution, hydration, and relation loading.\n *\n * @example\n * ```typescript\n * const users = await User.query()\n * .select([\"id\", \"name\", \"email\"])\n * .where(\"status\", \"active\")\n * .orderBy(\"createdAt\", \"desc\")\n * .limit(10)\n * .get();\n * ```\n */\nexport class PostgresQueryBuilder<T = unknown>\n extends QueryBuilder<T>\n implements QueryBuilderContract<T>\n{\n // ──────────────────────────────────────────────────────────────\n // POSTGRES-SPECIFIC STATE\n // ──────────────────────────────────────────────────────────────\n\n /** Data source backing this builder. */\n public readonly dataSource: DataSource;\n\n /** Hydration callback for transforming result rows into model instances. */\n public hydrateCallback?: (data: unknown, index: number) => unknown;\n\n /** Invoked before query execution. */\n private fetchingCallback?: (query: this) => void | Promise<void>;\n\n /** Invoked after fetch but before hydration. */\n private hydratingCallback?: (records: unknown[], context: unknown) => void | Promise<void>;\n\n /** Invoked after fetch and hydration. */\n private fetchedCallback?: (records: unknown[], context: unknown) => void | Promise<void>;\n\n /**\n * Map of relations registered via `joinWith()`.\n * Keyed by dot-notation path (e.g. \"organizationAiModel.aiModel\").\n */\n public joinRelations = new Map<string, JoinRelationConfig>();\n\n /**\n * Idempotency guard for `applyJoinRelations()` so calling `parse()` then\n * `get()` (or `parse()` twice) doesn't double-emit `selectRelatedColumns`\n * operations.\n */\n private joinRelationsApplied = false;\n\n /**\n * Idempotency guard for `applyCountRelations()` — see `joinRelationsApplied`.\n */\n private countRelationsApplied = false;\n\n /**\n * Idempotency guard for `applyHasRelations()` — see `joinRelationsApplied`.\n */\n private hasRelationsApplied = false;\n\n /**\n * Alias → SQL expression for two-arg `groupBy` aggregates. Recorded by the\n * `groupBy` override; consumed by `applyGroupByAggregates` to rewrite a\n * `having()` on the alias into the underlying expression (Postgres forbids\n * SELECT aliases in HAVING).\n */\n private aggregateAliases = new Map<string, string>();\n\n /**\n * Idempotency guard for `applyGroupByAggregates()` — see `joinRelationsApplied`.\n */\n private groupByAggregatesApplied = false;\n\n // ──────────────────────────────────────────────────────────────\n // CONSTRUCTOR\n // ──────────────────────────────────────────────────────────────\n\n /**\n * @param table - Target table name\n * @param dataSource - Optional (uses default data source from registry if omitted)\n */\n public constructor(\n public readonly table: string,\n dataSource?: DataSource,\n ) {\n super();\n this.dataSource = dataSource ?? dataSourceRegistry.get()!;\n }\n\n // ──────────────────────────────────────────────────────────────\n // DRIVER\n // ──────────────────────────────────────────────────────────────\n\n private get driver(): PostgresDriver {\n return this.dataSource.driver as PostgresDriver;\n }\n\n // ──────────────────────────────────────────────────────────────\n // CLONE\n // ──────────────────────────────────────────────────────────────\n\n public clone(): this {\n const cloned = new PostgresQueryBuilder<T>(this.table, this.dataSource) as this;\n\n // Copy base-class state\n cloned.operations = [...this.operations];\n cloned.pendingGlobalScopes = this.pendingGlobalScopes;\n cloned.availableLocalScopes = this.availableLocalScopes;\n cloned.disabledGlobalScopes = new Set(this.disabledGlobalScopes);\n cloned.scopesApplied = this.scopesApplied;\n cloned.eagerLoadRelations = new Map(this.eagerLoadRelations);\n cloned.countRelations = new Map(this.countRelations);\n cloned.relationDefinitions = this.relationDefinitions;\n cloned.modelClass = this.modelClass;\n\n // Copy PG-specific state\n cloned.hydrateCallback = this.hydrateCallback;\n cloned.joinRelations = new Map(this.joinRelations);\n cloned.joinRelationsApplied = this.joinRelationsApplied;\n cloned.countRelationsApplied = this.countRelationsApplied;\n cloned.hasRelationsApplied = this.hasRelationsApplied;\n cloned.aggregateAliases = new Map(this.aggregateAliases);\n cloned.groupByAggregatesApplied = this.groupByAggregatesApplied;\n\n return cloned;\n }\n\n // ============================================================================\n // PG-SPECIFIC FLUENT METHODS\n // ============================================================================\n\n /**\n * Native-query escape hatch. Passes `operations[]` to the callback for\n * direct manipulation. Use sparingly — only when fluent API is insufficient.\n *\n * @example\n * q.raw(ops => ops.push({ type: \"whereRaw\", data: { expression: \"1=1\" } }))\n */\n public raw(callback: (operations: Op[]) => void): this {\n callback(this.operations);\n return this;\n }\n\n /**\n * Record a DISTINCT flag AND auto-select the field(s).\n * In PostgreSQL, DISTINCT ON (col) requires the col to appear in SELECT.\n *\n * @example\n * q.distinctValues(\"category\") // SELECT category … DISTINCT ON (category)\n * q.distinctValues([\"category\", \"status\"]) // both fields in DISTINCT ON and SELECT\n */\n public override distinctValues(fields?: string | string[]): this {\n // Record the base DISTINCT flag op\n super.distinctValues(fields);\n // Also add a select for the field(s) so they appear in the SELECT clause\n if (fields) {\n const fieldArr = Array.isArray(fields) ? fields : [fields];\n this.addOperation(\"select\", { fields: fieldArr });\n }\n return this;\n }\n\n /**\n * GROUP BY with computed aggregates.\n *\n * Single-arg form defers to the base builder. With `aggregates`, each entry\n * is translated to SQL — via the dialect for `$agg.*` helpers, verbatim for\n * a raw SQL string — and pushed through the proven `selectRaw` projection\n * (the same plumbing `similarTo` / `applyCountRelations` rely on). The\n * grouped columns are projected explicitly because `SELECT *` is invalid\n * alongside `GROUP BY`. The alias → expression map is recorded so\n * `applyGroupByAggregates` can later rewrite `having()` on the alias.\n *\n * `$agg.distinct/floor/first/last` throw (MongoDB-only on Postgres v1);\n * MongoDB operator objects throw (not portable to SQL).\n *\n * @example\n * Order.query().groupBy(\"category\", {\n * orders: $agg.count(),\n * revenue: $agg.sum(\"amount\"),\n * }).having(\"revenue\", \">\", 1000);\n */\n public groupBy(fields: GroupByInput): this;\n public groupBy(fields: GroupByInput, aggregates: Record<string, RawExpression>): this;\n public groupBy(fields: GroupByInput, aggregates?: Record<string, RawExpression>): this {\n if (!aggregates) {\n return super.groupBy(fields);\n }\n\n const fieldList = Array.isArray(fields) ? fields : [fields];\n\n this.addOperation(\"select\", { fields: fieldList });\n\n for (const [alias, expression] of Object.entries(aggregates)) {\n let sql: string;\n\n if (isAggregateExpression(expression)) {\n sql = this.driver.dialect.aggregateToSql(expression);\n } else if (typeof expression === \"string\") {\n sql = expression;\n } else {\n throw new Error(\n `groupBy aggregate \"${alias}\" must be a $agg.* helper or a raw SQL ` +\n `string on Postgres; got ${typeof expression}. MongoDB operator ` +\n `objects are not portable to SQL — use selectRaw with explicit SQL.`,\n );\n }\n\n this.aggregateAliases.set(alias, sql);\n\n this.addOperation(\"selectRaw\", {\n expression: `${sql} AS ${this.driver.dialect.quoteIdentifier(alias)}`,\n bindings: [],\n });\n }\n\n return super.groupBy(fields);\n }\n\n /**\n * Nearest-neighbour vector similarity search via pgvector cosine distance.\n *\n * Adds two operations atomically:\n * 1. `selectRaw` → `1 - (column <=> $n::vector) AS <alias>`\n * Makes the similarity score available on every returned row.\n * 2. `orderByRaw` → `column <=> $n::vector`\n * Tells the PostgreSQL query planner to use the IVFFlat/HNSW vector index.\n * Using the alias in ORDER BY would bypass the index — the raw expression is required.\n *\n * @example\n * ```typescript\n * const results = await Vector.query()\n * .where({ organization_id: \"org-123\", content_type: \"summary\" })\n * .similarTo(\"embedding\", queryEmbedding)\n * .limit(5)\n * .get<VectorRow & { score: number }>();\n * ```\n */\n public similarTo(column: string, embedding: number[], alias = \"score\"): this {\n // pgvector expects the literal format: [n,n,n,...]\n const literal = `[${embedding.join(\",\")}]`;\n const quotedCol = this.driver.dialect.quoteIdentifier(column);\n const quotedTable = this.driver.dialect.quoteIdentifier(this.table);\n\n // 0 — Preserve all table columns.\n // Adding a selectRaw suppresses the parser's \"SELECT *\" fallback,\n // so we must explicitly include table.* before the score expression.\n this.addOperation(\"selectRaw\", {\n expression: `${quotedTable}.*`,\n bindings: [],\n });\n\n // 1 — Add similarity score to SELECT\n this.addOperation(\"selectRaw\", {\n expression: `1 - (${quotedCol} <=> ?::vector) AS ${alias}`,\n bindings: [literal],\n });\n\n // 2 — ORDER BY the raw expression so the vector index is used\n this.addOperation(\"orderByRaw\", {\n expression: `${quotedCol} <=> ?::vector`,\n bindings: [literal],\n });\n\n return this;\n }\n\n /** Set a hydration callback that transforms each result row. */\n public hydrate(callback: (data: unknown, index: number) => unknown): this {\n this.hydrateCallback = callback;\n return this;\n }\n\n /** Register a callback invoked before query execution. */\n public onFetching(callback: (query: this) => void | Promise<void>): () => void {\n this.fetchingCallback = callback;\n return () => {\n this.fetchingCallback = undefined;\n };\n }\n\n /** Register a callback invoked after fetch but before hydration. */\n public onHydrating(\n callback: (records: unknown[], context: unknown) => void | Promise<void>,\n ): () => void {\n this.hydratingCallback = callback;\n return () => {\n this.hydratingCallback = undefined;\n };\n }\n\n /** Register a callback invoked after fetch and hydration. */\n public onFetched(\n callback: (records: unknown[], context: unknown) => void | Promise<void>,\n ): () => void {\n this.fetchedCallback = callback;\n return () => {\n this.fetchedCallback = undefined;\n };\n }\n\n // ============================================================================\n // SCOPES\n // ============================================================================\n\n /** Apply pending global scopes to the operations list. */\n private applyPendingScopes(): void {\n if (!this.pendingGlobalScopes || this.scopesApplied) return;\n\n const beforeOps: Op[] = [];\n const afterOps: Op[] = [];\n\n for (const [name, { callback, timing }] of this.pendingGlobalScopes as Map<\n string,\n GlobalScopeDefinition\n >) {\n if (this.disabledGlobalScopes.has(name)) continue;\n\n const temp = new PostgresQueryBuilder(this.table, this.dataSource);\n callback(temp as unknown as QueryBuilderContract<T>);\n\n if (timing === \"before\") {\n beforeOps.push(...temp.operations);\n } else {\n afterOps.push(...temp.operations);\n }\n }\n\n this.operations = [...beforeOps, ...this.operations, ...afterOps];\n this.scopesApplied = true;\n }\n\n // ============================================================================\n // WHERE — POSTGRES-SPECIFIC (driver.dialect required)\n // ============================================================================\n\n /** Array field contains a value (or object with key). */\n public whereArrayContains(field: string, value: unknown, key?: string): this {\n const quotedField = this.driver.dialect.quoteIdentifier(field);\n if (key) {\n this.addOperation(\"whereRaw\", {\n expression: `${quotedField} @> ?::jsonb`,\n bindings: [JSON.stringify([{ [key]: value }])],\n });\n } else {\n this.addOperation(\"whereRaw\", {\n expression: `? = ANY(${quotedField})`,\n bindings: [value],\n });\n }\n return this;\n }\n\n /** Array field does NOT contain a value (or object with key). */\n public whereArrayNotContains(field: string, value: unknown, key?: string): this {\n const quotedField = this.driver.dialect.quoteIdentifier(field);\n if (key) {\n this.addOperation(\"whereRaw\", {\n expression: `NOT (${quotedField} @> ?::jsonb)`,\n bindings: [JSON.stringify([{ [key]: value }])],\n });\n } else {\n this.addOperation(\"whereRaw\", {\n expression: `NOT (? = ANY(${quotedField}))`,\n bindings: [value],\n });\n }\n return this;\n }\n\n /** Array field contains value OR is empty. */\n public whereArrayHasOrEmpty(field: string, value: unknown, key?: string): this {\n const quotedField = this.driver.dialect.quoteIdentifier(field);\n if (key) {\n this.addOperation(\"whereRaw\", {\n expression: `(${quotedField} @> ?::jsonb OR ${quotedField} = '[]'::jsonb OR ${quotedField} IS NULL)`,\n bindings: [JSON.stringify([{ [key]: value }])],\n });\n } else {\n this.addOperation(\"whereRaw\", {\n expression: `(? = ANY(${quotedField}) OR array_length(${quotedField}, 1) IS NULL)`,\n bindings: [value],\n });\n }\n return this;\n }\n\n /** Array field does NOT contain value OR is empty. */\n public whereArrayNotHaveOrEmpty(field: string, value: unknown, key?: string): this {\n const quotedField = this.driver.dialect.quoteIdentifier(field);\n if (key) {\n this.addOperation(\"whereRaw\", {\n expression: `(NOT (${quotedField} @> ?::jsonb) OR ${quotedField} = '[]'::jsonb OR ${quotedField} IS NULL)`,\n bindings: [JSON.stringify([{ [key]: value }])],\n });\n } else {\n this.addOperation(\"whereRaw\", {\n expression: `(NOT (? = ANY(${quotedField})) OR array_length(${quotedField}, 1) IS NULL)`,\n bindings: [value],\n });\n }\n return this;\n }\n\n // ============================================================================\n // joinWith — RESOLVE RELATION DEFINITIONS\n // ============================================================================\n\n /**\n * Load relations via SQL JOINs (single query) with optional per-relation constraints.\n *\n * Supports:\n * - `joinWith(\"author\")` / `joinWith([\"author\", \"category\"])`\n * - `joinWith({ actions: q => q.where(\"status\", \"pending\").limit(5) })`\n * - `joinWith({ organizationAiModel: \"id,name\", actions: q => q.orderBy(\"sort_order\") })`\n *\n * @example\n * ChatMessage.joinWith({\n * actions: q => q.where(\"status\", \"pending\").orderBy(\"sort_order\", \"asc\").limit(5),\n * organizationAiModel: \"id,createdAt\",\n * })\n */\n public override joinWith(...args: unknown[]): this {\n // Normalise all args into an array of { path, constraint } pairs\n type Entry = { path: string; constraint?: string | ((q: QueryBuilder) => void) };\n const entries: Entry[] = [];\n\n for (const arg of args) {\n if (typeof arg === \"string\") {\n entries.push({ path: arg });\n } else if (Array.isArray(arg)) {\n for (const rel of arg) {\n entries.push({ path: rel });\n }\n } else if (typeof arg === \"object\" && arg !== null) {\n for (const [rel, val] of Object.entries(arg)) {\n entries.push({ path: rel, constraint: val });\n }\n }\n }\n\n for (const { path, constraint } of entries) {\n // Parse each dot-notation path segment (supports \"rel1.rel2\" nesting)\n const segments = path.split(\".\");\n let currentModel: unknown = this.modelClass;\n let currentPath = \"\";\n\n for (let i = 0; i < segments.length; i++) {\n const rawSeg = segments[i];\n // String shorthand: \"relName:col1,col2\"\n const colonIdx = rawSeg.indexOf(\":\");\n const segName = colonIdx === -1 ? rawSeg : rawSeg.slice(0, colonIdx);\n const segColumns =\n colonIdx === -1\n ? undefined\n : rawSeg\n .slice(colonIdx + 1)\n .split(\",\")\n .filter(Boolean);\n\n currentPath = currentPath ? `${currentPath}.${segName}` : segName;\n\n // If already registered, update if new select columns given; advance model\n if (this.joinRelations.has(currentPath)) {\n const existing = this.joinRelations.get(currentPath)!;\n if (segColumns) existing.select = segColumns;\n\n // Apply constraint only on the deepest segment\n if (i === segments.length - 1 && constraint !== undefined) {\n existing.constraintOps = this._resolveConstraintOps(constraint);\n }\n\n currentModel = tryResolveModelClass(existing.model);\n continue;\n }\n\n if (!this.relationDefinitions) continue;\n\n const def = (\n i === 0\n ? (this.relationDefinitions as Record<string, unknown>)\n : (currentModel as { relations?: Record<string, unknown> })?.relations\n )?.[segName] as Record<string, unknown> | undefined;\n\n if (!def) {\n throw new Error(\n `Relation \"${segName}\" not found on model ${(currentModel as { name?: string })?.name ?? \"unknown\"}`,\n );\n }\n\n // Resolve select columns: colon shorthand > constraint string > def.select\n let selectColumns: string[] | undefined =\n segColumns ?? (def.select as string[] | undefined);\n\n let constraintOps: Op[] | undefined;\n if (i === segments.length - 1 && constraint !== undefined) {\n if (typeof constraint === \"string\") {\n selectColumns = constraint.split(\",\").filter(Boolean);\n } else {\n constraintOps = this._resolveConstraintOps(constraint);\n }\n }\n\n const alias = currentPath.replace(/\\./g, \"_\");\n\n this.joinRelations.set(currentPath, {\n alias,\n type: def.type as JoinRelationConfig[\"type\"],\n model: def.model as ModelRef | undefined,\n localKey: def.localKey as string | undefined,\n foreignKey: def.foreignKey as string | undefined,\n ownerKey: def.ownerKey as string | undefined,\n parentPath: i > 0 ? currentPath.substring(0, currentPath.lastIndexOf(\".\")) : null,\n relationName: segName,\n parentModel: currentModel as ModelRef | undefined,\n select: selectColumns,\n constraintOps,\n });\n\n currentModel = tryResolveModelClass(def.model as ModelRef | undefined);\n\n if (!currentModel) {\n throw new Error(`Relation model not found for \"${segName}\" in \"${currentPath}\"`);\n }\n }\n }\n\n return this;\n }\n\n /** Run a joinWith constraint callback against a sub-QB and capture its operations. */\n private _resolveConstraintOps(constraint: string | ((q: QueryBuilder) => void)): Op[] {\n if (typeof constraint === \"string\") return [];\n const sub = new PostgresQueryBuilder(\"__sub__\", this.dataSource);\n constraint(sub);\n return sub.operations;\n }\n\n // ============================================================================\n // EXECUTION METHODS\n // ============================================================================\n\n /**\n * Execute the query and return all matching rows.\n */\n public async get<TResult = T>(): Promise<TResult[]> {\n this.applyPendingScopes();\n this._processJoinWithOps();\n this.applyJoinRelations();\n this.applyHasRelations();\n this.applyCountRelations();\n this.applyGroupByAggregates();\n\n if (this.fetchingCallback) {\n await this.fetchingCallback(this);\n }\n\n const parser = new PostgresQueryParser({\n table: this.table,\n operations: toParserOps(this.operations),\n });\n\n const { query = \"\", bindings = [] } = parser.parse();\n\n try {\n const result = await this.driver.query<TResult>(query, bindings);\n let records = result.rows;\n\n const joinedData = this.extractJoinedRelationData(records);\n\n if (this.hydratingCallback) {\n await this.hydratingCallback(records as unknown[], {});\n }\n\n if (this.hydrateCallback) {\n records = records.map((row, index) => this.hydrateCallback!(row, index)) as TResult[];\n }\n\n this.attachJoinedRelations(records, joinedData);\n\n await this.applyEagerLoading(records as unknown[]);\n\n if (this.fetchedCallback) {\n await this.fetchedCallback(records as unknown[], {});\n }\n\n this.operations = [];\n return records;\n } catch (error) {\n console.log(\"Error while executing:\", query, bindings);\n console.log(\"Query Builder Error:\", error);\n throw error;\n }\n }\n\n /** Get first result. */\n public async first<TResult = T>(): Promise<TResult | null> {\n const results = await this.limit(1).get<TResult>();\n return results[0] ?? null;\n }\n\n /** Get last result (by id desc). */\n public async last<TResult = T>(): Promise<TResult | null> {\n const results = await this.orderByDesc(\"id\").limit(1).get<TResult>();\n return results[0] ?? null;\n }\n\n /** Get random results. */\n public async random<TResult = T>(limit?: number): Promise<TResult[]> {\n this.orderByRaw(\"RANDOM()\");\n if (limit) this.limit(limit);\n return this.get<TResult>();\n }\n\n /** Get first or throw. */\n public async firstOrFail<TResult = T>(): Promise<TResult> {\n const result = await this.first<TResult>();\n if (!result) throw new Error(\"No records found\");\n return result;\n }\n\n /** Get first or call callback. */\n public async firstOr<TResult = T>(callback: () => TResult | Promise<TResult>): Promise<TResult> {\n const result = await this.first<TResult>();\n return result ?? (await callback());\n }\n\n /** Get first or return null. */\n public async firstOrNull<TResult = T>(): Promise<TResult | null> {\n return this.first<TResult>();\n }\n\n /** Get first or return default. */\n public async firstOrNew<TResult = T>(defaults: GenericObject): Promise<TResult> {\n const result = await this.first<TResult>();\n return result ?? (defaults as unknown as TResult);\n }\n\n /** Find by primary key. */\n public async find<TResult = T>(id: number | string): Promise<TResult | null> {\n return this.where(\"id\", id).first<TResult>();\n }\n\n /** Count matching rows. */\n public async count(): Promise<number> {\n this.applyPendingScopes();\n const countOps: PostgresParserOperation[] = toParserOps([\n ...this.operations.filter((op) => op.type.includes(\"where\") || op.type.includes(\"join\")),\n { type: \"selectRaw\", data: { expression: 'COUNT(*) AS \"count\"' } },\n ]);\n\n const parser = new PostgresQueryParser({ table: this.table, operations: countOps });\n const { query = \"\", bindings = [] } = parser.parse();\n const result = await this.driver.query<{ count: string }>(query, bindings);\n return parseInt(result.rows[0]?.count ?? \"0\", 10);\n }\n\n /** SUM a numeric field. */\n public async sum(field: string): Promise<number> {\n this.applyPendingScopes();\n const result = await this.selectRaw(`SUM(${field}) as sum`).first<{ sum: string }>();\n return parseFloat(result?.sum ?? \"0\");\n }\n\n /** AVG of a numeric field. */\n public async avg(field: string): Promise<number> {\n this.applyPendingScopes();\n const result = await this.selectRaw(`AVG(${field}) as avg`).first<{ avg: string }>();\n return parseFloat(result?.avg ?? \"0\");\n }\n\n /** MIN of a numeric field. */\n public async min(field: string): Promise<number> {\n this.applyPendingScopes();\n const result = await this.selectRaw(`MIN(${field}) as min`).first<{ min: string }>();\n return parseFloat(result?.min ?? \"0\");\n }\n\n /** MAX of a numeric field. */\n public async max(field: string): Promise<number> {\n this.applyPendingScopes();\n const result = await this.selectRaw(`MAX(${field}) as max`).first<{ max: string }>();\n return parseFloat(result?.max ?? \"0\");\n }\n\n /** Get distinct values for a field. */\n public async distinct<TResult = unknown>(field: string): Promise<TResult[]> {\n this.distinctValues(field);\n const results = await this.get<{ [key: string]: TResult }>();\n return results.map((row) => row[field]);\n }\n\n /** Get array of all values for a single field. */\n public async pluck(field: string): Promise<unknown[]> {\n const results = await this.select([field]).get<Record<string, unknown>>();\n return results.map((row) => row[field]);\n }\n\n /** Get a single scalar value. */\n public async value<TResult = unknown>(field: string): Promise<TResult | null> {\n const result = await this.select([field]).first<Record<string, TResult>>();\n return result?.[field] ?? null;\n }\n\n /** Check whether any matching rows exist. */\n public async exists(): Promise<boolean> {\n const count = await this.limit(1).count();\n return count > 0;\n }\n\n /** Check whether NO matching rows exist. */\n public async notExists(): Promise<boolean> {\n return !(await this.exists());\n }\n\n /** COUNT DISTINCT a field. */\n public async countDistinct(field: string): Promise<number> {\n const result = await this.selectRaw(`COUNT(DISTINCT ${field}) as count`).first<{\n count: string;\n }>();\n return parseInt(result?.count ?? \"0\", 10);\n }\n\n // ─── Aggregation shortcuts via latest/oldest ─────────────────\n\n /** Get latest records ordered by a column. */\n public async latest(column = \"createdAt\"): Promise<T[]> {\n return this.orderBy(column, \"desc\").get();\n }\n\n // ─── Increment / Decrement ───────────────────────────────────\n\n /** Increment a numeric field. Returns new value. */\n public async increment(field: string, amount = 1): Promise<number> {\n this.applyPendingScopes();\n const { sql: filterSql, params: filterParams } = this.buildFilter();\n // The filter's placeholders are numbered $1..$N, so the amount must bind\n // AFTER them as $N+1 — otherwise it collides with the first filter param\n // (e.g. `... + $1 WHERE id = $1`) and the wrong value lands in each slot.\n const amountPlaceholder = `$${filterParams.length + 1}`;\n const updateSql =\n `UPDATE ${this.driver.dialect.quoteIdentifier(this.table)} ` +\n `SET ${this.driver.dialect.quoteIdentifier(field)} = COALESCE(${this.driver.dialect.quoteIdentifier(field)}, 0) + ${amountPlaceholder} ` +\n (filterSql ? `WHERE ${filterSql.replace(\"WHERE \", \"\")} ` : \"\") +\n `RETURNING ${this.driver.dialect.quoteIdentifier(field)}`;\n const result = await this.driver.query<Record<string, number>>(updateSql, [\n ...filterParams,\n amount,\n ]);\n return result.rows[0]?.[field] ?? 0;\n }\n\n /** Decrement a numeric field. Returns new value. */\n public async decrement(field: string, amount = 1): Promise<number> {\n return this.increment(field, -amount);\n }\n\n /** Increment a field for all matching rows. Returns affected row count. */\n public async incrementMany(field: string, amount = 1): Promise<number> {\n this.applyPendingScopes();\n const { sql: filterSql, params: filterParams } = this.buildFilter();\n // Amount binds last ($N+1) so it never collides with the filter's $1..$N.\n const amountPlaceholder = `$${filterParams.length + 1}`;\n const updateSql =\n `UPDATE ${this.driver.dialect.quoteIdentifier(this.table)} ` +\n `SET ${this.driver.dialect.quoteIdentifier(field)} = COALESCE(${this.driver.dialect.quoteIdentifier(field)}, 0) + ${amountPlaceholder}` +\n (filterSql ? ` WHERE ${filterSql.replace(\"WHERE \", \"\")}` : \"\");\n const result = await this.driver.query(updateSql, [...filterParams, amount]);\n return result.rowCount ?? 0;\n }\n\n /** Decrement a field for all matching rows. Returns affected row count. */\n public async decrementMany(field: string, amount = 1): Promise<number> {\n return this.incrementMany(field, -amount);\n }\n\n // ─── Chunking / Pagination ───────────────────────────────────\n\n /**\n * Process results in memory-efficient chunks.\n *\n * @example\n * await User.query().chunk(100, async (rows, idx) => { ... })\n */\n public async chunk(size: number, callback: ChunkCallback<T>): Promise<void> {\n let chunkIndex = 0;\n let hasMore = true;\n\n while (hasMore) {\n const chunk = await this.clone()\n .skip(chunkIndex * size)\n .limit(size)\n .get();\n if (chunk.length === 0) break;\n\n const shouldContinue = await callback(chunk, chunkIndex);\n if (shouldContinue === false) break;\n\n hasMore = chunk.length === size;\n chunkIndex++;\n }\n }\n\n /** Page-based pagination. */\n public async paginate(options?: PaginationOptions): Promise<PaginationResult<T>> {\n const page = options?.page ?? 1;\n const limit = options?.limit ?? 10;\n const skip = (page - 1) * limit;\n\n const [data, total] = await Promise.all([\n this.clone().skip(skip).limit(limit).get(),\n this.count(),\n ]);\n\n return {\n data,\n pagination: {\n total,\n page,\n limit,\n pages: Math.ceil(total / limit),\n },\n };\n }\n\n /**\n * Set cursor pagination hints fluently.\n * The recorded values are picked up by `cursorPaginate()` when no explicit\n * options are passed.\n *\n * @example\n * User.query().cursor(lastId).cursorPaginate({ limit: 20 })\n */\n public cursor(after?: unknown, before?: unknown): this {\n this.addOperation(\"cursor\", { after, before });\n return this;\n }\n\n /** Cursor-based pagination. */\n public async cursorPaginate(\n options?: CursorPaginationOptions,\n ): Promise<CursorPaginationResult<T>> {\n // Fall back to fluently-recorded cursor op if options.cursor not provided\n const cursorOp = this.getOps(\"cursor\")[0];\n const recordedCursor = cursorOp?.data.after;\n\n const {\n limit = 10,\n cursor = recordedCursor,\n column = \"id\",\n direction = \"next\",\n } = options ?? {};\n\n if (cursor) {\n this.where(column, direction === \"next\" ? \">\" : \"<\", cursor);\n }\n\n this.orderBy(column, direction === \"next\" ? \"asc\" : \"desc\");\n const results = await this.limit(limit + 1).get();\n const hasMore = results.length > limit;\n let data = hasMore ? results.slice(0, limit) : results;\n if (direction === \"prev\") data = data.reverse();\n\n let nextCursor: unknown;\n let prevCursor: unknown;\n let hasPrev = false;\n\n if (data.length > 0) {\n const firstItem = (data[0] as Record<string, unknown>)[column];\n const lastItem = (data[data.length - 1] as Record<string, unknown>)[column];\n\n if (direction === \"next\") {\n nextCursor = hasMore ? lastItem : undefined;\n if (cursor) {\n hasPrev = true;\n prevCursor = firstItem;\n }\n } else {\n prevCursor = hasMore ? firstItem : undefined;\n hasPrev = hasMore;\n if (cursor) nextCursor = lastItem;\n }\n }\n\n return { data, pagination: { hasMore, hasPrev, nextCursor, prevCursor } };\n }\n\n // ─── Mutation methods ────────────────────────────────────────\n\n /** Delete matching rows. Returns deleted count. */\n public async delete(): Promise<number> {\n this.applyPendingScopes();\n const { sql, params } = this.buildFilter();\n const deleteSql = `DELETE FROM ${this.driver.dialect.quoteIdentifier(this.table)} ${sql}`;\n const result = await this.driver.query(deleteSql, params);\n return result.rowCount ?? 0;\n }\n\n /** Delete the first matching row. */\n public async deleteOne(): Promise<number> {\n return this.limit(1).delete();\n }\n\n /** Update matching rows. */\n public async update(fields: Record<string, unknown>): Promise<number> {\n this.applyPendingScopes();\n const result = await this.driver.updateMany(this.table, {}, { $set: fields });\n return result.modifiedCount;\n }\n\n /** Unset fields from matching rows. */\n public async unset(...fields: string[]): Promise<number> {\n this.applyPendingScopes();\n const updateObj: Record<string, 1> = {};\n for (const field of fields) updateObj[field] = 1;\n const result = await this.driver.updateMany(this.table, {}, { $unset: updateObj });\n return result.modifiedCount;\n }\n\n // ─── Inspection / Debugging ───────────────────────────────────\n\n /**\n * Return the SQL + bindings without executing.\n *\n * Runs the same prelude as `get()` (scopes, joinWith expansion, joinRelations,\n * countRelations) so the preview matches what would actually be sent to the\n * database. The apply* methods are idempotent — calling `parse()` then `get()`\n * does not double-emit operations.\n */\n public parse(): DriverQuery {\n this.applyPendingScopes();\n this._processJoinWithOps();\n this.applyJoinRelations();\n this.applyHasRelations();\n this.applyCountRelations();\n this.applyGroupByAggregates();\n\n const parser = new PostgresQueryParser({\n table: this.table,\n operations: toParserOps(this.operations),\n });\n return parser.parse();\n }\n\n /** Formatted SQL string (for logging/debugging). */\n public pretty(): string {\n const { query = \"\", bindings } = this.parse();\n return `${query}\\n-- Bindings: ${JSON.stringify(bindings ?? [])}`;\n }\n\n /** Run EXPLAIN ANALYZE on the query. */\n public async explain(): Promise<unknown> {\n const { query = \"\", bindings = [] } = this.parse();\n const result = await this.driver.query(\n `EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) ${query}`,\n bindings,\n );\n return result.rows;\n }\n\n // ─── Utility ──────────────────────────────────────────────────\n\n /** Extend the builder with a driver-specific extension. */\n public extend<R>(extension: string, ..._args: unknown[]): R {\n throw new Error(`Extension \"${extension}\" is not supported by PostgresQueryBuilder`);\n }\n\n /** Pluck scalar values for a single field (alias for pluck). */\n public async pluckOne<TResult = unknown>(field: string): Promise<TResult[]> {\n const results = await this.select([field]).get<Record<string, TResult>>();\n return results.map((row) => row[field]);\n }\n\n // ============================================================================\n // JOIN RELATIONS — INTERNAL PIPELINE\n // ============================================================================\n\n /**\n * Before `get()` runs the parser, consume any joinWith ops recorded by the base\n * class and expand them into the joinRelations Map.\n */\n private _processJoinWithOps(): void {\n const joinWithOps = this.operations.filter((op) => op.type === \"joinWith\");\n if (joinWithOps.length === 0) return;\n\n // Remove joinWith ops from main operations — they are consumed here\n this.operations = this.operations.filter((op) => op.type !== \"joinWith\");\n\n for (const op of joinWithOps) {\n const constraints = op.data.constraints as Record<\n string,\n string | ((q: QueryBuilder) => void)\n >;\n for (const [path, constraint] of Object.entries(constraints)) {\n // Re-delegate to the extended joinWith implementation\n if (!constraint || constraint === \"\") {\n this.joinWith(path);\n } else {\n this.joinWith({ [path]: constraint });\n }\n }\n }\n }\n\n /**\n * Translate each entry in `joinRelations` into actual JOIN + selectRelatedColumns operations.\n *\n * Idempotent — guarded by `joinRelationsApplied` so repeat calls (e.g.\n * `parse()` followed by `get()`) don't double-emit operations.\n */\n private applyJoinRelations(): void {\n if (this.joinRelationsApplied || this.joinRelations.size === 0) {\n return;\n }\n\n this.joinRelationsApplied = true;\n\n for (const [path, config] of this.joinRelations) {\n const RelatedModel = tryResolveModelClass(config.model) as\n | { table: string; name?: string; primaryKey?: string }\n | undefined;\n\n if (!RelatedModel) {\n throw new Error(`Relation model not found for ${path}`);\n }\n\n const relatedTable = (RelatedModel as { table: string }).table;\n const alias = config.alias;\n const parentTable = config.parentPath\n ? this.joinRelations.get(config.parentPath)!.alias\n : this.table;\n\n const parentModel = config.parentModel as { name?: string; primaryKey?: string } | undefined;\n const relatedModelMeta = RelatedModel as { name?: string; primaryKey?: string };\n\n let localField: string;\n let foreignField: string;\n\n const conventions = this.dataSource?.relationDefaults;\n\n if (config.type === \"belongsTo\") {\n localField =\n config.foreignKey ?? inferBelongsToForeignKey(config.relationName ?? \"\", conventions);\n foreignField = config.ownerKey ?? relatedModelMeta.primaryKey ?? \"id\";\n } else {\n localField = config.localKey ?? parentModel?.primaryKey ?? \"id\";\n foreignField =\n config.foreignKey ?? inferHasForeignKey(parentModel?.name ?? \"Model\", conventions);\n }\n\n // hasMany uses a correlated subquery in SELECT (no JOIN) to avoid row explosion\n if (config.type !== \"hasMany\") {\n this.addOperation(\"leftJoin\", {\n table: relatedTable,\n alias,\n localField: `${parentTable}.${localField}`,\n foreignField,\n // For hasOne/belongsTo joinWith with a constraint callback, the parser\n // appends the constraint's where-clauses to the JOIN's ON condition\n // (not the outer WHERE, which would convert LEFT JOIN semantics into\n // INNER JOIN — main rows without a matching constraint-passing related\n // row would disappear).\n constraintOps: config.constraintOps,\n });\n }\n\n this.addOperation(\"selectRelatedColumns\", {\n alias,\n relationName: config.relationName,\n path,\n table: relatedTable,\n select: config.select,\n type: config.type,\n foreignKey: foreignField,\n localKey: localField,\n parentTable,\n constraintOps: config.constraintOps, // passed through to parser\n });\n }\n }\n\n // ============================================================================\n // HAS RELATIONS — INTERNAL PIPELINE\n // ============================================================================\n\n /**\n * Translate every `has` / `whereHas` / `orWhereHas` / `doesntHave` /\n * `whereDoesntHave` operation into an equivalent `whereRaw` (or\n * `orWhereRaw`) carrying an EXISTS / NOT EXISTS / COUNT-comparison\n * subquery. Keeps the parser pure (no schema awareness) — same pattern as\n * `applyJoinRelations` and `applyCountRelations`.\n *\n * In-place rewrite preserves position so the boolean (AND/OR) stays\n * correctly slotted relative to other where conditions.\n *\n * Idempotent — guarded by `hasRelationsApplied` so repeat calls (e.g.\n * `parse()` followed by `get()`) don't double-translate.\n */\n private applyHasRelations(): void {\n if (this.hasRelationsApplied) {\n return;\n }\n\n const HAS_OP_TYPES = new Set([\n \"has\",\n \"whereHas\",\n \"orWhereHas\",\n \"doesntHave\",\n \"whereDoesntHave\",\n ]);\n\n const hasAnyHasOp = this.operations.some((op) => HAS_OP_TYPES.has(op.type));\n\n if (!hasAnyHasOp) {\n this.hasRelationsApplied = true;\n return;\n }\n\n this.hasRelationsApplied = true;\n\n this.operations = this.operations.map((op) => {\n if (!HAS_OP_TYPES.has(op.type)) {\n return op;\n }\n\n return this.translateHasOp(op);\n });\n\n this.rebuildIndex();\n }\n\n /**\n * Translate one has-family operation into its `whereRaw`/`orWhereRaw`\n * equivalent. Resolves the relation definition, builds the EXISTS or\n * COUNT-comparison subquery, and returns the replacement op.\n */\n private translateHasOp(op: Op): Op {\n const data = op.data as {\n relation: string;\n subquery?: Op[];\n operator?: string;\n count?: number;\n };\n\n const definition = this.relationDefinitions?.[data.relation] as\n | Record<string, unknown>\n | undefined;\n\n if (!definition) {\n const modelName = (this.modelClass as { name?: string } | undefined)?.name ?? \"unknown\";\n throw new Error(`${op.type}: Relation \"${data.relation}\" not found on model ${modelName}`);\n }\n\n const RelatedModel = tryResolveModelClass(definition.model as ModelRef | undefined) as\n | { table?: string; name?: string; primaryKey?: string }\n | undefined;\n\n if (!RelatedModel || !(RelatedModel as { table?: string }).table) {\n throw new Error(`${op.type}: Related model not resolvable for \"${data.relation}\"`);\n }\n\n const subquery = this.buildHasSubquery(\n op.type,\n data.relation,\n definition,\n RelatedModel as { table: string; name: string; primaryKey?: string },\n data.subquery,\n data.operator,\n data.count,\n );\n\n const targetType = op.type === \"orWhereHas\" ? \"orWhereRaw\" : \"whereRaw\";\n\n return {\n type: targetType,\n data: {\n expression: subquery.expression,\n bindings: subquery.bindings,\n },\n };\n }\n\n /**\n * Build the SQL fragment that goes inside a `whereRaw` op for a has-family\n * translation. Branches on relation type AND on the operation type:\n *\n * - `has` with default operator/count → `EXISTS (SELECT 1 FROM ...)`\n * - `has` with custom operator/count → `(SELECT COUNT(*) FROM ...) <op> <count>`\n * - `whereHas` / `orWhereHas` → `EXISTS (SELECT 1 ... AND <constraint>)`\n * - `doesntHave` → `NOT EXISTS (SELECT 1 FROM ...)`\n * - `whereDoesntHave` → `NOT EXISTS (SELECT 1 ... AND <constraint>)`\n */\n private buildHasSubquery(\n opType: string,\n relationName: string,\n definition: Record<string, unknown>,\n RelatedModel: { table: string; name: string; primaryKey?: string },\n constraintOps: Op[] | undefined,\n operator: string | undefined,\n count: number | undefined,\n ): { expression: string; bindings: unknown[] } {\n const dialect = this.driver.dialect;\n const quotedSelfTable = dialect.quoteIdentifier(this.table);\n const quotedRelatedTable = dialect.quoteIdentifier(RelatedModel.table);\n const relationType = definition.type as string;\n const selfModel = this.modelClass as { name?: string; primaryKey?: string } | undefined;\n const conventions = this.dataSource?.relationDefaults;\n\n const where = this.extractCountWhereFragment(RelatedModel.table, constraintOps);\n\n let fromClause: string;\n let joinCondition: string;\n\n if (relationType === \"hasMany\" || relationType === \"hasOne\") {\n const localKey = (definition.localKey as string | undefined) ?? selfModel?.primaryKey ?? \"id\";\n const foreignKey =\n (definition.foreignKey as string | undefined) ??\n inferHasForeignKey(selfModel?.name ?? \"Model\", conventions);\n\n fromClause = quotedRelatedTable;\n joinCondition =\n `${quotedRelatedTable}.${dialect.quoteIdentifier(foreignKey)} = ` +\n `${quotedSelfTable}.${dialect.quoteIdentifier(localKey)}`;\n } else if (relationType === \"belongsTo\") {\n const ownerKey =\n (definition.localKey as string | undefined) ?? RelatedModel.primaryKey ?? \"id\";\n const foreignKey =\n (definition.foreignKey as string | undefined) ??\n inferBelongsToForeignKey(relationName, conventions);\n\n fromClause = quotedRelatedTable;\n joinCondition =\n `${quotedRelatedTable}.${dialect.quoteIdentifier(ownerKey)} = ` +\n `${quotedSelfTable}.${dialect.quoteIdentifier(foreignKey)}`;\n } else if (relationType === \"belongsToMany\") {\n const pivotTableName =\n (definition.pivot as string | undefined) ??\n inferPivotTable(selfModel?.name ?? \"Model\", RelatedModel.name, conventions);\n\n const quotedPivot = dialect.quoteIdentifier(pivotTableName);\n const pivotLocalCol =\n (definition.localKey as string | undefined) ??\n inferPivotKey(selfModel?.name ?? \"Model\", conventions);\n const pivotForeignCol =\n (definition.foreignKey as string | undefined) ??\n inferPivotKey(RelatedModel.name, conventions);\n const selfPk =\n (definition.pivotLocalKey as string | undefined) ?? selfModel?.primaryKey ?? \"id\";\n const relatedPk =\n (definition.pivotForeignKey as string | undefined) ?? RelatedModel.primaryKey ?? \"id\";\n\n // Constraint-free: pivot-only count. With constraint: INNER JOIN related so\n // the constraint can target related columns.\n if (!constraintOps || constraintOps.length === 0) {\n fromClause = quotedPivot;\n joinCondition =\n `${quotedPivot}.${dialect.quoteIdentifier(pivotLocalCol)} = ` +\n `${quotedSelfTable}.${dialect.quoteIdentifier(selfPk)}`;\n } else {\n fromClause =\n `${quotedPivot} INNER JOIN ${quotedRelatedTable} ON ` +\n `${quotedRelatedTable}.${dialect.quoteIdentifier(relatedPk)} = ` +\n `${quotedPivot}.${dialect.quoteIdentifier(pivotForeignCol)}`;\n joinCondition =\n `${quotedPivot}.${dialect.quoteIdentifier(pivotLocalCol)} = ` +\n `${quotedSelfTable}.${dialect.quoteIdentifier(selfPk)}`;\n }\n } else {\n throw new Error(\n `${opType}: Unsupported relation type \"${relationType}\" for \"${relationName}\"`,\n );\n }\n\n const fullWhere = where.fragment ? `${joinCondition} AND ${where.fragment}` : joinCondition;\n\n // `has` with custom operator/count compiles to a COUNT comparison; everything\n // else uses EXISTS / NOT EXISTS for short-circuit behaviour.\n const isCountComparison =\n opType === \"has\" && ((operator !== undefined && operator !== \">=\") || (count ?? 1) !== 1);\n\n if (isCountComparison) {\n const op = operator ?? \">=\";\n const compareCount = count ?? 1;\n\n return {\n expression: `(SELECT COUNT(*) FROM ${fromClause} WHERE ${fullWhere}) ${op} ${compareCount}`,\n bindings: where.bindings,\n };\n }\n\n const negate = opType === \"doesntHave\" || opType === \"whereDoesntHave\";\n const keyword = negate ? \"NOT EXISTS\" : \"EXISTS\";\n\n return {\n expression: `${keyword} (SELECT 1 FROM ${fromClause} WHERE ${fullWhere})`,\n bindings: where.bindings,\n };\n }\n\n // ============================================================================\n // COUNT RELATIONS — INTERNAL PIPELINE\n // ============================================================================\n\n /**\n * Translate each entry in `countRelations` into a correlated COUNT subquery\n * emitted as a `selectRaw` operation. Runs after `applyJoinRelations` so the\n * \"preserve main table columns\" guard sees any joins already in place.\n *\n * Idempotent — guarded by `countRelationsApplied` so repeat calls (e.g.\n * `parse()` followed by `get()`) don't double-emit operations.\n */\n private applyCountRelations(): void {\n if (this.countRelationsApplied || this.countRelations.size === 0) {\n return;\n }\n\n this.countRelationsApplied = true;\n\n this.ensureMainColumnsForCount();\n\n for (const [alias, entry] of this.countRelations) {\n const definition = this.relationDefinitions?.[entry.relation] as\n | Record<string, unknown>\n | undefined;\n\n if (!definition) {\n const modelName = (this.modelClass as { name?: string } | undefined)?.name ?? \"unknown\";\n throw new Error(`withCount: Relation \"${entry.relation}\" not found on model ${modelName}`);\n }\n\n const RelatedModel = tryResolveModelClass(definition.model as ModelRef | undefined) as\n | { table?: string; name?: string }\n | undefined;\n\n if (!RelatedModel || !(RelatedModel as { table?: string }).table) {\n throw new Error(\n `withCount: Related model not resolvable for \"${entry.relation}\" (alias \"${alias}\")`,\n );\n }\n\n const subquery = this.buildCountSubquery(\n alias,\n entry.relation,\n definition,\n RelatedModel as { table: string; name: string },\n entry.constraintOps,\n );\n\n this.addOperation(\"selectRaw\", {\n expression: subquery.expression,\n bindings: subquery.bindings,\n });\n }\n }\n\n /**\n * Without an explicit `select(...)` or any `selectRaw`/`selectRelatedColumns`\n * already pushed, the parser's \"no selects → SELECT *\" fallback would be\n * suppressed once we add count expressions. Push `<table>.*` first so the\n * caller's columns survive.\n */\n private ensureMainColumnsForCount(): void {\n const hasExistingSelect = this.operations.some(\n (op) => op.type === \"select\" || op.type === \"selectRaw\" || op.type === \"selectRelatedColumns\",\n );\n\n if (hasExistingSelect) {\n return;\n }\n\n const quotedTable = this.driver.dialect.quoteIdentifier(this.table);\n\n this.addOperation(\"selectRaw\", {\n expression: `${quotedTable}.*`,\n bindings: [],\n });\n }\n\n /**\n * Build a single correlated-subquery expression for a count entry. Branches\n * on relation type (hasMany/hasOne/belongsTo/belongsToMany). The optional\n * constraint callback's where-ops are translated via a sub-parser and\n * spliced into the subquery's WHERE clause.\n */\n private buildCountSubquery(\n alias: string,\n relationName: string,\n definition: Record<string, unknown>,\n RelatedModel: { table: string; name: string },\n constraintOps: Op[] | undefined,\n ): { expression: string; bindings: unknown[] } {\n const dialect = this.driver.dialect;\n const quotedAlias = dialect.quoteIdentifier(alias);\n const quotedSelfTable = dialect.quoteIdentifier(this.table);\n const quotedRelatedTable = dialect.quoteIdentifier(RelatedModel.table);\n const relationType = definition.type as string;\n\n const selfModel = this.modelClass as { name?: string; primaryKey?: string } | undefined;\n const relatedMeta = RelatedModel as { name: string; primaryKey?: string; table: string };\n const conventions = this.dataSource?.relationDefaults;\n\n if (relationType === \"hasMany\" || relationType === \"hasOne\") {\n const localKey = (definition.localKey as string | undefined) ?? selfModel?.primaryKey ?? \"id\";\n const foreignKey =\n (definition.foreignKey as string | undefined) ??\n inferHasForeignKey(selfModel?.name ?? \"Model\", conventions);\n const where = this.extractCountWhereFragment(RelatedModel.table, constraintOps);\n\n const fkCondition =\n `${quotedRelatedTable}.${dialect.quoteIdentifier(foreignKey)} = ` +\n `${quotedSelfTable}.${dialect.quoteIdentifier(localKey)}`;\n const fullWhere = where.fragment ? `${fkCondition} AND ${where.fragment}` : fkCondition;\n\n return {\n expression: `(SELECT COUNT(*) FROM ${quotedRelatedTable} WHERE ${fullWhere})::int AS ${quotedAlias}`,\n bindings: where.bindings,\n };\n }\n\n if (relationType === \"belongsTo\") {\n const ownerKey =\n (definition.localKey as string | undefined) ?? relatedMeta.primaryKey ?? \"id\";\n const foreignKey =\n (definition.foreignKey as string | undefined) ??\n inferBelongsToForeignKey(relationName, conventions);\n const where = this.extractCountWhereFragment(RelatedModel.table, constraintOps);\n\n const condition =\n `${quotedRelatedTable}.${dialect.quoteIdentifier(ownerKey)} = ` +\n `${quotedSelfTable}.${dialect.quoteIdentifier(foreignKey)}`;\n const fullWhere = where.fragment ? `${condition} AND ${where.fragment}` : condition;\n\n return {\n expression: `(SELECT COUNT(*) FROM ${quotedRelatedTable} WHERE ${fullWhere})::int AS ${quotedAlias}`,\n bindings: where.bindings,\n };\n }\n\n if (relationType === \"belongsToMany\") {\n const pivotTableName =\n (definition.pivot as string | undefined) ??\n inferPivotTable(selfModel?.name ?? \"Model\", relatedMeta.name, conventions);\n\n const quotedPivot = dialect.quoteIdentifier(pivotTableName);\n const pivotLocalCol =\n (definition.localKey as string | undefined) ??\n inferPivotKey(selfModel?.name ?? \"Model\", conventions);\n const pivotForeignCol =\n (definition.foreignKey as string | undefined) ??\n inferPivotKey(relatedMeta.name, conventions);\n const selfPk =\n (definition.pivotLocalKey as string | undefined) ?? selfModel?.primaryKey ?? \"id\";\n const relatedPk =\n (definition.pivotForeignKey as string | undefined) ?? relatedMeta.primaryKey ?? \"id\";\n\n const pivotCondition =\n `${quotedPivot}.${dialect.quoteIdentifier(pivotLocalCol)} = ` +\n `${quotedSelfTable}.${dialect.quoteIdentifier(selfPk)}`;\n\n if (!constraintOps || constraintOps.length === 0) {\n return {\n expression: `(SELECT COUNT(*) FROM ${quotedPivot} WHERE ${pivotCondition})::int AS ${quotedAlias}`,\n bindings: [],\n };\n }\n\n const where = this.extractCountWhereFragment(RelatedModel.table, constraintOps);\n const join =\n `INNER JOIN ${quotedRelatedTable} ON ${quotedRelatedTable}.${dialect.quoteIdentifier(relatedPk)} = ` +\n `${quotedPivot}.${dialect.quoteIdentifier(pivotForeignCol)}`;\n const fullWhere = where.fragment ? `${pivotCondition} AND ${where.fragment}` : pivotCondition;\n\n return {\n expression: `(SELECT COUNT(*) FROM ${quotedPivot} ${join} WHERE ${fullWhere})::int AS ${quotedAlias}`,\n bindings: where.bindings,\n };\n }\n\n throw new Error(`withCount: Unsupported relation type \"${relationType}\" for \"${relationName}\"`);\n }\n\n /**\n * Run a constraint's where-ops through a fresh sub-parser to obtain a SQL\n * WHERE-fragment plus bindings. Strips the leading `WHERE ` and rewrites\n * `$N` placeholders back to `?` so the outer parser renumbers them\n * consistently when it processes the enclosing `selectRaw` operation.\n *\n * Non-where ops (orderBy / limit / etc.) are silently dropped — they have\n * no meaning inside a COUNT subquery.\n */\n private extractCountWhereFragment(\n relatedTable: string,\n constraintOps: Op[] | undefined,\n ): { fragment: string; bindings: unknown[] } {\n if (!constraintOps || constraintOps.length === 0) {\n return { fragment: \"\", bindings: [] };\n }\n\n const whereOps = constraintOps.filter(\n (op) => op.type.startsWith(\"where\") || op.type.startsWith(\"orWhere\"),\n );\n\n if (whereOps.length === 0) {\n return { fragment: \"\", bindings: [] };\n }\n\n const subParser = new PostgresQueryParser({\n table: relatedTable,\n operations: toParserOps(whereOps),\n });\n\n const { query = \"\", bindings = [] } = subParser.parse();\n const match = query.match(/WHERE\\s+(.+)$/);\n\n if (!match) {\n return { fragment: \"\", bindings: [] };\n }\n\n const fragment = match[1].replace(/\\$\\d+/g, \"?\");\n\n return { fragment, bindings: bindings ?? [] };\n }\n\n // ============================================================================\n // GROUP-BY AGGREGATES — INTERNAL PIPELINE\n // ============================================================================\n\n /**\n * Rewrite every `having` op whose field matches a recorded aggregate alias\n * into a `havingRaw` carrying the underlying SQL expression. PostgreSQL\n * forbids SELECT aliases in HAVING, so `having(\"revenue\", \">\", 1000)` on a\n * `groupBy` aggregate would otherwise throw at runtime. A `having` on a\n * grouped column (no alias match) is left untouched. Runs at parse time\n * (not in the `groupBy` override) so it is independent of fluent call order.\n *\n * Idempotent — guarded by `groupByAggregatesApplied` so repeat calls (e.g.\n * `parse()` followed by `get()`) don't double-process.\n */\n private applyGroupByAggregates(): void {\n if (this.groupByAggregatesApplied) {\n return;\n }\n\n this.groupByAggregatesApplied = true;\n\n if (this.aggregateAliases.size === 0) {\n return;\n }\n\n this.operations = this.operations.map((operation) => {\n if (operation.type !== \"having\") {\n return operation;\n }\n\n const field = operation.data.field as string;\n const sql = this.aggregateAliases.get(field);\n\n if (!sql) {\n return operation;\n }\n\n const operator = (operation.data.operator as string) ?? \"=\";\n\n return {\n type: \"havingRaw\",\n data: {\n expression: `${sql} ${operator} ?`,\n bindings: [operation.data.value],\n },\n };\n });\n\n this.rebuildIndex();\n }\n\n // ============================================================================\n // EAGER LOADING — INTERNAL PIPELINE\n // ============================================================================\n\n /**\n * Run the RelationLoader against the fetched rows for every relation\n * registered via `with()`. Mutates each model instance in place — attaches\n * loaded relations onto `model.loadedRelations` and as direct properties.\n *\n * Lives here (not in `buildQuery`'s `onFetched` callback as it did\n * historically) so any code path that calls `get()` — including\n * `Model.newQueryBuilder()` direct instantiation, custom builder subclasses\n * via `static builder`, or any `eagerLoadRelations`-bearing builder — gets\n * eager-loading. Previously the loader was only installed when the builder\n * was constructed via `Model.query()` / `buildQuery`, so bypassing that\n * factory made `with()` a silent no-op.\n *\n * Skipped silently when `modelClass` is absent (raw driver-level\n * `queryBuilder()` usage has no relations map to consult).\n */\n private async applyEagerLoading(records: unknown[]): Promise<void> {\n if (!this.modelClass || this.eagerLoadRelations.size === 0 || records.length === 0) {\n return;\n }\n\n const constraints: Record<string, (query: QueryBuilderContract) => void> = {};\n\n for (const [name, constraint] of this.eagerLoadRelations) {\n if (typeof constraint === \"function\") {\n constraints[name] = constraint as (query: QueryBuilderContract) => void;\n }\n }\n\n const loader = new RelationLoader(records as never, this.modelClass as never);\n await loader.load([...this.eagerLoadRelations.keys()], constraints);\n }\n\n /**\n * Extract per-relation data from raw DB rows (before hydration).\n * Returns a Map of row index → nested relation data tree.\n */\n private extractJoinedRelationData(records: unknown[]): Map<number, Record<string, unknown>> {\n const result = new Map<number, Record<string, unknown>>();\n if (this.joinRelations.size === 0) return result;\n\n (records as Record<string, unknown>[]).forEach((record, index) => {\n const relationData: Record<string, unknown> = {};\n\n // Process shallower paths first so parents exist before children\n const sortedPaths = Array.from(this.joinRelations.keys()).sort(\n (a, b) => a.split(\".\").length - b.split(\".\").length,\n );\n\n for (const path of sortedPaths) {\n const config = this.joinRelations.get(path)!;\n const columnName = config.alias;\n\n const relatedData = record[columnName];\n delete record[columnName];\n\n const parsedData =\n relatedData !== null &&\n !(\n typeof relatedData === \"object\" &&\n Object.values(relatedData as object).every((v) => v === null)\n )\n ? relatedData\n : null;\n\n const parts = path.split(\".\");\n const lastPart = parts.pop()!;\n let current = relationData;\n\n for (const part of parts) {\n if (!current[part]) current[part] = {};\n current = current[part] as Record<string, unknown>;\n }\n\n current[lastPart] = parsedData;\n }\n\n result.set(index, relationData);\n });\n\n return result;\n }\n\n /**\n * Attach extracted relation data to hydrated model instances.\n */\n private attachJoinedRelations(\n records: unknown[],\n joinedData: Map<number, Record<string, unknown>>,\n ): void {\n if (this.joinRelations.size === 0) return;\n\n const attachNested = (model: unknown, dataTree: unknown, currentPath = \"\"): void => {\n if (!dataTree || typeof dataTree !== \"object\") return;\n\n for (const [key, data] of Object.entries(dataTree as Record<string, unknown>)) {\n const path = currentPath ? `${currentPath}.${key}` : key;\n const config = this.joinRelations.get(path);\n if (!config) continue;\n\n if (data === null) {\n attachLoadedRelation(model as object, key, null);\n continue;\n }\n\n const RelatedModel = resolveModelClass(config.model as string);\n if (!RelatedModel) continue;\n\n const childKeys = Array.from(this.joinRelations.keys())\n .filter((p) => p.startsWith(`${path}.`))\n .map((p) => p.split(\".\")[path.split(\".\").length]);\n\n if (config.type === \"hasMany\") {\n const rows = Array.isArray(data) ? data : [];\n const instances = rows.map((row: unknown) => {\n const rowData = { ...(row as object) } as Record<string, unknown>;\n for (const childKey of childKeys) delete rowData[childKey];\n return (RelatedModel as { hydrate: (d: unknown) => unknown }).hydrate(rowData);\n });\n\n attachLoadedRelation(model as object, key, instances as never);\n } else {\n const modelData = { ...(data as object) } as Record<string, unknown>;\n for (const childKey of childKeys) delete modelData[childKey];\n\n const relatedInstance = (RelatedModel as { hydrate: (d: unknown) => unknown }).hydrate(\n modelData,\n );\n attachNested(relatedInstance, data, path);\n\n attachLoadedRelation(model as object, key, relatedInstance as never);\n }\n }\n };\n\n records.forEach((model, index) => {\n const relationData = joinedData.get(index);\n if (relationData) attachNested(model, relationData);\n });\n }\n\n // ============================================================================\n // INTERNAL HELPERS\n // ============================================================================\n\n /**\n * Build a WHERE-only SQL fragment from `where*` operations on the current builder.\n * Used by DELETE / UPDATE / increment paths.\n */\n private buildFilter(): { sql: string; params: unknown[] } {\n const whereOps = this.operations.filter(\n (op) => op.type.includes(\"where\") || op.type.includes(\"Where\"),\n );\n\n if (whereOps.length === 0) return { sql: \"\", params: [] };\n\n const parser = new PostgresQueryParser({\n table: this.table,\n operations: toParserOps(whereOps),\n });\n\n const { query = \"\", bindings = [] } = parser.parse();\n const whereMatch = query.match(/WHERE .+$/);\n return { sql: whereMatch ? whereMatch[0] : \"\", params: bindings };\n }\n}\n","import type { PendingOperation } from \"./migration\";\n\n/**\n * Converts PendingOperation objects to SQL strings for a specific dialect.\n */\nexport abstract class SQLSerializer {\n /**\n * Serialize a single pending operation into one or more SQL strings.\n *\n * Return `string` for single-statement operations, `string[]` for\n * multi-statement ones (e.g. `createTimestamps` emits two ALTER TABLE\n * statements), and `null` for no-ops.\n */\n abstract serialize(operation: PendingOperation, table: string): string | string[] | null;\n\n /**\n * Serialize an array of operations to a flat list of SQL strings.\n *\n * Array results from serialize() are automatically flattened, and nulls\n * (no-ops) are filtered out.\n */\n serializeAll(operations: PendingOperation[], table: string): string[] {\n const result: string[] = [];\n\n for (const op of operations) {\n const sql = this.serialize(op, table);\n if (sql === null) continue;\n if (Array.isArray(sql)) {\n result.push(...sql);\n } else {\n result.push(sql);\n }\n }\n\n return result;\n }\n}\n","import type { SqlDialectContract } from \"../sql/sql-dialect.contract\";\nimport type { PendingOperation } from \"../../migration/migration\";\nimport { SQLSerializer } from \"../../migration/sql-serializer\";\nimport type {\n ColumnDefinition,\n ForeignKeyDefinition,\n FullTextIndexOptions,\n GeoIndexOptions,\n IndexDefinition,\n VectorIndexOptions,\n} from \"../../contracts/migration-driver.contract\";\n\n/**\n * PostgreSQL-specific SQL serializer.\n *\n * Converts pending migration operations into valid PostgreSQL DDL statements.\n */\nexport class PostgresSQLSerializer extends SQLSerializer {\n public constructor(private readonly dialect: SqlDialectContract) {\n super();\n }\n\n public serialize(operation: PendingOperation, table: string): string | string[] | null {\n switch (operation.type) {\n case \"createTable\":\n return this.createTable(table);\n case \"createTableIfNotExists\":\n return this.createTableIfNotExists(table);\n case \"dropTable\":\n return this.dropTable(table);\n case \"dropTableIfExists\":\n return this.dropTableIfExists(table);\n case \"renameTable\":\n return this.renameTable(table, operation.payload as string);\n case \"truncateTable\":\n return this.truncateTable(table);\n case \"addColumn\":\n return this.addColumn(table, operation.payload as ColumnDefinition);\n case \"dropColumn\":\n return this.dropColumn(table, operation.payload as string);\n case \"dropColumns\":\n // This is handled via map in serializeAll or loop, but Postgres supports multiple DROP COLUMN\n // For simplicity, we can serialize multiple statements if we want, or handle it here\n // Actually, dropColumns payload is string[]. We can join them.\n return this.dropColumns(table, operation.payload as string[]);\n case \"renameColumn\": {\n const payload = operation.payload as { from: string; to: string };\n return this.renameColumn(table, payload.from, payload.to);\n }\n case \"modifyColumn\":\n // Modify column might require multiple statements in Postgres (type, nullability, default).\n // SQLSerializer's serialize return is just a string, so we'll separate them by semicolon\n // Or wait, Postgres allows multiple ALTER COLUMN in one ALTER TABLE statement.\n return this.modifyColumn(table, operation.payload as ColumnDefinition);\n case \"createIndex\":\n return this.createIndex(table, operation.payload as IndexDefinition);\n case \"dropIndex\":\n return this.dropIndex(table, operation.payload as string | string[]);\n case \"createUniqueIndex\": {\n const payload = operation.payload as { columns: string[]; name?: string };\n return this.createIndex(table, { columns: payload.columns, name: payload.name, unique: true });\n }\n case \"dropUniqueIndex\":\n return this.dropIndex(table, operation.payload as string[]);\n case \"createFullTextIndex\": {\n const payload = operation.payload as { columns: string[]; options?: FullTextIndexOptions };\n return this.createFullTextIndex(table, payload.columns, payload.options);\n }\n case \"dropFullTextIndex\":\n return this.dropIndex(table, operation.payload as string);\n case \"createGeoIndex\": {\n const payload = operation.payload as { column: string; options?: GeoIndexOptions };\n return this.createGeoIndex(table, payload.column, payload.options);\n }\n case \"dropGeoIndex\":\n return this.dropIndex(table, `idx_${table}_geo_${operation.payload}`);\n case \"createVectorIndex\": {\n const payload = operation.payload as { column: string; options: VectorIndexOptions };\n return this.createVectorIndex(table, payload.column, payload.options);\n }\n case \"dropVectorIndex\":\n return this.dropIndex(table, `idx_${table}_vector_${operation.payload}`);\n case \"createTTLIndex\": {\n const payload = operation.payload as { column: string; expireAfterSeconds: number };\n return this.createTTLIndex(table, payload.column, payload.expireAfterSeconds);\n }\n case \"dropTTLIndex\":\n return this.dropIndex(table, `idx_${table}_ttl_${operation.payload}`);\n case \"addForeignKey\":\n return this.addForeignKey(table, operation.payload as ForeignKeyDefinition);\n case \"dropForeignKey\":\n return this.dropForeignKey(table, operation.payload as string);\n case \"addPrimaryKey\":\n return this.addPrimaryKey(table, operation.payload as string[]);\n case \"dropPrimaryKey\":\n return this.dropPrimaryKey(table);\n case \"addCheck\":\n // addCheck is not natively implemented in MigrationDriverContract but exists in OperationType\n return null;\n case \"dropCheck\":\n return null;\n case \"createTimestamps\":\n // createTimestamps needs to inject two columns. We return two statements.\n return this.createTimestamps(table);\n case \"rawStatement\": {\n const payload = operation.payload as string;\n // ensure string doesn't end with a semicolon if it's already one statement\n return payload;\n }\n case \"setSchemaValidation\":\n case \"removeSchemaValidation\":\n // Not implemented in PostgreSQL\n return null;\n default:\n return null;\n }\n }\n\n // ============================================================================\n // TABLE OPERATIONS\n // ============================================================================\n\n private createTable(table: string): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n return `CREATE TABLE ${quotedTable} ()`;\n }\n\n private createTableIfNotExists(table: string): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n return `CREATE TABLE IF NOT EXISTS ${quotedTable} ()`;\n }\n\n private dropTable(table: string): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n return `DROP TABLE ${quotedTable} CASCADE`;\n }\n\n private dropTableIfExists(table: string): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n return `DROP TABLE IF EXISTS ${quotedTable} CASCADE`;\n }\n\n private renameTable(from: string, to: string): string {\n const quotedFrom = this.dialect.quoteIdentifier(from);\n const quotedTo = this.dialect.quoteIdentifier(to);\n return `ALTER TABLE ${quotedFrom} RENAME TO ${quotedTo}`;\n }\n\n private truncateTable(table: string): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n return `TRUNCATE TABLE ${quotedTable}`;\n }\n\n // ============================================================================\n // COLUMN OPERATIONS\n // ============================================================================\n\n private addColumn(table: string, column: ColumnDefinition): string | string[] {\n const quotedTable = this.dialect.quoteIdentifier(table);\n const quotedColumn = this.dialect.quoteIdentifier(column.name);\n\n let sqlType: string;\n if (column.autoIncrement) {\n if (column.type === \"bigInteger\") {\n sqlType = \"BIGSERIAL\";\n } else {\n sqlType = \"SERIAL\";\n }\n } else {\n sqlType = this.dialect.getSqlType(column.type, {\n length: column.length,\n precision: column.precision,\n scale: column.scale,\n dimensions: column.dimensions,\n });\n }\n\n let sql = `ALTER TABLE ${quotedTable} ADD COLUMN ${quotedColumn} ${sqlType}`;\n\n if (column.generated) {\n sql += ` GENERATED ALWAYS AS (${column.generated.expression})`;\n if (column.generated.stored) {\n sql += \" STORED\";\n }\n } else {\n if (!column.autoIncrement && column.nullable === false) {\n sql += \" NOT NULL\";\n }\n\n if (column.defaultValue !== undefined) {\n if (\n typeof column.defaultValue === \"object\" &&\n column.defaultValue !== null &&\n (column.defaultValue as any).__type === \"CURRENT_TIMESTAMP\"\n ) {\n sql += \" DEFAULT NOW()\";\n } else if (column.isRawDefault === false) {\n const escaped = String(column.defaultValue).replace(/'/g, \"''\");\n sql += ` DEFAULT '${escaped}'`;\n } else if (typeof column.defaultValue === \"boolean\") {\n sql += ` DEFAULT ${column.defaultValue ? \"TRUE\" : \"FALSE\"}`;\n } else if (typeof column.defaultValue === \"number\") {\n sql += ` DEFAULT ${column.defaultValue}`;\n } else {\n sql += ` DEFAULT ${column.defaultValue}`; // raw default\n }\n }\n\n if (column.primary) {\n sql += \" PRIMARY KEY\";\n }\n\n if (column.unique) {\n sql += \" UNIQUE\";\n }\n }\n\n // pgvector: ensure the extension is active before the vector column is created.\n // SQLGrammar classifies CREATE EXTENSION as Phase 1, so this will always\n // run before any CREATE TABLE / ADD COLUMN statement regardless of batch order.\n if (column.type === \"vector\") {\n return [\"CREATE EXTENSION IF NOT EXISTS vector\", sql];\n }\n\n return sql;\n }\n\n private dropColumn(table: string, column: string): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n const quotedColumn = this.dialect.quoteIdentifier(column);\n return `ALTER TABLE ${quotedTable} DROP COLUMN ${quotedColumn}`;\n }\n\n private dropColumns(table: string, columns: string[]): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n const drops = columns.map((col) => `DROP COLUMN ${this.dialect.quoteIdentifier(col)}`).join(\", \");\n return `ALTER TABLE ${quotedTable} ${drops}`;\n }\n\n private renameColumn(table: string, from: string, to: string): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n const quotedFrom = this.dialect.quoteIdentifier(from);\n const quotedTo = this.dialect.quoteIdentifier(to);\n return `ALTER TABLE ${quotedTable} RENAME COLUMN ${quotedFrom} TO ${quotedTo}`;\n }\n\n private modifyColumn(table: string, column: ColumnDefinition): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n const quotedColumn = this.dialect.quoteIdentifier(column.name);\n const sqlType = this.dialect.getSqlType(column.type, {\n length: column.length,\n precision: column.precision,\n scale: column.scale,\n dimensions: column.dimensions,\n });\n\n const alters: string[] = [];\n alters.push(`ALTER COLUMN ${quotedColumn} TYPE ${sqlType}`);\n\n if (column.nullable === false) {\n alters.push(`ALTER COLUMN ${quotedColumn} SET NOT NULL`);\n } else if (column.nullable === true) {\n alters.push(`ALTER COLUMN ${quotedColumn} DROP NOT NULL`);\n }\n\n if (column.defaultValue !== undefined) {\n let defaultVal: string;\n if (\n typeof column.defaultValue === \"object\" &&\n column.defaultValue !== null &&\n (column.defaultValue as any).__type === \"CURRENT_TIMESTAMP\"\n ) {\n defaultVal = \"NOW()\";\n } else if (typeof column.defaultValue === \"string\") {\n defaultVal = `'${column.defaultValue}'`;\n } else {\n defaultVal = String(column.defaultValue);\n }\n alters.push(`ALTER COLUMN ${quotedColumn} SET DEFAULT ${defaultVal}`);\n }\n\n return `ALTER TABLE ${quotedTable} ${alters.join(\", \")}`;\n }\n\n private createTimestamps(table: string): string[] {\n const quotedTable = this.dialect.quoteIdentifier(table);\n return [\n `ALTER TABLE ${quotedTable} ADD COLUMN \"created_at\" TIMESTAMPTZ NOT NULL DEFAULT NOW()`,\n `ALTER TABLE ${quotedTable} ADD COLUMN \"updated_at\" TIMESTAMPTZ NOT NULL DEFAULT NOW()`,\n ];\n }\n\n // ============================================================================\n // INDEX OPERATIONS\n // ============================================================================\n\n private createIndex(table: string, index: IndexDefinition): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n let indexName: string;\n if (index.name) {\n indexName = index.name;\n } else {\n const colStr = Array.isArray(index.columns) ? index.columns.join(\"_\") : index.columns;\n indexName = `idx_${table}_${colStr}`;\n }\n const quotedIndexName = this.dialect.quoteIdentifier(indexName);\n const uniqueKeyword = index.unique ? \"UNIQUE \" : \"\";\n const concurrentlyKeyword = index.concurrently ? \"CONCURRENTLY \" : \"\";\n\n let columnsPart: string;\n\n if (index.expressions && index.expressions.length > 0) {\n columnsPart = index.expressions.map((expr) => `(${expr})`).join(\", \");\n } else {\n const columns = index.columns.map((col, i) => {\n const quotedCol = this.dialect.quoteIdentifier(col);\n const direction = index.directions?.[i]?.toUpperCase() ?? \"\";\n return direction ? `${quotedCol} ${direction}` : quotedCol;\n });\n columnsPart = columns.join(\", \");\n }\n\n let sql = `CREATE ${uniqueKeyword}INDEX ${concurrentlyKeyword}${quotedIndexName} ON ${quotedTable} (${columnsPart})`;\n\n if (index.include && index.include.length > 0) {\n const includeCols = index.include.map((col) => this.dialect.quoteIdentifier(col)).join(\", \");\n sql += ` INCLUDE (${includeCols})`;\n }\n\n if (index.where && Object.keys(index.where).length > 0) {\n const conditions = Object.entries(index.where)\n .map(([key, value]) => {\n const quotedKey = this.dialect.quoteIdentifier(key);\n return typeof value === \"string\" ? `${quotedKey} = '${value}'` : `${quotedKey} = ${value}`;\n })\n .join(\" AND \");\n sql += ` WHERE ${conditions}`;\n }\n\n return sql;\n }\n\n private dropIndex(table: string, indexNameOrColumns: string | string[]): string {\n let indexName: string;\n if (typeof indexNameOrColumns === \"string\") {\n indexName = indexNameOrColumns;\n } else {\n indexName = `idx_${table}_${indexNameOrColumns.join(\"_\")}`;\n }\n const quotedIndexName = this.dialect.quoteIdentifier(indexName);\n return `DROP INDEX IF EXISTS ${quotedIndexName}`;\n }\n\n private createFullTextIndex(table: string, columns: string[], options?: FullTextIndexOptions): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n const indexName = options?.name ?? `idx_${table}_fulltext_${columns.join(\"_\")}`;\n const quotedIndexName = this.dialect.quoteIdentifier(indexName);\n const language = options?.language ?? \"english\";\n\n const tsvectors = columns.map((col) => {\n const weight = options?.weights?.[col] ?? \"A\";\n return `setweight(to_tsvector('${language}', COALESCE(${this.dialect.quoteIdentifier(col)}, '')), '${weight}')`;\n });\n\n return `CREATE INDEX ${quotedIndexName} ON ${quotedTable} USING GIN ((${tsvectors.join(\" || \")}))`;\n }\n\n private createGeoIndex(table: string, column: string, options?: GeoIndexOptions): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n const quotedColumn = this.dialect.quoteIdentifier(column);\n const indexName = options?.name ?? `idx_${table}_geo_${column}`;\n const quotedIndexName = this.dialect.quoteIdentifier(indexName);\n\n return `CREATE INDEX ${quotedIndexName} ON ${quotedTable} USING GIST (${quotedColumn})`;\n }\n\n private createVectorIndex(table: string, column: string, options: VectorIndexOptions): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n const quotedColumn = this.dialect.quoteIdentifier(column);\n const indexName = options.name ?? `idx_${table}_vector_${column}`;\n const quotedIndexName = this.dialect.quoteIdentifier(indexName);\n\n const opClass =\n options.similarity === \"euclidean\"\n ? \"vector_l2_ops\"\n : options.similarity === \"dotProduct\"\n ? \"vector_ip_ops\"\n : \"vector_cosine_ops\";\n\n const lists = options.lists ?? 100;\n\n return `CREATE INDEX ${quotedIndexName} ON ${quotedTable} USING ivfflat (${quotedColumn} ${opClass}) WITH (lists = ${lists})`;\n }\n\n private createTTLIndex(table: string, column: string, expireAfterSeconds: number): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n const quotedColumn = this.dialect.quoteIdentifier(column);\n const indexName = `idx_${table}_ttl_${column}`;\n const quotedIndexName = this.dialect.quoteIdentifier(indexName);\n\n return `CREATE INDEX ${quotedIndexName} ON ${quotedTable} (${quotedColumn}) WHERE ${quotedColumn} < NOW() - INTERVAL '${expireAfterSeconds} seconds'`;\n }\n\n // ============================================================================\n // CONSTRAINTS\n // ============================================================================\n\n private addForeignKey(table: string, foreignKey: ForeignKeyDefinition): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n const quotedColumn = this.dialect.quoteIdentifier(foreignKey.column);\n const quotedRefTable = this.dialect.quoteIdentifier(foreignKey.referencesTable);\n const quotedRefColumn = this.dialect.quoteIdentifier(foreignKey.referencesColumn);\n\n const constraintName =\n foreignKey.name ?? `fk_${table}_${foreignKey.column}_${foreignKey.referencesTable}`;\n const quotedConstraint = this.dialect.quoteIdentifier(constraintName);\n\n let sql = `ALTER TABLE ${quotedTable} ADD CONSTRAINT ${quotedConstraint} FOREIGN KEY (${quotedColumn}) REFERENCES ${quotedRefTable} (${quotedRefColumn})`;\n\n if (foreignKey.onDelete) {\n sql += ` ON DELETE ${this.mapForeignKeyAction(foreignKey.onDelete)}`;\n }\n\n if (foreignKey.onUpdate) {\n sql += ` ON UPDATE ${this.mapForeignKeyAction(foreignKey.onUpdate)}`;\n }\n\n return sql;\n }\n\n private dropForeignKey(table: string, name: string): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n const quotedConstraint = this.dialect.quoteIdentifier(name);\n return `ALTER TABLE ${quotedTable} DROP CONSTRAINT ${quotedConstraint}`;\n }\n\n private addPrimaryKey(table: string, columns: string[]): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n const quotedColumns = columns.map((c) => this.dialect.quoteIdentifier(c)).join(\", \");\n const constraintName = `pk_${table}`;\n const quotedConstraint = this.dialect.quoteIdentifier(constraintName);\n\n return `ALTER TABLE ${quotedTable} ADD CONSTRAINT ${quotedConstraint} PRIMARY KEY (${quotedColumns})`;\n }\n\n private dropPrimaryKey(table: string): string {\n const quotedTable = this.dialect.quoteIdentifier(table);\n const constraintName = `pk_${table}`;\n const quotedConstraint = this.dialect.quoteIdentifier(constraintName);\n\n return `ALTER TABLE ${quotedTable} DROP CONSTRAINT ${quotedConstraint}`;\n }\n\n private mapForeignKeyAction(\n action: \"cascade\" | \"restrict\" | \"setNull\" | \"noAction\",\n ): string {\n switch (action) {\n case \"cascade\": return \"CASCADE\";\n case \"restrict\": return \"RESTRICT\";\n case \"setNull\": return \"SET NULL\";\n case \"noAction\": return \"NO ACTION\";\n default: return \"NO ACTION\";\n }\n }\n}\n","/**\r\n * PostgreSQL Sync Adapter\r\n *\r\n * Implements the SyncAdapterContract for batch update operations\r\n * on embedded/denormalized data in PostgreSQL.\r\n *\r\n * @module cascade/drivers/postgres\r\n */\r\n\r\nimport type { SyncAdapterContract, SyncInstruction } from \"../../contracts/sync-adapter.contract\";\r\nimport type { PostgresDriver } from \"./postgres-driver\";\r\n\r\n/**\r\n * PostgreSQL Sync Adapter.\r\n *\r\n * Handles batch updates for embedded/denormalized data stored\r\n * in JSONB columns. In a normalized SQL world, this is less common\r\n * than in MongoDB, but still useful for JSONB documents.\r\n *\r\n * @example\r\n * ```typescript\r\n * const syncAdapter = driver.syncAdapter();\r\n *\r\n * // Update embedded user data in posts\r\n * await syncAdapter.executeBatch([\r\n * {\r\n * targetTable: 'posts',\r\n * filter: { 'author.id': 123 },\r\n * update: { 'author.name': 'New Name' },\r\n * // ... other fields\r\n * }\r\n * ]);\r\n * ```\r\n */\r\nexport class PostgresSyncAdapter implements SyncAdapterContract {\r\n /**\r\n * Create a new sync adapter.\r\n *\r\n * @param driver - The PostgreSQL driver instance\r\n */\r\n public constructor(private readonly driver: PostgresDriver) {}\r\n\r\n /**\r\n * Execute a batch of sync instructions.\r\n *\r\n * @param instructions - Array of sync instructions\r\n * @returns Total number of affected rows\r\n */\r\n public async executeBatch(instructions: SyncInstruction[]): Promise<number> {\r\n let totalAffected = 0;\r\n\r\n for (const instruction of instructions) {\r\n if (instruction.isArrayUpdate) {\r\n totalAffected += await this.executeArrayUpdate(instruction);\r\n } else {\r\n totalAffected += await this.executeOne(instruction);\r\n }\r\n }\r\n\r\n return totalAffected;\r\n }\r\n\r\n /**\r\n * Execute a single sync instruction.\r\n *\r\n * @param instruction - Sync instruction\r\n * @returns Number of affected rows\r\n */\r\n public async executeOne(instruction: SyncInstruction): Promise<number> {\r\n const { targetTable, filter, update } = instruction;\r\n return this.executeJsonbUpdate(targetTable, filter, update);\r\n }\r\n\r\n /**\r\n * Execute an array update instruction with positional operators.\r\n *\r\n * @param instruction - Sync instruction with array update info\r\n * @returns Number of affected rows\r\n */\r\n public async executeArrayUpdate(instruction: SyncInstruction): Promise<number> {\r\n const { targetTable, filter, update, arrayField, identifierField, identifierValue } =\r\n instruction;\r\n\r\n if (!arrayField || !identifierField || identifierValue === undefined) {\r\n // Fall back to regular update if array info is missing\r\n return this.executeOne(instruction);\r\n }\r\n\r\n return this.executeArrayElementUpdate(\r\n targetTable,\r\n filter,\r\n arrayField,\r\n { [identifierField]: identifierValue },\r\n update,\r\n );\r\n }\r\n\r\n /**\r\n * Execute an update on JSONB fields.\r\n *\r\n * @param table - Table name\r\n * @param filter - Row filter\r\n * @param update - Fields to update\r\n * @returns Number of affected rows\r\n */\r\n private async executeJsonbUpdate(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n update: Record<string, unknown>,\r\n ): Promise<number> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const setClauses: string[] = [];\r\n const params: unknown[] = [];\r\n let paramIndex = 1;\r\n\r\n // Build SET clauses for each update field\r\n for (const [path, value] of Object.entries(update)) {\r\n if (path.includes(\".\")) {\r\n // JSONB path update: \"column.nested.field\" -> jsonb_set\r\n const [column, ...pathParts] = path.split(\".\");\r\n const quotedColumn = this.driver.dialect.quoteIdentifier(column);\r\n const jsonPath = `{${pathParts.join(\",\")}}`;\r\n const placeholder = this.driver.dialect.placeholder(paramIndex++);\r\n params.push(JSON.stringify(value));\r\n\r\n setClauses.push(\r\n `${quotedColumn} = jsonb_set(COALESCE(${quotedColumn}, '{}'::jsonb), '${jsonPath}', ${placeholder}::jsonb)`,\r\n );\r\n } else {\r\n // Regular column update\r\n const quotedColumn = this.driver.dialect.quoteIdentifier(path);\r\n const placeholder = this.driver.dialect.placeholder(paramIndex++);\r\n params.push(value);\r\n\r\n setClauses.push(`${quotedColumn} = ${placeholder}`);\r\n }\r\n }\r\n\r\n // Build WHERE clause\r\n const whereClauses: string[] = [];\r\n for (const [key, value] of Object.entries(filter)) {\r\n if (key.includes(\".\")) {\r\n // JSONB path filter: intermediate segments use -> (jsonb), final uses ->> (text).\r\n // e.g. \"column.a\" → \"column\"->>'a', \"column.a.b\" → \"column\"->'a'->>'b'\r\n const [column, ...pathParts] = key.split(\".\");\r\n const quotedColumn = this.driver.dialect.quoteIdentifier(column);\r\n const intermediateExpr = pathParts\r\n .slice(0, -1)\r\n .map((p) => `->'${p}'`)\r\n .join(\"\");\r\n const finalExpr = `->>'${pathParts[pathParts.length - 1]}'`;\r\n const placeholder = this.driver.dialect.placeholder(paramIndex++);\r\n params.push(value);\r\n\r\n whereClauses.push(`${quotedColumn}${intermediateExpr}${finalExpr} = ${placeholder}`);\r\n } else {\r\n const quotedKey = this.driver.dialect.quoteIdentifier(key);\r\n const placeholder = this.driver.dialect.placeholder(paramIndex++);\r\n params.push(value);\r\n\r\n whereClauses.push(`${quotedKey} = ${placeholder}`);\r\n }\r\n }\r\n\r\n const sql = `UPDATE ${quotedTable} SET ${setClauses.join(\", \")} WHERE ${whereClauses.join(\" AND \")}`;\r\n\r\n const result = await this.driver.query(sql, params);\r\n return result.rowCount ?? 0;\r\n }\r\n\r\n /**\r\n * Execute an update on elements within a JSONB array.\r\n *\r\n * @param table - Table name\r\n * @param filter - Row filter\r\n * @param arrayField - JSONB array column\r\n * @param arrayFilter - Filter to match array elements\r\n * @param update - Fields to update on matched elements\r\n * @returns Number of affected rows\r\n */\r\n private async executeArrayElementUpdate(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n arrayField: string,\r\n arrayFilter: Record<string, unknown>,\r\n update: Record<string, unknown>,\r\n ): Promise<number> {\r\n const quotedTable = this.driver.dialect.quoteIdentifier(table);\r\n const quotedArrayField = this.driver.dialect.quoteIdentifier(arrayField);\r\n\r\n const params: unknown[] = [];\r\n let paramIndex = 1;\r\n\r\n // Build array element filter condition\r\n const arrayFilterCondition = Object.entries(arrayFilter)\r\n .map(([key, value]) => {\r\n params.push(value);\r\n return `elem->>'${key}' = ${this.driver.dialect.placeholder(paramIndex++)}`;\r\n })\r\n .join(\" AND \");\r\n\r\n // Build update expression for matched elements\r\n const updateExpr = Object.entries(update)\r\n .map(([key, value]) => {\r\n params.push(JSON.stringify(value));\r\n return `'${key}', ${this.driver.dialect.placeholder(paramIndex++)}::jsonb`;\r\n })\r\n .join(\", \");\r\n\r\n // Build WHERE clause for row filter\r\n const whereClauses = Object.entries(filter).map(([key, value]) => {\r\n const quotedKey = this.driver.dialect.quoteIdentifier(key);\r\n params.push(value);\r\n return `${quotedKey} = ${this.driver.dialect.placeholder(paramIndex++)}`;\r\n });\r\n\r\n // Use a CTE to update array elements.\r\n // ctid is PostgreSQL's built-in physical row identifier, available on every\r\n // table regardless of the primary key column name.\r\n const sql = `\r\n WITH updated AS (\r\n SELECT ctid, (\r\n SELECT jsonb_agg(\r\n CASE\r\n WHEN ${arrayFilterCondition}\r\n THEN elem || jsonb_build_object(${updateExpr})\r\n ELSE elem\r\n END\r\n )\r\n FROM jsonb_array_elements(${quotedArrayField}) elem\r\n ) AS new_array\r\n FROM ${quotedTable}\r\n WHERE ${whereClauses.join(\" AND \")}\r\n )\r\n UPDATE ${quotedTable} t\r\n SET ${quotedArrayField} = u.new_array\r\n FROM updated u\r\n WHERE t.ctid = u.ctid\r\n `;\r\n\r\n const result = await this.driver.query(sql, params);\r\n return result.rowCount ?? 0;\r\n }\r\n}\r\n","/**\r\n * PostgreSQL Driver\r\n *\r\n * Main driver implementation for PostgreSQL database operations.\r\n * Implements the DriverContract interface to provide a unified API\r\n * for CRUD operations, transactions, and query building.\r\n *\r\n * Uses the `pg` package for database connectivity with connection pooling.\r\n *\r\n * @module cascade/drivers/postgres\r\n */\r\n\r\nimport { colors } from \"@mongez/copper\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport { databaseTransactionContext } from \"../../context/database-transaction-context\";\r\nimport type {\r\n CreateDatabaseOptions,\r\n DriverContract,\r\n DriverEventListener,\r\n DriverTransactionContract,\r\n DropDatabaseOptions,\r\n InsertResult,\r\n TransactionContext,\r\n UpdateOperations,\r\n UpdateResult,\r\n} from \"../../contracts/database-driver.contract\";\r\nimport type { DriverBlueprintContract } from \"../../contracts/driver-blueprint.contract\";\r\nimport type { MigrationDriverContract } from \"../../contracts/migration-driver.contract\";\r\nimport type { QueryBuilderContract } from \"../../contracts/query-builder.contract\";\r\nimport type { SyncAdapterContract } from \"../../contracts/sync-adapter.contract\";\r\nimport { TransactionRollbackError } from \"../../errors/transaction-rollback.error\";\r\nimport { SQLSerializer } from \"../../migration/sql-serializer\";\r\nimport { SqlDatabaseDirtyTracker } from \"../../sql-database-dirty-tracker\";\r\nimport type { ModelDefaults } from \"../../types\";\r\nimport { DatabaseDriver } from \"../../utils/connect-to-database\";\r\nimport { isValidDateValue } from \"../../utils/is-valid-date-value\";\r\nimport { PostgresBlueprint } from \"./postgres-blueprint\";\r\nimport { PostgresDialect } from \"./postgres-dialect\";\r\nimport { PostgresMigrationDriver } from \"./postgres-migration-driver\";\r\nimport { PostgresQueryBuilder } from \"./postgres-query-builder\";\r\nimport { PostgresSQLSerializer } from \"./postgres-sql-serializer\";\r\nimport { PostgresSyncAdapter } from \"./postgres-sync-adapter\";\r\nimport type { PostgresPoolConfig, PostgresQueryResult, PostgresTransactionOptions } from \"./types\";\r\n\r\n/**\r\n * Lazily loaded pg module types.\r\n */\r\ntype PgPool = import(\"pg\").Pool;\r\ntype PgPoolClient = import(\"pg\").PoolClient;\r\ntype PgPoolConfig = import(\"pg\").PoolConfig;\r\n\r\n/**\r\n * Cached pg module reference.\r\n */\r\nlet pgModule: typeof import(\"pg\") | undefined;\r\n\r\n/**\r\n * Lazily load the pg package.\r\n *\r\n * @returns The pg module\r\n * @throws Error if pg is not installed\r\n */\r\nasync function loadPg(): Promise<typeof import(\"pg\")> {\r\n if (pgModule) {\r\n return pgModule;\r\n }\r\n\r\n try {\r\n pgModule = await import(\"pg\");\r\n return pgModule;\r\n } catch {\r\n throw new Error(\r\n 'The \"pg\" package is required for PostgreSQL support. ' + \"Please install it: npm install pg\",\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * PostgreSQL database driver implementing the Cascade DriverContract.\r\n *\r\n * Provides connection pooling, CRUD operations, transactions, and\r\n * integration with Cascade's query builder and migration systems.\r\n *\r\n * @example\r\n * ```typescript\r\n * const driver = new PostgresDriver({\r\n * host: 'localhost',\r\n * port: 5432,\r\n * database: 'myapp',\r\n * user: 'postgres',\r\n * password: 'secret'\r\n * });\r\n *\r\n * await driver.connect();\r\n *\r\n * // Insert a document\r\n * const result = await driver.insert('users', { name: 'Alice', email: 'alice@example.com' });\r\n *\r\n * // Query using the query builder\r\n * const users = await driver.queryBuilder('users')\r\n * .where('name', 'Alice')\r\n * .get();\r\n *\r\n * await driver.disconnect();\r\n * ```\r\n */\r\nexport class PostgresDriver implements DriverContract {\r\n /**\r\n * Driver name identifier.\r\n */\r\n public readonly name = \"postgres\" as DatabaseDriver;\r\n\r\n /**\r\n * SQL dialect for PostgreSQL-specific syntax.\r\n */\r\n public readonly dialect = new PostgresDialect();\r\n\r\n /**\r\n * PostgreSQL driver model defaults.\r\n *\r\n * PostgreSQL follows SQL conventions:\r\n * - snake_case naming for columns (created_at, updated_at, deleted_at)\r\n * - Native AUTO_INCREMENT for IDs (no manual generation)\r\n * - Timestamps enabled by default\r\n * - Permanent delete strategy (hard deletes)\r\n */\r\n public readonly modelDefaults: Partial<ModelDefaults> = {\r\n namingConvention: \"snake_case\",\r\n createdAtColumn: \"created_at\",\r\n updatedAtColumn: \"updated_at\",\r\n deletedAtColumn: \"deleted_at\",\r\n timestamps: true,\r\n autoGenerateId: false, // PostgreSQL uses SERIAL/BIGSERIAL\r\n strictMode: \"fail\",\r\n deleteStrategy: \"permanent\",\r\n };\r\n\r\n /**\r\n * Connection pool instance.\r\n */\r\n private _pool: PgPool | undefined;\r\n\r\n /**\r\n * Event listeners for driver lifecycle events.\r\n */\r\n private readonly _eventListeners = new Map<string, Set<DriverEventListener>>();\r\n\r\n /**\r\n * Whether the driver is currently connected.\r\n */\r\n private _isConnected = false;\r\n\r\n /**\r\n * Blueprint instance (lazy-loaded).\r\n */\r\n private _blueprint: DriverBlueprintContract | undefined;\r\n\r\n /**\r\n * Migration driver instance (lazy-loaded).\r\n */\r\n private _migrationDriver: MigrationDriverContract | undefined;\r\n\r\n /**\r\n * Sync adapter instance (lazy-loaded).\r\n */\r\n private _syncAdapter: SyncAdapterContract | undefined;\r\n\r\n /**\r\n * Create a new PostgreSQL driver instance.\r\n *\r\n * @param config - PostgreSQL connection configuration\r\n */\r\n public constructor(private readonly config: PostgresPoolConfig) {}\r\n\r\n /**\r\n * Get the connection pool instance.\r\n *\r\n * @throws Error if not connected\r\n */\r\n public get pool(): PgPool {\r\n if (!this._pool) {\r\n throw new Error(\"PostgreSQL driver is not connected. Call connect() first.\");\r\n }\r\n return this._pool;\r\n }\r\n\r\n /**\r\n * Get database native client\r\n */\r\n public getClient<Client = PgPool>(): Client {\r\n return this.pool as Client;\r\n }\r\n\r\n /**\r\n * Check if the driver is currently connected.\r\n */\r\n public get isConnected(): boolean {\r\n return this._isConnected;\r\n }\r\n\r\n /**\r\n * Get the driver blueprint (information schema).\r\n */\r\n public get blueprint(): DriverBlueprintContract {\r\n if (!this._blueprint) {\r\n this._blueprint = new PostgresBlueprint(this);\r\n }\r\n return this._blueprint;\r\n }\r\n\r\n /**\r\n * Establish connection to the PostgreSQL database.\r\n *\r\n * Creates a connection pool with the configured options.\r\n * Emits 'connected' event on successful connection.\r\n */\r\n public async connect(): Promise<void> {\r\n if (this._isConnected) {\r\n return;\r\n }\r\n\r\n const pg = await loadPg();\r\n\r\n try {\r\n const poolConfig: PgPoolConfig = {\r\n host: this.config.host ?? \"localhost\",\r\n port: this.config.port ?? 5432,\r\n database: this.config.database,\r\n user: this.config.user,\r\n password: this.config.password,\r\n connectionString: this.config.connectionString,\r\n max: this.config.max ?? 10,\r\n min: this.config.min ?? 0,\r\n idleTimeoutMillis: this.config.idleTimeoutMillis ?? 30000,\r\n connectionTimeoutMillis: this.config.connectionTimeoutMillis ?? 2000,\r\n application_name: this.config.application_name ?? \"cascade\",\r\n ssl: this.config.ssl,\r\n };\r\n\r\n log.info(\r\n \"database.postgres\",\r\n \"connection\",\r\n `Connecting to database ${colors.bold(colors.yellowBright(this.config.database))}`,\r\n );\r\n\r\n this._pool = new pg.Pool(poolConfig);\r\n\r\n // Test the connection\r\n const client = await this._pool.connect();\r\n client.release();\r\n\r\n log.success(\r\n \"database.postgres\",\r\n \"connection\",\r\n `Connected to database ${colors.bold(colors.yellowBright(this.config.database))}`,\r\n );\r\n\r\n this._isConnected = true;\r\n this.emit(\"connected\");\r\n } catch (error) {\r\n // Boot-time database connection failure is unrecoverable in every\r\n // realistic caller (app boot, CLI migrations, workers) — `fatal` makes\r\n // \"page on fatal only\" alerting clean. Per-query failures stay at error.\r\n log.fatal(\"database.postgres\", \"connection\", \"Failed to connect to database\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Close the database connection pool.\r\n *\r\n * Waits for all active queries to complete before closing.\r\n * Emits 'disconnected' event on successful disconnection.\r\n */\r\n public async disconnect(): Promise<void> {\r\n if (!this._isConnected || !this._pool) {\r\n return;\r\n }\r\n\r\n await this._pool.end();\r\n this._pool = undefined;\r\n this._isConnected = false;\r\n this.emit(\"disconnected\");\r\n }\r\n\r\n /**\r\n * Register an event listener for driver lifecycle events.\r\n *\r\n * @param event - Event name ('connected', 'disconnected', etc.)\r\n * @param listener - Callback function to invoke\r\n */\r\n public on(event: string, listener: DriverEventListener): void {\r\n if (!this._eventListeners.has(event)) {\r\n this._eventListeners.set(event, new Set());\r\n }\r\n\r\n this._eventListeners.get(event)!.add(listener);\r\n }\r\n\r\n /**\r\n * Serialize data for storage in PostgreSQL.\r\n *\r\n * Handles Date objects, BigInt, and other JavaScript types\r\n * that need special handling for PostgreSQL storage.\r\n *\r\n * @param data - The data object to serialize\r\n * @returns Serialized data ready for PostgreSQL\r\n */\r\n public serialize(data: Record<string, unknown>): Record<string, unknown> {\r\n const serialized: Record<string, unknown> = {};\r\n\r\n for (const [key, value] of Object.entries(data)) {\r\n if (value === undefined) {\r\n continue; // Skip undefined values\r\n }\r\n\r\n if (value instanceof Date) {\r\n serialized[key] = value.toISOString();\r\n } else if (typeof value === \"bigint\") {\r\n serialized[key] = value.toString();\r\n } else if (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\r\n // Nested objects will be stored as JSONB\r\n serialized[key] = value;\r\n } else if (\r\n Array.isArray(value) &&\r\n value.length > 0 &&\r\n value.every((v) => typeof v === \"number\")\r\n ) {\r\n // pgvector columns expect the literal '[n1,n2,...]' format.\r\n // If we pass a raw JS number[] the pg driver serializes it as a\r\n // PostgreSQL array '{n1,n2,...}' which the vector type rejects.\r\n serialized[key] = `[${value.join(\",\")}]`;\r\n } else {\r\n serialized[key] = value;\r\n }\r\n }\r\n\r\n return serialized;\r\n }\r\n\r\n /**\r\n * Get the dirty tracker for this driver.\r\n */\r\n public getDirtyTracker(data: Record<string, unknown>): SqlDatabaseDirtyTracker {\r\n return new SqlDatabaseDirtyTracker(data);\r\n }\r\n\r\n /**\r\n * Deserialize data retrieved from PostgreSQL.\r\n *\r\n * Converts PostgreSQL types back to JavaScript equivalents.\r\n *\r\n * @param data - The data object from PostgreSQL\r\n * @returns Deserialized JavaScript object\r\n */\r\n public deserialize(data: Record<string, unknown>): Record<string, unknown> {\r\n // PostgreSQL pg driver handles most type conversions automatically\r\n // Special handling can be added here if needed\r\n for (const [key, value] of Object.entries(data)) {\r\n // Only re-inflate strings — pg already returns Date objects from DB reads\r\n if (typeof value !== \"string\") continue;\r\n\r\n if (isValidDateValue(value)) {\r\n data[key] = new Date(value);\r\n continue;\r\n }\r\n\r\n // pgvector columns are returned as '[n1,n2,...]' strings.\r\n // charCodeAt is faster than startsWith/endsWith — no string allocation.\r\n // '[' = 91, ']' = 93\r\n if (value.charCodeAt(0) === 91 && value.charCodeAt(value.length - 1) === 93) {\r\n const parts = value.slice(1, -1).split(\",\");\r\n const nums = new Array<number>(parts.length);\r\n let isNumericVector = parts.length > 0;\r\n\r\n for (let i = 0; i < parts.length; i++) {\r\n const n = +parts[i]; // unary + is the fastest string-to-number coercion\r\n if (!Number.isFinite(n)) {\r\n isNumericVector = false;\r\n break; // early-exit — not a numeric vector, leave value untouched\r\n }\r\n nums[i] = n;\r\n }\r\n\r\n if (isNumericVector) {\r\n data[key] = nums;\r\n }\r\n }\r\n }\r\n\r\n return data;\r\n }\r\n\r\n /**\r\n * Insert a single row into a table.\r\n *\r\n * Uses INSERT ... RETURNING to get the inserted row with generated values.\r\n *\r\n * @param table - Target table name\r\n * @param document - Data to insert\r\n * @param options - Optional insertion options\r\n * @returns The inserted document\r\n */\r\n public async insert(\r\n table: string,\r\n document: Record<string, unknown>,\r\n _options?: Record<string, unknown>,\r\n ): Promise<InsertResult> {\r\n const serialized = this.serialize(document);\r\n\r\n // Filter out id if null/undefined to let PostgreSQL SERIAL auto-generate\r\n const filteredData = Object.fromEntries(\r\n Object.entries(serialized).filter(([key, value]) => {\r\n // Exclude id if null/undefined (let SERIAL handle it)\r\n if (key === \"id\" && (value === null || value === undefined)) {\r\n return false;\r\n }\r\n return true;\r\n }),\r\n );\r\n\r\n const columns = Object.keys(filteredData);\r\n const values = Object.values(filteredData);\r\n\r\n if (columns.length === 0) {\r\n throw new Error(\"Cannot insert empty document\");\r\n }\r\n\r\n const quotedColumns = columns.map((c) => this.dialect.quoteIdentifier(c)).join(\", \");\r\n const placeholders = columns.map((_, i) => this.dialect.placeholder(i + 1)).join(\", \");\r\n const quotedTable = this.dialect.quoteIdentifier(table);\r\n\r\n const sql = `INSERT INTO ${quotedTable} (${quotedColumns}) VALUES (${placeholders}) RETURNING *`;\r\n\r\n const result = await this.query<Record<string, unknown>>(sql, values);\r\n\r\n return {\r\n document: result.rows[0],\r\n };\r\n }\r\n\r\n /**\r\n * Insert multiple rows into a table.\r\n *\r\n * Uses a single INSERT statement with multiple value sets for efficiency.\r\n *\r\n * @param table - Target table name\r\n * @param documents - Array of documents to insert\r\n * @param options - Optional insertion options\r\n * @returns Array of inserted documents\r\n */\r\n public async insertMany(\r\n table: string,\r\n documents: Record<string, unknown>[],\r\n _options?: Record<string, unknown>,\r\n ): Promise<InsertResult[]> {\r\n if (documents.length === 0) {\r\n return [];\r\n }\r\n\r\n // Get all unique columns across all documents\r\n const allColumns = new Set<string>();\r\n for (const doc of documents) {\r\n const serialized = this.serialize(doc);\r\n Object.keys(serialized).forEach((key) => allColumns.add(key));\r\n }\r\n const columns = Array.from(allColumns);\r\n\r\n const quotedColumns = columns.map((c) => this.dialect.quoteIdentifier(c)).join(\", \");\r\n const quotedTable = this.dialect.quoteIdentifier(table);\r\n\r\n // Build value sets and params\r\n const valueSets: string[] = [];\r\n const params: unknown[] = [];\r\n let paramIndex = 1;\r\n\r\n for (const doc of documents) {\r\n const serialized = this.serialize(doc);\r\n const rowPlaceholders: string[] = [];\r\n\r\n for (const col of columns) {\r\n if (col in serialized) {\r\n rowPlaceholders.push(this.dialect.placeholder(paramIndex++));\r\n params.push(serialized[col]);\r\n } else {\r\n rowPlaceholders.push(\"DEFAULT\");\r\n }\r\n }\r\n\r\n valueSets.push(`(${rowPlaceholders.join(\", \")})`);\r\n }\r\n\r\n const sql = `INSERT INTO ${quotedTable} (${quotedColumns}) VALUES ${valueSets.join(\", \")} RETURNING *`;\r\n\r\n const result = await this.query<Record<string, unknown>>(sql, params);\r\n\r\n return result.rows as unknown as InsertResult[];\r\n }\r\n\r\n /**\r\n * Update a single row matching the filter.\r\n *\r\n * @param table - Target table name\r\n * @param filter - Filter conditions\r\n * @param update - Update operations ($set, $unset, $inc)\r\n * @param options - Optional update options\r\n * @returns Update result with modified count\r\n */\r\n public async update(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n update: UpdateOperations,\r\n _options?: Record<string, unknown>,\r\n ): Promise<UpdateResult> {\r\n const { sql, params } = this.buildUpdateQuery(table, filter, update, 1);\r\n try {\r\n const result = await this.query(sql, params);\r\n\r\n return {\r\n modifiedCount: result.rowCount ?? 0,\r\n };\r\n } catch (error) {\r\n console.log(\"PG Query Error in:\", sql, params);\r\n\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Find one and update a single row matching the filter and return the updated row\r\n * @param table - Target table name\r\n * @param filter - Filter conditions\r\n * @param update - Update operations ($set, $unset, $inc)\r\n * @param options - Optional update options\r\n * @returns The updated row or null\r\n */\r\n public async findOneAndUpdate<T = unknown>(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n update: UpdateOperations,\r\n _options?: Record<string, unknown>,\r\n ): Promise<T | null> {\r\n const { sql, params } = this.buildUpdateQuery(table, filter, update, 1);\r\n // Add RETURNING * to get the updated row back\r\n const sqlWithReturning = `${sql} RETURNING *`;\r\n const result = await this.query<T>(sqlWithReturning, params);\r\n return result.rows[0] ?? null;\r\n }\r\n\r\n /**\r\n * Update multiple rows matching the filter.\r\n *\r\n * @param table - Target table name\r\n * @param filter - Filter conditions\r\n * @param update - Update operations\r\n * @param options - Optional update options\r\n * @returns Update result with modified count\r\n */\r\n public async updateMany(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n update: UpdateOperations,\r\n _options?: Record<string, unknown>,\r\n ): Promise<UpdateResult> {\r\n const { sql, params } = this.buildUpdateQuery(table, filter, update);\r\n\r\n const result = await this.query(sql, params);\r\n\r\n return {\r\n modifiedCount: result.rowCount ?? 0,\r\n };\r\n }\r\n\r\n /**\r\n * Replace a document matching the filter.\r\n *\r\n * Completely replaces the document (not a partial update).\r\n *\r\n * @param table - Target table name\r\n * @param filter - Filter conditions\r\n * @param document - New document data\r\n * @param options - Optional options\r\n * @returns The replaced document or null\r\n */\r\n public async replace<T = unknown>(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n document: Record<string, unknown>,\r\n _options?: Record<string, unknown>,\r\n ): Promise<T | null> {\r\n const serialized = this.serialize(document);\r\n const columns = Object.keys(serialized);\r\n const values = Object.values(serialized);\r\n\r\n const quotedTable = this.dialect.quoteIdentifier(table);\r\n const setClauses = columns\r\n .map((col, i) => `${this.dialect.quoteIdentifier(col)} = ${this.dialect.placeholder(i + 1)}`)\r\n .join(\", \");\r\n\r\n const { whereClause, whereParams } = this.buildWhereClause(filter, columns.length + 1);\r\n\r\n const sql = `UPDATE ${quotedTable} SET ${setClauses} ${whereClause} RETURNING *`;\r\n const params = [...values, ...whereParams];\r\n\r\n const result = await this.query<T>(sql, params);\r\n\r\n return result.rows[0] ?? null;\r\n }\r\n\r\n /**\r\n * Upsert (insert or update) a single row.\r\n *\r\n * Uses PostgreSQL's INSERT ... ON CONFLICT ... DO UPDATE syntax.\r\n *\r\n * @param table - Target table name\r\n * @param filter - Filter conditions to find existing row (used for conflict detection)\r\n * @param document - Document data to insert or update\r\n * @param options - Upsert options (conflictColumns for conflict target)\r\n * @returns The upserted row\r\n */\r\n public async upsert<T = unknown>(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n document: Record<string, unknown>,\r\n options?: Record<string, unknown>,\r\n ): Promise<T> {\r\n const serialized = this.serialize(document);\r\n const columns = Object.keys(serialized);\r\n const values = Object.values(serialized);\r\n\r\n if (columns.length === 0) {\r\n throw new Error(\"Cannot upsert empty document\");\r\n }\r\n\r\n const quotedTable = this.dialect.quoteIdentifier(table);\r\n const quotedColumns = columns.map((c) => this.dialect.quoteIdentifier(c)).join(\", \");\r\n const placeholders = columns.map((_, i) => this.dialect.placeholder(i + 1)).join(\", \");\r\n\r\n // Determine conflict columns from options or filter\r\n const conflictColumns = (options?.conflictColumns as string[]) ?? Object.keys(filter);\r\n if (conflictColumns.length === 0) {\r\n throw new Error(\"Upsert requires conflictColumns option or filter with columns\");\r\n }\r\n\r\n const quotedConflictColumns = conflictColumns\r\n .map((c) => this.dialect.quoteIdentifier(c))\r\n .join(\", \");\r\n\r\n // Build UPDATE clause for ON CONFLICT\r\n // Update all columns except the conflict columns (they stay the same)\r\n const updateColumns = columns.filter((col) => !conflictColumns.includes(col));\r\n const setClauses = updateColumns\r\n .map((col, i) => {\r\n const valueIndex = columns.indexOf(col) + 1;\r\n return `${this.dialect.quoteIdentifier(col)} = ${this.dialect.placeholder(valueIndex)}`;\r\n })\r\n .join(\", \");\r\n\r\n // If there are no columns to update (all columns are conflict columns), use EXCLUDED\r\n const updateClause =\r\n setClauses.length > 0\r\n ? setClauses\r\n : columns\r\n .map(\r\n (col) =>\r\n `${this.dialect.quoteIdentifier(col)} = EXCLUDED.${this.dialect.quoteIdentifier(col)}`,\r\n )\r\n .join(\", \");\r\n\r\n const sql = `INSERT INTO ${quotedTable} (${quotedColumns}) VALUES (${placeholders}) ON CONFLICT (${quotedConflictColumns}) DO UPDATE SET ${updateClause} RETURNING *`;\r\n\r\n const result = await this.query<T>(sql, values);\r\n\r\n return result.rows[0]! as T;\r\n }\r\n\r\n /**\r\n * Find one and delete a single row matching the filter and return the deleted row.\r\n *\r\n * @param table - Target table name\r\n * @param filter - Filter conditions\r\n * @param options - Optional delete options\r\n * @returns The deleted row or null\r\n */\r\n public async findOneAndDelete<T = unknown>(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n _options?: Record<string, unknown>,\r\n ): Promise<T | null> {\r\n const quotedTable = this.dialect.quoteIdentifier(table);\r\n const { whereClause, whereParams } = this.buildWhereClause(filter, 1);\r\n\r\n // Use ctid for single row deletion with RETURNING\r\n const sql = `DELETE FROM ${quotedTable} WHERE ctid IN (SELECT ctid FROM ${quotedTable} ${whereClause} LIMIT 1) RETURNING *`;\r\n\r\n const result = await this.query<T>(sql, whereParams);\r\n\r\n return result.rows[0] ? (result.rows[0] as T) : null;\r\n }\r\n\r\n /**\r\n * Delete a single row matching the filter.\r\n *\r\n * @param table - Target table name\r\n * @param filter - Filter conditions\r\n * @param options - Optional options\r\n * @returns Number of deleted rows (0 or 1)\r\n */\r\n public async delete(\r\n table: string,\r\n filter?: Record<string, unknown>,\r\n _options?: Record<string, unknown>,\r\n ): Promise<number> {\r\n const quotedTable = this.dialect.quoteIdentifier(table);\r\n const { whereClause, whereParams } = this.buildWhereClause(filter ?? {}, 1);\r\n\r\n // Use ctid for single row deletion\r\n const sql = `DELETE FROM ${quotedTable} WHERE ctid IN (SELECT ctid FROM ${quotedTable} ${whereClause} LIMIT 1)`;\r\n\r\n const result = await this.query(sql, whereParams);\r\n\r\n return result.rowCount ?? 0;\r\n }\r\n\r\n /**\r\n * Delete multiple rows matching the filter.\r\n *\r\n * @param table - Target table name\r\n * @param filter - Filter conditions\r\n * @param options - Optional options\r\n * @returns Number of deleted rows\r\n */\r\n public async deleteMany(\r\n table: string,\r\n filter?: Record<string, unknown>,\r\n _options?: Record<string, unknown>,\r\n ): Promise<number> {\r\n const quotedTable = this.dialect.quoteIdentifier(table);\r\n const { whereClause, whereParams } = this.buildWhereClause(filter ?? {}, 1);\r\n\r\n const sql = `DELETE FROM ${quotedTable} ${whereClause}`;\r\n\r\n const result = await this.query(sql, whereParams);\r\n\r\n return result.rowCount ?? 0;\r\n }\r\n\r\n /**\r\n * Truncate a table (remove all rows).\r\n *\r\n * Uses TRUNCATE TABLE for fast deletion with RESTART IDENTITY.\r\n *\r\n * @param table - Target table name\r\n * @param options - Optional options\r\n * @param options.cascade - If true, automatically truncate all tables with foreign key references (use with caution)\r\n * @returns Number of deleted rows (always 0 for TRUNCATE)\r\n */\r\n public async truncateTable(table: string, options?: { cascade?: boolean }): Promise<number> {\r\n const quotedTable = this.dialect.quoteIdentifier(table);\r\n const cascadeClause = options?.cascade ? \" CASCADE\" : \"\";\r\n await this.query(`TRUNCATE TABLE ${quotedTable} RESTART IDENTITY${cascadeClause}`);\r\n return 0; // TRUNCATE doesn't return row count\r\n }\r\n\r\n /**\r\n * Get a query builder for the specified table.\r\n *\r\n * @param table - Target table name\r\n * @returns Query builder instance\r\n */\r\n public queryBuilder<T = unknown>(table: string): QueryBuilderContract<T> {\r\n return new PostgresQueryBuilder<T>(table) as unknown as QueryBuilderContract<T>;\r\n }\r\n\r\n /**\r\n * Begin a new database transaction.\r\n *\r\n * Acquires a client from the pool and starts a transaction.\r\n * The client is stored in AsyncLocalStorage for automatic\r\n * participation by subsequent queries.\r\n *\r\n * @param options - Optional transaction options\r\n * @returns Transaction contract with commit/rollback methods\r\n */\r\n public async beginTransaction(\r\n options?: PostgresTransactionOptions,\r\n ): Promise<DriverTransactionContract<PgPoolClient>> {\r\n const client = await this.pool.connect();\r\n\r\n let beginSql = \"BEGIN\";\r\n if (options?.isolationLevel) {\r\n beginSql += ` ISOLATION LEVEL ${options.isolationLevel.toUpperCase()}`;\r\n }\r\n if (options?.readOnly) {\r\n beginSql += \" READ ONLY\";\r\n }\r\n if (options?.deferrable) {\r\n beginSql += \" DEFERRABLE\";\r\n }\r\n\r\n await client.query(beginSql);\r\n\r\n return {\r\n context: client,\r\n commit: async () => {\r\n await client.query(\"COMMIT\");\r\n client.release();\r\n },\r\n rollback: async () => {\r\n await client.query(\"ROLLBACK\");\r\n client.release();\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Execute a function within a transaction scope (recommended pattern).\r\n *\r\n * Automatically commits on success, rolls back on any error, and guarantees\r\n * resource cleanup. This is the recommended way to use transactions.\r\n *\r\n * @param fn - Async function to execute within transaction\r\n * @param options - Transaction options (isolation level, read-only, etc.)\r\n * @returns The return value of the callback function\r\n * @throws {Error} If transaction fails or is explicitly rolled back\r\n */\r\n public async transaction<T>(\r\n fn: (ctx: TransactionContext) => Promise<T>,\r\n options?: Record<string, unknown>,\r\n ): Promise<T> {\r\n // Prevent nested transaction() calls\r\n if (databaseTransactionContext.hasActiveTransaction()) {\r\n // throw new Error(\r\n // \"Nested transaction() calls are not supported. \" +\r\n // \"Use beginTransaction() with savepoints for advanced transaction patterns.\",\r\n // );\r\n }\r\n\r\n const tx = await this.beginTransaction(options);\r\n\r\n // Set transaction context for queries within callback\r\n databaseTransactionContext.enter({ session: tx.context });\r\n\r\n try {\r\n // Create transaction context with rollback method\r\n const ctx: TransactionContext = {\r\n rollback(reason?: string): never {\r\n throw new TransactionRollbackError(reason);\r\n },\r\n };\r\n\r\n // Execute callback\r\n const result = await fn(ctx);\r\n\r\n // Auto-commit on success\r\n await tx.commit();\r\n\r\n return result;\r\n } catch (error) {\r\n // Auto-rollback on any error (including explicit rollback)\r\n await tx.rollback();\r\n log.error(\r\n `database.postgress`,\r\n \"transaction\",\r\n \"Transaction operation failed, rolled back everything\",\r\n );\r\n throw error;\r\n } finally {\r\n // Guaranteed cleanup\r\n databaseTransactionContext.exit();\r\n }\r\n }\r\n\r\n /**\r\n * Perform an atomic update operation.\r\n *\r\n * Builds and executes an UPDATE query for the given filter and operations.\r\n *\r\n * @param table - Target table name\r\n * @param filter - Filter conditions\r\n * @param operations - Update operations\r\n * @param options - Optional options\r\n * @returns Update result\r\n */\r\n public async atomic(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n operations: UpdateOperations,\r\n _options?: Record<string, unknown>,\r\n ): Promise<UpdateResult> {\r\n const { sql, params } = this.buildUpdateQuery(table, filter, operations, 1);\r\n\r\n const result = await this.query(sql, params);\r\n\r\n return {\r\n modifiedCount: result.rowCount ?? 0,\r\n };\r\n }\r\n\r\n /**\r\n * Get the sync adapter for bulk denormalized updates.\r\n *\r\n * @returns Sync adapter instance\r\n */\r\n public syncAdapter(): SyncAdapterContract {\r\n if (!this._syncAdapter) {\r\n this._syncAdapter = new PostgresSyncAdapter(this);\r\n }\r\n return this._syncAdapter;\r\n }\r\n\r\n /**\r\n * Get the migration driver for schema operations.\r\n *\r\n * @returns Migration driver instance\r\n */\r\n public migrationDriver(): MigrationDriverContract {\r\n if (!this._migrationDriver) {\r\n this._migrationDriver = new PostgresMigrationDriver(this);\r\n }\r\n\r\n return this._migrationDriver;\r\n }\r\n\r\n /**\r\n * Return a SQL serializer for this driver's dialect.\r\n * Used by Migration.toSQL() to convert pending operations to SQL strings.\r\n */\r\n public getSQLSerializer(): SQLSerializer {\r\n return new PostgresSQLSerializer(this.dialect);\r\n }\r\n\r\n /**\r\n * Execute a raw SQL query.\r\n *\r\n * Automatically uses the transaction client if one is active.\r\n *\r\n * @param sql - SQL query string\r\n * @param params - Query parameters\r\n * @returns Query result\r\n */\r\n public async query<T = Record<string, unknown>>(\r\n sql: string,\r\n params: unknown[] = [],\r\n ): Promise<PostgresQueryResult<T>> {\r\n // Check for active transaction client\r\n const txClient = databaseTransactionContext.getSession() as PgPoolClient | undefined;\r\n\r\n const startTime = this.config.logging ? performance.now() : 0;\r\n\r\n let paramsString = \"\";\r\n if (this.config.logging && params.length > 0) {\r\n paramsString = JSON.stringify(params);\r\n if (paramsString.length > 300) {\r\n paramsString = paramsString.substring(0, 300) + \"...\";\r\n }\r\n paramsString = ` | Params: ${paramsString}`;\r\n }\r\n\r\n try {\r\n let result;\r\n if (this.config.logging) {\r\n log.info({\r\n module: \"database.postgres\",\r\n action: \"query.executing\",\r\n message: `${sql}${paramsString}`,\r\n context: { params, sql },\r\n });\r\n }\r\n if (txClient) {\r\n result = await txClient.query(sql, params);\r\n } else {\r\n result = await this.pool.query(sql, params);\r\n }\r\n\r\n if (this.config.logging) {\r\n const duration = (performance.now() - startTime).toFixed(2);\r\n log.success({\r\n module: \"database.postgres\",\r\n action: \"query.executed\",\r\n message: `[${duration}ms] ${sql}${paramsString}`,\r\n context: { params, sql, duration },\r\n });\r\n }\r\n\r\n return result as PostgresQueryResult<T>;\r\n } catch (error) {\r\n if (this.config.logging) {\r\n const duration = (performance.now() - startTime).toFixed(2);\r\n log.error({\r\n module: \"database.postgres\",\r\n action: \"query.error\",\r\n message: `[${duration}ms] ${sql}${paramsString}`,\r\n context: {\r\n sql,\r\n params,\r\n error: error instanceof Error ? error.message : String(error),\r\n },\r\n });\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Emit an event to all registered listeners.\r\n *\r\n * @param event - Event name\r\n * @param args - Event arguments\r\n */\r\n private emit(event: string, ...args: unknown[]): void {\r\n const listeners = this._eventListeners.get(event);\r\n if (listeners) {\r\n for (const listener of listeners) {\r\n listener(...args);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Build a simple WHERE clause from a filter object.\r\n *\r\n * @param filter - Filter conditions\r\n * @param startParamIndex - Starting parameter index\r\n * @returns Object with WHERE clause string and parameters\r\n */\r\n private buildWhereClause(\r\n filter: Record<string, unknown>,\r\n startParamIndex: number,\r\n ): { whereClause: string; whereParams: unknown[] } {\r\n const conditions: string[] = [];\r\n const params: unknown[] = [];\r\n let paramIndex = startParamIndex;\r\n\r\n for (const [key, value] of Object.entries(filter)) {\r\n const quotedKey = this.dialect.quoteIdentifier(key);\r\n\r\n if (value === null) {\r\n conditions.push(`${quotedKey} IS NULL`);\r\n } else {\r\n conditions.push(`${quotedKey} = ${this.dialect.placeholder(paramIndex++)}`);\r\n params.push(value);\r\n }\r\n }\r\n\r\n const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(\" AND \")}` : \"\";\r\n\r\n return { whereClause, whereParams: params };\r\n }\r\n\r\n /**\r\n * Build an UPDATE query from update operations.\r\n *\r\n * @param table - Target table name\r\n * @param filter - Filter conditions\r\n * @param update - Update operations\r\n * @param limit - Optional limit (for single row update)\r\n * @returns Object with SQL and parameters\r\n */\r\n private buildUpdateQuery(\r\n table: string,\r\n filter: Record<string, unknown>,\r\n update: UpdateOperations,\r\n limit?: number,\r\n ): { sql: string; params: unknown[] } {\r\n const setClauses: string[] = [];\r\n const params: unknown[] = [];\r\n let paramIndex = 1;\r\n\r\n // Handle $set\r\n if (update.$set) {\r\n for (const [key, value] of Object.entries(update.$set)) {\r\n setClauses.push(\r\n `${this.dialect.quoteIdentifier(key)} = ${this.dialect.placeholder(paramIndex++)}`,\r\n );\r\n params.push(value);\r\n }\r\n }\r\n\r\n // Handle $unset (set to NULL)\r\n if (update.$unset) {\r\n for (const key of Object.keys(update.$unset)) {\r\n setClauses.push(`${this.dialect.quoteIdentifier(key)} = NULL`);\r\n }\r\n }\r\n\r\n // Handle $inc\r\n if (update.$inc) {\r\n for (const [key, amount] of Object.entries(update.$inc)) {\r\n const quotedKey = this.dialect.quoteIdentifier(key);\r\n setClauses.push(\r\n `${quotedKey} = COALESCE(${quotedKey}, 0) + ${this.dialect.placeholder(paramIndex++)}`,\r\n );\r\n params.push(amount);\r\n }\r\n }\r\n\r\n // Handle $dec\r\n if (update.$dec) {\r\n for (const [key, amount] of Object.entries(update.$dec)) {\r\n const quotedKey = this.dialect.quoteIdentifier(key);\r\n setClauses.push(\r\n `${quotedKey} = COALESCE(${quotedKey}, 0) - ${this.dialect.placeholder(paramIndex++)}`,\r\n );\r\n params.push(amount);\r\n }\r\n }\r\n\r\n if (setClauses.length === 0) {\r\n throw new Error(\"No update operations specified\");\r\n }\r\n\r\n const quotedTable = this.dialect.quoteIdentifier(table);\r\n const { whereClause, whereParams } = this.buildWhereClause(filter, paramIndex);\r\n params.push(...whereParams);\r\n\r\n let sql = `UPDATE ${quotedTable} SET ${setClauses.join(\", \")} ${whereClause}`;\r\n\r\n // For single row update, use ctid subquery\r\n if (limit === 1 && whereClause) {\r\n sql = `UPDATE ${quotedTable} SET ${setClauses.join(\", \")} WHERE ctid IN (SELECT ctid FROM ${quotedTable} ${whereClause} LIMIT 1)`;\r\n }\r\n\r\n return { sql, params };\r\n }\r\n\r\n // ============================================================\r\n // Database Lifecycle Operations\r\n // ============================================================\r\n\r\n /**\r\n * Create a new database.\r\n *\r\n * Note: This requires connecting to a system database (like 'postgres')\r\n * since you cannot create a database while connected to it.\r\n *\r\n * @param name - Database name to create\r\n * @param options - Creation options (encoding, template, etc.)\r\n * @returns true if created, false if already exists\r\n */\r\n public async createDatabase(name: string, options?: CreateDatabaseOptions): Promise<boolean> {\r\n // Check if database already exists\r\n if (await this.databaseExists(name)) {\r\n return false;\r\n }\r\n\r\n // Build CREATE DATABASE statement\r\n const quotedName = this.dialect.quoteIdentifier(name);\r\n let sql = `CREATE DATABASE ${quotedName}`;\r\n\r\n const withClauses: string[] = [];\r\n\r\n if (options?.encoding) {\r\n withClauses.push(`ENCODING = '${options.encoding}'`);\r\n }\r\n if (options?.template) {\r\n withClauses.push(`TEMPLATE = ${this.dialect.quoteIdentifier(options.template)}`);\r\n }\r\n if (options?.locale) {\r\n withClauses.push(`LC_COLLATE = '${options.locale}'`);\r\n withClauses.push(`LC_CTYPE = '${options.locale}'`);\r\n }\r\n if (options?.owner) {\r\n withClauses.push(`OWNER = ${this.dialect.quoteIdentifier(options.owner)}`);\r\n }\r\n\r\n if (withClauses.length > 0) {\r\n sql += ` WITH ${withClauses.join(\" \")}`;\r\n }\r\n\r\n try {\r\n await this.query(sql);\r\n log.success(\"database\", \"lifecycle\", `Created database ${name}`);\r\n return true;\r\n } catch (error) {\r\n log.error(\"database\", \"lifecycle\", `Failed to create database ${name}: ${error}`);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Drop a database.\r\n *\r\n * @param name - Database name to drop\r\n * @param options - Drop options\r\n * @returns true if dropped, false if didn't exist\r\n */\r\n public async dropDatabase(name: string, options?: DropDatabaseOptions): Promise<boolean> {\r\n // Check if database exists first (if ifExists option not set)\r\n if (!options?.ifExists && !(await this.databaseExists(name))) {\r\n return false;\r\n }\r\n\r\n const quotedName = this.dialect.quoteIdentifier(name);\r\n let sql = \"DROP DATABASE\";\r\n\r\n if (options?.ifExists) {\r\n sql += \" IF EXISTS\";\r\n }\r\n\r\n sql += ` ${quotedName}`;\r\n\r\n // PostgreSQL 13+ supports WITH (FORCE) to terminate active connections\r\n if (options?.force) {\r\n sql += \" WITH (FORCE)\";\r\n }\r\n\r\n try {\r\n await this.query(sql);\r\n log.success(\"database\", \"lifecycle\", `Dropped database ${name}`);\r\n return true;\r\n } catch (error) {\r\n log.error(\"database\", \"lifecycle\", `Failed to drop database ${name}: ${error}`);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Check if a database exists.\r\n *\r\n * @param name - Database name to check\r\n * @returns true if database exists\r\n */\r\n public async databaseExists(name: string): Promise<boolean> {\r\n const result = await this.query<{ exists: boolean }>(\r\n `SELECT EXISTS(SELECT 1 FROM pg_database WHERE datname = $1) as exists`,\r\n [name],\r\n );\r\n\r\n return result.rows[0]?.exists ?? false;\r\n }\r\n\r\n /**\r\n * List all databases.\r\n *\r\n * @returns Array of database names\r\n */\r\n public async listDatabases(): Promise<string[]> {\r\n const result = await this.query<{ datname: string }>(\r\n `SELECT datname FROM pg_database WHERE datistemplate = false ORDER BY datname`,\r\n );\r\n\r\n return result.rows.map((row) => row.datname);\r\n }\r\n\r\n // ============================================================\r\n // Table Management Operations\r\n // ============================================================\r\n\r\n /**\r\n * Drop a table.\r\n *\r\n * @param name - Table name to drop\r\n * @throws Error if table doesn't exist\r\n */\r\n public async dropTable(name: string): Promise<void> {\r\n const quotedName = this.dialect.quoteIdentifier(name);\r\n await this.query(`DROP TABLE ${quotedName}`);\r\n log.success(\"database\", \"table\", `Dropped table ${name}`);\r\n }\r\n\r\n /**\r\n * Drop a table if it exists.\r\n *\r\n * @param name - Table name to drop\r\n */\r\n public async dropTableIfExists(name: string): Promise<void> {\r\n const quotedName = this.dialect.quoteIdentifier(name);\r\n await this.query(`DROP TABLE IF EXISTS ${quotedName}`);\r\n }\r\n\r\n /**\r\n * Drop all tables in the current database.\r\n *\r\n * Uses CASCADE to handle foreign key dependencies.\r\n * Useful for `migrate:fresh` command.\r\n */\r\n public async dropAllTables(): Promise<void> {\r\n // Get all tables from blueprint\r\n const tables = await this.blueprint.listTables();\r\n\r\n if (tables.length === 0) {\r\n return;\r\n }\r\n\r\n // Drop all tables with CASCADE to handle foreign keys\r\n for (const table of tables) {\r\n const quotedName = this.dialect.quoteIdentifier(table);\r\n await this.query(`DROP TABLE IF EXISTS ${quotedName} CASCADE`);\r\n }\r\n\r\n log.success(\"database\", \"table\", `Dropped ${tables.length} tables`);\r\n }\r\n}\r\n","import { DriverContract, TransactionContext } from \"../contracts\";\nimport { DataSource } from \"../data-source/data-source\";\nimport { dataSourceRegistry } from \"../data-source/data-source-registry\";\nimport { MongoDbDriver } from \"../drivers/mongodb/mongodb-driver\";\nimport { PostgresDriver } from \"../drivers/postgres\";\nimport type { DeleteStrategy, MigrationDefaults, ModelDefaults, RelationDefaults } from \"../types\";\n\n/**\n * Supported database driver types.\n */\nexport type DatabaseDriver = \"mongodb\" | \"postgres\" | \"mysql\";\n\n/**\n * Default model configuration options.\n *\n * These settings will be applied to all models using this data source,\n * unless overridden by individual model static properties.\n *\n * This is a re-export of Partial<ModelDefaults> for backward compatibility\n * and to provide clearer naming in the connection config context.\n *\n * The full hierarchy is:\n * 1. Model static property (highest priority)\n * 2. Database config modelDefaults (this type)\n * 3. Driver defaults (e.g., snake_case for PostgreSQL, camelCase for MongoDB)\n * 4. Framework defaults (fallback values)\n *\n * @see ModelDefaults for complete type definition and documentation\n */\nexport type ModelDefaultConfig = Partial<ModelDefaults>;\n\n/**\n * Connection options for establishing a database connection.\n *\n * Generic type that separates concerns:\n * - Shared config (driver, name, database, connection details)\n * - Driver options (cascade-next driver-specific settings)\n * - Client options (native database client settings)\n * - Model options (default model behaviors)\n *\n * @template TDriverOptions - Driver-specific options (e.g., MongoDriverOptions)\n * @template TClientOptions - Native client options (e.g., MongoClientOptions from mongodb package)\n *\n * @example\n * ```typescript\n * // MongoDB\n * import type { MongoClientOptions } from \"mongodb\";\n * import type { MongoDriverOptions } from \"@warlock.js/cascade\";\n *\n * const config: ConnectionOptions<MongoDriverOptions, MongoClientOptions> = {\n * driver: \"mongodb\",\n * database: \"myapp\",\n * host: \"localhost\",\n * port: 27017,\n * driverOptions: {\n * autoGenerateId: true,\n * counterCollection: \"counters\",\n * },\n * clientOptions: {\n * minPoolSize: 5,\n * maxPoolSize: 10,\n * },\n * modelOptions: {\n * randomIncrement: true,\n * initialId: 1000,\n * },\n * };\n * ```\n */\nexport type ConnectionOptions<TDriverOptions = any, TClientOptions = any> = {\n // ============================================================================\n // SHARED CONFIGURATION (Framework-level)\n // ============================================================================\n\n /**\n * Database driver to use.\n * @default \"mongodb\"\n */\n driver?: DatabaseDriver;\n\n /**\n * Unique name for this data source.\n * Used for registration in DataSourceRegistry.\n * @default \"default\"\n */\n name?: string;\n\n /**\n * Whether this should be the default data source.\n * @default true\n */\n isDefault?: boolean;\n\n /**\n * Database name (required).\n */\n database: string;\n\n /**\n * Enable database operation logging (queries, execution time, parameters).\n * Highly recommended to keep this disabled in production to prevent sensitive data leakage.\n *\n * @default false\n */\n logging?: boolean;\n\n // ============================================================================\n // CONNECTION DETAILS (Shared across drivers)\n // ============================================================================\n\n /**\n * Database connection URI.\n * Alternative to specifying host/port separately.\n *\n * @example \"mongodb://localhost:27017/mydb\"\n * @example \"postgresql://user:pass@localhost:5432/mydb\"\n */\n uri?: string;\n\n /**\n * Database host.\n * @default \"localhost\"\n */\n host?: string;\n\n /**\n * Database port.\n * @default 27017 (MongoDB), 5432 (PostgreSQL)\n */\n port?: number;\n\n /**\n * Database username for authentication.\n */\n username?: string;\n\n /**\n * Database password for authentication.\n */\n password?: string;\n\n /**\n * Authentication source database.\n * Typically \"admin\" for MongoDB.\n */\n authSource?: string;\n\n // ============================================================================\n // DRIVER OPTIONS (Package-level, driver-specific)\n // ============================================================================\n\n /**\n * Driver-specific options.\n *\n * For MongoDB: { autoGenerateId, counterCollection, transactionOptions }\n * For PostgreSQL: { schema, ... }\n */\n driverOptions?: TDriverOptions;\n\n // ============================================================================\n // CLIENT OPTIONS (Native database client library)\n // ============================================================================\n\n /**\n * Native database client options.\n *\n * For MongoDB: MongoClientOptions from 'mongodb' package\n * For PostgreSQL: PoolConfig from 'pg' package\n */\n clientOptions?: TClientOptions;\n\n // ============================================================================\n // MODEL OPTIONS (Model defaults)\n // ============================================================================\n\n /**\n * Default model configuration for all models using this data source.\n *\n * These settings override driver defaults but are overridden by\n * individual model static properties.\n *\n * **Configuration Hierarchy (highest to lowest):**\n * 1. Model static property - `User.createdAtColumn = \"creation_date\"`\n * 2. **modelOptions (this)** - Database-wide overrides\n * 3. Driver defaults - PostgreSQL: snake_case, MongoDB: camelCase\n * 4. Framework defaults - Fallback values\n *\n * @example\n * ```typescript\n * // PostgreSQL database with custom settings\n * {\n * driver: \"postgres\",\n * modelOptions: {\n * // Override PostgreSQL default (snake_case) to use camelCase\n * namingConvention: \"camelCase\",\n * createdAtColumn: \"createdAt\",\n * updatedAtColumn: \"updatedAt\",\n *\n * // ID generation settings (for MongoDB)\n * randomIncrement: true,\n * initialId: 1000,\n *\n * // Deletion settings\n * deleteStrategy: \"soft\",\n * trashTable: \"archive\", // All models use same trash table\n * }\n * }\n *\n * // MongoDB database with defaults\n * {\n * driver: \"mongodb\",\n * modelOptions: {\n * // MongoDB already uses camelCase by default\n * randomIncrement: true,\n * initialId: 10000,\n * deleteStrategy: \"trash\", // Use RecycleBin\n * }\n * }\n * ```\n */\n modelOptions?: ModelDefaultConfig;\n\n /**\n * Migration-level defaults (UUID strategy, etc.).\n *\n * These defaults override driver migration defaults but can be\n * overridden by individual migration calls.\n *\n * @default undefined (uses driver defaults)\n *\n * @example\n * ```typescript\n * migrationDefaults: {\n * uuidStrategy: \"v7\", // Use UUID v7 for all migrations\n * }\n * ```\n */\n migrationOptions?: MigrationDefaults;\n\n /**\n * Defaults for relation conventions — foreign-key suffix and pivot-table\n * naming order. Controls how `@BelongsTo` / `@HasOne` / `@HasMany` /\n * `@BelongsToMany` infer column / table names when none are explicitly\n * configured on the decorator.\n *\n * @default undefined (uses framework defaults: `\"_id\"` suffix + alphabetical pivot)\n *\n * @example\n * ```typescript\n * relationOptions: {\n * foreignKeySuffix: \"_id\",\n * pivotTableNamingOrder: \"alphabetical\",\n * }\n * ```\n */\n relationOptions?: RelationDefaults;\n\n // ============================================================================\n // DATA SOURCE DEFAULTS\n // ============================================================================\n\n /**\n * Default delete strategy for models using this data source.\n *\n * - MongoDB: Typically `\"trash\"` (uses RecycleBin collection)\n * - PostgreSQL: Typically `\"permanent\"` or `\"soft\"`\n *\n * Can be overridden by model static property or destroy() options.\n *\n * @default undefined (falls back to \"permanent\")\n */\n defaultDeleteStrategy?: DeleteStrategy;\n\n /**\n * Default trash table/collection name for \"trash\" delete strategy.\n *\n * - MongoDB: Typically `\"RecycleBin\"`\n * - If not set, defaults to `{table}Trash` pattern\n *\n * Can be overridden by Model.trashTable static property.\n *\n * @default undefined (uses {table}Trash pattern)\n */\n defaultTrashTable?: string;\n\n // ============================================================================\n // MIGRATION OPTIONS\n // ============================================================================\n\n /**\n * Migration configuration options.\n */\n migrations?: {\n /**\n * Whether to wrap migrations in database transactions.\n *\n * Overrides driver defaults:\n * - PostgreSQL default: `true` (DDL is transactional)\n * - MongoDB default: `false` (DDL cannot be transactional)\n *\n * Individual migrations can override this with their own `transactional` property.\n *\n * @default undefined (uses driver default)\n */\n transactional?: boolean;\n\n /**\n * Name of the migrations tracking table/collection.\n *\n * @default \"_migrations\"\n */\n table?: string;\n };\n};\n\n/**\n * Connect to a database and register the data source.\n *\n * This is a high-level utility function that simplifies database connection\n * for small to medium projects. It handles driver instantiation, connection,\n * data source creation, and automatic registration.\n *\n * **Supported Drivers:**\n * - `mongodb` (default) - MongoDB driver with optional auto ID generation\n * - `postgres` - PostgreSQL driver (not yet implemented)\n * - `mysql` - MySQL driver (not yet implemented)\n *\n * **Features:**\n * - Automatic driver instantiation based on driver name\n * - Connection establishment and error handling\n * - DataSource creation and registration\n * - Support for MongoDB-specific features (ID generation, transactions)\n *\n * @param options - Connection configuration options\n * @returns A connected and registered DataSource instance\n * @throws {Error} If connection fails or driver is not implemented\n *\n * @example\n * ```typescript\n * // MongoDB with new structure\n * const dataSource = await connectToDatabase({\n * driver: \"mongodb\",\n * database: \"myapp\",\n * host: \"localhost\",\n * port: 27017,\n * driverOptions: {\n * autoGenerateId: true,\n * },\n * clientOptions: {\n * minPoolSize: 5,\n * maxPoolSize: 10,\n * },\n * modelOptions: {\n * randomIncrement: true,\n * initialId: 1000,\n * },\n * });\n * ```\n */\nexport async function connectToDatabase<TDriverOptions = any, TClientOptions = any>(\n options: ConnectionOptions<TDriverOptions, TClientOptions>,\n): Promise<DataSource> {\n // Default values\n const driverType = options.driver ?? \"mongodb\";\n const dataSourceName = options.name ?? \"default\";\n const isDefault = options.isDefault ?? true;\n\n // Create driver based on type\n let driver: DriverContract;\n\n switch (driverType) {\n case \"mongodb\": {\n driver = new MongoDbDriver(\n {\n database: options.database,\n uri: options.uri,\n host: options.host,\n port: options.port,\n username: options.username,\n password: options.password,\n authSource: options.authSource,\n logging: options.logging,\n clientOptions: options.clientOptions as any,\n },\n options.driverOptions as any,\n );\n break;\n }\n\n case \"postgres\": {\n driver = new PostgresDriver({\n database: options.database,\n connectionString: options.uri,\n host: options.host,\n port: options.port ?? 5432,\n user: options.username,\n password: options.password,\n logging: options.logging,\n // Spread any additional client options (pool settings, SSL, etc.)\n ...(options.clientOptions as object),\n });\n break;\n }\n\n case \"mysql\":\n throw new Error(\"MySQL driver is not yet implemented. Coming soon!\");\n\n default:\n throw new Error(\n `Unknown driver: \"${driverType}\". Supported drivers: mongodb, postgres, mysql`,\n );\n }\n\n // Create data source\n const dataSource = new DataSource({\n name: dataSourceName,\n driver,\n isDefault,\n defaultDeleteStrategy: options.defaultDeleteStrategy,\n defaultTrashTable: options.defaultTrashTable,\n modelDefaults: options.modelOptions,\n migrationDefaults: options.migrationOptions,\n relationDefaults: options.relationOptions,\n migrations: options.migrations,\n });\n\n // Register data source\n dataSourceRegistry.register(dataSource);\n\n // Connect to the database\n try {\n await driver.connect();\n } catch (error) {\n console.log(error);\n\n throw new Error(\n `Failed to connect to ${driverType} database: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n\n return dataSource;\n}\n\n/**\n * Get current driver instance.\n *\n * @example\n * ```typescript\n * const driver = getDatabaseDriver();\n *\n * // Pass type to return Postgres driver type\n * const pgDriver = getDatabaseDriver<PostgresDriver>();\n * ```\n */\nexport function getDatabaseDriver<T extends DriverContract = any>(): T {\n const driver = dataSourceRegistry.get().driver;\n\n return driver as unknown as T;\n}\n\n/**\n * Perform database transaction(s)\n * Shorthand to `dataSourceRegister.get().driver.transaction\n */\nexport async function transaction<T = any>(\n fn: (ctx: TransactionContext) => Promise<T>,\n options?: Record<string, unknown>,\n): Promise<T> {\n return getDatabaseDriver().transaction(fn, options);\n}\n","import { type TransformerCallback } from \"@warlock.js/seal\";\nimport { type Model } from \"../model/model\";\n\ntype transformCallbackOptions = {\n model: Model;\n column: string;\n value: any;\n isChanged: boolean;\n isNew: boolean;\n};\n\nexport type ModelTransformCallback = (options: transformCallbackOptions) => string;\n\n/**\n * Transfer value before saving it into the database\n */\nexport function useModelTransformer(callback: ModelTransformCallback) {\n const transformCallback: TransformerCallback = (data, { context }) => {\n const model = context.rootContext?.model as Model;\n const column = context.key;\n const value = data;\n const isChanged = model.isDirty(column);\n const isNew = model.isNew;\n return callback({ model, column, value, isChanged, isNew });\n };\n\n return transformCallback;\n}\n","import type { Infer, ObjectValidator } from \"@warlock.js/seal\";\nimport type { ModelSchema } from \"../model/model\";\nimport { Model } from \"../model/model\";\nimport { registerModelInRegistry } from \"../model/register-model\";\nimport type { DeleteStrategy, StrictMode } from \"../types\";\n\n/**\n * Configuration options for defining a model.\n */\nexport type DefineModelOptions<TSchema extends ModelSchema> = {\n /**\n * The database table/collection name.\n */\n table: string;\n\n /**\n * Model name\n * If provided, it will be registered in the models registery\n */\n name?: string;\n\n /**\n * The validation schema for the model.\n * Use `v.object()` from @warlock.js/seal to define the schema.\n */\n schema: ObjectValidator;\n\n /**\n * Delete strategy for this model. Controls how `destroy()` handles records.\n *\n * - `\"trash\"` — Moves the record to a trash table/collection, then deletes from the source.\n * - `\"permanent\"` — Hard delete. The record is removed from the database.\n * - `\"soft\"` — Sets a `deletedAt` timestamp; the row stays in place.\n *\n * When omitted, the runtime resolves the strategy in this priority order:\n * `destroy()` call options → this model's static → data source `defaultDeleteStrategy` → `\"permanent\"`.\n */\n deleteStrategy?: DeleteStrategy;\n\n /**\n * Behavior when the model is asked to write a field that is not declared in `schema`.\n *\n * - `\"strip\"` — Drop unknown fields silently (default).\n * - `\"fail\"` — Throw a validation error on unknown fields.\n * - `\"allow\"` — Pass unknown fields through to the database as-is.\n */\n strictMode?: StrictMode;\n\n /**\n * Auto-generate a sequential `id` field on insert (NoSQL only).\n *\n * SQL drivers use native AUTO_INCREMENT and ignore this. When omitted, the\n * MongoDB driver defaults to `true`; the PostgreSQL driver defaults to `false`.\n */\n autoGenerateId?: boolean;\n\n /**\n * Use a random increment (1–10) instead of a fixed step when auto-generating IDs.\n *\n * When omitted, falls through to the driver/data-source default.\n */\n randomIncrement?: boolean;\n\n /**\n * Initial ID value for the first record when auto-generating IDs.\n *\n * When omitted, falls through to the driver/data-source default (typically `1`).\n */\n initialId?: number;\n\n /**\n * Optional: Custom instance properties (getters/setters/methods).\n * Define computed properties, custom getters, or instance methods.\n *\n * The `this` context will be the Model instance, giving you access to\n * all Model methods like `get()`, `set()`, `save()`, etc.\n *\n * @example\n * ```typescript\n * properties: {\n * get fullName(this: Model<UserSchema>) {\n * return `${this.get(\"firstName\")} ${this.get(\"lastName\")}`;\n * },\n * get isActive(this: Model<UserSchema>) {\n * return this.get(\"status\") === \"active\";\n * },\n * async sendEmail(this: Model<UserSchema>, subject: string) {\n * // this.get(), this.save(), etc. all work!\n * },\n * }\n * ```\n */\n properties?: ThisType<Model<TSchema>> & Record<string, any>;\n\n /**\n * Optional: Custom static methods.\n * Define class-level methods like custom finders or utilities.\n *\n * @example\n * ```typescript\n * statics: {\n * async findByEmail(email: string) {\n * return this.first({ email });\n * },\n * async findActive() {\n * return this.query().where(\"status\", \"active\").get();\n * },\n * }\n * ```\n */\n statics?: Record<string, any>;\n};\n\n/**\n * Define a model with a clean, concise API.\n *\n * This utility function creates a Model class with the specified configuration,\n * reducing boilerplate and providing a more declarative way to define models.\n *\n * @param options - Model configuration options\n * @returns A Model class with the specified configuration\n *\n * @example\n * ```typescript\n * import { defineModel } from \"@warlock.js/cascade\";\n * import { v } from \"@warlock.js/seal\";\n *\n * export const User = defineModel({\n * table: \"users\",\n * schema: v.object({\n * name: v.string().required().trim(),\n * email: v.string().email().required().lowercase(),\n * password: v.string().required().min(6),\n * role: v.string().default(\"user\"),\n * }),\n * deleteStrategy: \"soft\",\n * });\n *\n * // Usage\n * const user = await User.create({\n * name: \"John Doe\",\n * email: \"john@example.com\",\n * password: \"secret123\",\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With type inference\n * export const Post = defineModel({\n * table: \"posts\",\n * schema: v.object({\n * title: v.string().required(),\n * content: v.string().required(),\n * authorId: v.number().required(),\n * published: v.boolean().default(false),\n * }),\n * });\n *\n * // TypeScript knows the exact type!\n * const post = await Post.create({\n * title: \"Hello World\",\n * content: \"My first post\",\n * authorId: 1,\n * });\n *\n * console.log(post.title); // ✅ Type-safe!\n * ```\n */\nexport function defineModel<\n TSchema extends ModelSchema,\n TSchemaValidator extends ObjectValidator = ObjectValidator,\n TProperties extends Record<string, any> = {},\n TStatics extends Record<string, any> = {},\n>(\n options: DefineModelOptions<TSchema> & {\n schema: TSchemaValidator;\n properties?: ThisType<Model<Infer.Output<TSchemaValidator>>> & TProperties;\n statics?: ThisType<typeof Model<Infer.Output<TSchemaValidator>>> & TStatics;\n },\n) {\n type InferredSchema = Infer.Output<TSchemaValidator>;\n\n class DefinedModel extends Model<InferredSchema> {\n /**\n * Table/collection name\n */\n public static table = options.table;\n\n /**\n * Validation schema\n */\n public static schema = options.schema;\n\n /**\n * Delete strategy. When undefined, the runtime resolves via call options →\n * data source `defaultDeleteStrategy` → `\"permanent\"`.\n */\n public static deleteStrategy: DeleteStrategy | undefined = options.deleteStrategy;\n\n /**\n * Strict mode for unknown fields. Defaults to `\"strip\"` to match the base\n * `Model` static default.\n */\n public static strictMode: StrictMode = options.strictMode || \"strip\";\n\n /**\n * Auto-generate sequential IDs (NoSQL only). Defaults to `true` to match\n * the base `Model` static default.\n */\n public static autoGenerateId: boolean = options.autoGenerateId ?? true;\n\n /**\n * Random increment for auto-generated IDs. When undefined, falls through\n * to the data-source default.\n */\n public static randomIncrement: boolean | undefined = options.randomIncrement;\n\n /**\n * Initial ID value for the first record when auto-generating IDs. When\n * undefined, falls through to the data-source default.\n */\n public static initialId: number | undefined = options.initialId;\n }\n\n // Apply custom instance properties (getters/setters/methods)\n if (options.properties) {\n Object.defineProperties(\n DefinedModel.prototype,\n Object.getOwnPropertyDescriptors(options.properties),\n );\n }\n\n if (options.name) {\n registerModelInRegistry(options.name, DefinedModel);\n }\n\n // Apply custom static methods\n if (options.statics) {\n Object.defineProperties(DefinedModel, Object.getOwnPropertyDescriptors(options.statics));\n }\n\n // Return with proper type inference.\n //\n // The constructed type references the EXPORTED `Model` (instance + statics)\n // rather than the local `DefinedModel` class. `DefinedModel` is declared\n // inside this function, so emitting it into the public `.d.ts` would force the\n // declaration emitter to inline it as an anonymous class type — which fails\n // with TS4094 (\"anonymous class type may not be private or protected\", from\n // Model's `protected isActiveColumn`) and crashes the dts bundler on Model's\n // getters. `DefinedModel` adds no instance members over `Model<InferredSchema>`\n // and no statics beyond those already declared on `Model`, so this is a\n // faithful, emittable equivalent of the previously-inferred return type.\n type DefinedModelClass = {\n new (initialData?: Partial<InferredSchema>): Model<InferredSchema> & TProperties;\n } & Omit<typeof Model, \"new\"> &\n TStatics;\n\n return DefinedModel as unknown as DefinedModelClass;\n}\n\n/**\n * Type helper to infer the schema type from a defined model.\n *\n * @example\n * ```typescript\n * const User = defineModel({\n * table: \"users\",\n * schema: v.object({\n * name: v.string(),\n * email: v.string(),\n * }),\n * });\n *\n * type UserType = ModelType<typeof User>;\n * // { name: string; email: string; }\n * ```\n */\nexport type ModelType<T extends ReturnType<typeof defineModel>> = T extends new (\n ...args: any[]\n) => infer R\n ? R extends Model<infer S>\n ? S\n : never\n : never;\n","import type { DataSource } from \"../data-source/data-source\";\nimport { dataSourceRegistry } from \"../data-source/data-source-registry\";\n\n/**\n * Execute a callback once the driver is connected.\n *\n * If the driver is already connected, the callback is executed immediately.\n * Otherwise, it waits for the \"connected\" event.\n *\n * **Use Case:**\n * Useful for ensuring database-dependent operations only run after connection\n * is established, especially in small to medium projects with a single data source.\n *\n * @param dataSourceOrNameOrCallback - Data source instance, name, or callback function\n * @param callback - Function to execute once connected (optional if first param is callback)\n *\n * @example\n * ```typescript\n * // With default data source (just callback)\n * await connectToDatabase({ database: \"myapp\" });\n *\n * onceConnected((ds) => {\n * console.log(\"Database is ready!\");\n * console.log(\"Connected to:\", ds.name);\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With data source name\n * onceConnected(\"primary\", (ds) => {\n * console.log(\"Primary database is ready!\");\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With data source instance\n * const dataSource = await connectToDatabase({ database: \"myapp\" });\n *\n * onceConnected(dataSource, (ds) => {\n * console.log(\"Database is ready!\");\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With driver instance\n * const driver = new MongoDbDriver(config);\n * const dataSource = new DataSource({ name: \"primary\", driver });\n *\n * onceConnected(dataSource, () => {\n * // Start application server\n * app.listen(3000);\n * });\n *\n * // Connect after setting up the callback\n * await driver.connect();\n * ```\n *\n * @example\n * ```typescript\n * // Chaining operations\n * onceConnected(async (ds) => {\n * // Seed database\n * await seedDatabase();\n *\n * // Run migrations\n * await runMigrations();\n *\n * console.log(\"Database ready!\");\n * });\n * ```\n */\nexport function onceConnected(\n dataSourceOrNameOrCallback: DataSource | string | ((dataSource: DataSource) => void),\n callback?: (dataSource: DataSource) => void,\n): void {\n // Determine if first parameter is a callback\n let targetDataSource: DataSource | string;\n let actualCallback: (dataSource: DataSource) => void;\n\n if (typeof dataSourceOrNameOrCallback === \"function\") {\n // First param is callback, use default data source\n actualCallback = dataSourceOrNameOrCallback;\n targetDataSource = \"default\";\n } else {\n // First param is data source name or instance\n if (!callback) {\n throw new Error(\"Callback is required when providing a data source name or instance.\");\n }\n actualCallback = callback;\n targetDataSource = dataSourceOrNameOrCallback;\n }\n\n // Try to get the data source if it's a string\n let resolvedDataSource: DataSource | undefined;\n if (typeof targetDataSource === \"string\") {\n try {\n resolvedDataSource =\n targetDataSource === \"default\"\n ? dataSourceRegistry.get()\n : dataSourceRegistry.get(targetDataSource);\n } catch {\n // Data source not registered yet, will wait for event\n }\n } else {\n resolvedDataSource = targetDataSource;\n }\n\n // If data source is resolved and already connected, fire immediately\n if (resolvedDataSource && resolvedDataSource.driver.isConnected) {\n actualCallback(resolvedDataSource);\n return;\n }\n\n // Otherwise, wait for the connected event\n const listener = (ds: DataSource) => {\n const matches =\n typeof targetDataSource === \"string\"\n ? targetDataSource === \"default\"\n ? ds.isDefault\n : ds.name === targetDataSource\n : ds === targetDataSource;\n\n if (matches) {\n // Remove the listener once our condition is met\n dataSourceRegistry.off(\"connected\", listener);\n actualCallback(ds);\n }\n // If it doesn't match, we do nothing and just wait for the next \"connected\" event targeting our DB\n };\n\n dataSourceRegistry.on(\"connected\", listener);\n}\n\n/**\n * Execute a callback once the driver is disconnected.\n *\n * If the driver is already disconnected, the callback is executed immediately.\n * Otherwise, it waits for the \"disconnected\" event.\n *\n * **Use Case:**\n * Useful for cleanup operations, graceful shutdown, or reconnection logic.\n *\n * @param dataSourceOrNameOrCallback - Data source instance, name, or callback function\n * @param callback - Function to execute once disconnected (optional if first param is callback)\n *\n * @example\n * ```typescript\n * // With default data source (just callback)\n * await connectToDatabase({ database: \"myapp\" });\n *\n * onceDisconnected((ds) => {\n * console.log(\"Database disconnected!\");\n * console.log(\"Attempting reconnection...\");\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With data source name\n * onceDisconnected(\"primary\", (ds) => {\n * console.log(\"Primary database disconnected!\");\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With data source instance\n * const dataSource = await connectToDatabase({ database: \"myapp\" });\n *\n * onceDisconnected(dataSource, (ds) => {\n * console.log(\"Database disconnected!\");\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Graceful shutdown with default data source\n * process.on(\"SIGTERM\", async () => {\n * console.log(\"Shutting down...\");\n *\n * onceDisconnected(() => {\n * console.log(\"Database closed, exiting process\");\n * process.exit(0);\n * });\n *\n * const dataSource = DataSourceRegistry.getDefault();\n * await dataSource?.driver.disconnect();\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Cleanup resources on disconnect\n * onceDisconnected(async (ds) => {\n * // Close file handles\n * await closeFileHandles();\n *\n * // Clear caches\n * clearCaches();\n *\n * console.log(\"Cleanup complete\");\n * });\n * ```\n */\nexport function onceDisconnected(\n dataSourceOrNameOrCallback: DataSource | string | ((dataSource: DataSource) => void),\n callback?: (dataSource: DataSource) => void,\n): void {\n // Determine if first parameter is a callback\n let targetDataSource: DataSource | string;\n let actualCallback: (dataSource: DataSource) => void;\n\n if (typeof dataSourceOrNameOrCallback === \"function\") {\n // First param is callback, use default data source\n actualCallback = dataSourceOrNameOrCallback;\n targetDataSource = \"default\";\n } else {\n // First param is data source name or instance\n if (!callback) {\n throw new Error(\"Callback is required when providing a data source name or instance.\");\n }\n actualCallback = callback;\n targetDataSource = dataSourceOrNameOrCallback;\n }\n\n // Try to get the data source if it's a string\n let resolvedDataSource: DataSource | undefined;\n if (typeof targetDataSource === \"string\") {\n try {\n resolvedDataSource =\n targetDataSource === \"default\"\n ? dataSourceRegistry.get()\n : dataSourceRegistry.get(targetDataSource);\n } catch {\n // Data source not registered yet, will wait for event\n }\n } else {\n resolvedDataSource = targetDataSource;\n }\n\n // If data source is resolved and already disconnected, fire immediately\n if (resolvedDataSource && !resolvedDataSource.driver.isConnected) {\n actualCallback(resolvedDataSource);\n return;\n }\n\n // Otherwise, wait for the disconnected event\n const listener = (ds: DataSource) => {\n const matches =\n typeof targetDataSource === \"string\"\n ? targetDataSource === \"default\"\n ? ds.isDefault\n : ds.name === targetDataSource\n : ds === targetDataSource;\n\n if (matches) {\n actualCallback(ds);\n } else {\n // Not the one we're looking for, keep listening\n dataSourceRegistry.once(\"disconnected\", listener);\n }\n };\n\n dataSourceRegistry.once(\"disconnected\", listener);\n}\n","import type {\n ColumnDefinition,\n ColumnType,\n ForeignKeyDefinition,\n VectorIndexOptions,\n} from \"../contracts/migration-driver.contract\";\n\n/**\n * Reference to the Migration type to avoid circular imports.\n * The actual type is injected at runtime.\n */\ntype MigrationLike = {\n addPendingIndex(index: { columns: string[]; unique?: boolean }): void;\n addForeignKeyOperation(fk: ForeignKeyDefinition): void;\n addPendingVectorIndex?(column: string, options: Omit<VectorIndexOptions, \"column\">): void;\n};\n\n/**\n * Mutable foreign key definition being built via ColumnBuilder.\n */\ninterface MutableForeignKeyDefinition {\n name?: string;\n column: string;\n referencesTable: string;\n referencesColumn: string;\n onDelete: ForeignKeyDefinition[\"onDelete\"];\n onUpdate: ForeignKeyDefinition[\"onUpdate\"];\n}\n\n/**\n * Fluent builder for defining column properties.\n *\n * Allows chaining modifiers like `.nullable()`, `.unique()`, `.default()`.\n * Each column builder is bound to a parent migration and accumulates\n * the column definition through method chains.\n *\n * @example\n * ```typescript\n * this.string(\"email\")\n * .nullable()\n * .unique()\n * .default(\"guest@example.com\");\n * ```\n *\n * @example\n * ```typescript\n * this.integer(\"age\")\n * .unsigned()\n * .comment(\"User's age in years\");\n * ```\n */\nexport class ColumnBuilder {\n /** Mutable column definition being accumulated */\n private readonly definition: ColumnDefinition;\n\n /** Mutable foreign key definition, set when .references() is called */\n private fkDefinition?: MutableForeignKeyDefinition;\n\n /** Temporary storage for generated expression before .stored() or .virtual() is called */\n private generatedExpression?: string;\n\n /**\n * Create a new column builder.\n *\n * @param migration - Parent migration instance for index registration\n * @param name - Column name\n * @param type - Column data type\n * @param options - Optional initial configuration\n */\n public constructor(\n private readonly migration: MigrationLike,\n name: string,\n type: ColumnType,\n options: Partial<\n Pick<ColumnDefinition, \"length\" | \"precision\" | \"scale\" | \"dimensions\" | \"values\">\n > = {},\n ) {\n this.definition = {\n name,\n type,\n nullable: false,\n ...options,\n };\n }\n\n // ============================================================================\n // NULLABILITY\n // ============================================================================\n\n /**\n * Mark column as nullable (allows NULL values).\n *\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.string(\"middleName\").nullable();\n * ```\n */\n public nullable(): this {\n this.definition.nullable = true;\n return this;\n }\n\n /**\n * Mark column as not nullable (disallows NULL values).\n *\n * This is the default, but can be used for clarity.\n *\n * @returns This builder for chaining\n */\n public notNullable(): this {\n this.definition.nullable = false;\n return this;\n }\n\n // ============================================================================\n // DEFAULT VALUES\n // ============================================================================\n\n /**\n * Set default value for the column as a raw SQL expression.\n *\n * The value will be used as-is in the SQL statement without escaping.\n * Use this for database functions and expressions.\n *\n * @param value - Default value (SQL expression, number, or boolean)\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.uuid(\"id\").default(\"gen_random_uuid()\");\n * this.timestamp(\"created_at\").default(\"NOW()\");\n * this.integer(\"version\").default(1);\n * this.boolean(\"is_active\").default(true);\n * ```\n */\n public default(value: string | number | boolean): this {\n this.definition.defaultValue = value;\n this.definition.isRawDefault = true;\n return this;\n }\n\n /**\n * Set default value for the column as a literal string.\n *\n * The value will be properly escaped and quoted in the SQL statement.\n * Use this for literal string values, not SQL expressions.\n *\n * @param value - Default string value (will be escaped)\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.text(\"status\").defaultString(\"active\");\n * this.text(\"greeting\").defaultString(\"Hello, World!\");\n * ```\n */\n public defaultString(value: string): this {\n this.definition.defaultValue = value;\n this.definition.isRawDefault = false;\n return this;\n }\n\n /**\n * Set default value to the current timestamp.\n *\n * Database-agnostic. Generates NOW() / CURRENT_TIMESTAMP / GETDATE() based on driver.\n *\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.timestamp(\"created_at\").useCurrent();\n * ```\n */\n public useCurrent(): this {\n this.definition.defaultValue = { __type: \"CURRENT_TIMESTAMP\" };\n return this;\n }\n\n /**\n * Set column to update to current timestamp on row update.\n *\n * MySQL only. Other databases ignore this.\n *\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.timestamp(\"updated_at\").useCurrent().useCurrentOnUpdate();\n * ```\n */\n public useCurrentOnUpdate(): this {\n this.definition.onUpdateCurrent = true;\n return this;\n }\n\n // ============================================================================\n // INDEXES\n // ============================================================================\n\n /**\n * Add unique constraint/index on this column.\n *\n * Registers a pending unique index with the parent migration.\n *\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.string(\"email\").unique();\n * ```\n */\n public unique(): this {\n this.migration.addPendingIndex({\n columns: [this.definition.name],\n unique: true,\n });\n return this;\n }\n\n /**\n * Add regular index on this column.\n *\n * Registers a pending index with the parent migration.\n *\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.string(\"email\").index();\n * ```\n */\n public index(): this {\n this.migration.addPendingIndex({\n columns: [this.definition.name],\n });\n return this;\n }\n\n /**\n * Add a vector search index on this column.\n *\n * Registers a pending vector index with the parent migration.\n *\n * @param options - Vector index options\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.vector(1536).vectorIndex({ similarity: \"cosine\" });\n * ```\n */\n public vectorIndex(options: Omit<VectorIndexOptions, \"dimensions\"> = {}): this {\n if (this.migration.addPendingVectorIndex) {\n this.migration.addPendingVectorIndex(this.definition.name, {\n ...options,\n dimensions: this.definition.dimensions || 0,\n });\n }\n return this;\n }\n\n // ============================================================================\n // PRIMARY KEY & AUTO INCREMENT\n // ============================================================================\n\n /**\n * Mark as primary key.\n *\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.integer(\"id\").primary();\n * ```\n */\n public primary(): this {\n this.definition.primary = true;\n return this;\n }\n\n /**\n * Mark as auto-increment (numeric types only).\n *\n * SQL databases will use native AUTO_INCREMENT/SERIAL.\n * NoSQL databases ignore this.\n *\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.integer(\"id\").primary().autoIncrement();\n * ```\n */\n public autoIncrement(): this {\n this.definition.autoIncrement = true;\n return this;\n }\n\n // ============================================================================\n // NUMERIC MODIFIERS\n // ============================================================================\n\n /**\n * Mark as unsigned (numeric types only).\n *\n * Disallows negative values and doubles the positive range.\n *\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.integer(\"age\").unsigned();\n * ```\n */\n public unsigned(): this {\n this.definition.unsigned = true;\n return this;\n }\n\n // ============================================================================\n // METADATA\n // ============================================================================\n\n /**\n * Add comment/description to column.\n *\n * Stored as column metadata in the database.\n *\n * @param text - Comment text\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.string(\"sku\").comment(\"Stock Keeping Unit code\");\n * ```\n */\n public comment(text: string): this {\n this.definition.comment = text;\n return this;\n }\n\n // ============================================================================\n // CONSTRAINTS\n // ============================================================================\n\n /**\n * Add a CHECK constraint scoped to this column.\n *\n * @param expression - SQL CHECK expression (can reference the column by name)\n * @param name - Constraint name (defaults to `check_<column>`)\n * @returns This builder for chaining\n */\n public check(expression: string, name?: string): this {\n this.definition.checkConstraint = {\n expression,\n name: name ?? `check_${this.definition.name}`,\n };\n return this;\n }\n\n // ============================================================================\n // COLUMN POSITIONING (MySQL/MariaDB only)\n // ============================================================================\n\n /**\n * Position this column after another column.\n *\n * MySQL/MariaDB only. Ignored by PostgreSQL and NoSQL drivers.\n *\n * @param columnName - Column to position after\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.string(\"middle_name\").after(\"first_name\");\n * ```\n */\n public after(columnName: string): this {\n this.definition.after = columnName;\n return this;\n }\n\n /**\n * Position this column as the first column in the table.\n *\n * MySQL/MariaDB only. Ignored by PostgreSQL and NoSQL drivers.\n *\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.integer(\"id\").primary().first();\n * ```\n */\n public first(): this {\n this.definition.first = true;\n return this;\n }\n\n // ============================================================================\n // FOREIGN KEY\n // ============================================================================\n\n /**\n * Declare a foreign key constraint on this column.\n *\n * Accepts either a raw table-name string or a Model class (anything with a\n * static `table` property). Using a Model class is preferred — it is\n * type-safe and automatically tracks table renames.\n *\n * Pushes an `addForeignKey` operation immediately using a mutable reference —\n * subsequent `.on()`, `.onDelete()`, `.onUpdate()` calls mutate the same\n * definition that is already queued, so no `.add()` terminator is needed.\n *\n * Referenced column defaults to `\"id\"` — use `.on()` to override.\n *\n * @param tableOrModel - Referenced table name OR a Model class with a static `table` property\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * // Preferred — model class reference (type-safe, rename-proof)\n * this.uuid(\"organization_id\").references(Organization).onDelete(\"cascade\");\n *\n * // Also supported — raw table string\n * this.uuid(\"organization_id\").references(\"organizations\").onDelete(\"cascade\");\n * this.uuid(\"organization_id\").references(Organization.table).onDelete(\"cascade\");\n * ```\n */\n public references(tableOrModel: string | { table: string }): this {\n const tableName = typeof tableOrModel === \"string\" ? tableOrModel : tableOrModel.table;\n\n this.fkDefinition = {\n column: this.definition.name,\n referencesTable: tableName,\n referencesColumn: \"id\",\n onDelete: \"restrict\",\n onUpdate: \"restrict\",\n };\n this.migration.addForeignKeyOperation(this.fkDefinition as ForeignKeyDefinition);\n return this;\n }\n\n /**\n * Set the referenced column for the foreign key.\n *\n * Only meaningful after `.references()`. Defaults to `\"id\"` if omitted.\n *\n * @param column - Referenced column name\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.integer(\"user_id\").references(\"users\").on(\"custom_id\");\n * ```\n */\n public on(column: string): this {\n if (this.fkDefinition) {\n this.fkDefinition.referencesColumn = column;\n }\n return this;\n }\n\n /**\n * Set the ON DELETE action for the foreign key.\n *\n * Only meaningful after `.references()`.\n *\n * @param action - Action when the referenced row is deleted\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.integer(\"user_id\").references(\"users\").onDelete(\"cascade\");\n * ```\n */\n public onDelete(action: ForeignKeyDefinition[\"onDelete\"]): this {\n if (this.fkDefinition) {\n this.fkDefinition.onDelete = action;\n }\n return this;\n }\n\n /**\n * Set the ON UPDATE action for the foreign key.\n *\n * Only meaningful after `.references()`.\n *\n * @param action - Action when the referenced row's key is updated\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.integer(\"user_id\").references(\"users\").onUpdate(\"cascade\");\n * ```\n */\n public onUpdate(action: ForeignKeyDefinition[\"onUpdate\"]): this {\n if (this.fkDefinition) {\n this.fkDefinition.onUpdate = action;\n }\n return this;\n }\n\n /**\n * Shorthand for `.onDelete(\"cascade\").onUpdate(\"cascade\")`.\n *\n * Only meaningful after `.references()`.\n *\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.integer(\"user_id\").references(\"users\").cascadeAll();\n * ```\n */\n public cascadeAll(): this {\n if (this.fkDefinition) {\n this.fkDefinition.onDelete = \"cascade\";\n this.fkDefinition.onUpdate = \"cascade\";\n }\n return this;\n }\n\n // ============================================================================\n // COLUMN MODIFICATION\n // ============================================================================\n\n /**\n * Mark this column definition as a modification of an existing column.\n *\n * Pushes a `modifyColumn` operation instead of `addColumn`.\n * This method breaks the builder chain and returns the parent migration.\n *\n * @returns The parent migration instance (breaks builder chain)\n *\n * @example\n * ```typescript\n * // Make email nullable\n * this.string(\"email\").nullable().change();\n *\n * // Increase length\n * this.string(\"name\", 255).change();\n *\n * // Change type\n * this.text(\"description\").change();\n * ```\n */\n public change(): unknown {\n const operations = (this.migration as any).pendingOperations;\n\n // Remove the addColumn pushed by the column type method (e.g. uuid(), string())\n const lastOp = operations[operations.length - 1];\n if (lastOp?.type === \"addColumn\" && lastOp.payload === this.definition) {\n operations.pop();\n }\n\n // If .references() was called before .change(), the addForeignKey op is now\n // last in the queue. We must pop it, push modifyColumn first, then re-push\n // the FK — because SQL requires: ALTER COLUMN (type change) → ADD CONSTRAINT (FK).\n let pendingFkOp: (typeof operations)[number] | undefined;\n if (this.fkDefinition) {\n const tail = operations[operations.length - 1];\n if (tail?.type === \"addForeignKey\" && tail.payload === this.fkDefinition) {\n pendingFkOp = operations.pop();\n }\n }\n\n // Push modifyColumn — it must precede the FK constraint\n operations.push({ type: \"modifyColumn\", payload: this.definition });\n\n // Re-queue the FK after the column modification\n if (pendingFkOp) {\n operations.push(pendingFkOp);\n }\n\n return this.migration;\n }\n\n /**\n * @alias change\n */\n public modify(): unknown {\n return this.change();\n }\n\n // ============================================================================\n // GENERATED COLUMNS\n // ============================================================================\n\n /**\n * Mark this column as a generated column with the given SQL expression.\n *\n * Must be followed by `.stored()` or `.virtual()` to specify storage type.\n *\n * PostgreSQL: GENERATED ALWAYS AS (...) STORED\n * MySQL: GENERATED ALWAYS AS (...) STORED | VIRTUAL\n *\n * @param expression - SQL expression to compute the value\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.string(\"full_name\")\n * .generatedAs(\"CONCAT(first_name, ' ', last_name)\")\n * .stored();\n *\n * this.decimal(\"price_with_tax\")\n * .generatedAs(\"price * 1.2\")\n * .virtual();\n * ```\n */\n public generatedAs(expression: string): this {\n this.generatedExpression = expression;\n return this;\n }\n\n /**\n * Mark the generated column as stored (computed and persisted to disk).\n *\n * Must be called after `.generatedAs()`.\n *\n * @returns This builder for chaining\n */\n public stored(): this {\n if (this.generatedExpression) {\n this.definition.generated = {\n expression: this.generatedExpression,\n stored: true,\n };\n }\n return this;\n }\n\n /**\n * Mark the generated column as virtual (computed on read, not stored).\n *\n * Must be called after `.generatedAs()`. Not supported by PostgreSQL.\n *\n * @returns This builder for chaining\n */\n public virtual(): this {\n if (this.generatedExpression) {\n this.definition.generated = {\n expression: this.generatedExpression,\n stored: false,\n };\n }\n return this;\n }\n\n // ============================================================================\n // ACCESSOR\n // ============================================================================\n\n /**\n * Get the built column definition.\n *\n * Called internally by the Migration class to extract the final definition.\n *\n * @returns The accumulated column definition\n */\n public getDefinition(): ColumnDefinition {\n return this.definition;\n }\n}\n","import type { ForeignKeyDefinition } from \"../contracts/migration-driver.contract\";\n\n/**\n * Reference to the Migration type to avoid circular imports.\n */\ntype MigrationLike = {\n addForeignKeyOperation(fk: ForeignKeyDefinition): void;\n};\n\n/**\n * Mutable foreign key definition being built.\n */\ninterface MutableForeignKeyDefinition {\n name?: string;\n column: string;\n referencesTable: string;\n referencesColumn: string;\n onDelete: ForeignKeyDefinition[\"onDelete\"];\n onUpdate: ForeignKeyDefinition[\"onUpdate\"];\n}\n\n/**\n * Fluent builder for foreign key constraints.\n *\n * Allows building foreign key definitions with a chainable API.\n * SQL-only feature; NoSQL drivers ignore foreign keys.\n *\n * The operation is pushed when `.references()` is called using a mutable\n * reference — subsequent `.onDelete()` / `.onUpdate()` calls mutate the\n * same definition already queued in pendingOperations.\n *\n * @example\n * ```typescript\n * this.foreign(\"user_id\")\n * .references(\"users\", \"id\")\n * .onDelete(\"cascade\")\n * .onUpdate(\"cascade\");\n * ```\n */\nexport class ForeignKeyBuilder {\n /** Mutable foreign key definition being accumulated */\n private readonly definition: MutableForeignKeyDefinition;\n\n /**\n * Create a new foreign key builder.\n *\n * @param migration - Parent migration instance\n * @param column - Local column name that will reference another table\n */\n public constructor(\n private readonly migration: MigrationLike,\n column: string,\n ) {\n this.definition = {\n column,\n referencesTable: \"\",\n referencesColumn: \"id\",\n onDelete: \"restrict\",\n onUpdate: \"restrict\",\n };\n }\n\n /**\n * Set the constraint name.\n *\n * @param name - Constraint name (auto-generated if not provided)\n * @returns This builder for chaining\n */\n public name(name: string): this {\n this.definition.name = name;\n return this;\n }\n\n /**\n * Set the referenced table and column, and register the foreign key operation.\n *\n * Pushes the operation immediately using a mutable reference — any\n * `.onDelete()` / `.onUpdate()` calls after this will mutate the same\n * definition already queued in pendingOperations.\n *\n * @param table - Referenced table name\n * @param column - Referenced column name (default: \"id\")\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.foreign(\"user_id\").references(\"users\", \"id\");\n * this.foreign(\"category_id\").references(\"categories\"); // defaults to \"id\"\n * ```\n */\n public references(table: string, column = \"id\"): this {\n this.definition.referencesTable = table;\n this.definition.referencesColumn = column;\n this.migration.addForeignKeyOperation(this.definition as ForeignKeyDefinition);\n return this;\n }\n\n /**\n * Set the ON DELETE action.\n *\n * @param action - Action to take when referenced row is deleted\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.foreign(\"user_id\")\n * .references(\"users\")\n * .onDelete(\"cascade\"); // Delete child when parent is deleted\n * ```\n */\n public onDelete(action: ForeignKeyDefinition[\"onDelete\"]): this {\n this.definition.onDelete = action;\n return this;\n }\n\n /**\n * Set the ON UPDATE action.\n *\n * @param action - Action to take when referenced row's key is updated\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.foreign(\"user_id\")\n * .references(\"users\")\n * .onUpdate(\"cascade\"); // Update child when parent key changes\n * ```\n */\n public onUpdate(action: ForeignKeyDefinition[\"onUpdate\"]): this {\n this.definition.onUpdate = action;\n return this;\n }\n\n /**\n * Shorthand for `.onDelete(\"cascade\").onUpdate(\"cascade\")`.\n *\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * this.foreign(\"user_id\").references(\"users\").cascadeAll();\n * ```\n */\n public cascadeAll(): this {\n this.definition.onDelete = \"cascade\";\n this.definition.onUpdate = \"cascade\";\n return this;\n }\n\n}\n","import { ColumnBuilder } from \"./column-builder\";\n\n/**\n * A no-op migration sink used by standalone column helpers.\n *\n * When column helpers are used in `Migration.create()` / `Migration.alter()`,\n * the builder is constructed without a real migration context. The actual\n * operations are dequeued from the ColumnBuilder's definition and replayed\n * onto the real migration instance at execution time.\n *\n * Index and FK operations queued on this sink are collected and transferred\n * to the real migration by the factory methods.\n */\nclass DetachedMigrationSink {\n /** Pending indexes registered via .unique() / .index() on a helper column. */\n public readonly pendingIndexes: { columns: string[]; unique?: boolean }[] = [];\n\n /** Pending FK definitions registered via .references() on a helper column. */\n public readonly pendingForeignKeys: object[] = [];\n\n /** Pending Vector index definitions registered via .vectorIndex() on a helper column. */\n public readonly pendingVectorIndexes: {\n column: string;\n options: import(\"../contracts/migration-driver.contract\").VectorIndexOptions;\n }[] = [];\n\n public addPendingIndex(index: { columns: string[]; unique?: boolean }): void {\n this.pendingIndexes.push(index);\n }\n\n public addForeignKeyOperation(fk: object): void {\n this.pendingForeignKeys.push(fk);\n }\n\n public addPendingVectorIndex(\n column: string,\n options: Omit<import(\"../contracts/migration-driver.contract\").VectorIndexOptions, \"column\">,\n ): void {\n this.pendingVectorIndexes.push({ column, options: options as any });\n }\n}\n\n/**\n * A `ColumnBuilder` that carries its own detached sink so it can be\n * constructed outside of a migration class and later merged in.\n */\nexport class DetachedColumnBuilder extends ColumnBuilder {\n public readonly sink: DetachedMigrationSink;\n\n public constructor(\n type: ConstructorParameters<typeof ColumnBuilder>[2],\n name: string,\n options: ConstructorParameters<typeof ColumnBuilder>[3] = {},\n ) {\n const sink = new DetachedMigrationSink();\n super(sink as any, name, type, options);\n this.sink = sink;\n }\n}\n\n// ============================================================================\n// STRING HELPERS\n// ============================================================================\n\n/**\n * Standalone column helper: string / varchar.\n *\n * @example\n * ```typescript\n * import { Migration, string } from \"@warlock.js/cascade\";\n *\n * export default Migration.create(User, {\n * username: string(50).unique(),\n * });\n * ```\n */\nexport function string(length = 255): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"string\", \"__placeholder__\", { length });\n}\n\n/**\n * Standalone column helper: fixed-length CHAR.\n *\n * @example\n * ```typescript\n * code: char(3) // CHAR(3)\n * ```\n */\nexport function char(length: number): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"char\", \"__placeholder__\", { length });\n}\n\n/**\n * Standalone column helper: TEXT (unlimited length).\n *\n * @example\n * ```typescript\n * import { Migration, text } from \"@warlock.js/cascade\";\n *\n * export default Migration.create(User, {\n * bio: text().nullable(),\n * });\n * ```\n */\nexport function text(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"text\", \"__placeholder__\");\n}\n\n/**\n * Standalone column helper: MEDIUMTEXT.\n */\nexport function mediumText(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"mediumText\", \"__placeholder__\");\n}\n\n/**\n * Standalone column helper: LONGTEXT.\n */\nexport function longText(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"longText\", \"__placeholder__\");\n}\n\n// ============================================================================\n// NUMERIC HELPERS\n// ============================================================================\n\n/**\n * Standalone column helper: INTEGER.\n *\n * @example\n * ```typescript\n * age: integer().unsigned()\n * ```\n */\nexport function integer(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"integer\", \"__placeholder__\");\n}\n\n/** Alias for `integer()`. */\nexport const int = integer;\n\n/**\n * Standalone column helper: SMALLINT.\n */\nexport function smallInteger(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"smallInteger\", \"__placeholder__\");\n}\n\n/** Alias for `smallInteger()`. */\nexport const smallInt = smallInteger;\n\n/**\n * Standalone column helper: TINYINT.\n */\nexport function tinyInteger(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"tinyInteger\", \"__placeholder__\");\n}\n\n/** Alias for `tinyInteger()`. */\nexport const tinyInt = tinyInteger;\n\n/**\n * Standalone column helper: BIGINT.\n */\nexport function bigInteger(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"bigInteger\", \"__placeholder__\");\n}\n\n/** Alias for `bigInteger()`. */\nexport const bigInt = bigInteger;\n\n/**\n * Standalone column helper: FLOAT.\n */\nexport function float(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"float\", \"__placeholder__\");\n}\n\n/**\n * Standalone column helper: DOUBLE.\n */\nexport function double(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"double\", \"__placeholder__\");\n}\n\n/**\n * Standalone column helper: DECIMAL.\n *\n * @example\n * ```typescript\n * price: decimal(10, 2) // DECIMAL(10,2)\n * ```\n */\nexport function decimal(precision = 8, scale = 2): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"decimal\", \"__placeholder__\", { precision, scale });\n}\n\n// ============================================================================\n// BOOLEAN HELPERS\n// ============================================================================\n\n/**\n * Standalone column helper: BOOLEAN.\n *\n * Named `boolCol` to avoid collision with the TypeScript / JS `boolean` primitive.\n *\n * @example\n * ```typescript\n * is_active: boolCol().default(true)\n * ```\n */\nexport function boolCol(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"boolean\", \"__placeholder__\");\n}\n\n/** Alias for `boolCol()`. */\nexport { boolCol as bool };\n\n// ============================================================================\n// DATE / TIME HELPERS\n// ============================================================================\n\n/**\n * Standalone column helper: DATE.\n */\nexport function date(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"date\", \"__placeholder__\");\n}\n\n/**\n * Standalone column helper: DATETIME.\n */\nexport function dateTime(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"dateTime\", \"__placeholder__\");\n}\n\n/**\n * Standalone column helper: TIMESTAMP.\n *\n * @example\n * ```typescript\n * started_at: timestamp().default(\"NOW()\")\n * ```\n */\nexport function timestamp(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"timestamp\", \"__placeholder__\");\n}\n\n/**\n * Standalone column helper: TIME.\n */\nexport function time(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"time\", \"__placeholder__\");\n}\n\n/**\n * Standalone column helper: YEAR.\n */\nexport function year(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"year\", \"__placeholder__\");\n}\n\n// ============================================================================\n// JSON & BINARY HELPERS\n// ============================================================================\n\n/**\n * Standalone column helper: JSON.\n *\n * Named `jsonCol` to avoid collision with the TS/JSON built-in names.\n * Use `json()` is fine for most cases though — this alias exists for clarity.\n *\n * @example\n * ```typescript\n * metadata: json().nullable()\n * ```\n */\nexport function json(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"json\", \"__placeholder__\");\n}\n\n/**\n * Alias for `json()`. Named `objectCol` to avoid collision with TS `object` type.\n */\nexport function objectCol(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"json\", \"__placeholder__\");\n}\n\n/**\n * Standalone column helper: BINARY / BLOB.\n */\nexport function binary(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"binary\", \"__placeholder__\");\n}\n\n/**\n * Alias for `binary()`. Named `blobCol` to avoid collision with the Web `Blob` API.\n */\nexport function blobCol(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"binary\", \"__placeholder__\");\n}\n\n// ============================================================================\n// IDENTIFIER HELPERS\n// ============================================================================\n\n/**\n * Standalone column helper: UUID.\n *\n * @example\n * ```typescript\n * import { Migration, uuid } from \"@warlock.js/cascade\";\n *\n * export default Migration.create(Chat, {\n * organization_id: uuid().references(Organization).onDelete(\"cascade\"),\n * });\n * ```\n */\nexport function uuid(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"uuid\", \"__placeholder__\");\n}\n\n/**\n * Standalone column helper: ULID.\n */\nexport function ulid(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"ulid\", \"__placeholder__\");\n}\n\n// ============================================================================\n// NETWORK HELPERS\n// ============================================================================\n\n/**\n * Standalone column helper: IP address.\n */\nexport function ipAddress(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"ipAddress\", \"__placeholder__\");\n}\n\n/**\n * Standalone column helper: MAC address.\n */\nexport function macAddress(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"macAddress\", \"__placeholder__\");\n}\n\n// ============================================================================\n// SPATIAL HELPERS\n// ============================================================================\n\n/**\n * Standalone column helper: geo point.\n */\nexport function point(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"point\", \"__placeholder__\");\n}\n\n/**\n * Standalone column helper: polygon.\n */\nexport function polygon(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"polygon\", \"__placeholder__\");\n}\n\n/**\n * Standalone column helper: line string.\n */\nexport function lineString(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"lineString\", \"__placeholder__\");\n}\n\n/**\n * Standalone column helper: generic geometry.\n */\nexport function geometry(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"geometry\", \"__placeholder__\");\n}\n\n// ============================================================================\n// AI / ML HELPERS\n// ============================================================================\n\n/**\n * Standalone column helper: vector (for AI embeddings).\n *\n * @param dimensions - Embedding size (e.g. 1536 for text-embedding-3-small)\n *\n * @example\n * ```typescript\n * embedding: vector(1536)\n * ```\n */\nexport function vector(dimensions: number): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"vector\", \"__placeholder__\", { dimensions });\n}\n\n// ============================================================================\n// ENUM & SET HELPERS\n// ============================================================================\n\n/**\n * Standalone column helper: ENUM.\n *\n * @example\n * ```typescript\n * status: enumCol([\"active\", \"inactive\", \"pending\"])\n * ```\n */\nexport function enumCol(values: string[]): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"enum\", \"__placeholder__\", { values });\n}\n\n/**\n * Standalone column helper: SET (multiple values).\n */\nexport function setCol(values: string[]): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"set\", \"__placeholder__\", { values });\n}\n\n// ============================================================================\n// POSTGRESQL ARRAY HELPERS\n// ============================================================================\n\n/** Standalone helper: INTEGER[] */\nexport function arrayInt(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"arrayInt\", \"__placeholder__\");\n}\n\n/** Standalone helper: BIGINT[] */\nexport function arrayBigInt(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"arrayBigInt\", \"__placeholder__\");\n}\n\n/** Standalone helper: REAL[] */\nexport function arrayFloat(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"arrayFloat\", \"__placeholder__\");\n}\n\n/** Standalone helper: DECIMAL[] */\nexport function arrayDecimal(precision?: number, scale?: number): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"arrayDecimal\", \"__placeholder__\", { precision, scale });\n}\n\n/** Standalone helper: BOOLEAN[] */\nexport function arrayBoolean(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"arrayBoolean\", \"__placeholder__\");\n}\n\n/** Standalone helper: TEXT[] */\nexport function arrayText(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"arrayText\", \"__placeholder__\");\n}\n\n/** Standalone helper: DATE[] */\nexport function arrayDate(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"arrayDate\", \"__placeholder__\");\n}\n\n/** Standalone helper: TIMESTAMPTZ[] */\nexport function arrayTimestamp(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"arrayTimestamp\", \"__placeholder__\");\n}\n\n/** Standalone helper: UUID[] */\nexport function arrayUuid(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"arrayUuid\", \"__placeholder__\");\n}\n\n/** Standalone helper: JSONB[] */\nexport function arrayJson(): DetachedColumnBuilder {\n return new DetachedColumnBuilder(\"arrayJson\", \"__placeholder__\");\n}\n","import type {\r\n ColumnDefinition,\r\n ForeignKeyDefinition,\r\n FullTextIndexOptions,\r\n GeoIndexOptions,\r\n IndexDefinition,\r\n MigrationDriverContract,\r\n TableIndexInformation,\r\n VectorIndexOptions,\r\n} from \"../contracts/migration-driver.contract\";\r\nimport type { DataSource } from \"../data-source/data-source\";\r\nimport type { ChildModel, Model } from \"../model/model\";\r\nimport type { MigrationDefaults } from \"../types\";\r\nimport { DatabaseDriver } from \"../utils/connect-to-database\";\r\nimport { ColumnBuilder } from \"./column-builder\";\r\nimport { ForeignKeyBuilder } from \"./foreign-key-builder\";\r\n\r\n/**\r\n * Pending operation types supported by migrations.\r\n */\r\nexport type OperationType =\r\n | \"addColumn\"\r\n | \"dropColumn\"\r\n | \"dropColumns\"\r\n | \"renameColumn\"\r\n | \"modifyColumn\"\r\n | \"createIndex\"\r\n | \"dropIndex\"\r\n | \"createUniqueIndex\"\r\n | \"dropUniqueIndex\"\r\n | \"createFullTextIndex\"\r\n | \"dropFullTextIndex\"\r\n | \"createGeoIndex\"\r\n | \"dropGeoIndex\"\r\n | \"createVectorIndex\"\r\n | \"dropVectorIndex\"\r\n | \"createTTLIndex\"\r\n | \"dropTTLIndex\"\r\n | \"addForeignKey\"\r\n | \"dropForeignKey\"\r\n | \"addPrimaryKey\"\r\n | \"dropPrimaryKey\"\r\n | \"addCheck\"\r\n | \"dropCheck\"\r\n | \"createTable\"\r\n | \"createTableIfNotExists\"\r\n | \"dropTable\"\r\n | \"dropTableIfExists\"\r\n | \"renameTable\"\r\n | \"truncateTable\"\r\n | \"createTimestamps\"\r\n | \"rawStatement\"\r\n | \"setSchemaValidation\"\r\n | \"removeSchemaValidation\";\r\n\r\n/**\r\n * Pending operation to be executed when migration runs.\r\n */\r\nexport type PendingOperation = {\r\n readonly type: OperationType;\r\n readonly payload: unknown;\r\n};\r\n\r\n/**\r\n * Contract for a migration class.\r\n */\r\nexport interface MigrationContract {\r\n /**\r\n * Table/collection name for this migration.\r\n */\r\n readonly table: string;\r\n\r\n /**\r\n * Optional data source override.\r\n */\r\n readonly dataSource?: string | DataSource;\r\n\r\n /**\r\n * Whether to wrap migration in a transaction.\r\n */\r\n readonly transactional?: boolean;\r\n\r\n /**\r\n * Define schema changes for the up migration.\r\n */\r\n up(): void | Promise<void>;\r\n\r\n /**\r\n * Define rollback operations for the down migration.\r\n */\r\n down(): void | Promise<void>;\r\n\r\n /**\r\n * Set the migration driver.\r\n *\r\n * @param driver - Migration driver instance\r\n * @internal\r\n */\r\n setDriver(driver: MigrationDriverContract): void;\r\n\r\n /**\r\n * Set migration defaults from the resolved DataSource.\r\n *\r\n * @param defaults - Migration defaults (UUID strategy, etc.)\r\n * @internal\r\n */\r\n setMigrationDefaults(defaults?: MigrationDefaults): void;\r\n\r\n /**\r\n * Get the migration driver.\r\n *\r\n * @returns The migration driver instance\r\n */\r\n getDriver(): MigrationDriverContract;\r\n\r\n /**\r\n * Execute all pending operations.\r\n *\r\n * @internal\r\n */\r\n execute(): Promise<void>;\r\n\r\n /**\r\n * Add a pending index definition.\r\n *\r\n * @param index - Index definition\r\n * @internal\r\n */\r\n addPendingIndex(index: IndexDefinition): void;\r\n\r\n /**\r\n * Add a foreign key operation.\r\n *\r\n * @param fk - Foreign key definition\r\n * @internal\r\n */\r\n addForeignKeyOperation(fk: ForeignKeyDefinition): void;\r\n\r\n /**\r\n * Create the table/collection.\r\n */\r\n createTable(): MigrationContract;\r\n\r\n /**\r\n * Create table if not exists\r\n */\r\n createTableIfNotExists(): MigrationContract;\r\n\r\n /**\r\n * Drop the table/collection.\r\n */\r\n dropTable(): MigrationContract;\r\n\r\n /**\r\n * Drop the table/collection if it exists.\r\n */\r\n dropTableIfExists(): MigrationContract;\r\n\r\n /**\r\n * Rename the table/collection.\r\n *\r\n * @param newName - New table name\r\n */\r\n renameTableTo(newName: string): MigrationContract;\r\n\r\n /**\r\n * Truncate the table — remove all rows without logging or firing triggers.\r\n */\r\n truncateTable(): MigrationContract;\r\n\r\n /**\r\n * Add a string/varchar column.\r\n */\r\n string(column: string, length?: number): ColumnBuilder;\r\n\r\n /**\r\n * Add a fixed-length char column.\r\n */\r\n char(column: string, length: number): ColumnBuilder;\r\n\r\n /**\r\n * Add a text column (unlimited length).\r\n */\r\n text(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a medium text column.\r\n */\r\n mediumText(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a long text column.\r\n */\r\n longText(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add an integer column.\r\n */\r\n integer(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Alias for integer().\r\n */\r\n int(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a small integer column.\r\n */\r\n smallInteger(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Alias for smallInteger().\r\n */\r\n smallInt(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a tiny integer column.\r\n */\r\n tinyInteger(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Alias for tinyInteger().\r\n */\r\n tinyInt(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a big integer column.\r\n */\r\n bigInteger(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Alias for bigInteger().\r\n */\r\n bigInt(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a float column.\r\n */\r\n float(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a double precision column.\r\n */\r\n double(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a decimal column with precision and scale.\r\n */\r\n decimal(column: string, precision?: number, scale?: number): ColumnBuilder;\r\n\r\n /**\r\n * Add a boolean column.\r\n */\r\n boolean(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Alias for boolean().\r\n */\r\n bool(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a date column (date only, no time).\r\n */\r\n date(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a datetime column (date and time).\r\n */\r\n dateTime(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a timestamp column.\r\n */\r\n timestamp(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a time column (time only, no date).\r\n */\r\n time(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a year column.\r\n */\r\n year(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a JSON column.\r\n */\r\n json(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Alias for json().\r\n */\r\n object(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a binary/blob column.\r\n */\r\n binary(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Alias for binary().\r\n */\r\n blob(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a UUID column.\r\n */\r\n uuid(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a ULID column.\r\n */\r\n ulid(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add an IP address column.\r\n */\r\n ipAddress(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a MAC address column.\r\n */\r\n macAddress(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a geo point column.\r\n */\r\n point(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a polygon column.\r\n */\r\n polygon(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a line string column.\r\n */\r\n lineString(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a generic geometry column.\r\n */\r\n geometry(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add an enum column with allowed values.\r\n */\r\n enum(column: string, values: string[]): ColumnBuilder;\r\n\r\n /**\r\n * Add a set column (multiple values from a set).\r\n */\r\n set(column: string, values: string[]): ColumnBuilder;\r\n\r\n // ── PostgreSQL array types ──────────────────────────────────────────────────\r\n\r\n /** INTEGER[] — array of integers. */\r\n arrayInt(column: string): ColumnBuilder;\r\n\r\n /** BIGINT[] — array of big integers. */\r\n arrayBigInt(column: string): ColumnBuilder;\r\n\r\n /** REAL[] — array of floats. */\r\n arrayFloat(column: string): ColumnBuilder;\r\n\r\n /** DECIMAL[] — array of decimals (optional precision/scale). */\r\n arrayDecimal(column: string, precision?: number, scale?: number): ColumnBuilder;\r\n\r\n /** BOOLEAN[] — array of booleans. */\r\n arrayBoolean(column: string): ColumnBuilder;\r\n\r\n /** TEXT[] — array of text values. */\r\n arrayText(column: string): ColumnBuilder;\r\n\r\n /** DATE[] — array of dates. */\r\n arrayDate(column: string): ColumnBuilder;\r\n\r\n /** TIMESTAMPTZ[] — array of timestamps with time zone. */\r\n arrayTimestamp(column: string): ColumnBuilder;\r\n\r\n /** UUID[] — array of UUIDs. */\r\n arrayUuid(column: string): ColumnBuilder;\r\n\r\n /** JSONB[] — array of JSON objects. */\r\n arrayJson(column: string): ColumnBuilder;\r\n\r\n /**\r\n * Add an auto-increment primary key column.\r\n */\r\n id(name?: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a big integer auto-increment primary key column.\r\n */\r\n bigId(name?: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a UUID primary key column.\r\n */\r\n uuidId(name?: string): ColumnBuilder;\r\n\r\n /**\r\n * Add a UUID primary key column with automatic generation.\r\n *\r\n * PostgreSQL: Uses gen_random_uuid() (built-in since PG 13)\r\n * MongoDB: Application-level UUID generation\r\n *\r\n * @param name - Column name (default: \"id\")\r\n * @returns Column builder for chaining modifiers\r\n *\r\n * @example\r\n * ```typescript\r\n * this.primaryUuid(); // id UUID PRIMARY KEY DEFAULT gen_random_uuid()\r\n * this.primaryUuid(\"organization_id\"); // Custom column name\r\n * ```\r\n */\r\n primaryUuid(name?: string): ColumnBuilder;\r\n\r\n /**\r\n * Add createdAt and updatedAt timestamp columns.\r\n */\r\n timestamps(): MigrationContract;\r\n\r\n /**\r\n * Add a deletedAt column for soft deletes.\r\n */\r\n softDeletes(column?: string): ColumnBuilder;\r\n\r\n /**\r\n * Drop a column.\r\n */\r\n dropColumn(column: string): MigrationContract;\r\n\r\n /**\r\n * Drop multiple columns.\r\n */\r\n dropColumns(...columns: string[]): MigrationContract;\r\n\r\n /**\r\n * Rename a column.\r\n */\r\n renameColumn(from: string, to: string): MigrationContract;\r\n\r\n /**\r\n * Create an index on one or more columns.\r\n *\r\n * @param columns - Column(s) to index\r\n * @param name - Optional index name\r\n * @param options - Optional index options (include, concurrently)\r\n */\r\n index(\r\n columns: string | string[],\r\n name?: string,\r\n options?: { include?: string[]; concurrently?: boolean },\r\n ): MigrationContract;\r\n\r\n /**\r\n * Drop an index by name or columns.\r\n */\r\n dropIndex(nameOrColumns: string | string[]): MigrationContract;\r\n\r\n /**\r\n * Create a unique constraint/index.\r\n *\r\n * @param columns - Column(s) to make unique\r\n * @param name - Optional constraint name\r\n * @param options - Optional index options (include, concurrently)\r\n */\r\n unique(\r\n columns: string | string[],\r\n name?: string,\r\n options?: { include?: string[]; concurrently?: boolean },\r\n ): MigrationContract;\r\n\r\n /**\r\n * Drop a unique constraint/index.\r\n */\r\n dropUnique(columns: string | string[]): MigrationContract;\r\n\r\n /**\r\n * Create an expression-based index.\r\n *\r\n * @param expressions - SQL expression(s) to index, e.g., ['lower(email)', 'upper(name)']\r\n * @param name - Optional index name\r\n * @param options - Optional index options (concurrently)\r\n */\r\n expressionIndex(\r\n expressions: string | string[],\r\n name?: string,\r\n options?: { concurrently?: boolean },\r\n ): MigrationContract;\r\n\r\n /**\r\n * Create a full-text search index.\r\n */\r\n fullText(columns: string | string[], options?: FullTextIndexOptions): MigrationContract;\r\n\r\n /**\r\n * Drop a full-text search index.\r\n */\r\n dropFullText(name: string): MigrationContract;\r\n\r\n /**\r\n * Create a geo-spatial index.\r\n */\r\n geoIndex(column: string, options?: GeoIndexOptions): MigrationContract;\r\n\r\n /**\r\n * Drop a geo-spatial index.\r\n */\r\n dropGeoIndex(column: string): MigrationContract;\r\n\r\n /**\r\n * Create a vector search index for AI embeddings.\r\n */\r\n vectorIndex(column: string, options: VectorIndexOptions): MigrationContract;\r\n\r\n /**\r\n * Drop a vector search index.\r\n */\r\n dropVectorIndex(column: string): MigrationContract;\r\n\r\n /**\r\n * Create a TTL (time-to-live) index for automatic document expiration.\r\n */\r\n ttlIndex(column: string, expireAfterSeconds: number): MigrationContract;\r\n\r\n /**\r\n * Drop a TTL index.\r\n */\r\n dropTTLIndex(column: string): MigrationContract;\r\n\r\n /**\r\n * Add a composite primary key.\r\n */\r\n primaryKey(columns: string[]): MigrationContract;\r\n\r\n /**\r\n * Drop the primary key constraint.\r\n */\r\n dropPrimaryKey(): MigrationContract;\r\n\r\n /**\r\n * Start building a foreign key constraint.\r\n */\r\n foreign(column: string): ForeignKeyBuilder;\r\n\r\n /**\r\n * Drop a foreign key constraint.\r\n *\r\n * When `referencesTable` is provided, the constraint name is auto-computed\r\n * using the same convention as `addForeignKey`:\r\n * `fk_{table}_{column}_{referencesTable}`\r\n *\r\n * When omitted, `columnOrConstraint` is used as the raw constraint name.\r\n */\r\n dropForeign(columnOrConstraint: string, referencesTable?: string): MigrationContract;\r\n\r\n /**\r\n * Set JSON schema validation rules on the collection.\r\n */\r\n schemaValidation(schema: object): MigrationContract;\r\n\r\n /**\r\n * Remove schema validation rules from the collection.\r\n */\r\n dropSchemaValidation(): MigrationContract;\r\n\r\n /**\r\n * Check if a table exists.\r\n */\r\n hasTable(tableName: string): Promise<boolean>;\r\n\r\n /**\r\n * Check if a column exists in the current table.\r\n */\r\n hasColumn(columnName: string): Promise<boolean>;\r\n\r\n /**\r\n * Get all columns in the current table.\r\n */\r\n getColumns(): Promise<ColumnDefinition[]>;\r\n\r\n /**\r\n * List all tables in the current database/connection.\r\n */\r\n listTables(): Promise<string[]>;\r\n\r\n /**\r\n * Get all indexes on the current table.\r\n */\r\n getIndexes(): Promise<TableIndexInformation[]>;\r\n\r\n /**\r\n * Check if a named index exists on the current table.\r\n */\r\n hasIndex(indexName: string): Promise<boolean>;\r\n\r\n /**\r\n * Queue a raw SQL string for execution within the migration.\r\n *\r\n * @param sql - SQL statement to execute\r\n */\r\n raw(sql: string): this;\r\n\r\n /**\r\n * Execute raw operations with direct driver/connection access.\r\n *\r\n * @param callback - Callback receiving the native connection\r\n */\r\n withConnection<T>(callback: (connection: unknown) => Promise<T>): Promise<T>;\r\n\r\n /**\r\n * Add a vector column for storing AI embeddings.\r\n *\r\n * @param column - Column name\r\n * @param dimensions - Embedding size (e.g. 1536 for text-embedding-3-small)\r\n */\r\n vector(column: string, dimensions: number): ColumnBuilder;\r\n}\r\n\r\n/**\r\n * Constructor for the migration class.\r\n */\r\nexport interface MigrationConstructor {\r\n new (): MigrationContract;\r\n migrationName?: string;\r\n createdAt?: string;\r\n transactional?: boolean;\r\n order?: number;\r\n}\r\n\r\n/**\r\n * Base class for all database migrations.\r\n *\r\n * Provides a fluent API for defining schema changes that work across\r\n * both SQL and NoSQL databases. The migration driver handles translating\r\n * operations to native database commands.\r\n *\r\n * Migrations are executed in order based on their `createdAt` timestamp,\r\n * which is typically extracted from the filename (e.g., `2024-01-15_create-users`).\r\n *\r\n * @example\r\n * ```typescript\r\n * // Using Migration.for() to bind to a model\r\n * export default class extends Migration.for(User) {\r\n * public up(): void {\r\n * this.string(\"email\").unique();\r\n * this.integer(\"age\").nullable();\r\n * this.geoIndex(\"location\");\r\n * }\r\n *\r\n * public down(): void {\r\n * this.dropColumn(\"email\");\r\n * this.dropColumn(\"age\");\r\n * this.dropGeoIndex(\"location\");\r\n * }\r\n * }\r\n * ```\r\n *\r\n * @example\r\n * ```typescript\r\n * // Manual table migration (without model binding)\r\n * export default class CreateUsersTable extends Migration {\r\n * public readonly table = \"users\";\r\n *\r\n * public up(): void {\r\n * this.createTable();\r\n * this.id();\r\n * this.string(\"name\");\r\n * this.string(\"email\").unique();\r\n * this.timestamps();\r\n * }\r\n *\r\n * public down(): void {\r\n * this.dropTable();\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport abstract class Migration implements MigrationContract {\r\n /**\r\n * Migration name that will be labeled with\r\n * If record is enabled in migration, it will be stored as migration name\r\n * in database\r\n *\r\n * @example\r\n * ```typescript\r\n * \"2024-01-15_create-users\";\r\n * ```\r\n */\r\n public static migrationName?: string;\r\n\r\n /**\r\n * Table/collection name for this migration.\r\n *\r\n * Must be defined by each migration class (either directly or via `Migration.for()`).\r\n */\r\n public readonly table!: string;\r\n\r\n /**\r\n * Sort order\r\n * If not provided, it will be ordered alphabetically\r\n */\r\n public static readonly order?: number;\r\n\r\n /**\r\n * Optional data source override.\r\n *\r\n * If specified, this migration will use a specific data source\r\n * instead of the default one. Can be a string name or DataSource instance.\r\n */\r\n public readonly dataSource?: string | DataSource;\r\n\r\n /**\r\n * Optional timestamp override.\r\n *\r\n * By default, the migration runner extracts this from the filename.\r\n * Set explicitly to override the execution order.\r\n *\r\n * Format: ISO 8601 or any parseable date string.\r\n */\r\n public static readonly createdAt?: string;\r\n\r\n /**\r\n * Whether to wrap migration in a transaction.\r\n *\r\n * Defaults to `true` for SQL databases that support DDL transactions.\r\n * Set to `false` for operations that cannot be transactional.\r\n *\r\n * Note: MongoDB does not support transactions for most DDL operations.\r\n */\r\n public readonly transactional?: boolean;\r\n\r\n /**\r\n * Migration driver instance (injected by the runner).\r\n */\r\n protected driver!: MigrationDriverContract;\r\n\r\n /**\r\n * Migration defaults from the resolved DataSource.\r\n * @internal\r\n */\r\n /** @internal — readable by factory-generated subclasses */\r\n protected _migrationDefaults?: MigrationDefaults;\r\n\r\n /**\r\n * Queued operations to execute.\r\n */\r\n private readonly pendingOperations: PendingOperation[] = [];\r\n\r\n // ============================================================================\r\n // ABSTRACT METHODS\r\n // ============================================================================\r\n\r\n /**\r\n * Define schema changes for the up migration.\r\n *\r\n * Called when running migrations forward. Add columns, indexes,\r\n * constraints, etc. in this method.\r\n */\r\n public abstract up(): void | Promise<void>;\r\n\r\n /**\r\n * Define rollback operations for the down migration.\r\n *\r\n * Called when rolling back migrations. Drop columns, indexes,\r\n * and undo any changes made in `up()`.\r\n */\r\n public abstract down(): void | Promise<void>;\r\n\r\n // ============================================================================\r\n // STATIC FACTORY\r\n // ============================================================================\r\n\r\n /**\r\n * Create a migration class bound to a specific model.\r\n *\r\n * Automatically inherits the model's table name and data source,\r\n * reducing boilerplate and ensuring consistency.\r\n *\r\n * @param model - Model class to bind\r\n * @returns Abstract migration class bound to the model\r\n *\r\n * @example\r\n * ```typescript\r\n * export default class extends Migration.for(User) {\r\n * public up(): void {\r\n * this.string(\"avatar\").nullable();\r\n * }\r\n *\r\n * public down(): void {\r\n * this.dropColumn(\"avatar\");\r\n * }\r\n * }\r\n * ```\r\n */\r\n public static for<T extends ChildModel<Model>>(model: T): MigrationConstructor {\r\n abstract class BoundMigration extends Migration {\r\n public readonly table = model.table;\r\n public readonly dataSource = model.dataSource;\r\n }\r\n\r\n return BoundMigration as unknown as MigrationConstructor;\r\n }\r\n\r\n /**\r\n * Create a migration that executes raw SQL statements.\r\n *\r\n * Intended for external packages that ship engine-specific DDL — typically a\r\n * one-shot `CREATE TABLE` bundle whose `up` is the only direction that matters.\r\n * The `down` direction is optional; when omitted, rollback is a recorded no-op.\r\n *\r\n * Raw SQL is engine-locked by definition. This factory is rejected on MongoDB\r\n * data sources at execute time — use the fluent builder for cross-engine work.\r\n *\r\n * @param options - Migration name, SQL statements, and optional overrides\r\n * @returns Migration constructor ready to register with the runner\r\n *\r\n * @example\r\n * ```typescript\r\n * export const createAuthTables = Migration.rawSql({\r\n * name: \"create_auth_tables\",\r\n * up: [\r\n * `CREATE TABLE users (id UUID PRIMARY KEY, email TEXT UNIQUE NOT NULL)`,\r\n * `CREATE TABLE sessions (id UUID PRIMARY KEY, user_id UUID REFERENCES users(id))`,\r\n * ],\r\n * });\r\n * ```\r\n */\r\n public static rawSql(options: {\r\n /**\r\n * Migration name. Used as the tracking key in the migrations table — must\r\n * be unique across the application.\r\n */\r\n name: string;\r\n /**\r\n * SQL statement(s) to execute on the up direction.\r\n */\r\n up: string | string[];\r\n /**\r\n * Optional SQL statement(s) for rollback. If omitted, `down()` is a no-op\r\n * and rollback simply removes the tracking record.\r\n */\r\n down?: string | string[];\r\n /**\r\n * Optional data source override (string name or DataSource instance).\r\n */\r\n dataSource?: string | DataSource;\r\n /**\r\n * Whether to wrap execution in a transaction. Defaults to the runner's\r\n * resolved default.\r\n */\r\n transactional?: boolean;\r\n }): MigrationConstructor {\r\n const { name, up, down, dataSource, transactional } = options;\r\n\r\n const toStatements = (input: string | string[]): string[] =>\r\n Array.isArray(input) ? input : [input];\r\n\r\n class RawSqlMigration extends Migration {\r\n public readonly table = \"\";\r\n public readonly dataSource = dataSource;\r\n public readonly transactional = transactional;\r\n\r\n public up(): void {\r\n this.guardEngine();\r\n for (const sql of toStatements(up)) {\r\n this.raw(sql);\r\n }\r\n }\r\n\r\n public down(): void {\r\n if (down === undefined) return;\r\n this.guardEngine();\r\n for (const sql of toStatements(down)) {\r\n this.raw(sql);\r\n }\r\n }\r\n\r\n private guardEngine(): void {\r\n if (this.databaseEngine === \"mongodb\") {\r\n throw new Error(\r\n `Migration.rawSql (\"${name}\") is not supported on mongodb data sources — use the fluent builder instead.`,\r\n );\r\n }\r\n }\r\n }\r\n\r\n RawSqlMigration.migrationName = name;\r\n return RawSqlMigration as unknown as MigrationConstructor;\r\n }\r\n\r\n // ============================================================================\r\n // DRIVER INJECTION\r\n // ============================================================================\r\n\r\n /**\r\n * Set the migration driver.\r\n *\r\n * Called by the migration runner before executing up/down.\r\n *\r\n * @param driver - Migration driver instance\r\n * @internal\r\n */\r\n public setDriver(driver: MigrationDriverContract): void {\r\n this.driver = driver;\r\n }\r\n\r\n /**\r\n * Set migration defaults from the resolved DataSource.\r\n *\r\n * @param defaults - Migration defaults (UUID strategy, etc.)\r\n * @internal\r\n */\r\n public setMigrationDefaults(defaults?: MigrationDefaults): void {\r\n this._migrationDefaults = defaults;\r\n }\r\n\r\n /**\r\n * Get the migration driver.\r\n *\r\n * @returns The migration driver instance\r\n */\r\n public getDriver(): MigrationDriverContract {\r\n return this.driver;\r\n }\r\n\r\n /**\r\n * Get database engine (MongoDB, Postgress...etc)\r\n */\r\n public get databaseEngine(): DatabaseDriver {\r\n return this.driver.driver.name;\r\n }\r\n\r\n // ============================================================================\r\n // EXECUTE OPERATIONS\r\n // ============================================================================\r\n\r\n /**\r\n * Execute all pending operations.\r\n *\r\n * @deprecated Use toSQL() instead — migrations now generate SQL rather than\r\n * executing DDL directly through the driver.\r\n * @internal\r\n */\r\n public async execute(): Promise<void> {\r\n for (const op of this.pendingOperations) {\r\n await this.executeOperation(op);\r\n }\r\n\r\n this.pendingOperations.length = 0;\r\n }\r\n\r\n /**\r\n * Serialize all queued pending operations into a flat list of SQL strings.\r\n *\r\n * Call this AFTER invoking `up()` or `down()` to extract the SQL for the\r\n * operations that were queued during that call. The pending queue is cleared\r\n * after serializing so the instance is safe to reuse.\r\n *\r\n * @example\r\n * ```typescript\r\n * const migration = new CreateUsersTable();\r\n * migration.setDriver(driver);\r\n *\r\n * // Up SQL\r\n * await migration.up();\r\n * const upSQL = migration.toSQL();\r\n *\r\n * // Down SQL — reuse the same instance\r\n * await migration.down();\r\n * const downSQL = migration.toSQL();\r\n * ```\r\n */\r\n public toSQL(): string[] {\r\n const serializer = this.driver.driver.getSQLSerializer();\r\n const statements = serializer.serializeAll(this.pendingOperations, this.table);\r\n this.pendingOperations.length = 0;\r\n return statements;\r\n }\r\n\r\n /**\r\n * Execute a single pending operation.\r\n */\r\n private async executeOperation(op: PendingOperation): Promise<void> {\r\n switch (op.type) {\r\n case \"addColumn\": {\r\n const column = op.payload as ColumnDefinition;\r\n await this.driver.addColumn(this.table, column);\r\n\r\n if (column.checkConstraint) {\r\n await this.driver.addCheck(\r\n this.table,\r\n column.checkConstraint.name,\r\n column.checkConstraint.expression,\r\n );\r\n }\r\n break;\r\n }\r\n\r\n case \"dropColumn\":\r\n await this.driver.dropColumn(this.table, op.payload as string);\r\n break;\r\n\r\n case \"dropColumns\":\r\n await this.driver.dropColumns(this.table, op.payload as string[]);\r\n break;\r\n\r\n case \"renameColumn\": {\r\n const { from, to } = op.payload as { from: string; to: string };\r\n await this.driver.renameColumn(this.table, from, to);\r\n break;\r\n }\r\n\r\n case \"modifyColumn\":\r\n await this.driver.modifyColumn(this.table, op.payload as ColumnDefinition);\r\n break;\r\n\r\n case \"createIndex\":\r\n await this.driver.createIndex(this.table, op.payload as IndexDefinition);\r\n break;\r\n\r\n case \"dropIndex\":\r\n await this.driver.dropIndex(this.table, op.payload as string);\r\n break;\r\n\r\n case \"createUniqueIndex\": {\r\n const { columns, name } = op.payload as {\r\n columns: string[];\r\n name?: string;\r\n };\r\n await this.driver.createUniqueIndex(this.table, columns, name);\r\n break;\r\n }\r\n\r\n case \"dropUniqueIndex\":\r\n await this.driver.dropUniqueIndex(this.table, op.payload as string[]);\r\n break;\r\n\r\n case \"createFullTextIndex\": {\r\n const { columns, options } = op.payload as {\r\n columns: string[];\r\n options?: FullTextIndexOptions;\r\n };\r\n await this.driver.createFullTextIndex(this.table, columns, options);\r\n break;\r\n }\r\n\r\n case \"dropFullTextIndex\":\r\n await this.driver.dropFullTextIndex(this.table, op.payload as string);\r\n break;\r\n\r\n case \"createGeoIndex\": {\r\n const { column, options } = op.payload as {\r\n column: string;\r\n options?: GeoIndexOptions;\r\n };\r\n await this.driver.createGeoIndex(this.table, column, options);\r\n break;\r\n }\r\n\r\n case \"dropGeoIndex\":\r\n await this.driver.dropGeoIndex(this.table, op.payload as string);\r\n break;\r\n\r\n case \"createVectorIndex\": {\r\n const { column, options } = op.payload as {\r\n column: string;\r\n options: VectorIndexOptions;\r\n };\r\n await this.driver.createVectorIndex(this.table, column, options);\r\n break;\r\n }\r\n\r\n case \"dropVectorIndex\":\r\n await this.driver.dropVectorIndex(this.table, op.payload as string);\r\n break;\r\n\r\n case \"createTTLIndex\": {\r\n const { column, seconds } = op.payload as {\r\n column: string;\r\n seconds: number;\r\n };\r\n await this.driver.createTTLIndex(this.table, column, seconds);\r\n break;\r\n }\r\n\r\n case \"dropTTLIndex\":\r\n await this.driver.dropTTLIndex(this.table, op.payload as string);\r\n break;\r\n\r\n case \"addForeignKey\":\r\n await this.driver.addForeignKey(this.table, op.payload as ForeignKeyDefinition);\r\n break;\r\n\r\n case \"dropForeignKey\":\r\n await this.driver.dropForeignKey(this.table, op.payload as string);\r\n break;\r\n\r\n case \"addPrimaryKey\":\r\n await this.driver.addPrimaryKey(this.table, op.payload as string[]);\r\n break;\r\n\r\n case \"dropPrimaryKey\":\r\n await this.driver.dropPrimaryKey(this.table);\r\n break;\r\n\r\n case \"addCheck\": {\r\n const { name, expression } = op.payload as { name: string; expression: string };\r\n await this.driver.addCheck(this.table, name, expression);\r\n break;\r\n }\r\n\r\n case \"dropCheck\":\r\n await this.driver.dropCheck(this.table, op.payload as string);\r\n break;\r\n\r\n case \"createTable\":\r\n await this.driver.createTable(this.table);\r\n break;\r\n\r\n case \"createTableIfNotExists\":\r\n await this.driver.createTableIfNotExists(this.table);\r\n break;\r\n\r\n case \"dropTable\":\r\n await this.driver.dropTable(this.table);\r\n break;\r\n\r\n case \"dropTableIfExists\":\r\n await this.driver.dropTableIfExists(this.table);\r\n break;\r\n\r\n case \"renameTable\":\r\n await this.driver.renameTable(this.table, op.payload as string);\r\n break;\r\n\r\n case \"truncateTable\":\r\n await this.driver.truncateTable(this.table);\r\n break;\r\n\r\n case \"createTimestamps\":\r\n await this.driver.createTimestampColumns(this.table);\r\n break;\r\n\r\n case \"rawStatement\":\r\n await this.driver.raw(async (client: any) => {\r\n const sql = op.payload as string;\r\n // Handle different driver APIs\r\n if (typeof client.query === \"function\") {\r\n // PostgreSQL, MySQL - client is the driver instance\r\n await client.query(sql);\r\n } else if (typeof client.command === \"function\") {\r\n // MongoDB - client is the Db instance\r\n await client.command({ $eval: sql });\r\n } else {\r\n throw new Error(\"Unsupported database driver for statement execution\");\r\n }\r\n });\r\n break;\r\n\r\n case \"setSchemaValidation\":\r\n await this.driver.setSchemaValidation(this.table, op.payload as object);\r\n break;\r\n\r\n case \"removeSchemaValidation\":\r\n await this.driver.removeSchemaValidation(this.table);\r\n break;\r\n }\r\n }\r\n\r\n // ============================================================================\r\n // SCHEMA INSPECTION\r\n // ============================================================================\r\n\r\n /**\r\n * Check if a table exists.\r\n *\r\n * Useful for conditional migrations and idempotent operations.\r\n *\r\n * @param tableName - Table name to check\r\n * @returns Promise resolving to true if table exists\r\n *\r\n * @example\r\n * ```typescript\r\n * public async up() {\r\n * if (await this.hasTable(\"users_backup\")) {\r\n * this.dropTable(\"users_backup\");\r\n * }\r\n * // ... rest of migration\r\n * }\r\n * ```\r\n */\r\n public async hasTable(tableName: string): Promise<boolean> {\r\n return this.driver.tableExists(tableName);\r\n }\r\n\r\n /**\r\n * Check if a column exists in the current table.\r\n *\r\n * @param columnName - Column name to check\r\n * @returns Promise resolving to true if column exists\r\n *\r\n * @example\r\n * ```typescript\r\n * public async up() {\r\n * if (!(await this.hasColumn(\"email\"))) {\r\n * this.string(\"email\").unique();\r\n * }\r\n * }\r\n * ```\r\n */\r\n public async hasColumn(columnName: string): Promise<boolean> {\r\n const columns = await this.getColumns();\r\n return columns.some((col) => col.name === columnName);\r\n }\r\n\r\n /**\r\n * Get all columns in the current table.\r\n *\r\n * @returns Promise resolving to array of column definitions\r\n *\r\n * @example\r\n * ```typescript\r\n * const columns = await this.getColumns();\r\n * if (columns.find(col => col.type === \"string\" && !col.length)) {\r\n * // migrate all unbounded strings\r\n * }\r\n * ```\r\n */\r\n public async getColumns(): Promise<ColumnDefinition[]> {\r\n return this.driver.listColumns(this.table);\r\n }\r\n\r\n /**\r\n * List all tables in the current database/connection.\r\n *\r\n * @returns Promise resolving to array of table names\r\n *\r\n * @example\r\n * ```typescript\r\n * const tables = await this.listTables();\r\n * for (const table of tables) {\r\n * // process each table\r\n * }\r\n * ```\r\n */\r\n public async listTables(): Promise<string[]> {\r\n return this.driver.listTables();\r\n }\r\n\r\n /**\r\n * Get all indexes on the current table.\r\n */\r\n public async getIndexes(): Promise<TableIndexInformation[]> {\r\n return this.driver.listIndexes(this.table);\r\n }\r\n\r\n /**\r\n * Check if a named index exists on the current table.\r\n */\r\n public async hasIndex(indexName: string): Promise<boolean> {\r\n const indexes = await this.getIndexes();\r\n return indexes.some((idx) => idx.name === indexName);\r\n }\r\n\r\n // ============================================================================\r\n // INTERNAL HELPERS\r\n // ============================================================================\r\n\r\n /**\r\n * Add a pending index definition.\r\n *\r\n * Called by ColumnBuilder when .unique() or .index() is chained.\r\n * Routes into pendingOperations so indexes execute in definition order\r\n * alongside columns and constraints.\r\n *\r\n * @param index - Index definition\r\n * @internal\r\n */\r\n public addPendingIndex(index: IndexDefinition): void {\r\n if (index.unique) {\r\n this.pendingOperations.push({\r\n type: \"createUniqueIndex\",\r\n payload: { columns: index.columns, name: index.name },\r\n });\r\n } else {\r\n this.pendingOperations.push({\r\n type: \"createIndex\",\r\n payload: index,\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Add a foreign key operation.\r\n *\r\n * Called by ForeignKeyBuilder or ColumnBuilder when .references() is called.\r\n *\r\n * @param fk - Foreign key definition\r\n * @internal\r\n */\r\n public addForeignKeyOperation(fk: ForeignKeyDefinition): void {\r\n this.pendingOperations.push({\r\n type: \"addForeignKey\",\r\n payload: fk,\r\n });\r\n }\r\n\r\n // ============================================================================\r\n // TABLE OPERATIONS\r\n // ============================================================================\r\n\r\n /**\r\n * Create the table/collection.\r\n *\r\n * For SQL, this creates an empty table.\r\n * For MongoDB, this creates the collection.\r\n *\r\n * @returns This migration for chaining\r\n */\r\n public createTable(): this {\r\n this.pendingOperations.push({ type: \"createTable\", payload: null });\r\n return this;\r\n }\r\n\r\n /**\r\n * Create table if not exists\r\n */\r\n public createTableIfNotExists(): this {\r\n this.pendingOperations.push({ type: \"createTableIfNotExists\", payload: null });\r\n return this;\r\n }\r\n\r\n /**\r\n * Drop the table/collection.\r\n *\r\n * @returns This migration for chaining\r\n */\r\n public dropTable(): this {\r\n this.pendingOperations.push({ type: \"dropTable\", payload: null });\r\n return this;\r\n }\r\n\r\n /**\r\n * Drop the table/collection if it exists.\r\n *\r\n * No error is thrown if the table doesn't exist.\r\n *\r\n * @returns This migration for chaining\r\n */\r\n public dropTableIfExists(): this {\r\n this.pendingOperations.push({ type: \"dropTableIfExists\", payload: null });\r\n return this;\r\n }\r\n\r\n /**\r\n * Rename the table/collection.\r\n *\r\n * @param newName - New table name\r\n * @returns This migration for chaining\r\n */\r\n public renameTableTo(newName: string): this {\r\n this.pendingOperations.push({ type: \"renameTable\", payload: newName });\r\n return this;\r\n }\r\n\r\n /**\r\n * Truncate the table — remove all rows without logging or firing triggers.\r\n *\r\n * Faster than DELETE with no WHERE clause. Resets auto-increment counters\r\n * on most databases.\r\n *\r\n * @returns This migration for chaining\r\n */\r\n public truncateTable(): this {\r\n this.pendingOperations.push({ type: \"truncateTable\", payload: null });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // COLUMN TYPES - STRING\r\n // ============================================================================\r\n\r\n /**\r\n * Add a string/varchar column.\r\n *\r\n * @param column - Column name\r\n * @param length - Max length (default: 255)\r\n * @returns Column builder for chaining modifiers\r\n *\r\n * @example\r\n * ```typescript\r\n * this.string(\"name\"); // VARCHAR(255)\r\n * this.string(\"code\", 10); // VARCHAR(10)\r\n * ```\r\n */\r\n public string(column: string, length = 255): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"string\", { length });\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a fixed-length char column.\r\n *\r\n * @param column - Column name\r\n * @param length - Exact length\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public char(column: string, length: number): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"char\", { length });\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a text column (unlimited length).\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public text(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"text\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a medium text column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public mediumText(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"mediumText\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a long text column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public longText(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"longText\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n // ============================================================================\r\n // COLUMN TYPES - NUMERIC\r\n // ============================================================================\r\n\r\n /**\r\n * Add an integer column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public integer(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"integer\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Alias for integer().\r\n */\r\n public int(column: string): ColumnBuilder {\r\n return this.integer(column);\r\n }\r\n\r\n /**\r\n * Add a small integer column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public smallInteger(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"smallInteger\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Alias for smallInteger().\r\n */\r\n public smallInt(column: string): ColumnBuilder {\r\n return this.smallInteger(column);\r\n }\r\n\r\n /**\r\n * Add a tiny integer column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public tinyInteger(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"tinyInteger\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Alias for tinyInteger().\r\n */\r\n public tinyInt(column: string): ColumnBuilder {\r\n return this.tinyInteger(column);\r\n }\r\n\r\n /**\r\n * Add a big integer column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public bigInteger(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"bigInteger\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Alias for bigInteger().\r\n */\r\n public bigInt(column: string): ColumnBuilder {\r\n return this.bigInteger(column);\r\n }\r\n\r\n /**\r\n * Add a float column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public float(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"float\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a double precision column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public double(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"double\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a decimal column with precision and scale.\r\n *\r\n * @param column - Column name\r\n * @param precision - Total digits (default: 8)\r\n * @param scale - Decimal places (default: 2)\r\n * @returns Column builder for chaining modifiers\r\n *\r\n * @example\r\n * ```typescript\r\n * this.decimal(\"price\", 10, 2); // DECIMAL(10,2) - up to 99999999.99\r\n * ```\r\n */\r\n public decimal(column: string, precision = 8, scale = 2): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"decimal\", {\r\n precision,\r\n scale,\r\n });\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n // ============================================================================\r\n // COLUMN TYPES - BOOLEAN\r\n // ============================================================================\r\n\r\n /**\r\n * Add a boolean column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public boolean(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"boolean\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Alias for boolean().\r\n */\r\n public bool(column: string): ColumnBuilder {\r\n return this.boolean(column);\r\n }\r\n\r\n // ============================================================================\r\n // COLUMN TYPES - DATE/TIME\r\n // ============================================================================\r\n\r\n /**\r\n * Add a date column (date only, no time).\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public date(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"date\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a datetime column (date and time).\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public dateTime(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"dateTime\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a timestamp column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public timestamp(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"timestamp\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a time column (time only, no date).\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public time(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"time\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a year column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public year(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"year\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n // ============================================================================\r\n // COLUMN TYPES - JSON & BINARY\r\n // ============================================================================\r\n\r\n /**\r\n * Add a JSON column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public json(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"json\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Alias for json().\r\n */\r\n public object(column: string): ColumnBuilder {\r\n return this.json(column);\r\n }\r\n\r\n /**\r\n * Add a binary/blob column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public binary(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"binary\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Alias for binary().\r\n */\r\n public blob(column: string): ColumnBuilder {\r\n return this.binary(column);\r\n }\r\n\r\n // ============================================================================\r\n // COLUMN TYPES - IDENTIFIERS\r\n // ============================================================================\r\n\r\n /**\r\n * Add a UUID column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public uuid(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"uuid\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a ULID column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public ulid(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"ulid\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n // ============================================================================\r\n // COLUMN TYPES - NETWORK\r\n // ============================================================================\r\n\r\n /**\r\n * Add an IP address column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public ipAddress(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"ipAddress\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a MAC address column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public macAddress(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"macAddress\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n // ============================================================================\r\n // COLUMN TYPES - GEO & SPATIAL\r\n // ============================================================================\r\n\r\n /**\r\n * Add a geo point column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public point(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"point\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a polygon column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public polygon(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"polygon\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a line string column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public lineString(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"lineString\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a generic geometry column.\r\n *\r\n * @param column - Column name\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public geometry(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"geometry\");\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n // ============================================================================\r\n // COLUMN TYPES - AI/ML\r\n // ============================================================================\r\n\r\n /**\r\n * Add a vector column for AI embeddings.\r\n *\r\n * Used for storing and searching ML embeddings (e.g., OpenAI, Cohere).\r\n *\r\n * @param column - Column name\r\n * @param dimensions - Vector dimensions (e.g., 1536 for OpenAI ada-002)\r\n * @returns Column builder for chaining modifiers\r\n *\r\n * @example\r\n * ```typescript\r\n * this.vector(\"embedding\", 1536); // OpenAI ada-002\r\n * this.vector(\"embedding\", 384); // Sentence Transformers\r\n * ```\r\n */\r\n public vector(column: string, dimensions: number): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"vector\", { dimensions });\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n // ============================================================================\r\n // COLUMN TYPES - ENUM & SET\r\n // ============================================================================\r\n\r\n /**\r\n * Add an enum column with allowed values.\r\n *\r\n * @param column - Column name\r\n * @param values - Allowed enum values\r\n * @returns Column builder for chaining modifiers\r\n *\r\n * @example\r\n * ```typescript\r\n * this.enum(\"status\", [\"pending\", \"active\", \"archived\"]);\r\n * ```\r\n */\r\n public enum(column: string, values: string[]): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"enum\", { values });\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a set column (multiple values from a set).\r\n *\r\n * @param column - Column name\r\n * @param values - Allowed set values\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public set(column: string, values: string[]): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"set\", { values });\r\n this.pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: builder.getDefinition(),\r\n });\r\n return builder;\r\n }\r\n\r\n // ============================================================================\r\n // COLUMN TYPES - POSTGRESQL ARRAYS\r\n // ============================================================================\r\n\r\n /**\r\n * Add an INTEGER[] column (array of integers).\r\n *\r\n * @example\r\n * ```typescript\r\n * this.arrayInt(\"scores\"); // INTEGER[]\r\n * ```\r\n */\r\n public arrayInt(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"arrayInt\");\r\n this.pendingOperations.push({ type: \"addColumn\", payload: builder.getDefinition() });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a BIGINT[] column (array of big integers).\r\n *\r\n * @example\r\n * ```typescript\r\n * this.arrayBigInt(\"ids\"); // BIGINT[]\r\n * ```\r\n */\r\n public arrayBigInt(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"arrayBigInt\");\r\n this.pendingOperations.push({ type: \"addColumn\", payload: builder.getDefinition() });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a REAL[] column (array of floats).\r\n *\r\n * @example\r\n * ```typescript\r\n * this.arrayFloat(\"weights\"); // REAL[]\r\n * ```\r\n */\r\n public arrayFloat(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"arrayFloat\");\r\n this.pendingOperations.push({ type: \"addColumn\", payload: builder.getDefinition() });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a DECIMAL[] column (array of decimals).\r\n *\r\n * @param precision - Total digits\r\n * @param scale - Digits after decimal point\r\n *\r\n * @example\r\n * ```typescript\r\n * this.arrayDecimal(\"prices\", 10, 2); // DECIMAL(10,2)[]\r\n * this.arrayDecimal(\"amounts\"); // DECIMAL[]\r\n * ```\r\n */\r\n public arrayDecimal(column: string, precision?: number, scale?: number): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"arrayDecimal\", { precision, scale });\r\n this.pendingOperations.push({ type: \"addColumn\", payload: builder.getDefinition() });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a BOOLEAN[] column (array of booleans).\r\n *\r\n * @example\r\n * ```typescript\r\n * this.arrayBoolean(\"flags\"); // BOOLEAN[]\r\n * ```\r\n */\r\n public arrayBoolean(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"arrayBoolean\");\r\n this.pendingOperations.push({ type: \"addColumn\", payload: builder.getDefinition() });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a TEXT[] column (array of text values).\r\n *\r\n * @example\r\n * ```typescript\r\n * this.arrayText(\"tags\"); // TEXT[]\r\n * ```\r\n */\r\n public arrayText(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"arrayText\");\r\n this.pendingOperations.push({ type: \"addColumn\", payload: builder.getDefinition() });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a DATE[] column (array of dates).\r\n *\r\n * @example\r\n * ```typescript\r\n * this.arrayDate(\"holidays\"); // DATE[]\r\n * ```\r\n */\r\n public arrayDate(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"arrayDate\");\r\n this.pendingOperations.push({ type: \"addColumn\", payload: builder.getDefinition() });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a TIMESTAMPTZ[] column (array of timestamps with time zone).\r\n *\r\n * @example\r\n * ```typescript\r\n * this.arrayTimestamp(\"events\"); // TIMESTAMPTZ[]\r\n * ```\r\n */\r\n public arrayTimestamp(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"arrayTimestamp\");\r\n this.pendingOperations.push({ type: \"addColumn\", payload: builder.getDefinition() });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a UUID[] column (array of UUIDs).\r\n *\r\n * @example\r\n * ```typescript\r\n * this.arrayUuid(\"relatedIds\"); // UUID[]\r\n * ```\r\n */\r\n public arrayUuid(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"arrayUuid\");\r\n this.pendingOperations.push({ type: \"addColumn\", payload: builder.getDefinition() });\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add a JSONB[] column — array of JSON objects.\r\n *\r\n * @example\r\n * ```typescript\r\n * this.arrayJson(\"metadata\"); // JSONB[]\r\n * ```\r\n */\r\n public arrayJson(column: string): ColumnBuilder {\r\n const builder = new ColumnBuilder(this, column, \"arrayJson\");\r\n this.pendingOperations.push({ type: \"addColumn\", payload: builder.getDefinition() });\r\n return builder;\r\n }\r\n\r\n // ============================================================================\r\n // SHORTCUTS\r\n // ============================================================================\r\n\r\n /**\r\n * Add an auto-increment primary key column.\r\n *\r\n * Creates an unsigned integer with primary key and auto-increment.\r\n *\r\n * @param name - Column name (default: \"id\")\r\n * @returns Column builder for chaining modifiers\r\n *\r\n * @example\r\n * ```typescript\r\n * this.id(); // Creates \"id\" column\r\n * this.id(\"userId\"); // Creates \"userId\" column\r\n * ```\r\n */\r\n public id(name = \"id\"): ColumnBuilder {\r\n return this.integer(name).primary().autoIncrement().unsigned();\r\n }\r\n\r\n /**\r\n * Add a big integer auto-increment primary key column.\r\n *\r\n * @param name - Column name (default: \"id\")\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public bigId(name = \"id\"): ColumnBuilder {\r\n return this.bigInteger(name).primary().autoIncrement().unsigned();\r\n }\r\n\r\n /**\r\n * Add a UUID primary key column.\r\n *\r\n * @param name - Column name (default: \"id\")\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public uuidId(name = \"id\"): ColumnBuilder {\r\n return this.uuid(name).primary();\r\n }\r\n\r\n /**\r\n * Add a UUID primary key column with automatic generation.\r\n *\r\n * Delegates UUID expression to the migration driver, which resolves\r\n * the default based on `migrationDefaults` from the DataSource config.\r\n *\r\n * Resolution order:\r\n * 1. `migrationDefaults.uuidExpression` (raw escape hatch)\r\n * 2. `migrationDefaults.uuidStrategy` (mapped per driver)\r\n * 3. Driver default (PostgreSQL: `gen_random_uuid()`, MongoDB: undefined)\r\n *\r\n * @param name - Column name (default: \"id\")\r\n * @returns Column builder for chaining modifiers\r\n *\r\n * @example\r\n * ```typescript\r\n * this.primaryUuid(); // id UUID PRIMARY KEY DEFAULT gen_random_uuid()\r\n * this.primaryUuid(\"organization_id\"); // Custom column name\r\n * ```\r\n */\r\n public primaryUuid(name = \"id\"): ColumnBuilder {\r\n const uuidDefault = this.driver.getUuidDefault(this._migrationDefaults);\r\n const builder = this.uuid(name).primary();\r\n\r\n if (uuidDefault) {\r\n builder.default(uuidDefault);\r\n }\r\n\r\n return builder;\r\n }\r\n\r\n /**\r\n * Add createdAt and updatedAt timestamp columns.\r\n *\r\n * Behavior varies by database driver:\r\n * - PostgreSQL: Creates TIMESTAMPTZ columns with NOW() defaults\r\n * - MongoDB: No-op (timestamps handled at application level)\r\n *\r\n * @returns This migration for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * this.timestamps(); // Driver-specific implementation\r\n * ```\r\n */\r\n public timestamps(): this {\r\n this.pendingOperations.push({ type: \"createTimestamps\", payload: null });\r\n return this;\r\n }\r\n\r\n /**\r\n * Add a deletedAt column for soft deletes.\r\n *\r\n * @param column - Column name (default: \"deletedAt\")\r\n * @returns Column builder for chaining modifiers\r\n */\r\n public softDeletes(column = \"deletedAt\"): ColumnBuilder {\r\n return this.dateTime(column).nullable();\r\n }\r\n\r\n // ============================================================================\r\n // DROP COLUMN OPERATIONS\r\n // ============================================================================\r\n\r\n /**\r\n * Drop a column.\r\n *\r\n * @param column - Column name to drop\r\n * @returns This migration for chaining\r\n */\r\n public dropColumn(column: string): this {\r\n this.pendingOperations.push({ type: \"dropColumn\", payload: column });\r\n return this;\r\n }\r\n\r\n /**\r\n * Drop multiple columns.\r\n *\r\n * @param columns - Column names to drop\r\n * @returns This migration for chaining\r\n */\r\n public dropColumns(...columns: string[]): this {\r\n this.pendingOperations.push({ type: \"dropColumns\", payload: columns });\r\n return this;\r\n }\r\n\r\n /**\r\n * Rename a column.\r\n *\r\n * @param from - Current column name\r\n * @param to - New column name\r\n * @returns This migration for chaining\r\n */\r\n public renameColumn(from: string, to: string): this {\r\n this.pendingOperations.push({\r\n type: \"renameColumn\",\r\n payload: { from, to },\r\n });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // INDEX OPERATIONS\r\n // ============================================================================\r\n\r\n /**\r\n * Create an index on one or more columns.\r\n *\r\n * @param columns - Column(s) to index\r\n * @param name - Optional index name\r\n * @param options - Optional index options (include, concurrently)\r\n * @returns This migration for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * this.index(\"email\");\r\n * this.index([\"firstName\", \"lastName\"], \"name_idx\");\r\n * this.index(\"userId\", \"idx_user\", { include: [\"name\", \"email\"] });\r\n * this.index(\"email\", \"idx_email\", { concurrently: true });\r\n * ```\r\n */\r\n public index(\r\n columns: string | string[],\r\n name?: string,\r\n options?: { include?: string[]; concurrently?: boolean },\r\n ): this {\r\n const cols = Array.isArray(columns) ? columns : [columns];\r\n this.pendingOperations.push({\r\n type: \"createIndex\",\r\n payload: {\r\n columns: cols,\r\n name,\r\n include: options?.include,\r\n concurrently: options?.concurrently,\r\n } as IndexDefinition,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Drop an index by name or columns.\r\n *\r\n * @param nameOrColumns - Index name (string) or columns array\r\n * @returns This migration for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * this.dropIndex(\"email_idx\"); // Drop by name\r\n * this.dropIndex([\"firstName\", \"lastName\"]); // Drop by columns\r\n * ```\r\n */\r\n public dropIndex(nameOrColumns: string | string[]): this {\r\n this.pendingOperations.push({\r\n type: \"dropIndex\",\r\n payload: nameOrColumns,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Create a unique constraint/index.\r\n *\r\n * @param columns - Column(s) to make unique\r\n * @param name - Optional constraint name\r\n * @param options - Optional index options (include, concurrently)\r\n * @returns This migration for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * this.unique(\"email\");\r\n * this.unique([\"userId\", \"roleId\"], \"unique_user_role\");\r\n * this.unique(\"email\", \"unique_email\", { include: [\"name\"] });\r\n * ```\r\n */\r\n public unique(\r\n columns: string | string[],\r\n name?: string,\r\n options?: { include?: string[]; concurrently?: boolean },\r\n ): this {\r\n const cols = Array.isArray(columns) ? columns : [columns];\r\n this.pendingOperations.push({\r\n type: \"createUniqueIndex\",\r\n payload: {\r\n columns: cols,\r\n name,\r\n include: options?.include,\r\n concurrently: options?.concurrently,\r\n },\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Drop a unique constraint/index.\r\n *\r\n * @param columns - Columns in the unique constraint\r\n * @returns This migration for chaining\r\n */\r\n public dropUnique(columns: string | string[]): this {\r\n const cols = Array.isArray(columns) ? columns : [columns];\r\n this.pendingOperations.push({ type: \"dropUniqueIndex\", payload: cols });\r\n return this;\r\n }\r\n\r\n /**\r\n * Create an expression-based index.\r\n *\r\n * Allows indexing on SQL expressions rather than plain columns.\r\n * Useful for case-insensitive searches, computed values, etc.\r\n *\r\n * **Note**: PostgreSQL-specific feature. MongoDB will silently ignore this.\r\n *\r\n * @param expressions - SQL expression(s) to index\r\n * @param name - Optional index name\r\n * @param options - Optional index options (concurrently)\r\n * @returns This migration for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * // Case-insensitive email index\r\n * this.expressionIndex(['lower(email)'], 'idx_email_lower');\r\n *\r\n * // Multiple expressions\r\n * this.expressionIndex(['lower(firstName)', 'lower(lastName)'], 'idx_name_lower');\r\n *\r\n * // With concurrent creation (requires transactional = false)\r\n * this.expressionIndex(['lower(email)'], 'idx_email_lower', { concurrently: true });\r\n * ```\r\n */\r\n public expressionIndex(\r\n expressions: string | string[],\r\n name?: string,\r\n options?: { concurrently?: boolean },\r\n ): this {\r\n const exprs = Array.isArray(expressions) ? expressions : [expressions];\r\n this.pendingOperations.push({\r\n type: \"createIndex\",\r\n payload: {\r\n columns: [], // Empty columns for expression indexes\r\n expressions: exprs,\r\n name,\r\n concurrently: options?.concurrently,\r\n } as IndexDefinition,\r\n });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // FULL-TEXT INDEX\r\n // ============================================================================\r\n\r\n /**\r\n * Create a full-text search index.\r\n *\r\n * @param columns - Column(s) to index\r\n * @param options - Full-text options\r\n * @returns This migration for chaining\r\n */\r\n public fullText(columns: string | string[], options?: FullTextIndexOptions): this {\r\n const cols = Array.isArray(columns) ? columns : [columns];\r\n this.pendingOperations.push({\r\n type: \"createFullTextIndex\",\r\n payload: { columns: cols, options },\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Drop a full-text search index.\r\n *\r\n * @param name - Index name\r\n * @returns This migration for chaining\r\n */\r\n public dropFullText(name: string): this {\r\n this.pendingOperations.push({ type: \"dropFullTextIndex\", payload: name });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // GEO INDEX\r\n // ============================================================================\r\n\r\n /**\r\n * Create a geo-spatial index.\r\n *\r\n * @param column - Geo column\r\n * @param options - Geo index options\r\n * @returns This migration for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * this.geoIndex(\"location\"); // 2dsphere index\r\n * this.geoIndex(\"coordinates\", { type: \"2d\" }); // 2d index\r\n * ```\r\n */\r\n public geoIndex(column: string, options?: GeoIndexOptions): this {\r\n this.pendingOperations.push({\r\n type: \"createGeoIndex\",\r\n payload: { column, options },\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Drop a geo-spatial index.\r\n *\r\n * @param column - Geo column\r\n * @returns This migration for chaining\r\n */\r\n public dropGeoIndex(column: string): this {\r\n this.pendingOperations.push({ type: \"dropGeoIndex\", payload: column });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // VECTOR INDEX\r\n // ============================================================================\r\n\r\n /**\r\n * Create a vector search index for AI embeddings.\r\n *\r\n * @param column - Vector column\r\n * @param options - Vector index options\r\n * @returns This migration for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * this.vectorIndex(\"embedding\", {\r\n * dimensions: 1536,\r\n * similarity: \"cosine\",\r\n * });\r\n * ```\r\n */\r\n public vectorIndex(column: string, options: VectorIndexOptions): this {\r\n this.pendingOperations.push({\r\n type: \"createVectorIndex\",\r\n payload: { column, options },\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Drop a vector search index.\r\n *\r\n * @param column - Vector column\r\n * @returns This migration for chaining\r\n */\r\n public dropVectorIndex(column: string): this {\r\n this.pendingOperations.push({ type: \"dropVectorIndex\", payload: column });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // TTL INDEX\r\n // ============================================================================\r\n\r\n /**\r\n * Create a TTL (time-to-live) index for automatic document expiration.\r\n *\r\n * Primarily for MongoDB. Documents are automatically deleted after the\r\n * specified time has passed since the date in the column.\r\n *\r\n * @param column - Date column to check for expiration\r\n * @param expireAfterSeconds - Seconds after which documents expire\r\n * @returns This migration for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * // Delete sessions 24 hours after createdAt\r\n * this.ttlIndex(\"createdAt\", 86400);\r\n * ```\r\n */\r\n public ttlIndex(column: string, expireAfterSeconds: number): this {\r\n this.pendingOperations.push({\r\n type: \"createTTLIndex\",\r\n payload: { column, seconds: expireAfterSeconds },\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Drop a TTL index.\r\n *\r\n * @param column - Column with TTL\r\n * @returns This migration for chaining\r\n */\r\n public dropTTLIndex(column: string): this {\r\n this.pendingOperations.push({ type: \"dropTTLIndex\", payload: column });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // PRIMARY KEY\r\n // ============================================================================\r\n\r\n /**\r\n * Add a composite primary key.\r\n *\r\n * @param columns - Columns to include in the primary key\r\n * @returns This migration for chaining\r\n */\r\n public primaryKey(columns: string[]): this {\r\n this.pendingOperations.push({ type: \"addPrimaryKey\", payload: columns });\r\n return this;\r\n }\r\n\r\n /**\r\n * Drop the primary key constraint.\r\n *\r\n * @returns This migration for chaining\r\n */\r\n public dropPrimaryKey(): this {\r\n this.pendingOperations.push({ type: \"dropPrimaryKey\", payload: null });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // CHECK CONSTRAINTS\r\n // ============================================================================\r\n\r\n /**\r\n * Add a CHECK constraint to the table.\r\n *\r\n * SQL-only feature. PostgreSQL, MySQL 8.0+, SQLite support this.\r\n * Validates that rows satisfy the given SQL expression.\r\n *\r\n * @param name - Constraint name\r\n * @param expression - SQL CHECK expression\r\n * @returns This migration for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * this.check(\"age_positive\", \"age >= 0\");\r\n * this.check(\"valid_email\", \"email LIKE '%@%'\");\r\n * this.check(\"price_range\", \"price BETWEEN 0 AND 1000000\");\r\n * ```\r\n */\r\n public check(name: string, expression: string): this {\r\n this.pendingOperations.push({\r\n type: \"addCheck\",\r\n payload: { name, expression },\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Drop a CHECK constraint by name.\r\n *\r\n * @param name - Constraint name\r\n * @returns This migration for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * this.dropCheck(\"age_positive\");\r\n * ```\r\n */\r\n public dropCheck(name: string): this {\r\n this.pendingOperations.push({\r\n type: \"dropCheck\",\r\n payload: name,\r\n });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // FOREIGN KEYS (SQL)\r\n // ============================================================================\r\n\r\n /**\r\n * Start building a foreign key constraint on an existing column.\r\n *\r\n * Use this when adding a foreign key to a column that was defined in a\r\n * previous migration. For new columns, prefer the inline form:\r\n * `this.integer(\"user_id\").references(\"users\").onDelete(\"cascade\")`\r\n *\r\n * SQL-only feature; NoSQL drivers ignore foreign keys.\r\n *\r\n * @param column - Local column that references another table\r\n * @returns Foreign key builder for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * this.foreign(\"user_id\")\r\n * .references(\"users\", \"id\")\r\n * .onDelete(\"cascade\");\r\n * ```\r\n */\r\n public foreign(column: string): ForeignKeyBuilder {\r\n return new ForeignKeyBuilder(this, column);\r\n }\r\n\r\n /**\r\n * Drop a foreign key constraint.\r\n *\r\n * Two calling forms:\r\n *\r\n * 1. Auto-compute the name (matches what `addForeignKey` generates):\r\n * ```typescript\r\n * this.dropForeign(\"unit_id\", Unit.table);\r\n * // → drops: fk_{table}_unit_id_units\r\n * ```\r\n *\r\n * 2. Raw constraint name (use when the name was set explicitly):\r\n * ```typescript\r\n * this.dropForeign(\"my_custom_fk_name\");\r\n * ```\r\n *\r\n * @param columnOrConstraint - Column name (auto mode) or raw constraint name (raw mode)\r\n * @param referencesTable - Referenced table name; triggers auto-name computation when provided\r\n * @returns This migration for chaining\r\n */\r\n public dropForeign(columnOrConstraint: string, referencesTable?: string): this {\r\n const constraintName = referencesTable\r\n ? `fk_${this.table}_${columnOrConstraint}_${referencesTable}`\r\n : columnOrConstraint;\r\n this.pendingOperations.push({ type: \"dropForeignKey\", payload: constraintName });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // SCHEMA VALIDATION (NoSQL)\r\n // ============================================================================\r\n\r\n /**\r\n * Set JSON schema validation rules on the collection.\r\n *\r\n * MongoDB-only feature. SQL databases ignore this.\r\n *\r\n * @param schema - JSON Schema object\r\n * @returns This migration for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * this.schemaValidation({\r\n * bsonType: \"object\",\r\n * required: [\"name\", \"email\"],\r\n * properties: {\r\n * name: { bsonType: \"string\" },\r\n * email: { bsonType: \"string\" },\r\n * },\r\n * });\r\n * ```\r\n */\r\n public schemaValidation(schema: object): this {\r\n this.pendingOperations.push({\r\n type: \"setSchemaValidation\",\r\n payload: schema,\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Remove schema validation rules from the collection.\r\n *\r\n * @returns This migration for chaining\r\n */\r\n public dropSchemaValidation(): this {\r\n this.pendingOperations.push({\r\n type: \"removeSchemaValidation\",\r\n payload: null,\r\n });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // RAW ACCESS\r\n // ============================================================================\r\n\r\n /**\r\n * Execute raw operations with direct driver/connection access.\r\n *\r\n * Use this when you need to bypass the migration API entirely and\r\n * interact with the native database driver directly.\r\n *\r\n * @param callback - Callback receiving the native connection\r\n * @returns Result from callback\r\n *\r\n * @example\r\n * ```typescript\r\n * await this.withConnection(async (db) => {\r\n * await db.collection(\"users\").updateMany({}, { $set: { active: true } });\r\n * });\r\n * ```\r\n */\r\n public async withConnection<T>(callback: (connection: unknown) => Promise<T>): Promise<T> {\r\n return this.driver.raw(callback);\r\n }\r\n\r\n /**\r\n * Queue a raw SQL string for execution within the migration.\r\n *\r\n * The statement is queued and executed in order with other migration\r\n * operations, within the transaction context if the migration is transactional.\r\n *\r\n * Use `withConnection()` instead if you need direct driver access.\r\n *\r\n * Works with PostgreSQL, MySQL, etc. For MongoDB, uses $eval command.\r\n *\r\n * @param sql - SQL statement to execute\r\n * @returns This migration for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * // Enable PostgreSQL extension\r\n * this.raw('CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"');\r\n *\r\n * // Create custom type\r\n * this.raw('CREATE TYPE mood AS ENUM (\\'happy\\', \\'sad\\', \\'neutral\\')');\r\n * ```\r\n */\r\n public raw(sql: string): this {\r\n this.pendingOperations.push({\r\n type: \"rawStatement\",\r\n payload: sql,\r\n });\r\n return this;\r\n }\r\n\r\n // ============================================================================\r\n // DECLARATIVE FACTORY STUBS\r\n // These are assigned after the class body — declared here so TS knows the\r\n // shape of the static members without triggering abstract-class restrictions.\r\n // ============================================================================\r\n\r\n /**\r\n * Create a declarative initial-table migration.\r\n * Implemented and assigned below the class body.\r\n */\r\n public static create: (\r\n model: ChildModel<Model<any>>,\r\n columns: ColumnMap,\r\n options?: MigrationCreateOptions,\r\n ) => MigrationConstructor;\r\n\r\n /**\r\n * Create a declarative alteration migration.\r\n * Implemented and assigned below the class body.\r\n */\r\n public static alter: (\r\n model: ChildModel<Model<any>>,\r\n schema: AlterSchema,\r\n options?: MigrationAlterOptions,\r\n ) => MigrationConstructor;\r\n}\r\n\r\nexport function migrate(\r\n model: ChildModel<Model<any>>,\r\n options?: {\r\n createdAt?: string;\r\n name?: string;\r\n up?: (this: MigrationContract) => void | Promise<void>;\r\n down?: (this: MigrationContract) => void | Promise<void>;\r\n transactional?: boolean;\r\n },\r\n): MigrationConstructor {\r\n return class AnonymousMigration extends Migration {\r\n public static migrationName?: string = options?.name;\r\n public static createdAt?: string = options?.createdAt;\r\n public readonly table: string = model.table;\r\n public static transactional?: boolean = options?.transactional;\r\n\r\n public async up() {\r\n await options?.up?.call(this);\r\n }\r\n\r\n public async down() {\r\n await options?.down?.call(this);\r\n }\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// DECLARATIVE FACTORIES\r\n// ============================================================================\r\n\r\n/**\r\n * A single composite index entry for `Migration.create()` options.\r\n *\r\n * @example\r\n * ```typescript\r\n * // Simple — columns only, name and type auto-resolved\r\n * { columns: [\"organization_id\", \"content_type\"] }\r\n *\r\n * // Named\r\n * { columns: [\"organization_id\", \"content_type\"], name: \"idx_org_content\" }\r\n *\r\n * // Typed (PostgreSQL)\r\n * { columns: [\"embedding\"], using: \"ivfflat\" }\r\n * ```\r\n */\r\nexport type IndexEntry = {\r\n /** Column(s) to include in the index. */\r\n columns: string | string[];\r\n /** Optional explicit index name. Auto-generated when omitted. */\r\n name?: string;\r\n /**\r\n * Index access method (PostgreSQL).\r\n * Defaults to `\"btree\"` when omitted.\r\n */\r\n using?: \"btree\" | \"hash\" | \"gin\" | \"gist\" | \"brin\" | \"ivfflat\" | \"hnsw\" | (string & {});\r\n /** Extra columns to include in a covering index (PostgreSQL `INCLUDE`). */\r\n include?: string[];\r\n /** Build the index without locking the table (PostgreSQL). */\r\n concurrently?: boolean;\r\n};\r\n\r\n/**\r\n * A single composite unique constraint entry for `Migration.create()` options.\r\n *\r\n * @example\r\n * ```typescript\r\n * // Simple\r\n * { columns: [\"organization_id\", \"email\"] }\r\n *\r\n * // Named — useful when you need to reference it in a future ALTER\r\n * { columns: [\"org_id\", \"content_id\", \"lang\"], name: \"uq_summary_idempotency\" }\r\n * ```\r\n */\r\nexport type UniqueEntry = {\r\n /** Column(s) that must be unique together. */\r\n columns: string | string[];\r\n /** Optional explicit constraint name. Auto-generated when omitted. */\r\n name?: string;\r\n /** Extra columns to include (PostgreSQL covering unique index). */\r\n include?: string[];\r\n /** Build the constraint without locking the table (PostgreSQL). */\r\n concurrently?: boolean;\r\n};\r\n\r\n/**\r\n * Options accepted by `Migration.create()`.\r\n */\r\nexport type MigrationCreateOptions = {\r\n /**\r\n * Sort order override.\r\n * @default 0\r\n */\r\n order?: number;\r\n\r\n /**\r\n * ISO timestamp override for migration ordering.\r\n * Normally extracted from the filename by the runner.\r\n */\r\n createdAt?: string;\r\n\r\n /**\r\n * Override the primary key type for this migration only.\r\n *\r\n * - `\"uuid\"` — UUID primary key (uses `primaryUuid()`)\r\n * - `\"int\"` — Auto-increment integer (uses `id()`)\r\n * - `\"bigInt\"` — Big auto-increment integer (uses `bigId()`)\r\n * - `false` — Skip primary key generation entirely\r\n *\r\n * When omitted, falls back to `migrationDefaults.primaryKey` from the\r\n * DataSource config, then to `\"int\"` as the framework default.\r\n */\r\n primaryKey?: \"uuid\" | \"int\" | \"bigInt\" | false;\r\n\r\n /**\r\n * Whether to add `timestamps()` (created_at / updated_at).\r\n * @default true\r\n */\r\n timestamps?: boolean;\r\n\r\n /**\r\n * Whether to wrap this migration in a transaction.\r\n * Falls back to DataSource / driver defaults when omitted.\r\n */\r\n transactional?: boolean;\r\n\r\n /**\r\n * Composite indexes to create on the table.\r\n *\r\n * Use this for multi-column indexes. Single-column indexes should be\r\n * defined at the column level via `.index()`.\r\n *\r\n * @example\r\n * ```typescript\r\n * index: [\r\n * { columns: [\"organization_id\", \"content_type\", \"content_id\"] },\r\n * { columns: [\"organization_id\", \"status\"], name: \"idx_org_status\" },\r\n * ]\r\n * ```\r\n */\r\n index?: IndexEntry[];\r\n\r\n /**\r\n * Composite unique constraints to create on the table.\r\n *\r\n * Use this for multi-column uniqueness. Single-column unique constraints\r\n * should be defined at the column level via `.unique()`.\r\n *\r\n * @example\r\n * ```typescript\r\n * unique: [\r\n * {\r\n * columns: [\"organization_id\", \"content_id\", \"content_language\"],\r\n * name: \"uq_summary_idempotency\",\r\n * },\r\n * ]\r\n * ```\r\n */\r\n unique?: UniqueEntry[];\r\n\r\n /**\r\n * Custom logic to execute after the declarative definitions.\r\n * Useful for data seeding or raw SQL following table creation.\r\n */\r\n up?: (this: Migration) => void | Promise<void>;\r\n\r\n /**\r\n * Raw SQL queries to run before the custom `up` logic.\r\n * Useful for triggering statements or custom constraints.\r\n */\r\n raw?: string | string[];\r\n\r\n /**\r\n * Custom rollback logic to execute before the default `dropTableIfExists`.\r\n */\r\n down?: (this: Migration) => void | Promise<void>;\r\n};\r\n\r\n/**\r\n * Column map accepted by `Migration.create()` and `Migration.alter()`.\r\n *\r\n * Keys become the column names; values are `DetachedColumnBuilder` instances\r\n * produced by the standalone column helpers (`uuid()`, `text()`, etc.).\r\n */\r\nexport type ColumnMap = Record<string, import(\"./column-helpers\").DetachedColumnBuilder>;\r\n\r\n/**\r\n * Options accepted by `Migration.alter()`.\r\n */\r\nexport type MigrationAlterOptions = {\r\n /** Sort order override. */\r\n order?: number;\r\n /** ISO timestamp override. */\r\n createdAt?: string;\r\n /** Whether to wrap in a transaction. */\r\n transactional?: boolean;\r\n\r\n /**\r\n * Custom logic to execute after the declarative definitions.\r\n */\r\n up?: (this: Migration) => void | Promise<void>;\r\n\r\n /**\r\n * Custom rollback logic to execute on rollback.\r\n * Unlike `create()`, `alter()` does not auto-infer rollbacks.\r\n */\r\n down?: (this: Migration) => void | Promise<void>;\r\n};\r\n\r\n/**\r\n * Schema map passed to `Migration.alter()`.\r\n *\r\n * Groups all table-level DDL operations by intent.\r\n * Any key can be omitted when not needed.\r\n *\r\n * @example\r\n * ```typescript\r\n * export default Migration.alter(User, {\r\n * // Column operations\r\n * add: { phone: text().nullable() },\r\n * drop: [\"legacy_column\"],\r\n * rename: { old_name: \"new_name\" },\r\n * modify: { email: string(320).notNullable() },\r\n *\r\n * // Index / constraint operations\r\n * addIndex: [{ columns: [\"first_name\", \"last_name\"] }],\r\n * addUnique: [{ columns: [\"email\"] }],\r\n * addForeign: [{ column: \"team_id\", references: Team }],\r\n * dropIndexes: [\"old_idx_name\"],\r\n * dropUnique: [[\"email\"]],\r\n * });\r\n * ```\r\n */\r\nexport type AlterSchema = {\r\n // ============================================================================\r\n // Column Operations\r\n // ============================================================================\r\n\r\n /** Columns to add. Keys become column names. */\r\n add?: ColumnMap;\r\n\r\n /** Column names to drop. */\r\n drop?: string[];\r\n\r\n /** Rename map: `{ oldName: newName }`. */\r\n rename?: Record<string, string>;\r\n\r\n /** Columns to modify. Keys become column names. */\r\n modify?: ColumnMap;\r\n\r\n // ============================================================================\r\n // Index Operations\r\n // ============================================================================\r\n\r\n /**\r\n * Regular indexes to add.\r\n *\r\n * @example\r\n * ```typescript\r\n * addIndex: [\r\n * { columns: \"email\" },\r\n * { columns: [\"first_name\", \"last_name\"], name: \"idx_full_name\" },\r\n * { columns: \"email\", options: { concurrently: true } },\r\n * ]\r\n * ```\r\n */\r\n addIndex?: Array<{\r\n columns: string | string[];\r\n name?: string;\r\n options?: { include?: string[]; concurrently?: boolean };\r\n }>;\r\n\r\n /**\r\n * Indexes to drop (by name or columns array).\r\n *\r\n * @example\r\n * ```typescript\r\n * dropIndex: [\"idx_old_name\", [\"first_name\", \"last_name\"]]\r\n * ```\r\n */\r\n dropIndex?: Array<string | string[]>;\r\n\r\n /**\r\n * Unique constraints / indexes to add.\r\n *\r\n * @example\r\n * ```typescript\r\n * addUnique: [{ columns: \"email\" }]\r\n * ```\r\n */\r\n addUnique?: Array<{\r\n columns: string | string[];\r\n name?: string;\r\n options?: { include?: string[]; concurrently?: boolean };\r\n }>;\r\n\r\n /**\r\n * Unique constraints to drop (by columns array).\r\n *\r\n * @example\r\n * ```typescript\r\n * dropUnique: [[\"email\"], [\"phone\"]]\r\n * ```\r\n */\r\n dropUnique?: Array<string | string[]>;\r\n\r\n /**\r\n * Expression-based indexes to add (PostgreSQL-specific).\r\n *\r\n * @example\r\n * ```typescript\r\n * addExpressionIndex: [\r\n * { expressions: \"lower(email)\", name: \"idx_email_lower\" },\r\n * ]\r\n * ```\r\n */\r\n addExpressionIndex?: Array<{\r\n expressions: string | string[];\r\n name?: string;\r\n options?: { concurrently?: boolean };\r\n }>;\r\n\r\n // ============================================================================\r\n // Specialized Indexes\r\n // ============================================================================\r\n\r\n /**\r\n * Full-text search indexes to add.\r\n *\r\n * @example\r\n * ```typescript\r\n * addFullText: [{ columns: [\"title\", \"body\"] }]\r\n * ```\r\n */\r\n addFullText?: Array<{\r\n columns: string | string[];\r\n options?: FullTextIndexOptions;\r\n }>;\r\n\r\n /** Full-text indexes to drop (by name). */\r\n dropFullText?: string[];\r\n\r\n /**\r\n * Geo-spatial indexes to add.\r\n *\r\n * @example\r\n * ```typescript\r\n * addGeoIndex: [{ column: \"location\" }]\r\n * ```\r\n */\r\n addGeoIndex?: Array<{\r\n column: string;\r\n options?: GeoIndexOptions;\r\n }>;\r\n\r\n /** Geo indexes to drop (by column name). */\r\n dropGeoIndex?: string[];\r\n\r\n /**\r\n * Vector search indexes to add.\r\n *\r\n * @example\r\n * ```typescript\r\n * addVectorIndex: [{ column: \"embedding\", options: { dimensions: 1536, similarity: \"cosine\" } }]\r\n * ```\r\n */\r\n addVectorIndex?: Array<{\r\n column: string;\r\n options: VectorIndexOptions;\r\n }>;\r\n\r\n /** Vector indexes to drop (by column name). */\r\n dropVectorIndex?: string[];\r\n\r\n /**\r\n * TTL indexes to add (MongoDB-primary).\r\n *\r\n * @example\r\n * ```typescript\r\n * addTTLIndex: [{ column: \"created_at\", expireAfterSeconds: 86400 }]\r\n * ```\r\n */\r\n addTTLIndex?: Array<{ column: string; expireAfterSeconds: number }>;\r\n\r\n /** TTL indexes to drop (by column name). */\r\n dropTTLIndex?: string[];\r\n\r\n // ============================================================================\r\n // Constraints (SQL)\r\n // ============================================================================\r\n\r\n /**\r\n * Foreign keys to add to existing columns.\r\n *\r\n * Accepts a Model class or a raw table-name string for `references`.\r\n *\r\n * @example\r\n * ```typescript\r\n * addForeign: [\r\n * { column: \"team_id\", references: Team, onDelete: \"cascade\" },\r\n * { column: \"owner_id\", references: \"users\", on: \"id\", onDelete: \"setNull\" },\r\n * ]\r\n * ```\r\n */\r\n addForeign?: Array<{\r\n column: string;\r\n references: string | { table: string };\r\n on?: string;\r\n onDelete?: \"cascade\" | \"restrict\" | \"setNull\" | \"noAction\";\r\n onUpdate?: \"cascade\" | \"restrict\" | \"setNull\" | \"noAction\";\r\n }>;\r\n\r\n /**\r\n * Foreign keys to drop.\r\n *\r\n * Two forms:\r\n * - `{ columnOrConstraint: \"team_id\", referencesTable: \"teams\" }` → auto-name resolution\r\n * - `{ columnOrConstraint: \"fk_my_custom_name\" }` → raw constraint name\r\n */\r\n dropForeign?: Array<{ columnOrConstraint: string; referencesTable?: string }>;\r\n\r\n /**\r\n * CHECK constraints to add.\r\n *\r\n * @example\r\n * ```typescript\r\n * addCheck: [{ name: \"age_positive\", expression: \"age >= 0\" }]\r\n * ```\r\n */\r\n addCheck?: Array<{ name: string; expression: string }>;\r\n\r\n /** CHECK constraints to drop (by name). */\r\n dropCheck?: string[];\r\n\r\n // ============================================================================\r\n // Raw SQL\r\n // ============================================================================\r\n\r\n /**\r\n * Raw SQL queries to execute as part of this alter operation.\r\n */\r\n raw?: string | string[];\r\n};\r\n\r\n/**\r\n * Wire a `ColumnMap` onto an active migration instance.\r\n *\r\n * Fixes up the placeholder column name in each `DetachedColumnBuilder`,\r\n * pushes the `addColumn` operation, and transfers any pending FK / index\r\n * side effects from the detached sink to the real migration.\r\n *\r\n * @internal\r\n */\r\nfunction wireColumns(migration: Migration, columns: ColumnMap): void {\r\n for (const [columnName, detached] of Object.entries(columns)) {\r\n // Overwrite the placeholder name with the real key\r\n const definition = detached.getDefinition();\r\n (definition as any).name = columnName;\r\n\r\n // Push the addColumn operation\r\n (migration as any).pendingOperations.push({\r\n type: \"addColumn\",\r\n payload: definition,\r\n });\r\n\r\n // Transfer any index operations registered via .unique() / .index()\r\n // Replace the placeholder column name with the real column name before transfer.\r\n for (const idx of detached.sink.pendingIndexes) {\r\n idx.columns = idx.columns.map((col) => (col === \"__placeholder__\" ? columnName : col));\r\n migration.addPendingIndex(idx);\r\n }\r\n\r\n // Transfer any FK operations registered via .references()\r\n for (const fk of detached.sink.pendingForeignKeys as any[]) {\r\n // Fix the column name on the FK definition too\r\n fk.column = columnName;\r\n migration.addForeignKeyOperation(fk);\r\n }\r\n\r\n // Transfer any Vector indexes registered via .vectorIndex()\r\n if (detached.sink.pendingVectorIndexes) {\r\n for (const vIdx of detached.sink.pendingVectorIndexes) {\r\n vIdx.column = columnName;\r\n migration.vectorIndex(vIdx.column, vIdx.options);\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Create a declarative initial-table migration.\r\n *\r\n * Automatically handles:\r\n * - `createTableIfNotExists()`\r\n * - Primary key (type resolved from `migrationDefaults.primaryKey` → options → `\"int\"`)\r\n * - `timestamps()`\r\n * - `down()` → `dropTableIfExists()`\r\n *\r\n * The class-based API remains available for complex migrations (raw SQL,\r\n * data backfills, conditional logic).\r\n *\r\n * @param model - Model class to bind (provides table name + data source)\r\n * @param columns - Column definitions keyed by column name\r\n * @param options - Optional overrides\r\n *\r\n * @example\r\n * ```typescript\r\n * import { Migration, uuid, text, timestamp } from \"@warlock.js/cascade\";\r\n * import { Organization } from \"app/organizations/models/organization\";\r\n * import { Chat } from \"../chat.model\";\r\n *\r\n * export default Migration.create(Chat, {\r\n * organization_id: uuid().references(Organization).onDelete(\"cascade\"),\r\n * title: text(),\r\n * status: text(),\r\n * started_at: timestamp().default(\"NOW()\"),\r\n * closed_at: timestamp().nullable(),\r\n * }, { order: 5 });\r\n * ```\r\n */\r\nMigration.create = function createMigration(\r\n model: ChildModel<Model<any>>,\r\n columns: ColumnMap,\r\n options: MigrationCreateOptions = {},\r\n): MigrationConstructor {\r\n const {\r\n order = 0,\r\n createdAt,\r\n primaryKey: primaryKeyOverride,\r\n timestamps: withTimestamps = true,\r\n transactional,\r\n } = options;\r\n\r\n return class DeclarativeMigration extends Migration {\r\n public static readonly order = order;\r\n public static readonly createdAt = createdAt;\r\n public static readonly transactional = transactional;\r\n public readonly table = model.table;\r\n public readonly dataSource = model.dataSource;\r\n\r\n public async up(): Promise<void> {\r\n this.createTableIfNotExists();\r\n\r\n // Resolve primary key type: option → migrationDefaults → \"int\"\r\n const pkType =\r\n primaryKeyOverride !== undefined\r\n ? primaryKeyOverride\r\n : (this._migrationDefaults?.primaryKey ?? \"int\");\r\n\r\n if (pkType === \"uuid\") {\r\n this.primaryUuid();\r\n } else if (pkType === \"bigInt\") {\r\n this.bigId();\r\n } else if (pkType === \"int\") {\r\n this.id();\r\n }\r\n // pkType === false → skip primary key\r\n\r\n wireColumns(this, columns);\r\n\r\n if (withTimestamps) {\r\n this.timestamps();\r\n }\r\n\r\n // ── Composite indexes ───────────────────────────────────────────────\r\n if (options.index) {\r\n for (const entry of options.index) {\r\n this.index(entry.columns, entry.name, {\r\n include: entry.include,\r\n concurrently: entry.concurrently,\r\n });\r\n }\r\n }\r\n\r\n // ── Composite unique constraints ────────────────────────────────────\r\n if (options.unique) {\r\n for (const entry of options.unique) {\r\n this.unique(entry.columns, entry.name, {\r\n include: entry.include,\r\n concurrently: entry.concurrently,\r\n });\r\n }\r\n }\r\n\r\n if (options.raw) {\r\n const rawQueries = Array.isArray(options.raw) ? options.raw : [options.raw];\r\n for (const query of rawQueries) {\r\n this.raw(query);\r\n }\r\n }\r\n\r\n if (options.up) {\r\n await options.up.call(this as unknown as Migration);\r\n }\r\n }\r\n\r\n public async down(): Promise<void> {\r\n if (options.down) {\r\n await options.down.call(this as unknown as Migration);\r\n }\r\n this.dropTableIfExists();\r\n }\r\n } as unknown as MigrationConstructor;\r\n};\r\n\r\n/**\r\n * Create a declarative alteration migration.\r\n *\r\n * @param model - Model class to bind\r\n * @param schema - What to add / drop / rename / modify\r\n * @param options - Optional overrides\r\n *\r\n * @example\r\n * ```typescript\r\n * import { Migration, text } from \"@warlock.js/cascade\";\r\n * import { User } from \"../user.model\";\r\n *\r\n * export default Migration.alter(User, {\r\n * add: {\r\n * phone: text().nullable(),\r\n * avatar: text().nullable(),\r\n * },\r\n * drop: [\"legacy_field\"],\r\n * rename: { old_name: \"new_name\" },\r\n * });\r\n * ```\r\n */\r\nMigration.alter = function alterMigration(\r\n model: ChildModel<Model<any>>,\r\n schema: AlterSchema,\r\n options: MigrationAlterOptions = {},\r\n): MigrationConstructor {\r\n const { order = 0, createdAt, transactional } = options;\r\n\r\n return class AlterMigration extends Migration {\r\n public static readonly order = order;\r\n public static readonly createdAt = createdAt;\r\n public static readonly transactional = transactional;\r\n public readonly table = model.table;\r\n public readonly dataSource = model.dataSource;\r\n\r\n public async up(): Promise<void> {\r\n // ── Column Operations ─────────────────────────────────────────────────\r\n if (schema.add) {\r\n wireColumns(this, schema.add);\r\n }\r\n\r\n if (schema.drop) {\r\n for (const col of schema.drop) {\r\n this.dropColumn(col);\r\n }\r\n }\r\n\r\n if (schema.rename) {\r\n for (const [from, to] of Object.entries(schema.rename)) {\r\n this.renameColumn(from, to);\r\n }\r\n }\r\n\r\n if (schema.modify) {\r\n for (const [columnName, detached] of Object.entries(schema.modify)) {\r\n const definition = detached.getDefinition();\r\n (definition as any).name = columnName;\r\n\r\n (this as any).pendingOperations.push({\r\n type: \"modifyColumn\",\r\n payload: definition,\r\n });\r\n\r\n // Transfer FK side effects\r\n for (const fk of detached.sink.pendingForeignKeys as any[]) {\r\n fk.column = columnName;\r\n this.addForeignKeyOperation(fk);\r\n }\r\n }\r\n }\r\n\r\n // ── Regular Indexes ───────────────────────────────────────────────────\r\n if (schema.addIndex) {\r\n for (const { columns, name, options: opts } of schema.addIndex) {\r\n this.index(columns, name, opts);\r\n }\r\n }\r\n\r\n if (schema.dropIndex) {\r\n for (const target of schema.dropIndex) {\r\n this.dropIndex(target);\r\n }\r\n }\r\n\r\n // ── Unique Indexes ────────────────────────────────────────────────────\r\n if (schema.addUnique) {\r\n for (const { columns, name, options: opts } of schema.addUnique) {\r\n this.unique(columns, name, opts);\r\n }\r\n }\r\n\r\n if (schema.dropUnique) {\r\n for (const cols of schema.dropUnique) {\r\n this.dropUnique(cols);\r\n }\r\n }\r\n\r\n // ── Expression Indexes ───────────────────────────────────────────────\r\n if (schema.addExpressionIndex) {\r\n for (const { expressions, name, options: opts } of schema.addExpressionIndex) {\r\n this.expressionIndex(expressions, name, opts);\r\n }\r\n }\r\n\r\n // ── Specialized Indexes ───────────────────────────────────────────────\r\n if (schema.addFullText) {\r\n for (const { columns, options: opts } of schema.addFullText) {\r\n this.fullText(columns, opts);\r\n }\r\n }\r\n\r\n if (schema.dropFullText) {\r\n for (const name of schema.dropFullText) {\r\n this.dropFullText(name);\r\n }\r\n }\r\n\r\n if (schema.addGeoIndex) {\r\n for (const { column, options: opts } of schema.addGeoIndex) {\r\n this.geoIndex(column, opts);\r\n }\r\n }\r\n\r\n if (schema.dropGeoIndex) {\r\n for (const column of schema.dropGeoIndex) {\r\n this.dropGeoIndex(column);\r\n }\r\n }\r\n\r\n if (schema.addVectorIndex) {\r\n for (const { column, options: opts } of schema.addVectorIndex) {\r\n this.vectorIndex(column, opts);\r\n }\r\n }\r\n\r\n if (schema.dropVectorIndex) {\r\n for (const column of schema.dropVectorIndex) {\r\n this.dropVectorIndex(column);\r\n }\r\n }\r\n\r\n if (schema.addTTLIndex) {\r\n for (const { column, expireAfterSeconds } of schema.addTTLIndex) {\r\n this.ttlIndex(column, expireAfterSeconds);\r\n }\r\n }\r\n\r\n if (schema.dropTTLIndex) {\r\n for (const column of schema.dropTTLIndex) {\r\n this.dropTTLIndex(column);\r\n }\r\n }\r\n\r\n // ── Foreign Keys ──────────────────────────────────────────────────────\r\n if (schema.addForeign) {\r\n for (const fk of schema.addForeign) {\r\n const tableName = typeof fk.references === \"string\" ? fk.references : fk.references.table;\r\n\r\n this.foreign(fk.column)\r\n .references(tableName, fk.on ?? \"id\")\r\n .onDelete(fk.onDelete ?? \"restrict\")\r\n .onUpdate(fk.onUpdate ?? \"restrict\");\r\n }\r\n }\r\n\r\n if (schema.dropForeign) {\r\n for (const { columnOrConstraint, referencesTable } of schema.dropForeign) {\r\n this.dropForeign(columnOrConstraint, referencesTable);\r\n }\r\n }\r\n\r\n // ── Check Constraints ─────────────────────────────────────────────────\r\n if (schema.addCheck) {\r\n for (const { name, expression } of schema.addCheck) {\r\n this.check(name, expression);\r\n }\r\n }\r\n\r\n if (schema.dropCheck) {\r\n for (const name of schema.dropCheck) {\r\n this.dropCheck(name);\r\n }\r\n }\r\n\r\n // ── Raw SQL ───────────────────────────────────────────────────────────\r\n if (schema.raw) {\r\n const rawQueries = Array.isArray(schema.raw) ? schema.raw : [schema.raw];\r\n for (const query of rawQueries) {\r\n this.raw(query);\r\n }\r\n }\r\n\r\n if (options.up) {\r\n await options.up.call(this as unknown as Migration);\r\n }\r\n }\r\n\r\n public async down(): Promise<void> {\r\n if (options.down) {\r\n await options.down.call(this as unknown as Migration);\r\n }\r\n }\r\n } as unknown as MigrationConstructor;\r\n};\r\n\r\n// The no-op re-assignments below silence the TS \"used before assigned\" check;\r\n// the real implementations are set by the Migration.create = ... and\r\n// Migration.alter = ... blocks immediately above.\r\n(Migration as any).__declarativeFactoriesAttached = true;\r\n","import type { SQLStatementType, TaggedSQL } from \"./types\";\n\n/**\n * Parses and sorts SQL statements globally based on their execution phase,\n * and classifies statements by their semantic type.\n */\nexport class SQLGrammar {\n /**\n * Determine the execution phase of a SQL statement (1–6).\n *\n * Phase ordering ensures DDL operations run in dependency-safe order\n * regardless of which migration file they originate from.\n *\n * | Phase | Statements |\n * |-------|-----------------------------------------------|\n * | 1 | CREATE EXTENSION, TYPE, DOMAIN, SCHEMA |\n * | 2 | CREATE TABLE |\n * | 3 | ADD COLUMN, ADD PRIMARY KEY |\n * | 4 | CREATE INDEX, ADD FOREIGN KEY |\n * | 5 | DROP COLUMN, ALTER COLUMN, DROP TABLE |\n * | 6 | Raw / unclassified |\n *\n * @example\n * SQLGrammar.phase(\"CREATE EXTENSION IF NOT EXISTS vector\"); // => 1\n * SQLGrammar.phase(\"ALTER TABLE users ADD COLUMN email TEXT\"); // => 3\n */\n public static phase(sql: string): 1 | 2 | 3 | 4 | 5 | 6 {\n const s = sql.trim().toUpperCase();\n\n // Phase 1: Preparation (Extensions, Enums, Domains, Types)\n if (\n s.startsWith(\"CREATE EXTENSION\") ||\n s.startsWith(\"CREATE TYPE\") ||\n s.startsWith(\"CREATE DOMAIN\") ||\n s.startsWith(\"CREATE SCHEMA\")\n ) {\n return 1;\n }\n\n // Phase 2: Table Creation\n if (s.startsWith(\"CREATE TABLE\")) {\n return 2;\n }\n\n // Phase 3 / 4 / 5: ALTER TABLE — broken down by clause\n if (s.startsWith(\"ALTER TABLE\")) {\n if (s.includes(\"ADD CONSTRAINT\") && s.includes(\"FOREIGN KEY\")) return 4;\n if (s.includes(\"DROP COLUMN\") || s.includes(\"DROP CONSTRAINT\") || s.includes(\"ALTER COLUMN\")) return 5;\n if (s.includes(\"ADD COLUMN\")) return 3;\n if (s.includes(\"ADD CONSTRAINT\") && s.includes(\"PRIMARY KEY\")) return 3;\n }\n\n // Phase 4: Index Creation\n if (s.startsWith(\"CREATE INDEX\") || s.startsWith(\"CREATE UNIQUE INDEX\")) {\n return 4;\n }\n\n // Phase 5: Destructive table/index operations\n if (s.startsWith(\"DROP TABLE\") || s.startsWith(\"TRUNCATE TABLE\") || s.startsWith(\"DROP INDEX\")) {\n return 5;\n }\n\n // Phase 6: Raw / unclassified (DML, triggers, procedures, views)\n return 6;\n }\n\n /**\n * Classify a SQL statement into its semantic statement type.\n *\n * This is independent of execution phase — it identifies *what* a statement\n * does, not *when* it should run. Use this for pre-flight checks, dry-run\n * display, selective filtering, and extension detection.\n *\n * @example\n * SQLGrammar.classify(\"CREATE EXTENSION IF NOT EXISTS vector\");\n * // => \"CREATE_EXTENSION\"\n *\n * SQLGrammar.classify(\"ALTER TABLE users ADD COLUMN email TEXT\");\n * // => \"ADD_COLUMN\"\n */\n public static classify(sql: string): SQLStatementType {\n const s = sql.trim().toUpperCase();\n\n if (s.startsWith(\"CREATE EXTENSION\")) return \"CREATE_EXTENSION\";\n if (s.startsWith(\"CREATE SCHEMA\")) return \"CREATE_SCHEMA\";\n if (s.startsWith(\"CREATE TYPE\")) return \"CREATE_TYPE\";\n if (s.startsWith(\"CREATE DOMAIN\")) return \"CREATE_DOMAIN\";\n if (s.startsWith(\"CREATE TABLE\")) return \"CREATE_TABLE\";\n if (s.startsWith(\"DROP TABLE\")) return \"DROP_TABLE\";\n if (s.startsWith(\"TRUNCATE TABLE\")) return \"TRUNCATE_TABLE\";\n if (s.startsWith(\"DROP INDEX\")) return \"DROP_INDEX\";\n\n // Must check UNIQUE before plain INDEX to avoid misclassification\n if (s.startsWith(\"CREATE UNIQUE INDEX\")) return \"CREATE_UNIQUE_INDEX\";\n if (s.startsWith(\"CREATE INDEX\")) return \"CREATE_INDEX\";\n\n if (s.startsWith(\"ALTER TABLE\")) {\n if (s.includes(\"ADD CONSTRAINT\") && s.includes(\"FOREIGN KEY\")) return \"ADD_FOREIGN_KEY\";\n if (s.includes(\"DROP CONSTRAINT\") && s.includes(\"FOREIGN KEY\")) return \"DROP_FOREIGN_KEY\";\n if (s.includes(\"ADD CONSTRAINT\") && s.includes(\"PRIMARY KEY\")) return \"ADD_PRIMARY_KEY\";\n if (s.includes(\"DROP CONSTRAINT\")) return \"DROP_PRIMARY_KEY\";\n if (s.includes(\"ADD COLUMN\")) return \"ADD_COLUMN\";\n if (s.includes(\"DROP COLUMN\")) return \"DROP_COLUMN\";\n if (s.includes(\"RENAME COLUMN\")) return \"RENAME_COLUMN\";\n if (s.includes(\"RENAME TO\")) return \"RENAME_TABLE\";\n if (s.includes(\"ALTER COLUMN\")) return \"MODIFY_COLUMN\";\n }\n\n return \"RAW\";\n }\n\n /**\n * Extract the extension name from a CREATE EXTENSION statement.\n *\n * Returns undefined if the statement is not a CREATE EXTENSION statement\n * or the name cannot be parsed.\n *\n * @example\n * SQLGrammar.extractExtensionName(\"CREATE EXTENSION IF NOT EXISTS vector\");\n * // => \"vector\"\n *\n * SQLGrammar.extractExtensionName(\"CREATE EXTENSION postgis\");\n * // => \"postgis\"\n */\n public static extractExtensionName(sql: string): string | undefined {\n // Matches: CREATE EXTENSION [IF NOT EXISTS] <name>\n const match = sql\n .trim()\n .match(/^CREATE\\s+EXTENSION\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(\\w+)/i);\n\n return match?.[1]?.toLowerCase();\n }\n\n /**\n * Sort an array of tagged SQL statements by phase, then creation date, then migration name.\n */\n public static sort(statements: TaggedSQL[]): TaggedSQL[] {\n return statements.slice().sort((a, b) => {\n // 1. Sort by Phase (ascending)\n if (a.phase !== b.phase) {\n return a.phase - b.phase;\n }\n\n // 2. Sort by CreatedAt (within same phase)\n let dateA = a.createdAt ? new Date(a.createdAt).getTime() : 0;\n let dateB = b.createdAt ? new Date(b.createdAt).getTime() : 0;\n if (isNaN(dateA)) dateA = 0;\n if (isNaN(dateB)) dateB = 0;\n\n if (dateA !== dateB) {\n return dateA - dateB;\n }\n\n // 3. Sort by Migration Name (tie-breaker)\n const nameA = a.migrationName || \"\";\n const nameB = b.migrationName || \"\";\n return nameA.localeCompare(nameB);\n });\n }\n}\n","import { colors } from \"@mongez/copper\";\nimport { log } from \"@warlock.js/logger\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport type { MigrationDriverContract } from \"../contracts/migration-driver.contract\";\nimport type { DataSource } from \"../data-source/data-source\";\nimport { dataSourceRegistry } from \"../data-source/data-source-registry\";\nimport { type Migration } from \"./migration\";\nimport { SQLGrammar } from \"./sql-grammar\";\nimport type { MigrationRecord, MigrationResult, TaggedSQL } from \"./types\";\n\n/**\n * Migration class type with static name property.\n */\ntype MigrationClass = (new () => Migration) & {\n migrationName: string;\n createdAt?: string;\n};\n\n/**\n * Resolved instance data for a single pending migration.\n * @internal\n */\ntype MigrationData = {\n MigrationClass: MigrationClass;\n migration: Migration;\n name: string;\n};\n\n/**\n * Options for migration execution.\n */\ntype ExecuteOptions = {\n /** Run in dry-run mode (no actual changes) */\n readonly dryRun?: boolean;\n /** Record to migrations table (default: true for batch, false for single) */\n readonly record?: boolean;\n};\n\n/**\n * Parse createdAt timestamp from custom format to Date.\n * Supports both: MM-DD-YYYY_HH-MM-SS and DD-MM-YYYY_HH-MM-SS\n * Intelligently detects format by checking if first value > 12 (must be day)\n * Falls back to standard Date parsing for ISO strings.\n */\nfunction parseCreatedAt(createdAt: string): Date | undefined {\n const match = createdAt.match(/^(\\d{2})-(\\d{2})-(\\d{4})_(\\d{2})-(\\d{2})-(\\d{2})$/);\n if (match) {\n const [, first, second, year, hour, minute, second_time] = match;\n const firstNum = parseInt(first);\n const secondNum = parseInt(second);\n\n let month: number, day: number;\n\n // Intelligently detect format:\n // If first > 12, it must be DD-MM-YYYY (day can't be month)\n // If second > 12, it must be MM-DD-YYYY (day can't be month)\n // Otherwise, assume MM-DD-YYYY (US format as default)\n if (firstNum > 12) {\n // DD-MM-YYYY format\n day = firstNum;\n month = secondNum;\n } else if (secondNum > 12) {\n // MM-DD-YYYY format\n month = firstNum;\n day = secondNum;\n } else {\n // Ambiguous - default to MM-DD-YYYY\n month = firstNum;\n day = secondNum;\n }\n\n const date = new Date(\n parseInt(year),\n month - 1, // JavaScript months are 0-indexed\n day,\n parseInt(hour),\n parseInt(minute),\n parseInt(second_time),\n );\n\n // Validate the date is actually valid\n if (isNaN(date.getTime())) {\n return undefined;\n }\n\n return date;\n }\n // Fallback to standard Date parsing for ISO strings\n try {\n const date = new Date(createdAt);\n return isNaN(date.getTime()) ? undefined : date;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Comparator for sorting migration classes.\n *\n * Priority:\n * 1. `createdAt` timestamp (older = earlier)\n * 2. Alphabetical by migration name (last resort)\n */\nfunction sortMigrations(\n a: { createdAt?: string; migrationName: string },\n b: { createdAt?: string; migrationName: string },\n): number {\n // Sort by createdAt timestamp\n const aDate = a.createdAt ? parseCreatedAt(a.createdAt) : undefined;\n const bDate = b.createdAt ? parseCreatedAt(b.createdAt) : undefined;\n\n if (aDate && bDate) return aDate.getTime() - bDate.getTime();\n if (aDate) return -1;\n if (bDate) return 1;\n\n // Last resort: alphabetical\n return a.migrationName.localeCompare(b.migrationName);\n}\n\n/**\n * Migration runner that executes migrations.\n *\n * This is a pure executor - it doesn't discover migrations.\n * Discovery is handled by the framework (e.g., @warlock.js/core CLI).\n *\n * The migration name is read from the static `name` property on the class,\n * which should be set by the CLI after importing:\n *\n * @example\n * ```typescript\n * // In CLI after importing:\n * const { default: MigrationClass } = await import(\"./create-users.migration.ts\");\n * MigrationClass.migrationName ??= \"create-users\";\n *\n * // Then register or execute:\n * runner.register(MigrationClass);\n * // or\n * await runner.execute(MigrationClass);\n * ```\n *\n * @example\n * ```typescript\n * // Simple direct execution\n * await runner.execute(CreateUsersTable);\n * await runner.rollback(CreateUsersTable);\n *\n * // Registry pattern for batch operations\n * runner.register(CreateUsersTable);\n * runner.register(AddEmailIndex);\n * await runner.runAll();\n * await runner.rollbackAll();\n * ```\n */\nexport class MigrationRunner {\n /** Registered migrations */\n public readonly migrations: MigrationClass[] = [];\n\n /** Data source to use */\n private dataSource?: DataSource;\n\n /** Cached migration driver */\n private cachedMigrationDriver?: MigrationDriverContract;\n\n /** Table name for tracking migrations */\n private readonly migrationsTable: string;\n\n /** Whether to log operations */\n private readonly verbose: boolean;\n\n /**\n * Create a new migration runner.\n *\n * @param options - Runner options\n */\n public constructor(\n options: {\n dataSource?: DataSource;\n migrationsTable?: string;\n verbose?: boolean;\n } = {},\n ) {\n this.dataSource = options.dataSource;\n this.migrationsTable = options.migrationsTable ?? \"_migrations\";\n this.verbose = options.verbose ?? true;\n }\n\n // ============================================================================\n // DATA SOURCE\n // ============================================================================\n\n /**\n * Set the data source.\n */\n public setDataSource(dataSource: DataSource): this {\n this.dataSource = dataSource;\n this.cachedMigrationDriver = undefined;\n return this;\n }\n\n /**\n * Get the data source.\n */\n private getDataSource(): DataSource {\n if (!this.dataSource) {\n this.dataSource = dataSourceRegistry.get();\n }\n return this.dataSource;\n }\n\n /**\n * Get the migration driver.\n */\n private getMigrationDriver(): MigrationDriverContract {\n if (!this.cachedMigrationDriver) {\n this.cachedMigrationDriver = this.getDataSource().driver.migrationDriver();\n }\n return this.cachedMigrationDriver;\n }\n\n // ============================================================================\n // REGISTRATION\n // ============================================================================\n\n /**\n * Register a migration.\n *\n * The migration name is read from `MigrationClass.migrationName`.\n *\n * @param MigrationClass - Migration class (must have static `name` set)\n * @param createdAt - Optional timestamp for ordering\n * @returns This runner for chaining\n *\n * @example\n * ```typescript\n * CreateUsersTable.migrationName = \"2024-01-15_create-users\";\n * runner.register(CreateUsersTable);\n * ```\n */\n public register(MigrationClass: MigrationClass): this {\n const name = MigrationClass.migrationName;\n if (!name) {\n throw new Error(\n `Migration class must have a static 'migrationName' property set. ` +\n `Set it in CLI after importing: MigrationClass.migrationName = \"filename\";`,\n );\n }\n // Avoid duplicates\n if (!this.migrations.some((m) => m.migrationName === name)) {\n this.migrations.push(MigrationClass);\n }\n\n return this;\n }\n\n /**\n * Register multiple migrations.\n *\n * @param migrations - Array of migration classes\n * @returns This runner for chaining\n */\n public registerMany(migrations: MigrationClass[]): this {\n for (const MigrationClass of migrations) {\n this.register(MigrationClass);\n }\n return this;\n }\n\n /**\n * Clear all registered migrations.\n */\n public clear(): this {\n this.migrations.length = 0;\n return this;\n }\n\n /**\n * Get all registered migration names.\n */\n public getRegisteredNames(): string[] {\n return this.migrations.map((m) => m.migrationName);\n }\n\n // ============================================================================\n // SINGLE EXECUTION\n // ============================================================================\n\n /**\n * Execute a single migration's up() method.\n *\n * @param MigrationClass - Migration class to execute\n * @param options - Execution options\n * @returns Migration result\n *\n * @example\n * ```typescript\n * await runner.execute(CreateUsersTable);\n * await runner.execute(AddEmailIndex, { dryRun: true });\n * ```\n */\n public async run(\n MigrationClass: MigrationClass,\n options: ExecuteOptions = {},\n ): Promise<MigrationResult> {\n return this.runMigration(MigrationClass, \"up\", {\n dryRun: options.dryRun,\n record: options.record ?? false,\n });\n }\n\n /**\n * Execute a single migration's down() method.\n *\n * @param MigrationClass - Migration class to rollback\n * @param options - Execution options\n * @returns Migration result\n *\n * @example\n * ```typescript\n * await runner.rollback(CreateUsersTable);\n * ```\n */\n public async rollback(\n MigrationClass: MigrationClass,\n options: ExecuteOptions = {},\n ): Promise<MigrationResult> {\n return this.runMigration(MigrationClass, \"down\", {\n dryRun: options.dryRun,\n record: options.record ?? false,\n });\n }\n\n // ============================================================================\n // BATCH EXECUTION (REGISTERED MIGRATIONS)\n // ============================================================================\n\n /**\n * Run all pending registered migrations.\n *\n * Only runs migrations not already in the migrations table.\n *\n * @param options - Execution options\n * @returns Results for each migration\n *\n * @example\n * ```typescript\n * runner.register(CreateUsersTable);\n * runner.register(AddEmailIndex);\n * const results = await runner.runAll();\n * ```\n */\n public async runAll(options: ExecuteOptions = {}): Promise<MigrationResult[]> {\n const { dryRun = false, record = true } = options;\n\n const results: MigrationResult[] = [];\n\n // Get pending migrations\n const pending = await this.getPendingMigrations();\n\n if (pending.length === 0) {\n log.warn(\"database\", \"migration\", \"Nothing to migrate.\");\n return results;\n }\n\n log.info(\n \"database\",\n \"migration\",\n `Found ${pending.length} pending migration(s). Generating SQL pool...`,\n );\n const nextBatch = await this.getNextBatchNumber();\n\n const taggedStatements: TaggedSQL[] = [];\n const migrationsData: MigrationData[] = [];\n\n // 1. Collect SQL from each pending migration.\n // Fire extension checks concurrently as we encounter CREATE EXTENSION\n // statements — they resolve before execution begins.\n const extensionChecks: Promise<void>[] = [];\n\n for (const MigrationClass of pending) {\n const migration = this.createMigrationInstance(MigrationClass);\n const name = MigrationClass.migrationName;\n\n await migration.up();\n const upStatements = migration.toSQL();\n\n migrationsData.push({ MigrationClass, migration, name });\n\n for (const sql of upStatements) {\n const statementType = SQLGrammar.classify(sql);\n\n if (statementType === \"CREATE_EXTENSION\") {\n const ext = SQLGrammar.extractExtensionName(sql);\n if (ext) extensionChecks.push(this.informIfExtensionMissing(ext));\n }\n\n taggedStatements.push({\n sql,\n phase: SQLGrammar.phase(sql),\n statementType,\n createdAt: MigrationClass.createdAt,\n migrationName: name,\n });\n }\n }\n\n // 2. Resolve all extension checks before any SQL is executed.\n // Each check displays a rich message if the extension is missing\n // but does not throw — execution continues and Postgres will\n // surface its own error with full context already shown.\n await Promise.all(extensionChecks);\n\n // 3. Sort all SQL statements globally across all pending migrations\n const sortedStatements = SQLGrammar.sort(taggedStatements);\n\n // 4. Execute in a single batch\n if (dryRun) {\n log.info(\"database\", \"migration\", \"Dry run enabled. Would execute the following statements:\");\n for (const statement of sortedStatements) {\n console.log(\n `-- [${statement.statementType}] Phase ${statement.phase} [${statement.migrationName}]`,\n );\n console.log(statement.sql + \";\\n\");\n }\n return [];\n }\n\n const driver = this.getDataSource().driver;\n\n let transactionFailed = false;\n let errorMessage = \"\";\n /** The migration name that owns the SQL statement that threw. */\n let failingMigrationName: string | undefined;\n\n const startTime = Date.now();\n\n /**\n * Execute all sorted statements, capturing which migration owns the\n * statement that throws — so we report a precise culprit instead of\n * blaming every migration in the batch.\n */\n const executeStatements = async (): Promise<void> => {\n for (const statement of sortedStatements) {\n try {\n await driver.query(statement.sql);\n } catch (err) {\n failingMigrationName = statement.migrationName;\n throw err;\n }\n }\n\n if (record) {\n for (const data of migrationsData) {\n await this.recordMigration(\n data.name,\n nextBatch,\n data.MigrationClass.createdAt\n ? parseCreatedAt(data.MigrationClass.createdAt)\n : new Date(),\n );\n }\n }\n };\n\n try {\n if (driver.transaction) {\n await driver.transaction(executeStatements);\n } else {\n await executeStatements();\n }\n } catch (err) {\n transactionFailed = true;\n errorMessage = err instanceof Error ? err.message : String(err);\n }\n\n const durationMs = Date.now() - startTime;\n\n // Report results per-migration.\n // Only the migration that owns the failing statement is marked as failed;\n // all others are reported as rolled back / not reached.\n for (const data of migrationsData) {\n const isCulprit = transactionFailed && data.name === failingMigrationName;\n const wasSkipped = transactionFailed && !isCulprit;\n\n results.push({\n name: data.name,\n table: data.migration.table,\n direction: \"up\",\n success: !transactionFailed,\n error: isCulprit ? errorMessage : undefined,\n durationMs: Math.round(durationMs / migrationsData.length),\n executedAt: new Date(),\n });\n\n if (isCulprit) {\n log.error(\n \"database\",\n \"migration\",\n `${colors.magenta(data.name)}: ✗ Failed: ${errorMessage}`,\n );\n } else if (wasSkipped) {\n log.warn(\n \"database\",\n \"migration\",\n `${colors.magenta(data.name)}: rolled back (batch transaction failed)`,\n );\n } else {\n log.success(\"database\", \"migration\", `Migrated: ${colors.magenta(data.name)} successfully`);\n }\n }\n\n if (transactionFailed) {\n log.error(\n \"database\",\n \"migration\",\n `Batch execution failed. Rollback performed if transactional.`,\n );\n throw new Error(\"Migration batch failed: \" + errorMessage);\n }\n\n const successCount = results.filter((r) => r.success).length;\n log.success(\n \"database\",\n \"migration\",\n `Migration bulk phase execution complete: ${successCount}/${pending.length} migrations processed successfully.`,\n );\n\n return results;\n }\n\n /**\n * Export migrations as phase-ordered SQL files in database/sql/ directory.\n * By default, it exports all registered migrations. Use `pendingOnly: true` to export only pending ones.\n */\n public async exportSQL(options: { pendingOnly?: boolean; compact?: boolean } = {}): Promise<void> {\n const migrationsToExport = options.pendingOnly\n ? await this.getPendingMigrations()\n : this.migrations;\n\n if (migrationsToExport.length === 0) {\n log.warn(\"database\", \"migration\", \"No migrations to export.\");\n return;\n }\n\n log.info(\n \"database\",\n \"migration\",\n `Exporting ${migrationsToExport.length} ${options.pendingOnly ? \"pending \" : \"\"}migration(s) to SQL files...`,\n );\n\n const upStatements: TaggedSQL[] = [];\n const downStatements: TaggedSQL[] = [];\n\n for (const MigrationClass of migrationsToExport) {\n const migration = this.createMigrationInstance(MigrationClass);\n const name = MigrationClass.migrationName;\n\n // Collect up SQL\n await migration.up();\n for (const sql of migration.toSQL()) {\n upStatements.push({\n sql,\n phase: SQLGrammar.phase(sql),\n statementType: SQLGrammar.classify(sql),\n createdAt: MigrationClass.createdAt,\n migrationName: name,\n });\n }\n\n // Collect down SQL (reuse same instance — toSQL() cleared pendingOps)\n await migration.down();\n for (const sql of migration.toSQL()) {\n downStatements.push({\n sql,\n phase: SQLGrammar.phase(sql),\n statementType: SQLGrammar.classify(sql),\n createdAt: MigrationClass.createdAt,\n migrationName: name,\n });\n }\n }\n\n const sortedUp = SQLGrammar.sort(upStatements);\n // Down SQL: reverse order (undo in reverse dependency order)\n const sortedDown = downStatements.reverse();\n\n const upSQLString = this.formatSQLForExport(sortedUp, options.compact);\n const downSQLString = this.formatSQLForExport(sortedDown, options.compact);\n\n const rootPath = process.cwd();\n const sqlDir = path.join(rootPath, \"database\", \"sql\");\n\n if (!fs.existsSync(sqlDir)) {\n fs.mkdirSync(sqlDir, { recursive: true });\n }\n\n const timestamp = new Date().toISOString().replace(/T/, \"_\").replace(/:/g, \"-\").split(\".\")[0];\n const upPath = path.join(sqlDir, `migration_${timestamp}.up.sql`);\n const downPath = path.join(sqlDir, `migration_${timestamp}.down.sql`);\n\n fs.writeFileSync(upPath, upSQLString);\n fs.writeFileSync(downPath, downSQLString);\n\n log.success(\"database\", \"migration\", `Exported to:\\n- ${upPath}\\n- ${downPath}`);\n }\n\n /**\n * Rollback the last batch of migrations.\n *\n * @param options - Execution options\n * @returns Results for each migration\n */\n public async rollbackLast(options: ExecuteOptions = {}): Promise<MigrationResult[]> {\n return this.rollbackBatches(1, options);\n }\n\n /**\n * Rollback N batches of migrations.\n *\n * @param batches - Number of batches to rollback\n * @param options - Execution options\n * @returns Results for each migration\n */\n public async rollbackBatches(\n batches: number,\n options: ExecuteOptions = {},\n ): Promise<MigrationResult[]> {\n const dryRun = options.dryRun ?? false;\n const record = options.record ?? true;\n const results: MigrationResult[] = [];\n\n const toRollback = await this.getMigrationsToRollback(batches);\n\n if (toRollback.length === 0) {\n log.warn(\"database\", \"migration\", \"Nothing to rollback.\");\n return results;\n }\n\n log.info(\"database\", \"migration\", `Rolling back ${toRollback.length} migration(s).`);\n\n for (const MigrationClass of toRollback) {\n const result = await this.runMigration(MigrationClass, \"down\", {\n dryRun,\n record,\n });\n results.push(result);\n\n if (!result.success) {\n break;\n }\n }\n\n const successCount = results.filter((r) => r.success).length;\n log.success(\n \"database\",\n \"migration\",\n `Rollback complete: ${successCount}/${toRollback.length} successful.`,\n );\n\n return results;\n }\n\n /**\n * Rollback all executed migrations.\n *\n * @param options - Execution options\n * @returns Results for each migration\n */\n public async rollbackAll(options: ExecuteOptions = {}): Promise<MigrationResult[]> {\n const executed = await this.getExecutedMigrations();\n if (executed.length === 0) {\n log.warn(\"database\", \"migration\", \"Nothing to rollback.\");\n return [];\n }\n\n const maxBatch = Math.max(...executed.map((r) => r.batch));\n return this.rollbackBatches(maxBatch, options);\n }\n\n /**\n * Reset and re-run: rollback all then run all.\n *\n * @param options - Execution options\n * @returns Combined results\n */\n public async fresh(options: ExecuteOptions = {}): Promise<MigrationResult[]> {\n const rollbackResults = await this.rollbackAll(options);\n const runResults = await this.runAll(options);\n return [...rollbackResults, ...runResults];\n }\n\n // ============================================================================\n // STATUS\n // ============================================================================\n\n /**\n * Get status of all registered migrations.\n */\n public async status(): Promise<\n Array<{\n name: string;\n table: string;\n executed: boolean;\n batch: number | null;\n }>\n > {\n const executed = await this.getExecutedMigrations();\n const executedMap = new Map(executed.map((r) => [r.name, r]));\n\n return this.migrations.map((MigrationClass) => {\n const instance = new MigrationClass();\n const name = MigrationClass.migrationName;\n const record = executedMap.get(name);\n return {\n name,\n table: instance.table,\n executed: !!record,\n batch: record?.batch ?? null,\n };\n });\n }\n\n // ============================================================================\n // EXTENSION PRE-FLIGHT\n // ============================================================================\n\n /**\n * Check whether a database extension is available and inform the developer\n * if it is not installed.\n *\n * Does NOT throw — execution proceeds normally. If the extension is truly\n * missing, the database will surface its own error with full context already\n * displayed to the developer.\n *\n * @example\n * await this.informIfExtensionMissing(\"vector\");\n */\n private async informIfExtensionMissing(extension: string): Promise<void> {\n try {\n const migrationDriver = this.getMigrationDriver();\n const isAvailable = await migrationDriver.isExtensionAvailable(extension);\n\n if (!isAvailable) {\n const hr = \"─\".repeat(60);\n console.log(`\\n${colors.yellow(hr)}`);\n console.log(colors.yellow(` ⚠ Missing Database Extension: ${colors.bold(extension)}`));\n console.log(colors.yellow(hr));\n console.log();\n console.log(` A pending migration requires the ${colors.cyan(extension)} extension,`);\n console.log(` which is not installed on your database server.`);\n console.log();\n console.log(\n ` ${colors.bold(\"This means the physical database server is missing the extension package.\")}`,\n );\n console.log(` You cannot simply run CREATE EXTENSION until the package is installed`);\n console.log(` on the host machine or Docker container.`);\n console.log();\n\n const docsUrl = migrationDriver.getExtensionDocsUrl(extension);\n if (docsUrl) {\n console.log(` ${colors.bold(\"Or follow the installation guide:\")}`);\n console.log(` ${colors.cyan(docsUrl)}`);\n }\n console.log(`\\n${colors.yellow(hr)}\\n`);\n }\n } catch {\n // If the check itself fails, silently skip — don't break the migration.\n }\n }\n\n // ============================================================================\n // PRIVATE HELPERS\n // ============================================================================\n\n /**\n * Run a single migration.\n */\n private async runMigration(\n MigrationClass: MigrationClass,\n direction: \"up\" | \"down\",\n options: {\n dryRun?: boolean;\n record?: boolean;\n batch?: number;\n } = {},\n ): Promise<MigrationResult> {\n const { dryRun = false, record = true } = options;\n const startTime = Date.now();\n let success = true;\n let error: string | undefined;\n\n const migration = new MigrationClass();\n const name = MigrationClass.migrationName;\n\n log.info(\n \"database\",\n \"migration\",\n `${direction === \"up\" ? \"Migrating\" : \"Rolling back\"}: ${colors.magenta(name)}...`,\n );\n\n try {\n if (!dryRun) {\n const driver = this.getMigrationDriver();\n migration.setDriver(driver);\n migration.setMigrationDefaults(this.getDataSource().migrationDefaults);\n\n // ============================================================================\n // TRANSACTION RESOLUTION (3-tier hierarchy)\n // ============================================================================\n // 1. Migration-level explicit override\n // 2. Config-level global override\n // 3. Driver default (PostgreSQL: true, MongoDB: false)\n const shouldUseTransaction =\n migration.transactional ??\n this.getDataSource().migrations?.transactional ??\n driver.getDefaultTransactional();\n\n // ============================================================================\n // EXECUTE WITH OR WITHOUT TRANSACTION\n // ============================================================================\n\n // Collect SQL for the requested direction\n if (direction === \"up\") {\n await migration.up();\n } else {\n await migration.down();\n }\n const sqlStatements = migration.toSQL();\n\n const databaseDriver = this.getDataSource().driver;\n\n if (shouldUseTransaction && databaseDriver.transaction) {\n // Transactional execution\n await databaseDriver.transaction(async () => {\n // Execute generated SQL statements sequentially (no phase-sorting here since it's single execution)\n for (const sql of sqlStatements) {\n await databaseDriver.query(sql);\n }\n\n // Record migration tracking\n if (record) {\n if (direction === \"up\") {\n const batch = options.batch ?? (await this.getNextBatchNumber());\n await this.recordMigration(\n name,\n batch,\n MigrationClass.createdAt ? parseCreatedAt(MigrationClass.createdAt) : new Date(),\n );\n } else {\n await this.removeMigrationRecord(name);\n }\n }\n });\n } else {\n // Non-transactional execution\n for (const sql of sqlStatements) {\n await databaseDriver.query(sql);\n }\n\n if (record) {\n if (direction === \"up\") {\n const batch = options.batch ?? (await this.getNextBatchNumber());\n await this.recordMigration(\n name,\n batch,\n MigrationClass.createdAt ? parseCreatedAt(MigrationClass.createdAt) : new Date(),\n );\n } else {\n await this.removeMigrationRecord(name);\n }\n }\n }\n }\n } catch (err) {\n success = false;\n error = err instanceof Error ? err.message : String(err);\n log.error(\"database\", \"migration\", `${colors.magenta(name)}: ✗ Failed: ${error}`);\n throw err;\n }\n\n const durationMs = Date.now() - startTime;\n\n if (success) {\n log.success(\n \"database\",\n \"migration\",\n `${direction == \"up\" ? \"Migrated\" : \"Rolled back\"}: ${colors.magenta(name)} successfully (${durationMs}ms)`,\n );\n }\n\n return {\n name,\n table: migration.table,\n direction,\n success,\n error,\n durationMs,\n executedAt: new Date(),\n };\n }\n\n /**\n * Create, configure, and return a ready-to-use migration instance.\n *\n * Centralises the repeated \"new + setDriver + setMigrationDefaults\" boilerplate\n * that all batch/single execution paths need.\n *\n * @internal\n */\n private createMigrationInstance(MigrationClass: MigrationClass): Migration {\n const migration = new MigrationClass();\n migration.setDriver(this.getMigrationDriver());\n migration.setMigrationDefaults(this.getDataSource().migrationDefaults);\n return migration;\n }\n\n /**\n * Format an ordered array of TaggedSQL into a human-readable SQL file string.\n *\n * Consecutive statements that belong to the same (phase, migration) group share\n * a single block comment at the top, avoiding the noisy per-statement repetition.\n *\n * Example output:\n * ```sql\n * /* Phase 3 [create-users] *\\/\n * ALTER TABLE \"users\" ADD COLUMN \"name\" TEXT NOT NULL;\n * ALTER TABLE \"users\" ADD COLUMN \"email\" TEXT NOT NULL;\n *\n * /* Phase 4 [create-users] *\\/\n * CREATE UNIQUE INDEX ...;\n * ```\n *\n * @internal\n */\n private formatSQLForExport(statements: TaggedSQL[], compact: boolean = false): string {\n const lines: string[] = [];\n\n if (compact) {\n // Just output raw statements, no grouping, no blank lines\n for (const stmt of statements) {\n lines.push(`${stmt.sql};`);\n }\n return lines.join(\"\\n\");\n }\n\n // Group statements by their phase and migration name\n const grouped = new Map<string, string[]>();\n\n for (const stmt of statements) {\n const groupKey = `Phase ${stmt.phase} [${stmt.migrationName}]`;\n if (!grouped.has(groupKey)) {\n grouped.set(groupKey, []);\n }\n grouped.get(groupKey)!.push(stmt.sql);\n }\n\n // Format each group\n for (const [groupKey, sqls] of grouped.entries()) {\n if (lines.length > 0) lines.push(\"\"); // blank line between groups\n lines.push(`/* ${groupKey} */`);\n for (const sql of sqls) {\n lines.push(`${sql};`);\n }\n }\n\n return lines.join(\"\\n\");\n }\n\n /**\n * Get pending (not executed) registered migrations.\n */\n private async getPendingMigrations(): Promise<MigrationClass[]> {\n const executed = await this.getExecutedMigrations();\n const executedNames = new Set(executed.map((r) => r.name));\n const migrations = this.migrations.filter((m) => !executedNames.has(m.migrationName));\n\n return migrations.sort(sortMigrations);\n }\n\n /**\n * Get migrations to rollback.\n */\n private async getMigrationsToRollback(batches: number): Promise<MigrationClass[]> {\n const executed = await this.getExecutedMigrations();\n if (executed.length === 0) return [];\n\n const batchNumbers = [...new Set(executed.map((r) => r.batch))]\n .sort((a, b) => b - a)\n .slice(0, batches);\n\n const toRollback = executed.filter((r) => batchNumbers.includes(r.batch)).reverse();\n\n const migrations = toRollback\n .map((r) => this.migrations.find((m) => m.migrationName === r.name))\n .filter((m): m is MigrationClass => !!m);\n\n return migrations.sort(sortMigrations);\n }\n\n /**\n * Get executed migration records.\n */\n public async getExecutedMigrations(): Promise<MigrationRecord[]> {\n const driver = this.getDataSource().driver;\n\n try {\n const migrationDriver = this.getMigrationDriver();\n\n // Ensure migrations table exists\n await migrationDriver.ensureMigrationsTable(this.migrationsTable);\n\n const queryBuilder = driver.queryBuilder<MigrationRecord>(this.migrationsTable);\n return await queryBuilder.orderBy(\"batch\", \"asc\").orderBy(\"name\", \"asc\").get();\n } catch {\n return [];\n }\n }\n\n /**\n * Record a migration.\n */\n private async recordMigration(name: string, batch: number, createdAt?: Date): Promise<void> {\n const driver = this.getDataSource().driver;\n const migrationDriver = this.getMigrationDriver();\n\n // Ensure migrations table exists\n await migrationDriver.ensureMigrationsTable(this.migrationsTable);\n\n await driver.insert(this.migrationsTable, {\n name,\n batch,\n executedAt: new Date(),\n createdAt,\n });\n }\n\n /**\n * Remove a migration record.\n */\n private async removeMigrationRecord(name: string): Promise<void> {\n const driver = this.getDataSource().driver;\n await driver.delete(this.migrationsTable, { name });\n }\n\n /**\n * Get next batch number.\n */\n private async getNextBatchNumber(): Promise<number> {\n const executed = await this.getExecutedMigrations();\n if (executed.length === 0) return 1;\n return Math.max(...executed.map((r) => r.batch)) + 1;\n }\n}\n\nexport const migrationRunner = new MigrationRunner();\n","import { dataSourceRegistry } from \"../data-source/data-source-registry\";\n\n/**\n * Selects which data source the operation runs against. Shared between every\n * function in this module — kept internal because it carries no semantic\n * beyond \"look up by registry name\".\n */\ntype DataSourceSelector = {\n /** Data source name from the registry. Omit to use the default source. */\n readonly connection?: string;\n};\n\n/**\n * Result of {@link createDatabase}.\n */\nexport type CreateDatabaseResult = {\n /** True if a new database was created; false if it already existed. */\n readonly created: boolean;\n /** The database name that was passed to the operation. */\n readonly name: string;\n};\n\n/**\n * Result of {@link dropAllTables}.\n */\nexport type DropAllTablesResult = {\n /** Names of tables that were dropped, in the order returned by the driver. */\n readonly tables: string[];\n /** Count of dropped tables (equal to `tables.length`). */\n readonly dropped: number;\n};\n\n/**\n * Create a database on the configured data source. Returns `created: false`\n * when the database already exists — drivers are responsible for the\n * idempotency check.\n *\n * @example\n * await createDatabase(\"analytics\");\n * await createDatabase(\"analytics\", { connection: \"warehouse\" });\n */\nexport async function createDatabase(\n name: string,\n options: DataSourceSelector = {},\n): Promise<CreateDatabaseResult> {\n const dataSource = dataSourceRegistry.get(options.connection);\n const created = await dataSource.driver.createDatabase(name);\n\n return { created, name };\n}\n\n/**\n * Drop every table on the configured data source. Lists tables first so the\n * caller receives the names that were affected — useful for printing,\n * confirmation prompts, or audit logging at the call site.\n *\n * @example\n * const { tables, dropped } = await dropAllTables();\n * console.log(`Dropped ${dropped} tables: ${tables.join(\", \")}`);\n */\nexport async function dropAllTables(\n options: DataSourceSelector = {},\n): Promise<DropAllTablesResult> {\n const dataSource = dataSourceRegistry.get(options.connection);\n const driver = dataSource.driver;\n\n const tables = await driver.blueprint.listTables();\n await driver.dropAllTables();\n\n return { tables, dropped: tables.length };\n}\n","import { migrationRunner } from \"../migration/migration-runner\";\nimport type { MigrationRecord, MigrationResult } from \"../migration/types\";\n\n/**\n * Options for exporting migrations as SQL files.\n */\nexport type ExportMigrationsSQLOptions = {\n /** Export only pending migrations. Default: false (exports all registered). */\n readonly pendingOnly?: boolean;\n /** Strip generated block comments and blank lines from the output. */\n readonly compact?: boolean;\n};\n\n/**\n * Options for rolling back migrations.\n */\nexport type RollbackMigrationsOptions = {\n /** Roll back every executed migration. Overrides `batches` when true. */\n readonly all?: boolean;\n /** Number of batches to roll back when `all` is not set. Default: 1. */\n readonly batches?: number;\n};\n\n/**\n * Run every pending migration registered on the migration runner.\n *\n * Caller is responsible for registering migration classes first via\n * `migrationRunner.register()` / `migrationRunner.registerMany()`. Returns one\n * result entry per executed migration.\n *\n * @example\n * migrationRunner.registerMany([CreateUsersTable, AddEmailIndex]);\n * const results = await runMigrations();\n */\nexport async function runMigrations(): Promise<MigrationResult[]> {\n return migrationRunner.runAll();\n}\n\n/**\n * Roll back executed migrations. By default rolls back the most recent batch;\n * pass `all: true` to undo every executed migration, or `batches: N` to undo\n * the last N batches.\n *\n * @example\n * await rollbackMigrations(); // last batch\n * await rollbackMigrations({ batches: 3 }); // last three batches\n * await rollbackMigrations({ all: true }); // everything\n */\nexport async function rollbackMigrations(\n options: RollbackMigrationsOptions = {},\n): Promise<MigrationResult[]> {\n if (options.all) {\n return migrationRunner.rollbackAll();\n }\n\n const batches = options.batches ?? 1;\n\n return migrationRunner.rollbackBatches(batches);\n}\n\n/**\n * Roll back every executed migration, then run every registered migration.\n * Equivalent to `rollbackMigrations({ all: true })` followed by\n * `runMigrations()`.\n *\n * @example\n * await freshMigrate();\n */\nexport async function freshMigrate(): Promise<MigrationResult[]> {\n return migrationRunner.fresh();\n}\n\n/**\n * Export registered migrations as phase-ordered `.up.sql` and `.down.sql`\n * files under `<cwd>/database/sql/`.\n *\n * @example\n * await exportMigrationsSQL();\n * await exportMigrationsSQL({ pendingOnly: true, compact: true });\n */\nexport async function exportMigrationsSQL(\n options: ExportMigrationsSQLOptions = {},\n): Promise<void> {\n return migrationRunner.exportSQL(options);\n}\n\n/**\n * Return the migration records persisted in the migrations table — one entry\n * per migration that has ever been executed against the configured data\n * source.\n *\n * @example\n * const executed = await listExecutedMigrations();\n * console.log(executed.map((record) => record.name));\n */\nexport async function listExecutedMigrations(): Promise<MigrationRecord[]> {\n return migrationRunner.getExecutedMigrations();\n}\n"],"mappings":"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"}