@fragno-dev/db 0.1.15 → 0.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 (402) hide show
  1. package/.turbo/turbo-build.log +242 -179
  2. package/CHANGELOG.md +40 -0
  3. package/README.md +123 -8
  4. package/dist/adapters/adapters.d.ts +5 -5
  5. package/dist/adapters/adapters.d.ts.map +1 -1
  6. package/dist/adapters/adapters.js.map +1 -1
  7. package/dist/adapters/drizzle/drizzle-adapter.d.ts +6 -21
  8. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
  9. package/dist/adapters/drizzle/drizzle-adapter.js +7 -54
  10. package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
  11. package/dist/adapters/drizzle/generate.d.ts +3 -0
  12. package/dist/adapters/drizzle/generate.d.ts.map +1 -1
  13. package/dist/adapters/drizzle/generate.js +36 -28
  14. package/dist/adapters/drizzle/generate.js.map +1 -1
  15. package/dist/adapters/generic-sql/driver-config.d.ts +74 -0
  16. package/dist/adapters/generic-sql/driver-config.d.ts.map +1 -0
  17. package/dist/adapters/generic-sql/driver-config.js +94 -0
  18. package/dist/adapters/generic-sql/driver-config.js.map +1 -0
  19. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts +43 -0
  20. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -0
  21. package/dist/adapters/generic-sql/generic-sql-adapter.js +87 -0
  22. package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -0
  23. package/dist/adapters/generic-sql/generic-sql-uow-executor.js +67 -0
  24. package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -0
  25. package/dist/adapters/generic-sql/migration/cold-kysely.js +33 -0
  26. package/dist/adapters/generic-sql/migration/cold-kysely.js.map +1 -0
  27. package/dist/adapters/generic-sql/migration/dialect/mysql.js +60 -0
  28. package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -0
  29. package/dist/adapters/generic-sql/migration/dialect/postgres.js +59 -0
  30. package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -0
  31. package/dist/adapters/generic-sql/migration/dialect/sqlite.js +96 -0
  32. package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -0
  33. package/dist/adapters/generic-sql/migration/executor.d.ts +15 -0
  34. package/dist/adapters/generic-sql/migration/executor.d.ts.map +1 -0
  35. package/dist/adapters/generic-sql/migration/executor.js +18 -0
  36. package/dist/adapters/generic-sql/migration/executor.js.map +1 -0
  37. package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts +66 -0
  38. package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -0
  39. package/dist/adapters/generic-sql/migration/prepared-migrations.js +68 -0
  40. package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -0
  41. package/dist/adapters/generic-sql/migration/sql-generator.js +212 -0
  42. package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -0
  43. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +32 -0
  44. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -0
  45. package/dist/adapters/generic-sql/query/cursor-utils.js +37 -0
  46. package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -0
  47. package/dist/adapters/generic-sql/query/dialect/mysql.js +33 -0
  48. package/dist/adapters/generic-sql/query/dialect/mysql.js.map +1 -0
  49. package/dist/adapters/generic-sql/query/dialect/postgres.js +32 -0
  50. package/dist/adapters/generic-sql/query/dialect/postgres.js.map +1 -0
  51. package/dist/adapters/generic-sql/query/dialect/sqlite.js +32 -0
  52. package/dist/adapters/generic-sql/query/dialect/sqlite.js.map +1 -0
  53. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +152 -0
  54. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -0
  55. package/dist/adapters/generic-sql/query/select-builder.js +69 -0
  56. package/dist/adapters/generic-sql/query/select-builder.js.map +1 -0
  57. package/dist/adapters/generic-sql/query/sql-query-compiler.js +145 -0
  58. package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -0
  59. package/dist/adapters/generic-sql/query/where-builder.js +129 -0
  60. package/dist/adapters/generic-sql/query/where-builder.js.map +1 -0
  61. package/dist/adapters/generic-sql/result-interpreter.js +74 -0
  62. package/dist/adapters/generic-sql/result-interpreter.js.map +1 -0
  63. package/dist/adapters/generic-sql/uow-decoder.js +105 -0
  64. package/dist/adapters/generic-sql/uow-decoder.js.map +1 -0
  65. package/dist/adapters/generic-sql/uow-encoder.js +93 -0
  66. package/dist/adapters/generic-sql/uow-encoder.js.map +1 -0
  67. package/dist/adapters/kysely/kysely-adapter.d.ts +5 -18
  68. package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
  69. package/dist/adapters/kysely/kysely-adapter.js +6 -165
  70. package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
  71. package/dist/adapters/{drizzle/drizzle-query.js → shared/from-unit-of-work-compiler.js} +47 -61
  72. package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -0
  73. package/dist/adapters/{drizzle/shared.d.ts → shared/table-name-mapper.d.ts} +2 -4
  74. package/dist/adapters/shared/table-name-mapper.d.ts.map +1 -0
  75. package/dist/adapters/shared/table-name-mapper.js +43 -0
  76. package/dist/adapters/shared/table-name-mapper.js.map +1 -0
  77. package/dist/adapters/shared/uow-operation-compiler.js +105 -0
  78. package/dist/adapters/shared/uow-operation-compiler.js.map +1 -0
  79. package/dist/db-fragment-definition-builder.d.ts +107 -19
  80. package/dist/db-fragment-definition-builder.d.ts.map +1 -1
  81. package/dist/db-fragment-definition-builder.js +134 -20
  82. package/dist/db-fragment-definition-builder.js.map +1 -1
  83. package/dist/fragments/internal-fragment.d.ts +39 -5
  84. package/dist/fragments/internal-fragment.d.ts.map +1 -1
  85. package/dist/fragments/internal-fragment.js +82 -10
  86. package/dist/fragments/internal-fragment.js.map +1 -1
  87. package/dist/hooks/hooks.d.ts +51 -0
  88. package/dist/hooks/hooks.d.ts.map +1 -0
  89. package/dist/hooks/hooks.js +88 -0
  90. package/dist/hooks/hooks.js.map +1 -0
  91. package/dist/migration-engine/generation-engine.d.ts +0 -2
  92. package/dist/migration-engine/generation-engine.d.ts.map +1 -1
  93. package/dist/migration-engine/generation-engine.js +23 -61
  94. package/dist/migration-engine/generation-engine.js.map +1 -1
  95. package/dist/mod.d.ts +34 -10
  96. package/dist/mod.d.ts.map +1 -1
  97. package/dist/mod.js +47 -16
  98. package/dist/mod.js.map +1 -1
  99. package/dist/node_modules/.pnpm/{rou3@0.7.8 → rou3@0.7.10}/node_modules/rou3/dist/index.js +1 -1
  100. package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js.map +1 -0
  101. package/dist/packages/fragno/dist/api/fragment-instantiator.js +69 -31
  102. package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -1
  103. package/dist/query/column-defaults.js +27 -0
  104. package/dist/query/column-defaults.js.map +1 -0
  105. package/dist/query/cursor.d.ts +4 -4
  106. package/dist/query/cursor.d.ts.map +1 -1
  107. package/dist/query/cursor.js +8 -6
  108. package/dist/query/cursor.js.map +1 -1
  109. package/dist/query/orm/orm.d.ts +1 -1
  110. package/dist/query/orm/orm.js.map +1 -1
  111. package/dist/query/serialize/create-sql-serializer.js +30 -0
  112. package/dist/query/serialize/create-sql-serializer.js.map +1 -0
  113. package/dist/query/serialize/dialect/mysql-serializer.js +87 -0
  114. package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -0
  115. package/dist/query/serialize/dialect/postgres-serializer.js +80 -0
  116. package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -0
  117. package/dist/query/serialize/dialect/sqlite-serializer.js +93 -0
  118. package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -0
  119. package/dist/query/serialize/sql-serializer.js +67 -0
  120. package/dist/query/serialize/sql-serializer.js.map +1 -0
  121. package/dist/query/{query.d.ts → simple-query-interface.d.ts} +5 -5
  122. package/dist/query/simple-query-interface.d.ts.map +1 -0
  123. package/dist/query/{execute-unit-of-work.d.ts → unit-of-work/execute-unit-of-work.d.ts} +50 -4
  124. package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -0
  125. package/dist/query/{execute-unit-of-work.js → unit-of-work/execute-unit-of-work.js} +150 -5
  126. package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -0
  127. package/dist/query/{retry-policy.d.ts → unit-of-work/retry-policy.d.ts} +1 -1
  128. package/dist/query/unit-of-work/retry-policy.d.ts.map +1 -0
  129. package/dist/query/{retry-policy.js → unit-of-work/retry-policy.js} +1 -1
  130. package/dist/query/unit-of-work/retry-policy.js.map +1 -0
  131. package/dist/query/{unit-of-work.d.ts → unit-of-work/unit-of-work.d.ts} +69 -21
  132. package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -0
  133. package/dist/query/{unit-of-work.js → unit-of-work/unit-of-work.js} +83 -22
  134. package/dist/query/unit-of-work/unit-of-work.js.map +1 -0
  135. package/dist/query/value-decoding.js +71 -0
  136. package/dist/query/value-decoding.js.map +1 -0
  137. package/dist/query/value-encoding.js +124 -0
  138. package/dist/query/value-encoding.js.map +1 -0
  139. package/dist/schema/type-conversion/create-sql-type-mapper.js +29 -0
  140. package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -0
  141. package/dist/schema/type-conversion/dialect/mysql.js +57 -0
  142. package/dist/schema/type-conversion/dialect/mysql.js.map +1 -0
  143. package/dist/schema/type-conversion/dialect/postgres.js +56 -0
  144. package/dist/schema/type-conversion/dialect/postgres.js.map +1 -0
  145. package/dist/schema/type-conversion/dialect/sqlite.js +52 -0
  146. package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -0
  147. package/dist/schema/type-conversion/type-mapping.js +63 -0
  148. package/dist/schema/type-conversion/type-mapping.js.map +1 -0
  149. package/dist/sql-driver/connection/connection-provider.d.ts +13 -0
  150. package/dist/sql-driver/connection/connection-provider.d.ts.map +1 -0
  151. package/dist/sql-driver/connection/connection-provider.js +19 -0
  152. package/dist/sql-driver/connection/connection-provider.js.map +1 -0
  153. package/dist/sql-driver/connection/single-connection-provider.js +23 -0
  154. package/dist/sql-driver/connection/single-connection-provider.js.map +1 -0
  155. package/dist/sql-driver/dialect-adapter/dialect-adapter.d.ts +7 -0
  156. package/dist/sql-driver/dialect-adapter/dialect-adapter.d.ts.map +1 -0
  157. package/dist/sql-driver/dialects/dialects.d.ts +2 -0
  158. package/dist/sql-driver/dialects/dialects.js +3 -0
  159. package/dist/sql-driver/dialects/durable-object-dialect.d.ts +72 -0
  160. package/dist/sql-driver/dialects/durable-object-dialect.d.ts.map +1 -0
  161. package/dist/sql-driver/dialects/durable-object-dialect.js +130 -0
  162. package/dist/sql-driver/dialects/durable-object-dialect.js.map +1 -0
  163. package/dist/sql-driver/driver/runtime-driver.d.ts +23 -0
  164. package/dist/sql-driver/driver/runtime-driver.d.ts.map +1 -0
  165. package/dist/sql-driver/driver/runtime-driver.js +56 -0
  166. package/dist/sql-driver/driver/runtime-driver.js.map +1 -0
  167. package/dist/sql-driver/query-executor/default-query-executor.js +26 -0
  168. package/dist/sql-driver/query-executor/default-query-executor.js.map +1 -0
  169. package/dist/sql-driver/query-executor/plugin.d.ts +17 -0
  170. package/dist/sql-driver/query-executor/plugin.d.ts.map +1 -0
  171. package/dist/sql-driver/query-executor/query-executor-base.js +25 -0
  172. package/dist/sql-driver/query-executor/query-executor-base.js.map +1 -0
  173. package/dist/sql-driver/query-executor/query-executor.d.ts +36 -0
  174. package/dist/sql-driver/query-executor/query-executor.d.ts.map +1 -0
  175. package/dist/sql-driver/sql-driver-adapter.d.ts +29 -0
  176. package/dist/sql-driver/sql-driver-adapter.d.ts.map +1 -0
  177. package/dist/sql-driver/sql-driver-adapter.js +68 -0
  178. package/dist/sql-driver/sql-driver-adapter.js.map +1 -0
  179. package/dist/sql-driver/sql-driver.d.ts +38 -0
  180. package/dist/sql-driver/sql-driver.d.ts.map +1 -0
  181. package/dist/sql-driver/sql-driver.js +1 -0
  182. package/dist/sql-driver/sql.js +50 -0
  183. package/dist/sql-driver/sql.js.map +1 -0
  184. package/dist/with-database.d.ts +6 -2
  185. package/dist/with-database.d.ts.map +1 -1
  186. package/dist/with-database.js +1 -1
  187. package/dist/with-database.js.map +1 -1
  188. package/package.json +39 -12
  189. package/src/adapters/adapters.ts +8 -5
  190. package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +61 -169
  191. package/src/adapters/drizzle/{drizzle-adapter-sqlite.test.ts → drizzle-adapter-sqlite3.test.ts} +31 -55
  192. package/src/adapters/drizzle/drizzle-adapter.ts +15 -107
  193. package/src/adapters/drizzle/generate.test.ts +2 -2
  194. package/src/adapters/drizzle/generate.ts +78 -34
  195. package/src/adapters/drizzle/migrate-drizzle.test.ts +19 -0
  196. package/src/adapters/drizzle/shared.ts +0 -34
  197. package/src/adapters/drizzle/test-utils.ts +3 -3
  198. package/src/adapters/generic-sql/README.md +14 -0
  199. package/src/adapters/generic-sql/driver-config.ts +144 -0
  200. package/src/adapters/generic-sql/generic-sql-adapter.test.ts +50 -0
  201. package/src/adapters/generic-sql/generic-sql-adapter.ts +146 -0
  202. package/src/adapters/generic-sql/generic-sql-uow-executor.ts +130 -0
  203. package/src/adapters/generic-sql/migration/cold-kysely.ts +55 -0
  204. package/src/adapters/{kysely/migration/execute-mysql.test.ts → generic-sql/migration/dialect/mysql.test.ts} +342 -484
  205. package/src/adapters/generic-sql/migration/dialect/mysql.ts +104 -0
  206. package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +1008 -0
  207. package/src/adapters/generic-sql/migration/dialect/postgres.ts +113 -0
  208. package/src/adapters/{kysely/migration/execute-sqlite.test.ts → generic-sql/migration/dialect/sqlite.test.ts} +307 -510
  209. package/src/adapters/generic-sql/migration/dialect/sqlite.ts +189 -0
  210. package/src/adapters/generic-sql/migration/executor.ts +33 -0
  211. package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +661 -0
  212. package/src/adapters/generic-sql/migration/prepared-migrations.ts +214 -0
  213. package/src/adapters/generic-sql/migration/sql-generator.ts +413 -0
  214. package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +36 -0
  215. package/src/adapters/generic-sql/query/cursor-utils.ts +56 -0
  216. package/src/adapters/generic-sql/query/dialect/mysql.ts +34 -0
  217. package/src/adapters/generic-sql/query/dialect/postgres.ts +32 -0
  218. package/src/adapters/generic-sql/query/dialect/sqlite.ts +32 -0
  219. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +1568 -0
  220. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +314 -0
  221. package/src/adapters/generic-sql/query/select-builder.test.ts +256 -0
  222. package/src/adapters/generic-sql/query/select-builder.ts +137 -0
  223. package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +195 -0
  224. package/src/adapters/generic-sql/query/sql-query-compiler.ts +367 -0
  225. package/src/adapters/generic-sql/query/where-builder.test.ts +744 -0
  226. package/src/adapters/generic-sql/query/where-builder.ts +211 -0
  227. package/src/adapters/generic-sql/result-interpreter.ts +102 -0
  228. package/src/adapters/generic-sql/test/generic-drizzle-adapter-sqlite3.test.ts +899 -0
  229. package/src/adapters/generic-sql/uow-decoder.test.ts +399 -0
  230. package/src/adapters/generic-sql/uow-decoder.ts +152 -0
  231. package/src/adapters/generic-sql/uow-encoder.test.ts +183 -0
  232. package/src/adapters/generic-sql/uow-encoder.ts +131 -0
  233. package/src/adapters/kysely/kysely-adapter-pglite.test.ts +26 -76
  234. package/src/adapters/kysely/{kysely-adapter-sqlite.test.ts → kysely-adapter-sqlocal.test.ts} +76 -17
  235. package/src/adapters/kysely/kysely-adapter.ts +10 -250
  236. package/src/adapters/{drizzle/drizzle-query.ts → shared/from-unit-of-work-compiler.ts} +110 -104
  237. package/src/adapters/shared/table-name-mapper.ts +50 -0
  238. package/src/adapters/shared/uow-operation-compiler.ts +211 -0
  239. package/src/db-fragment-definition-builder.test.ts +2 -2
  240. package/src/db-fragment-definition-builder.ts +461 -50
  241. package/src/db-fragment-instantiator.test.ts +78 -2
  242. package/src/db-fragment-integration.test.ts +14 -16
  243. package/src/fragments/internal-fragment.test.ts +434 -45
  244. package/src/fragments/internal-fragment.ts +183 -20
  245. package/src/hooks/hooks.test.ts +587 -0
  246. package/src/hooks/hooks.ts +179 -0
  247. package/src/migration-engine/generation-engine.test.ts +44 -54
  248. package/src/migration-engine/generation-engine.ts +48 -94
  249. package/src/mod.ts +117 -29
  250. package/src/query/column-defaults.ts +49 -0
  251. package/src/query/cursor.test.ts +31 -6
  252. package/src/query/cursor.ts +11 -7
  253. package/src/query/orm/orm.ts +1 -1
  254. package/src/query/query-type.test.ts +9 -9
  255. package/src/query/serialize/create-sql-serializer.ts +34 -0
  256. package/src/query/serialize/dialect/mysql-serializer.ts +142 -0
  257. package/src/query/serialize/dialect/postgres-serializer.ts +129 -0
  258. package/src/query/serialize/dialect/sqlite-serializer.test.ts +251 -0
  259. package/src/query/serialize/dialect/sqlite-serializer.ts +156 -0
  260. package/src/query/serialize/sql-serializer.ts +143 -0
  261. package/src/query/{query.ts → simple-query-interface.ts} +2 -2
  262. package/src/query/{execute-unit-of-work.test.ts → unit-of-work/execute-unit-of-work.test.ts} +571 -17
  263. package/src/query/{execute-unit-of-work.ts → unit-of-work/execute-unit-of-work.ts} +361 -12
  264. package/src/query/{unit-of-work-coordinator.test.ts → unit-of-work/unit-of-work-coordinator.test.ts} +290 -44
  265. package/src/query/{unit-of-work-types.test.ts → unit-of-work/unit-of-work-types.test.ts} +5 -3
  266. package/src/query/{unit-of-work.test.ts → unit-of-work/unit-of-work.test.ts} +100 -9
  267. package/src/query/{unit-of-work.ts → unit-of-work/unit-of-work.ts} +174 -49
  268. package/src/query/{result-transform.test.ts → value-decoding.test.ts} +45 -427
  269. package/src/query/value-decoding.ts +113 -0
  270. package/src/query/value-encoding.test.ts +390 -0
  271. package/src/query/value-encoding.ts +168 -0
  272. package/src/schema/create.test.ts +5 -1
  273. package/src/schema/serialize.test.ts +165 -407
  274. package/src/schema/type-conversion/create-sql-type-mapper.ts +28 -0
  275. package/src/schema/type-conversion/dialect/mysql.ts +64 -0
  276. package/src/schema/type-conversion/dialect/postgres.ts +62 -0
  277. package/src/schema/type-conversion/dialect/sqlite.ts +63 -0
  278. package/src/schema/type-conversion/type-mapping.test.ts +137 -0
  279. package/src/schema/type-conversion/type-mapping.ts +153 -0
  280. package/src/shared/connection-pool.ts +5 -5
  281. package/src/sql-driver/better-sqlite3.test.ts +126 -0
  282. package/src/sql-driver/connection/connection-provider.ts +27 -0
  283. package/src/sql-driver/connection/single-connection-provider.ts +42 -0
  284. package/src/sql-driver/dialect-adapter/dialect-adapter.ts +9 -0
  285. package/src/sql-driver/dialect-adapter/sqlite-dialect-adapter.ts +7 -0
  286. package/src/sql-driver/dialects/dialects.ts +1 -0
  287. package/src/sql-driver/dialects/durable-object-dialect.ts +260 -0
  288. package/src/sql-driver/driver/runtime-driver.ts +91 -0
  289. package/src/sql-driver/query-executor/default-query-executor.ts +38 -0
  290. package/src/sql-driver/query-executor/plugin.ts +22 -0
  291. package/src/sql-driver/query-executor/query-executor-base.ts +53 -0
  292. package/src/sql-driver/query-executor/query-executor.ts +44 -0
  293. package/src/sql-driver/sql-driver-adapter.ts +96 -0
  294. package/src/sql-driver/sql-driver.ts +53 -0
  295. package/src/sql-driver/sql.ts +57 -0
  296. package/src/sql-driver/sqlocal.test.ts +117 -0
  297. package/src/with-database.ts +35 -23
  298. package/tsdown.config.ts +7 -2
  299. package/dist/adapters/drizzle/drizzle-connection-pool.js +0 -40
  300. package/dist/adapters/drizzle/drizzle-connection-pool.js.map +0 -1
  301. package/dist/adapters/drizzle/drizzle-query.d.ts +0 -23
  302. package/dist/adapters/drizzle/drizzle-query.d.ts.map +0 -1
  303. package/dist/adapters/drizzle/drizzle-query.js.map +0 -1
  304. package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +0 -10
  305. package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +0 -1
  306. package/dist/adapters/drizzle/drizzle-uow-compiler.js +0 -334
  307. package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +0 -1
  308. package/dist/adapters/drizzle/drizzle-uow-decoder.js +0 -123
  309. package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +0 -1
  310. package/dist/adapters/drizzle/drizzle-uow-executor.js +0 -160
  311. package/dist/adapters/drizzle/drizzle-uow-executor.js.map +0 -1
  312. package/dist/adapters/drizzle/join-column-utils.js +0 -28
  313. package/dist/adapters/drizzle/join-column-utils.js.map +0 -1
  314. package/dist/adapters/drizzle/shared.d.ts.map +0 -1
  315. package/dist/adapters/drizzle/shared.js +0 -35
  316. package/dist/adapters/drizzle/shared.js.map +0 -1
  317. package/dist/adapters/kysely/kysely-connection-pool.js +0 -41
  318. package/dist/adapters/kysely/kysely-connection-pool.js.map +0 -1
  319. package/dist/adapters/kysely/kysely-query-builder.js +0 -321
  320. package/dist/adapters/kysely/kysely-query-builder.js.map +0 -1
  321. package/dist/adapters/kysely/kysely-query-compiler.js +0 -67
  322. package/dist/adapters/kysely/kysely-query-compiler.js.map +0 -1
  323. package/dist/adapters/kysely/kysely-query.d.ts +0 -23
  324. package/dist/adapters/kysely/kysely-query.d.ts.map +0 -1
  325. package/dist/adapters/kysely/kysely-query.js +0 -230
  326. package/dist/adapters/kysely/kysely-query.js.map +0 -1
  327. package/dist/adapters/kysely/kysely-shared.d.ts +0 -14
  328. package/dist/adapters/kysely/kysely-shared.d.ts.map +0 -1
  329. package/dist/adapters/kysely/kysely-shared.js +0 -33
  330. package/dist/adapters/kysely/kysely-shared.js.map +0 -1
  331. package/dist/adapters/kysely/kysely-uow-compiler.js +0 -193
  332. package/dist/adapters/kysely/kysely-uow-compiler.js.map +0 -1
  333. package/dist/adapters/kysely/kysely-uow-executor.js +0 -93
  334. package/dist/adapters/kysely/kysely-uow-executor.js.map +0 -1
  335. package/dist/adapters/kysely/migration/execute-base.js +0 -128
  336. package/dist/adapters/kysely/migration/execute-base.js.map +0 -1
  337. package/dist/adapters/kysely/migration/execute-factory.js +0 -34
  338. package/dist/adapters/kysely/migration/execute-factory.js.map +0 -1
  339. package/dist/adapters/kysely/migration/execute-mssql.js +0 -112
  340. package/dist/adapters/kysely/migration/execute-mssql.js.map +0 -1
  341. package/dist/adapters/kysely/migration/execute-mysql.js +0 -93
  342. package/dist/adapters/kysely/migration/execute-mysql.js.map +0 -1
  343. package/dist/adapters/kysely/migration/execute-postgres.js +0 -104
  344. package/dist/adapters/kysely/migration/execute-postgres.js.map +0 -1
  345. package/dist/adapters/kysely/migration/execute-sqlite.js +0 -123
  346. package/dist/adapters/kysely/migration/execute-sqlite.js.map +0 -1
  347. package/dist/adapters/kysely/migration/execute.js +0 -34
  348. package/dist/adapters/kysely/migration/execute.js.map +0 -1
  349. package/dist/migration-engine/create.d.ts +0 -37
  350. package/dist/migration-engine/create.d.ts.map +0 -1
  351. package/dist/migration-engine/create.js +0 -58
  352. package/dist/migration-engine/create.js.map +0 -1
  353. package/dist/migration-engine/shared.d.ts +0 -112
  354. package/dist/migration-engine/shared.d.ts.map +0 -1
  355. package/dist/node_modules/.pnpm/rou3@0.7.8/node_modules/rou3/dist/index.js.map +0 -1
  356. package/dist/query/execute-unit-of-work.d.ts.map +0 -1
  357. package/dist/query/execute-unit-of-work.js.map +0 -1
  358. package/dist/query/query.d.ts.map +0 -1
  359. package/dist/query/result-transform.js +0 -170
  360. package/dist/query/result-transform.js.map +0 -1
  361. package/dist/query/retry-policy.d.ts.map +0 -1
  362. package/dist/query/retry-policy.js.map +0 -1
  363. package/dist/query/unit-of-work.d.ts.map +0 -1
  364. package/dist/query/unit-of-work.js.map +0 -1
  365. package/dist/schema/serialize.js +0 -111
  366. package/dist/schema/serialize.js.map +0 -1
  367. package/src/adapters/drizzle/drizzle-adapter.test.ts +0 -122
  368. package/src/adapters/drizzle/drizzle-connection-pool.ts +0 -66
  369. package/src/adapters/drizzle/drizzle-query.test.ts +0 -499
  370. package/src/adapters/drizzle/drizzle-uow-compiler-mysql.test.ts +0 -1442
  371. package/src/adapters/drizzle/drizzle-uow-compiler-sqlite.test.ts +0 -1414
  372. package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +0 -1400
  373. package/src/adapters/drizzle/drizzle-uow-compiler.ts +0 -677
  374. package/src/adapters/drizzle/drizzle-uow-decoder.ts +0 -228
  375. package/src/adapters/drizzle/drizzle-uow-executor.ts +0 -309
  376. package/src/adapters/drizzle/join-column-utils.test.ts +0 -79
  377. package/src/adapters/drizzle/join-column-utils.ts +0 -39
  378. package/src/adapters/kysely/kysely-connection-pool.ts +0 -70
  379. package/src/adapters/kysely/kysely-query-builder.test.ts +0 -1344
  380. package/src/adapters/kysely/kysely-query-builder.ts +0 -666
  381. package/src/adapters/kysely/kysely-query-compiler.ts +0 -127
  382. package/src/adapters/kysely/kysely-query.test.ts +0 -498
  383. package/src/adapters/kysely/kysely-query.ts +0 -399
  384. package/src/adapters/kysely/kysely-shared.ts +0 -57
  385. package/src/adapters/kysely/kysely-uow-compiler.test.ts +0 -986
  386. package/src/adapters/kysely/kysely-uow-compiler.ts +0 -350
  387. package/src/adapters/kysely/kysely-uow-executor.ts +0 -164
  388. package/src/adapters/kysely/kysely-uow-joins.test.ts +0 -794
  389. package/src/adapters/kysely/migration/execute-base.ts +0 -256
  390. package/src/adapters/kysely/migration/execute-factory.ts +0 -53
  391. package/src/adapters/kysely/migration/execute-mssql.ts +0 -250
  392. package/src/adapters/kysely/migration/execute-mysql.ts +0 -211
  393. package/src/adapters/kysely/migration/execute-postgres.test.ts +0 -2657
  394. package/src/adapters/kysely/migration/execute-postgres.ts +0 -234
  395. package/src/adapters/kysely/migration/execute-sqlite.ts +0 -247
  396. package/src/adapters/kysely/migration/execute.ts +0 -50
  397. package/src/adapters/kysely/migration/kysely-migrator.test.ts +0 -261
  398. package/src/query/result-transform.ts +0 -274
  399. package/src/schema/serialize.ts +0 -407
  400. /package/dist/query/{query.js → simple-query-interface.js} +0 -0
  401. /package/src/query/{retry-policy.test.ts → unit-of-work/retry-policy.test.ts} +0 -0
  402. /package/src/query/{retry-policy.ts → unit-of-work/retry-policy.ts} +0 -0
