@fragno-dev/db 0.1.14 → 0.2.0

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