@@ -0,0 +1,587 @@
1
+ import SQLite from "better-sqlite3";
2
+ import { SqliteDialect } from "kysely";
3
+ import { beforeAll, describe, expect, it, vi } from "vitest";
4
+ import { instantiate } from "@fragno-dev/core";
5
+ import { prepareHookMutations, processHooks, type HooksMap, type HookContext } from "./hooks";
6
+ import { internalFragmentDef, internalSchema } from "../fragments/internal-fragment";
7
+ import type { FragnoPublicConfigWithDatabase } from "../db-fragment-definition-builder";
8
+ import { DrizzleAdapter } from "../adapters/drizzle/drizzle-adapter";
9
+ import { BetterSQLite3DriverConfig } from "../adapters/generic-sql/driver-config";
10
+ import { ExponentialBackoffRetryPolicy, NoRetryPolicy } from "../query/unit-of-work/retry-policy";
11
+ import type { FragnoId } from "../schema/create";
12
+
13
+ describe("Hook System", () => {
14
+ let sqliteDatabase: SQLite.Database;
15
+ let adapter: DrizzleAdapter;
16
+ let internalFragment: ReturnType<typeof instantiateFragment>;
17
+
18
+ function instantiateFragment(options: FragnoPublicConfigWithDatabase) {
19
+ return instantiate(internalFragmentDef).withConfig({}).withOptions(options).build();
20
+ }
21
+
22
+ beforeAll(async () => {
23
+ sqliteDatabase = new SQLite(":memory:");
24
+
25
+ const dialect = new SqliteDialect({
26
+ database: sqliteDatabase,
27
+ });
28
+
29
+ adapter = new DrizzleAdapter({
30
+ dialect,
31
+ driverConfig: new BetterSQLite3DriverConfig(),
32
+ });
33
+
34
+ {
35
+ const migrations = adapter.prepareMigrations(internalSchema, "");
36
+ await migrations.executeWithDriver(adapter.driver, 0);
37
+ }
38
+
39
+ const options: FragnoPublicConfigWithDatabase = {
40
+ databaseAdapter: adapter,
41
+ };
42
+
43
+ internalFragment = instantiateFragment(options);
44
+
45
+ return async () => {
46
+ await adapter.close();
47
+ };
48
+ }, 12000);
49
+
50
+ describe("prepareHookMutations", () => {
51
+ it("should create hook records for triggered hooks", async () => {
52
+ const namespace = "test-namespace";
53
+ const hooks: HooksMap = {
54
+ onTest: vi.fn(),
55
+ };
56
+ const onSuccess = vi.fn();
57
+ const onBeforeMutate = vi.fn();
58
+
59
+ await internalFragment.inContext(async function () {
60
+ await this.uow(
61
+ async ({ forSchema, executeMutate }) => {
62
+ const uow = forSchema(internalSchema, hooks);
63
+
64
+ // Trigger a hook
65
+ uow.triggerHook("onTest", { data: "test" });
66
+
67
+ // Prepare hook mutations
68
+ prepareHookMutations(uow, {
69
+ hooks,
70
+ namespace,
71
+ internalFragment,
72
+ defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 5 }),
73
+ });
74
+
75
+ await executeMutate();
76
+ },
77
+ {
78
+ onSuccess,
79
+ onBeforeMutate,
80
+ },
81
+ );
82
+ });
83
+
84
+ // Verify callbacks were executed
85
+ expect(onSuccess).toHaveBeenCalledOnce();
86
+ expect(onBeforeMutate).toHaveBeenCalledOnce();
87
+
88
+ // Verify hook was created
89
+ const events = await internalFragment.inContext(async function () {
90
+ return await this.uow(async ({ executeRetrieve }) => {
91
+ const result = internalFragment.services.hookService.getPendingHookEvents(namespace);
92
+ await executeRetrieve();
93
+ return result;
94
+ });
95
+ });
96
+
97
+ expect(events).toHaveLength(1);
98
+ expect(events[0]).toMatchObject({
99
+ hookName: "onTest",
100
+ payload: { data: "test" },
101
+ attempts: 0,
102
+ maxAttempts: 5,
103
+ });
104
+ });
105
+
106
+ it("should set maxAttempts to 1 when retry policy does not retry", async () => {
107
+ const namespace = "test-no-retry";
108
+ const hooks: HooksMap = {
109
+ onNoRetry: vi.fn(),
110
+ };
111
+
112
+ await internalFragment.inContext(async function () {
113
+ await this.uow(async ({ forSchema, executeMutate }) => {
114
+ const uow = forSchema(internalSchema, hooks);
115
+
116
+ uow.triggerHook("onNoRetry", { data: "test" });
117
+
118
+ prepareHookMutations(uow, {
119
+ hooks,
120
+ namespace,
121
+ internalFragment,
122
+ defaultRetryPolicy: new NoRetryPolicy(),
123
+ });
124
+
125
+ await executeMutate();
126
+ });
127
+ });
128
+
129
+ const events = await internalFragment.inContext(async function () {
130
+ return await this.uow(async ({ executeRetrieve }) => {
131
+ const result = internalFragment.services.hookService.getPendingHookEvents(namespace);
132
+ await executeRetrieve();
133
+ return result;
134
+ });
135
+ });
136
+
137
+ expect(events).toHaveLength(1);
138
+ expect(events[0]?.maxAttempts).toBe(1);
139
+ });
140
+
141
+ it("should use custom retry policy from trigger options", async () => {
142
+ const namespace = "test-custom-retry";
143
+ const hooks: HooksMap = {
144
+ onCustomRetry: vi.fn(),
145
+ };
146
+
147
+ await internalFragment.inContext(async function () {
148
+ await this.uow(async ({ forSchema, executeMutate }) => {
149
+ const uow = forSchema(internalSchema, hooks);
150
+
151
+ uow.triggerHook(
152
+ "onCustomRetry",
153
+ { data: "test" },
154
+ {
155
+ retryPolicy: new NoRetryPolicy(),
156
+ },
157
+ );
158
+
159
+ prepareHookMutations(uow, {
160
+ hooks,
161
+ namespace,
162
+ internalFragment,
163
+ defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 10 }),
164
+ });
165
+
166
+ await executeMutate();
167
+ });
168
+ });
169
+
170
+ const events = await internalFragment.inContext(async function () {
171
+ return await this.uow(async ({ executeRetrieve }) => {
172
+ const result = internalFragment.services.hookService.getPendingHookEvents(namespace);
173
+ await executeRetrieve();
174
+ return result;
175
+ });
176
+ });
177
+
178
+ expect(events[0]?.maxAttempts).toBe(1);
179
+ });
180
+ });
181
+
182
+ describe("processHooks", () => {
183
+ it("should execute hooks and mark them as completed", async () => {
184
+ const namespace = "test-success";
185
+ const hookFn = vi.fn();
186
+ const hooks: HooksMap = {
187
+ onSuccess: hookFn,
188
+ };
189
+
190
+ let eventId: FragnoId;
191
+
192
+ // Create a pending hook event
193
+ await internalFragment.inContext(async function () {
194
+ await this.uow(async ({ forSchema, executeMutate }) => {
195
+ const uow = forSchema(internalSchema);
196
+ eventId = uow.create("fragno_hooks", {
197
+ namespace,
198
+ hookName: "onSuccess",
199
+ payload: { email: "test@example.com" },
200
+ status: "pending",
201
+ attempts: 0,
202
+ maxAttempts: 5,
203
+ lastAttemptAt: null,
204
+ nextRetryAt: null,
205
+ error: null,
206
+ nonce: "test-nonce",
207
+ });
208
+ await executeMutate();
209
+ });
210
+ });
211
+
212
+ // Process hooks
213
+ await processHooks({
214
+ hooks,
215
+ namespace,
216
+ internalFragment,
217
+ defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 3 }),
218
+ });
219
+
220
+ // Verify hook was called
221
+ expect(hookFn).toHaveBeenCalledOnce();
222
+ expect(hookFn).toHaveBeenCalledWith({ email: "test@example.com" });
223
+
224
+ // Verify hook context (this)
225
+ const hookContext = hookFn.mock.contexts[0] as HookContext;
226
+ expect(hookContext.nonce).toBe("test-nonce");
227
+
228
+ // Verify event was marked as completed
229
+ const result = await internalFragment.inContext(async function () {
230
+ return await this.uow(async ({ forSchema, executeRetrieve }) => {
231
+ const uow = forSchema(internalSchema);
232
+ const findUow = uow.find("fragno_hooks", (b) =>
233
+ b.whereIndex("primary", (eb) => eb("id", "=", eventId)),
234
+ );
235
+ await executeRetrieve();
236
+ const [events] = await findUow.retrievalPhase;
237
+ return events?.[0];
238
+ });
239
+ });
240
+
241
+ expect(result?.status).toBe("completed");
242
+ expect(result?.lastAttemptAt).toBeInstanceOf(Date);
243
+ });
244
+
245
+ it("should mark failed hooks for retry", async () => {
246
+ const namespace = "test-failure";
247
+ const hookFn = vi.fn().mockRejectedValue(new Error("Hook failed"));
248
+ const hooks: HooksMap = {
249
+ onFailure: hookFn,
250
+ };
251
+
252
+ let eventId: FragnoId;
253
+
254
+ await internalFragment.inContext(async function () {
255
+ await this.uow(async ({ forSchema, executeMutate }) => {
256
+ const uow = forSchema(internalSchema);
257
+ eventId = uow.create("fragno_hooks", {
258
+ namespace,
259
+ hookName: "onFailure",
260
+ payload: { data: "test" },
261
+ status: "pending",
262
+ attempts: 0,
263
+ maxAttempts: 5,
264
+ lastAttemptAt: null,
265
+ nextRetryAt: null,
266
+ error: null,
267
+ nonce: "test-nonce",
268
+ });
269
+ await executeMutate();
270
+ });
271
+ });
272
+
273
+ await processHooks({
274
+ hooks,
275
+ namespace,
276
+ internalFragment,
277
+ defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 3 }),
278
+ });
279
+
280
+ expect(hookFn).toHaveBeenCalledOnce();
281
+
282
+ const result = await internalFragment.inContext(async function () {
283
+ return await this.uow(async ({ forSchema, executeRetrieve }) => {
284
+ const uow = forSchema(internalSchema);
285
+ const findUow = uow.find("fragno_hooks", (b) =>
286
+ b.whereIndex("primary", (eb) => eb("id", "=", eventId)),
287
+ );
288
+ await executeRetrieve();
289
+ const [events] = await findUow.retrievalPhase;
290
+ return events?.[0];
291
+ });
292
+ });
293
+
294
+ expect(result?.status).toBe("pending");
295
+ expect(result?.attempts).toBe(1);
296
+ expect(result?.error).toBe("Hook failed");
297
+ expect(result?.nextRetryAt).toBeInstanceOf(Date);
298
+ });
299
+
300
+ it("should mark failed hooks as permanently failed when max retries exceeded", async () => {
301
+ const namespace = "test-max-retries";
302
+ const hookFn = vi.fn().mockRejectedValue(new Error("Permanent failure"));
303
+ const hooks: HooksMap = {
304
+ onMaxRetries: hookFn,
305
+ };
306
+
307
+ let eventId: FragnoId;
308
+
309
+ await internalFragment.inContext(async function () {
310
+ await this.uow(async ({ forSchema, executeMutate }) => {
311
+ const uow = forSchema(internalSchema);
312
+ eventId = uow.create("fragno_hooks", {
313
+ namespace,
314
+ hookName: "onMaxRetries",
315
+ payload: { data: "test" },
316
+ status: "pending",
317
+ attempts: 0,
318
+ maxAttempts: 1,
319
+ lastAttemptAt: null,
320
+ nextRetryAt: null,
321
+ error: null,
322
+ nonce: "test-nonce",
323
+ });
324
+ await executeMutate();
325
+ });
326
+ });
327
+
328
+ await processHooks({
329
+ hooks,
330
+ namespace,
331
+ internalFragment,
332
+ defaultRetryPolicy: new NoRetryPolicy(),
333
+ });
334
+
335
+ const result = await internalFragment.inContext(async function () {
336
+ return await this.uow(async ({ forSchema, executeRetrieve }) => {
337
+ const uow = forSchema(internalSchema);
338
+ const findUow = uow.find("fragno_hooks", (b) =>
339
+ b.whereIndex("primary", (eb) => eb("id", "=", eventId)),
340
+ );
341
+ await executeRetrieve();
342
+ const [events] = await findUow.retrievalPhase;
343
+ return events?.[0];
344
+ });
345
+ });
346
+
347
+ expect(result?.status).toBe("failed");
348
+ expect(result?.attempts).toBe(1);
349
+ expect(result?.error).toBe("Permanent failure");
350
+ });
351
+
352
+ it("should handle missing hooks gracefully", async () => {
353
+ const namespace = "test-missing-hook";
354
+ const hooks: HooksMap = {
355
+ onExisting: vi.fn(),
356
+ };
357
+
358
+ let eventId: FragnoId;
359
+
360
+ await internalFragment.inContext(async function () {
361
+ await this.uow(async ({ forSchema, executeMutate }) => {
362
+ const uow = forSchema(internalSchema);
363
+ eventId = uow.create("fragno_hooks", {
364
+ namespace,
365
+ hookName: "onMissing",
366
+ payload: { data: "test" },
367
+ status: "pending",
368
+ attempts: 0,
369
+ maxAttempts: 1,
370
+ lastAttemptAt: null,
371
+ nextRetryAt: null,
372
+ error: null,
373
+ nonce: "test-nonce",
374
+ });
375
+ await executeMutate();
376
+ });
377
+ });
378
+
379
+ await processHooks({
380
+ hooks,
381
+ namespace,
382
+ internalFragment,
383
+ defaultRetryPolicy: new NoRetryPolicy(),
384
+ });
385
+
386
+ const result = await internalFragment.inContext(async function () {
387
+ return await this.uow(async ({ forSchema, executeRetrieve }) => {
388
+ const uow = forSchema(internalSchema);
389
+ const findUow = uow.find("fragno_hooks", (b) =>
390
+ b.whereIndex("primary", (eb) => eb("id", "=", eventId)),
391
+ );
392
+ await executeRetrieve();
393
+ const [events] = await findUow.retrievalPhase;
394
+ return events?.[0];
395
+ });
396
+ });
397
+
398
+ expect(result?.status).toBe("failed");
399
+ expect(result?.error).toBe("Hook 'onMissing' not found in hooks map");
400
+ });
401
+
402
+ it("should process multiple hooks in parallel", async () => {
403
+ const namespace = "test-parallel";
404
+ const hook1 = vi.fn();
405
+ const hook2 = vi.fn();
406
+ const hook3 = vi.fn();
407
+ const hooks: HooksMap = {
408
+ onHook1: hook1,
409
+ onHook2: hook2,
410
+ onHook3: hook3,
411
+ };
412
+
413
+ await internalFragment.inContext(async function () {
414
+ await this.uow(async ({ forSchema, executeMutate }) => {
415
+ const uow = forSchema(internalSchema);
416
+ uow.create("fragno_hooks", {
417
+ namespace,
418
+ hookName: "onHook1",
419
+ payload: { id: 1 },
420
+ status: "pending",
421
+ attempts: 0,
422
+ maxAttempts: 5,
423
+ lastAttemptAt: null,
424
+ nextRetryAt: null,
425
+ error: null,
426
+ nonce: "nonce-1",
427
+ });
428
+ uow.create("fragno_hooks", {
429
+ namespace,
430
+ hookName: "onHook2",
431
+ payload: { id: 2 },
432
+ status: "pending",
433
+ attempts: 0,
434
+ maxAttempts: 5,
435
+ lastAttemptAt: null,
436
+ nextRetryAt: null,
437
+ error: null,
438
+ nonce: "nonce-2",
439
+ });
440
+ uow.create("fragno_hooks", {
441
+ namespace,
442
+ hookName: "onHook3",
443
+ payload: { id: 3 },
444
+ status: "pending",
445
+ attempts: 0,
446
+ maxAttempts: 5,
447
+ lastAttemptAt: null,
448
+ nextRetryAt: null,
449
+ error: null,
450
+ nonce: "nonce-3",
451
+ });
452
+ await executeMutate();
453
+ });
454
+ });
455
+
456
+ await processHooks({
457
+ hooks,
458
+ namespace,
459
+ internalFragment,
460
+ defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 3 }),
461
+ });
462
+
463
+ expect(hook1).toHaveBeenCalledWith({ id: 1 });
464
+ expect(hook2).toHaveBeenCalledWith({ id: 2 });
465
+ expect(hook3).toHaveBeenCalledWith({ id: 3 });
466
+
467
+ // Verify all were marked as completed
468
+ const events = await internalFragment.inContext(async function () {
469
+ return await this.uow(async ({ forSchema, executeRetrieve }) => {
470
+ const uow = forSchema(internalSchema);
471
+ const findUow = uow.find("fragno_hooks", (b) =>
472
+ b.whereIndex("idx_namespace_status_retry", (eb) => eb("namespace", "=", namespace)),
473
+ );
474
+ await executeRetrieve();
475
+ const [results] = await findUow.retrievalPhase;
476
+ return results;
477
+ });
478
+ });
479
+
480
+ const completed = events.filter((e) => e.status === "completed");
481
+ expect(completed).toHaveLength(3);
482
+ });
483
+
484
+ it("should continue processing other hooks when one fails", async () => {
485
+ const namespace = "test-partial-failure";
486
+ const hook1 = vi.fn();
487
+ const hook2 = vi.fn().mockRejectedValue(new Error("Hook 2 failed"));
488
+ const hook3 = vi.fn();
489
+ const hooks: HooksMap = {
490
+ onHook1: hook1,
491
+ onHook2: hook2,
492
+ onHook3: hook3,
493
+ };
494
+
495
+ await internalFragment.inContext(async function () {
496
+ await this.uow(async ({ forSchema, executeMutate }) => {
497
+ const uow = forSchema(internalSchema);
498
+ uow.create("fragno_hooks", {
499
+ namespace,
500
+ hookName: "onHook1",
501
+ payload: { id: 1 },
502
+ status: "pending",
503
+ attempts: 0,
504
+ maxAttempts: 5,
505
+ lastAttemptAt: null,
506
+ nextRetryAt: null,
507
+ error: null,
508
+ nonce: "nonce-1",
509
+ });
510
+ uow.create("fragno_hooks", {
511
+ namespace,
512
+ hookName: "onHook2",
513
+ payload: { id: 2 },
514
+ status: "pending",
515
+ attempts: 0,
516
+ maxAttempts: 5,
517
+ lastAttemptAt: null,
518
+ nextRetryAt: null,
519
+ error: null,
520
+ nonce: "nonce-2",
521
+ });
522
+ uow.create("fragno_hooks", {
523
+ namespace,
524
+ hookName: "onHook3",
525
+ payload: { id: 3 },
526
+ status: "pending",
527
+ attempts: 0,
528
+ maxAttempts: 5,
529
+ lastAttemptAt: null,
530
+ nextRetryAt: null,
531
+ error: null,
532
+ nonce: "nonce-3",
533
+ });
534
+ await executeMutate();
535
+ });
536
+ });
537
+
538
+ await processHooks({
539
+ hooks,
540
+ namespace,
541
+ internalFragment,
542
+ defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 3 }),
543
+ });
544
+
545
+ expect(hook1).toHaveBeenCalledOnce();
546
+ expect(hook2).toHaveBeenCalledOnce();
547
+ expect(hook3).toHaveBeenCalledOnce();
548
+
549
+ // Verify hook1 and hook3 were completed, hook2 was marked for retry
550
+ const events = await internalFragment.inContext(async function () {
551
+ return await this.uow(async ({ forSchema, executeRetrieve }) => {
552
+ const uow = forSchema(internalSchema);
553
+ const findUow = uow.find("fragno_hooks", (b) =>
554
+ b.whereIndex("idx_namespace_status_retry", (eb) => eb("namespace", "=", namespace)),
555
+ );
556
+ await executeRetrieve();
557
+ const [results] = await findUow.retrievalPhase;
558
+ return results;
559
+ });
560
+ });
561
+
562
+ const completed = events.filter((e) => e.status === "completed");
563
+ const pending = events.filter((e) => e.status === "pending" && e.attempts === 1);
564
+
565
+ expect(completed).toHaveLength(2);
566
+ expect(pending).toHaveLength(1);
567
+ expect(pending[0]?.error).toBe("Hook 2 failed");
568
+ });
569
+
570
+ it("should do nothing when no pending events exist", async () => {
571
+ const namespace = "test-no-events";
572
+ const hookFn = vi.fn();
573
+ const hooks: HooksMap = {
574
+ onTest: hookFn,
575
+ };
576
+
577
+ await processHooks({
578
+ hooks,
579
+ namespace,
580
+ internalFragment,
581
+ defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 3 }),
582
+ });
583
+
584
+ expect(hookFn).not.toHaveBeenCalled();
585
+ });
586
+ });
587
+ });