@fragno-dev/db 0.1.15 → 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 (407) hide show
  1. package/.turbo/turbo-build.log +242 -179
  2. package/CHANGELOG.md +23 -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 +53 -19
  80. package/dist/db-fragment-definition-builder.d.ts.map +1 -1
  81. package/dist/db-fragment-definition-builder.js +89 -19
  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} +13 -3
  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} +17 -4
  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} +51 -18
  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} +58 -11
  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/create.d.ts +3 -0
  140. package/dist/schema/create.d.ts.map +1 -1
  141. package/dist/schema/create.js +4 -0
  142. package/dist/schema/create.js.map +1 -1
  143. package/dist/schema/type-conversion/create-sql-type-mapper.js +29 -0
  144. package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -0
  145. package/dist/schema/type-conversion/dialect/mysql.js +57 -0
  146. package/dist/schema/type-conversion/dialect/mysql.js.map +1 -0
  147. package/dist/schema/type-conversion/dialect/postgres.js +56 -0
  148. package/dist/schema/type-conversion/dialect/postgres.js.map +1 -0
  149. package/dist/schema/type-conversion/dialect/sqlite.js +52 -0
  150. package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -0
  151. package/dist/schema/type-conversion/type-mapping.js +63 -0
  152. package/dist/schema/type-conversion/type-mapping.js.map +1 -0
  153. package/dist/sql-driver/connection/connection-provider.d.ts +13 -0
  154. package/dist/sql-driver/connection/connection-provider.d.ts.map +1 -0
  155. package/dist/sql-driver/connection/connection-provider.js +19 -0
  156. package/dist/sql-driver/connection/connection-provider.js.map +1 -0
  157. package/dist/sql-driver/connection/single-connection-provider.js +23 -0
  158. package/dist/sql-driver/connection/single-connection-provider.js.map +1 -0
  159. package/dist/sql-driver/dialect-adapter/dialect-adapter.d.ts +7 -0
  160. package/dist/sql-driver/dialect-adapter/dialect-adapter.d.ts.map +1 -0
  161. package/dist/sql-driver/dialects/dialects.d.ts +2 -0
  162. package/dist/sql-driver/dialects/dialects.js +3 -0
  163. package/dist/sql-driver/dialects/durable-object-dialect.d.ts +72 -0
  164. package/dist/sql-driver/dialects/durable-object-dialect.d.ts.map +1 -0
  165. package/dist/sql-driver/dialects/durable-object-dialect.js +130 -0
  166. package/dist/sql-driver/dialects/durable-object-dialect.js.map +1 -0
  167. package/dist/sql-driver/driver/runtime-driver.d.ts +23 -0
  168. package/dist/sql-driver/driver/runtime-driver.d.ts.map +1 -0
  169. package/dist/sql-driver/driver/runtime-driver.js +56 -0
  170. package/dist/sql-driver/driver/runtime-driver.js.map +1 -0
  171. package/dist/sql-driver/query-executor/default-query-executor.js +26 -0
  172. package/dist/sql-driver/query-executor/default-query-executor.js.map +1 -0
  173. package/dist/sql-driver/query-executor/plugin.d.ts +17 -0
  174. package/dist/sql-driver/query-executor/plugin.d.ts.map +1 -0
  175. package/dist/sql-driver/query-executor/query-executor-base.js +25 -0
  176. package/dist/sql-driver/query-executor/query-executor-base.js.map +1 -0
  177. package/dist/sql-driver/query-executor/query-executor.d.ts +36 -0
  178. package/dist/sql-driver/query-executor/query-executor.d.ts.map +1 -0
  179. package/dist/sql-driver/sql-driver-adapter.d.ts +29 -0
  180. package/dist/sql-driver/sql-driver-adapter.d.ts.map +1 -0
  181. package/dist/sql-driver/sql-driver-adapter.js +68 -0
  182. package/dist/sql-driver/sql-driver-adapter.js.map +1 -0
  183. package/dist/sql-driver/sql-driver.d.ts +38 -0
  184. package/dist/sql-driver/sql-driver.d.ts.map +1 -0
  185. package/dist/sql-driver/sql-driver.js +1 -0
  186. package/dist/sql-driver/sql.js +50 -0
  187. package/dist/sql-driver/sql.js.map +1 -0
  188. package/dist/with-database.d.ts +6 -2
  189. package/dist/with-database.d.ts.map +1 -1
  190. package/dist/with-database.js +1 -1
  191. package/dist/with-database.js.map +1 -1
  192. package/package.json +37 -10
  193. package/src/adapters/adapters.ts +8 -5
  194. package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +60 -169
  195. package/src/adapters/drizzle/{drizzle-adapter-sqlite.test.ts → drizzle-adapter-sqlite3.test.ts} +31 -55
  196. package/src/adapters/drizzle/drizzle-adapter.ts +15 -107
  197. package/src/adapters/drizzle/generate.test.ts +2 -2
  198. package/src/adapters/drizzle/generate.ts +78 -34
  199. package/src/adapters/drizzle/migrate-drizzle.test.ts +19 -0
  200. package/src/adapters/drizzle/shared.ts +0 -34
  201. package/src/adapters/drizzle/test-utils.ts +3 -3
  202. package/src/adapters/generic-sql/README.md +14 -0
  203. package/src/adapters/generic-sql/driver-config.ts +144 -0
  204. package/src/adapters/generic-sql/generic-sql-adapter.test.ts +50 -0
  205. package/src/adapters/generic-sql/generic-sql-adapter.ts +146 -0
  206. package/src/adapters/generic-sql/generic-sql-uow-executor.ts +130 -0
  207. package/src/adapters/generic-sql/migration/cold-kysely.ts +55 -0
  208. package/src/adapters/{kysely/migration/execute-mysql.test.ts → generic-sql/migration/dialect/mysql.test.ts} +342 -484
  209. package/src/adapters/generic-sql/migration/dialect/mysql.ts +104 -0
  210. package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +1008 -0
  211. package/src/adapters/generic-sql/migration/dialect/postgres.ts +113 -0
  212. package/src/adapters/{kysely/migration/execute-sqlite.test.ts → generic-sql/migration/dialect/sqlite.test.ts} +307 -510
  213. package/src/adapters/generic-sql/migration/dialect/sqlite.ts +189 -0
  214. package/src/adapters/generic-sql/migration/executor.ts +33 -0
  215. package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +661 -0
  216. package/src/adapters/generic-sql/migration/prepared-migrations.ts +214 -0
  217. package/src/adapters/generic-sql/migration/sql-generator.ts +413 -0
  218. package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +36 -0
  219. package/src/adapters/generic-sql/query/cursor-utils.ts +56 -0
  220. package/src/adapters/generic-sql/query/dialect/mysql.ts +34 -0
  221. package/src/adapters/generic-sql/query/dialect/postgres.ts +32 -0
  222. package/src/adapters/generic-sql/query/dialect/sqlite.ts +32 -0
  223. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +1568 -0
  224. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +314 -0
  225. package/src/adapters/generic-sql/query/select-builder.test.ts +256 -0
  226. package/src/adapters/generic-sql/query/select-builder.ts +137 -0
  227. package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +195 -0
  228. package/src/adapters/generic-sql/query/sql-query-compiler.ts +367 -0
  229. package/src/adapters/generic-sql/query/where-builder.test.ts +744 -0
  230. package/src/adapters/generic-sql/query/where-builder.ts +211 -0
  231. package/src/adapters/generic-sql/result-interpreter.ts +102 -0
  232. package/src/adapters/generic-sql/test/generic-drizzle-adapter-sqlite3.test.ts +899 -0
  233. package/src/adapters/generic-sql/uow-decoder.test.ts +399 -0
  234. package/src/adapters/generic-sql/uow-decoder.ts +152 -0
  235. package/src/adapters/generic-sql/uow-encoder.test.ts +183 -0
  236. package/src/adapters/generic-sql/uow-encoder.ts +131 -0
  237. package/src/adapters/kysely/kysely-adapter-pglite.test.ts +26 -76
  238. package/src/adapters/kysely/{kysely-adapter-sqlite.test.ts → kysely-adapter-sqlocal.test.ts} +76 -17
  239. package/src/adapters/kysely/kysely-adapter.ts +10 -250
  240. package/src/adapters/{drizzle/drizzle-query.ts → shared/from-unit-of-work-compiler.ts} +110 -104
  241. package/src/adapters/shared/table-name-mapper.ts +50 -0
  242. package/src/adapters/shared/uow-operation-compiler.ts +211 -0
  243. package/src/db-fragment-definition-builder.test.ts +2 -2
  244. package/src/db-fragment-definition-builder.ts +281 -50
  245. package/src/db-fragment-instantiator.test.ts +78 -2
  246. package/src/db-fragment-integration.test.ts +14 -16
  247. package/src/fragments/internal-fragment.test.ts +434 -45
  248. package/src/fragments/internal-fragment.ts +184 -20
  249. package/src/hooks/hooks.test.ts +575 -0
  250. package/src/hooks/hooks.ts +179 -0
  251. package/src/migration-engine/generation-engine.test.ts +44 -54
  252. package/src/migration-engine/generation-engine.ts +48 -94
  253. package/src/mod.ts +117 -29
  254. package/src/query/column-defaults.ts +49 -0
  255. package/src/query/cursor.test.ts +31 -6
  256. package/src/query/cursor.ts +11 -7
  257. package/src/query/orm/orm.ts +1 -1
  258. package/src/query/query-type.test.ts +9 -9
  259. package/src/query/serialize/create-sql-serializer.ts +34 -0
  260. package/src/query/serialize/dialect/mysql-serializer.ts +142 -0
  261. package/src/query/serialize/dialect/postgres-serializer.ts +129 -0
  262. package/src/query/serialize/dialect/sqlite-serializer.test.ts +251 -0
  263. package/src/query/serialize/dialect/sqlite-serializer.ts +156 -0
  264. package/src/query/serialize/sql-serializer.ts +143 -0
  265. package/src/query/{query.ts → simple-query-interface.ts} +2 -2
  266. package/src/query/{execute-unit-of-work.test.ts → unit-of-work/execute-unit-of-work.test.ts} +16 -16
  267. package/src/query/{execute-unit-of-work.ts → unit-of-work/execute-unit-of-work.ts} +49 -8
  268. package/src/query/{unit-of-work-coordinator.test.ts → unit-of-work/unit-of-work-coordinator.test.ts} +41 -43
  269. package/src/query/{unit-of-work-types.test.ts → unit-of-work/unit-of-work-types.test.ts} +5 -3
  270. package/src/query/{unit-of-work.test.ts → unit-of-work/unit-of-work.test.ts} +100 -9
  271. package/src/query/{unit-of-work.ts → unit-of-work/unit-of-work.ts} +135 -32
  272. package/src/query/{result-transform.test.ts → value-decoding.test.ts} +45 -427
  273. package/src/query/value-decoding.ts +113 -0
  274. package/src/query/value-encoding.test.ts +390 -0
  275. package/src/query/value-encoding.ts +168 -0
  276. package/src/schema/create.test.ts +5 -1
  277. package/src/schema/create.ts +5 -0
  278. package/src/schema/serialize.test.ts +165 -407
  279. package/src/schema/type-conversion/create-sql-type-mapper.ts +28 -0
  280. package/src/schema/type-conversion/dialect/mysql.ts +64 -0
  281. package/src/schema/type-conversion/dialect/postgres.ts +62 -0
  282. package/src/schema/type-conversion/dialect/sqlite.ts +63 -0
  283. package/src/schema/type-conversion/type-mapping.test.ts +137 -0
  284. package/src/schema/type-conversion/type-mapping.ts +153 -0
  285. package/src/shared/connection-pool.ts +5 -5
  286. package/src/sql-driver/better-sqlite3.test.ts +126 -0
  287. package/src/sql-driver/connection/connection-provider.ts +27 -0
  288. package/src/sql-driver/connection/single-connection-provider.ts +42 -0
  289. package/src/sql-driver/dialect-adapter/dialect-adapter.ts +9 -0
  290. package/src/sql-driver/dialect-adapter/sqlite-dialect-adapter.ts +7 -0
  291. package/src/sql-driver/dialects/dialects.ts +1 -0
  292. package/src/sql-driver/dialects/durable-object-dialect.ts +260 -0
  293. package/src/sql-driver/driver/runtime-driver.ts +91 -0
  294. package/src/sql-driver/query-executor/default-query-executor.ts +38 -0
  295. package/src/sql-driver/query-executor/plugin.ts +22 -0
  296. package/src/sql-driver/query-executor/query-executor-base.ts +53 -0
  297. package/src/sql-driver/query-executor/query-executor.ts +44 -0
  298. package/src/sql-driver/sql-driver-adapter.ts +96 -0
  299. package/src/sql-driver/sql-driver.ts +53 -0
  300. package/src/sql-driver/sql.ts +57 -0
  301. package/src/sql-driver/sqlocal.test.ts +117 -0
  302. package/src/with-database.ts +35 -23
  303. package/tsdown.config.ts +7 -2
  304. package/dist/adapters/drizzle/drizzle-connection-pool.js +0 -40
  305. package/dist/adapters/drizzle/drizzle-connection-pool.js.map +0 -1
  306. package/dist/adapters/drizzle/drizzle-query.d.ts +0 -23
  307. package/dist/adapters/drizzle/drizzle-query.d.ts.map +0 -1
  308. package/dist/adapters/drizzle/drizzle-query.js.map +0 -1
  309. package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +0 -10
  310. package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +0 -1
  311. package/dist/adapters/drizzle/drizzle-uow-compiler.js +0 -334
  312. package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +0 -1
  313. package/dist/adapters/drizzle/drizzle-uow-decoder.js +0 -123
  314. package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +0 -1
  315. package/dist/adapters/drizzle/drizzle-uow-executor.js +0 -160
  316. package/dist/adapters/drizzle/drizzle-uow-executor.js.map +0 -1
  317. package/dist/adapters/drizzle/join-column-utils.js +0 -28
  318. package/dist/adapters/drizzle/join-column-utils.js.map +0 -1
  319. package/dist/adapters/drizzle/shared.d.ts.map +0 -1
  320. package/dist/adapters/drizzle/shared.js +0 -35
  321. package/dist/adapters/drizzle/shared.js.map +0 -1
  322. package/dist/adapters/kysely/kysely-connection-pool.js +0 -41
  323. package/dist/adapters/kysely/kysely-connection-pool.js.map +0 -1
  324. package/dist/adapters/kysely/kysely-query-builder.js +0 -321
  325. package/dist/adapters/kysely/kysely-query-builder.js.map +0 -1
  326. package/dist/adapters/kysely/kysely-query-compiler.js +0 -67
  327. package/dist/adapters/kysely/kysely-query-compiler.js.map +0 -1
  328. package/dist/adapters/kysely/kysely-query.d.ts +0 -23
  329. package/dist/adapters/kysely/kysely-query.d.ts.map +0 -1
  330. package/dist/adapters/kysely/kysely-query.js +0 -230
  331. package/dist/adapters/kysely/kysely-query.js.map +0 -1
  332. package/dist/adapters/kysely/kysely-shared.d.ts +0 -14
  333. package/dist/adapters/kysely/kysely-shared.d.ts.map +0 -1
  334. package/dist/adapters/kysely/kysely-shared.js +0 -33
  335. package/dist/adapters/kysely/kysely-shared.js.map +0 -1
  336. package/dist/adapters/kysely/kysely-uow-compiler.js +0 -193
  337. package/dist/adapters/kysely/kysely-uow-compiler.js.map +0 -1
  338. package/dist/adapters/kysely/kysely-uow-executor.js +0 -93
  339. package/dist/adapters/kysely/kysely-uow-executor.js.map +0 -1
  340. package/dist/adapters/kysely/migration/execute-base.js +0 -128
  341. package/dist/adapters/kysely/migration/execute-base.js.map +0 -1
  342. package/dist/adapters/kysely/migration/execute-factory.js +0 -34
  343. package/dist/adapters/kysely/migration/execute-factory.js.map +0 -1
  344. package/dist/adapters/kysely/migration/execute-mssql.js +0 -112
  345. package/dist/adapters/kysely/migration/execute-mssql.js.map +0 -1
  346. package/dist/adapters/kysely/migration/execute-mysql.js +0 -93
  347. package/dist/adapters/kysely/migration/execute-mysql.js.map +0 -1
  348. package/dist/adapters/kysely/migration/execute-postgres.js +0 -104
  349. package/dist/adapters/kysely/migration/execute-postgres.js.map +0 -1
  350. package/dist/adapters/kysely/migration/execute-sqlite.js +0 -123
  351. package/dist/adapters/kysely/migration/execute-sqlite.js.map +0 -1
  352. package/dist/adapters/kysely/migration/execute.js +0 -34
  353. package/dist/adapters/kysely/migration/execute.js.map +0 -1
  354. package/dist/migration-engine/create.d.ts +0 -37
  355. package/dist/migration-engine/create.d.ts.map +0 -1
  356. package/dist/migration-engine/create.js +0 -58
  357. package/dist/migration-engine/create.js.map +0 -1
  358. package/dist/migration-engine/shared.d.ts +0 -112
  359. package/dist/migration-engine/shared.d.ts.map +0 -1
  360. package/dist/node_modules/.pnpm/rou3@0.7.8/node_modules/rou3/dist/index.js.map +0 -1
  361. package/dist/query/execute-unit-of-work.d.ts.map +0 -1
  362. package/dist/query/execute-unit-of-work.js.map +0 -1
  363. package/dist/query/query.d.ts.map +0 -1
  364. package/dist/query/result-transform.js +0 -170
  365. package/dist/query/result-transform.js.map +0 -1
  366. package/dist/query/retry-policy.d.ts.map +0 -1
  367. package/dist/query/retry-policy.js.map +0 -1
  368. package/dist/query/unit-of-work.d.ts.map +0 -1
  369. package/dist/query/unit-of-work.js.map +0 -1
  370. package/dist/schema/serialize.js +0 -111
  371. package/dist/schema/serialize.js.map +0 -1
  372. package/src/adapters/drizzle/drizzle-adapter.test.ts +0 -122
  373. package/src/adapters/drizzle/drizzle-connection-pool.ts +0 -66
  374. package/src/adapters/drizzle/drizzle-query.test.ts +0 -499
  375. package/src/adapters/drizzle/drizzle-uow-compiler-mysql.test.ts +0 -1442
  376. package/src/adapters/drizzle/drizzle-uow-compiler-sqlite.test.ts +0 -1414
  377. package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +0 -1400
  378. package/src/adapters/drizzle/drizzle-uow-compiler.ts +0 -677
  379. package/src/adapters/drizzle/drizzle-uow-decoder.ts +0 -228
  380. package/src/adapters/drizzle/drizzle-uow-executor.ts +0 -309
  381. package/src/adapters/drizzle/join-column-utils.test.ts +0 -79
  382. package/src/adapters/drizzle/join-column-utils.ts +0 -39
  383. package/src/adapters/kysely/kysely-connection-pool.ts +0 -70
  384. package/src/adapters/kysely/kysely-query-builder.test.ts +0 -1344
  385. package/src/adapters/kysely/kysely-query-builder.ts +0 -666
  386. package/src/adapters/kysely/kysely-query-compiler.ts +0 -127
  387. package/src/adapters/kysely/kysely-query.test.ts +0 -498
  388. package/src/adapters/kysely/kysely-query.ts +0 -399
  389. package/src/adapters/kysely/kysely-shared.ts +0 -57
  390. package/src/adapters/kysely/kysely-uow-compiler.test.ts +0 -986
  391. package/src/adapters/kysely/kysely-uow-compiler.ts +0 -350
  392. package/src/adapters/kysely/kysely-uow-executor.ts +0 -164
  393. package/src/adapters/kysely/kysely-uow-joins.test.ts +0 -794
  394. package/src/adapters/kysely/migration/execute-base.ts +0 -256
  395. package/src/adapters/kysely/migration/execute-factory.ts +0 -53
  396. package/src/adapters/kysely/migration/execute-mssql.ts +0 -250
  397. package/src/adapters/kysely/migration/execute-mysql.ts +0 -211
  398. package/src/adapters/kysely/migration/execute-postgres.test.ts +0 -2657
  399. package/src/adapters/kysely/migration/execute-postgres.ts +0 -234
  400. package/src/adapters/kysely/migration/execute-sqlite.ts +0 -247
  401. package/src/adapters/kysely/migration/execute.ts +0 -50
  402. package/src/adapters/kysely/migration/kysely-migrator.test.ts +0 -261
  403. package/src/query/result-transform.ts +0 -274
  404. package/src/schema/serialize.ts +0 -407
  405. /package/dist/query/{query.js → simple-query-interface.js} +0 -0
  406. /package/src/query/{retry-policy.test.ts → unit-of-work/retry-policy.test.ts} +0 -0
  407. /package/src/query/{retry-policy.ts → unit-of-work/retry-policy.ts} +0 -0
@@ -1,4 +1,3 @@
1
- import { Kysely } from "kysely";
2
1
  import { SQLocalKysely } from "sqlocal/kysely";
3
2
  import { assert, beforeAll, describe, expect, it } from "vitest";
4
3
  import { z } from "zod";
@@ -8,6 +7,8 @@ import { defineFragment, instantiate } from "@fragno-dev/core";
8
7
  import { defineRoutes } from "@fragno-dev/core/route";
9
8
  import { withDatabase } from "./with-database";
10
9
  import type { FragnoPublicConfigWithDatabase } from "./db-fragment-definition-builder";
10
+ import { ConcurrencyConflictError } from "./query/unit-of-work/execute-unit-of-work";
11
+ import { SQLocalDriverConfig } from "./adapters/generic-sql/driver-config";
11
12
 
12
13
  describe.sequential("Database Fragment Integration", () => {
13
14
  // Schema 1: Users fragment
@@ -180,8 +181,6 @@ describe.sequential("Database Fragment Integration", () => {
180
181
  ]);
181
182
 
182
183
  let adapter: KyselyAdapter;
183
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
184
- let kysely: Kysely<any>;
185
184
  let usersFragment: ReturnType<typeof instantiateUsersFragment>;
186
185
  let ordersFragment: ReturnType<typeof instantiateOrdersFragment>;
187
186
 
@@ -211,23 +210,21 @@ describe.sequential("Database Fragment Integration", () => {
211
210
  beforeAll(async () => {
212
211
  // Create in-memory SQLite database with Kysely
213
212
  const { dialect } = new SQLocalKysely(":memory:");
214
- kysely = new Kysely({
215
- dialect,
216
- });
217
-
218
213
  adapter = new KyselyAdapter({
219
- db: kysely,
220
- provider: "sqlite",
214
+ dialect,
215
+ driverConfig: new SQLocalDriverConfig(),
221
216
  });
222
217
 
223
218
  // Run migrations for both schemas
224
- const usersMigrator = adapter.createMigrationEngine(usersSchema, "users");
225
- const usersPrep = await usersMigrator.prepareMigration({ updateSettings: false });
226
- await usersPrep.execute();
219
+ const usersPreparedMigrations = adapter.prepareMigrations(usersSchema, "users");
220
+ await usersPreparedMigrations.execute(0, usersSchema.version, {
221
+ updateVersionInMigration: false,
222
+ });
227
223
 
228
- const ordersMigrator = adapter.createMigrationEngine(ordersSchema, "orders");
229
- const ordersPrep = await ordersMigrator.prepareMigration({ updateSettings: false });
230
- await ordersPrep.execute();
224
+ const ordersPreparedMigrations = adapter.prepareMigrations(ordersSchema, "orders");
225
+ await ordersPreparedMigrations.execute(0, ordersSchema.version, {
226
+ updateVersionInMigration: false,
227
+ });
231
228
 
232
229
  // Instantiate fragments with shared database adapter
233
230
  const options: FragnoPublicConfigWithDatabase = {
@@ -375,7 +372,8 @@ describe.sequential("Database Fragment Integration", () => {
375
372
 
376
373
  if (currentAttempt === 0) {
377
374
  firstNonce = nonce;
378
- throw new Error("Test error");
375
+ // Trigger a conflict by throwing the specific conflict error
376
+ throw new ConcurrencyConflictError();
379
377
  }
380
378
 
381
379
  expect(nonce).toBe(firstNonce);
@@ -1,22 +1,17 @@
1
- import { drizzle } from "drizzle-orm/libsql";
1
+ import SQLite from "better-sqlite3";
2
+ import { SqliteDialect } from "kysely";
2
3
  import { beforeAll, describe, expect, it } from "vitest";
3
4
  import { instantiate } from "@fragno-dev/core";
4
- import { internalFragmentDef, settingsSchema } from "./internal-fragment";
5
+ import { internalFragmentDef, internalSchema, SETTINGS_NAMESPACE } from "./internal-fragment";
5
6
  import type { FragnoPublicConfigWithDatabase } from "../db-fragment-definition-builder";
6
7
  import { DrizzleAdapter } from "../adapters/drizzle/drizzle-adapter";
7
- import type { DBType } from "../adapters/drizzle/shared";
8
- import { writeAndLoadSchema } from "../adapters/drizzle/test-utils";
9
- import { createClient } from "@libsql/client";
10
- import { createRequire } from "node:module";
11
-
12
- // Import drizzle-kit for migrations
13
- const require = createRequire(import.meta.url);
14
- const { generateSQLiteDrizzleJson, generateSQLiteMigration } =
15
- require("drizzle-kit/api") as typeof import("drizzle-kit/api");
8
+ import { BetterSQLite3DriverConfig } from "../adapters/generic-sql/driver-config";
9
+ import { ExponentialBackoffRetryPolicy, NoRetryPolicy } from "../query/unit-of-work/retry-policy";
10
+ import type { FragnoId } from "../schema/create";
16
11
 
17
12
  describe("Internal Fragment", () => {
13
+ let sqliteDatabase: SQLite.Database;
18
14
  let adapter: DrizzleAdapter;
19
- let db: DBType;
20
15
  let fragment: ReturnType<typeof instantiateFragment>;
21
16
 
22
17
  function instantiateFragment(options: FragnoPublicConfigWithDatabase) {
@@ -24,36 +19,22 @@ describe("Internal Fragment", () => {
24
19
  }
25
20
 
26
21
  beforeAll(async () => {
27
- const { schemaModule, cleanup } = await writeAndLoadSchema(
28
- "internal-fragment",
29
- settingsSchema,
30
- "sqlite",
31
- "",
32
- );
22
+ sqliteDatabase = new SQLite(":memory:");
33
23
 
34
- const client = createClient({
35
- url: "file::memory:?cache=shared",
24
+ const dialect = new SqliteDialect({
25
+ database: sqliteDatabase,
36
26
  });
37
27
 
38
- db = drizzle(client, {
39
- schema: schemaModule,
40
- }) as unknown as DBType;
41
-
42
- // Generate and run migrations for both schemas
43
- const emptyJson = await generateSQLiteDrizzleJson({});
44
- const targetJson = await generateSQLiteDrizzleJson(schemaModule);
45
-
46
- const migrationStatements = await generateSQLiteMigration(emptyJson, targetJson);
47
-
48
- for (const statement of migrationStatements) {
49
- await client.execute(statement);
50
- }
51
-
52
28
  adapter = new DrizzleAdapter({
53
- db,
54
- provider: "sqlite",
29
+ dialect,
30
+ driverConfig: new BetterSQLite3DriverConfig(),
55
31
  });
56
32
 
33
+ {
34
+ const migrations = adapter.prepareMigrations(internalSchema, "");
35
+ await migrations.executeWithDriver(adapter.driver, 0);
36
+ }
37
+
57
38
  // Instantiate fragment with shared database adapter
58
39
  const options: FragnoPublicConfigWithDatabase = {
59
40
  databaseAdapter: adapter,
@@ -62,15 +43,14 @@ describe("Internal Fragment", () => {
62
43
  fragment = instantiateFragment(options);
63
44
 
64
45
  return async () => {
65
- client.close();
66
- await cleanup();
46
+ await adapter.close();
67
47
  };
68
48
  }, 12000);
69
49
 
70
50
  it("should get undefined for non-existent key", async () => {
71
51
  const result = await fragment.inContext(async function () {
72
52
  return await this.uow(async ({ executeRetrieve }) => {
73
- const valuePromise = fragment.services.settingsService.get("test-key");
53
+ const valuePromise = fragment.services.settingsService.get(SETTINGS_NAMESPACE, "test-key");
74
54
  await executeRetrieve();
75
55
  return await valuePromise;
76
56
  });
@@ -82,7 +62,11 @@ describe("Internal Fragment", () => {
82
62
  it("should set and get a value", async () => {
83
63
  await fragment.inContext(async function () {
84
64
  return await this.uow(async ({ executeMutate }) => {
85
- const setPromise = fragment.services.settingsService.set("test-key", "test-value");
65
+ const setPromise = fragment.services.settingsService.set(
66
+ SETTINGS_NAMESPACE,
67
+ "test-key",
68
+ "test-value",
69
+ );
86
70
  await executeMutate();
87
71
  await setPromise;
88
72
  });
@@ -90,7 +74,7 @@ describe("Internal Fragment", () => {
90
74
 
91
75
  const result = await fragment.inContext(async function () {
92
76
  return await this.uow(async ({ executeRetrieve }) => {
93
- const valuePromise = fragment.services.settingsService.get("test-key");
77
+ const valuePromise = fragment.services.settingsService.get(SETTINGS_NAMESPACE, "test-key");
94
78
  await executeRetrieve();
95
79
  return await valuePromise;
96
80
  });
@@ -105,7 +89,11 @@ describe("Internal Fragment", () => {
105
89
  it("should update an existing value", async () => {
106
90
  await fragment.inContext(async function () {
107
91
  return await this.uow(async ({ executeMutate }) => {
108
- const setPromise = fragment.services.settingsService.set("test-key", "updated-value");
92
+ const setPromise = fragment.services.settingsService.set(
93
+ SETTINGS_NAMESPACE,
94
+ "test-key",
95
+ "updated-value",
96
+ );
109
97
  await executeMutate();
110
98
  await setPromise;
111
99
  });
@@ -113,7 +101,7 @@ describe("Internal Fragment", () => {
113
101
 
114
102
  const result = await fragment.inContext(async function () {
115
103
  return await this.uow(async ({ executeRetrieve }) => {
116
- const valuePromise = fragment.services.settingsService.get("test-key");
104
+ const valuePromise = fragment.services.settingsService.get(SETTINGS_NAMESPACE, "test-key");
117
105
  await executeRetrieve();
118
106
  return await valuePromise;
119
107
  });
@@ -129,7 +117,7 @@ describe("Internal Fragment", () => {
129
117
  // First get the ID
130
118
  const setting = await fragment.inContext(async function () {
131
119
  return await this.uow(async ({ executeRetrieve }) => {
132
- const valuePromise = fragment.services.settingsService.get("test-key");
120
+ const valuePromise = fragment.services.settingsService.get(SETTINGS_NAMESPACE, "test-key");
133
121
  await executeRetrieve();
134
122
  return await valuePromise;
135
123
  });
@@ -149,7 +137,7 @@ describe("Internal Fragment", () => {
149
137
  // Verify it's gone
150
138
  const result = await fragment.inContext(async function () {
151
139
  return await this.uow(async ({ executeRetrieve }) => {
152
- const valuePromise = fragment.services.settingsService.get("test-key");
140
+ const valuePromise = fragment.services.settingsService.get(SETTINGS_NAMESPACE, "test-key");
153
141
  await executeRetrieve();
154
142
  return await valuePromise;
155
143
  });
@@ -158,3 +146,404 @@ describe("Internal Fragment", () => {
158
146
  expect(result).toBeUndefined();
159
147
  });
160
148
  });
149
+
150
+ describe("Hook Service", () => {
151
+ let sqliteDatabase: SQLite.Database;
152
+ let adapter: DrizzleAdapter;
153
+ let fragment: ReturnType<typeof instantiateFragment>;
154
+
155
+ function instantiateFragment(options: FragnoPublicConfigWithDatabase) {
156
+ return instantiate(internalFragmentDef).withConfig({}).withOptions(options).build();
157
+ }
158
+
159
+ beforeAll(async () => {
160
+ sqliteDatabase = new SQLite(":memory:");
161
+
162
+ const dialect = new SqliteDialect({
163
+ database: sqliteDatabase,
164
+ });
165
+
166
+ adapter = new DrizzleAdapter({
167
+ dialect,
168
+ driverConfig: new BetterSQLite3DriverConfig(),
169
+ });
170
+
171
+ {
172
+ const migrations = adapter.prepareMigrations(internalSchema, "");
173
+ await migrations.executeWithDriver(adapter.driver, 0);
174
+ }
175
+
176
+ const options: FragnoPublicConfigWithDatabase = {
177
+ databaseAdapter: adapter,
178
+ };
179
+
180
+ fragment = instantiateFragment(options);
181
+
182
+ return async () => {
183
+ await adapter.close();
184
+ };
185
+ }, 12000);
186
+
187
+ it("should create a hook event and retrieve it by namespace", async () => {
188
+ const nonce = "test-nonce-1";
189
+
190
+ await fragment.inContext(async function () {
191
+ return await this.uow(async ({ forSchema, executeMutate }) => {
192
+ const uow = forSchema(internalSchema);
193
+ uow.create("fragno_hooks", {
194
+ namespace: "test-namespace",
195
+ hookName: "onTest",
196
+ payload: { test: "data" },
197
+ status: "pending",
198
+ attempts: 0,
199
+ maxAttempts: 5,
200
+ lastAttemptAt: null,
201
+ nextRetryAt: null,
202
+ error: null,
203
+ nonce,
204
+ });
205
+ uow.create("fragno_hooks", {
206
+ namespace: "test-namespace",
207
+ hookName: "onTest",
208
+ payload: { test: "already-completed-data" },
209
+ status: "completed",
210
+ attempts: 0,
211
+ maxAttempts: 5,
212
+ lastAttemptAt: null,
213
+ nextRetryAt: null,
214
+ error: null,
215
+ nonce,
216
+ });
217
+ await executeMutate();
218
+ });
219
+ });
220
+
221
+ const events = await fragment.inContext(async function () {
222
+ return await this.uow(async ({ executeRetrieve }) => {
223
+ const eventsPromise = fragment.services.hookService.getPendingHookEvents("test-namespace");
224
+ await executeRetrieve();
225
+ return await eventsPromise;
226
+ });
227
+ });
228
+
229
+ expect(events).toHaveLength(1);
230
+ expect(events[0]).toMatchObject({
231
+ hookName: "onTest",
232
+ payload: { test: "data" },
233
+ attempts: 0,
234
+ maxAttempts: 5,
235
+ nonce,
236
+ });
237
+ });
238
+
239
+ it("should mark a hook event as completed", async () => {
240
+ const nonce = "test-nonce-2";
241
+ let eventId: FragnoId;
242
+
243
+ await fragment.inContext(async function () {
244
+ return await this.uow(async ({ forSchema, executeMutate }) => {
245
+ const uow = forSchema(internalSchema);
246
+ eventId = uow.create("fragno_hooks", {
247
+ namespace: "test-namespace",
248
+ hookName: "onComplete",
249
+ payload: { test: "data" },
250
+ status: "pending",
251
+ attempts: 0,
252
+ maxAttempts: 5,
253
+ lastAttemptAt: null,
254
+ nextRetryAt: null,
255
+ error: null,
256
+ nonce,
257
+ });
258
+ await executeMutate();
259
+ });
260
+ });
261
+
262
+ await fragment.inContext(async function () {
263
+ return await this.uow(async ({ executeMutate }) => {
264
+ fragment.services.hookService.markHookCompleted(eventId);
265
+ await executeMutate();
266
+ });
267
+ });
268
+
269
+ const result = await fragment.inContext(async function () {
270
+ return await this.uow(async ({ forSchema, executeRetrieve }) => {
271
+ const uow = forSchema(internalSchema);
272
+ const findUow = uow.find("fragno_hooks", (b) =>
273
+ b.whereIndex("primary", (eb) => eb("id", "=", eventId)),
274
+ );
275
+ await executeRetrieve();
276
+ const [events] = await findUow.retrievalPhase;
277
+ return events?.[0];
278
+ });
279
+ });
280
+
281
+ expect(result).toBeDefined();
282
+ expect(result?.status).toBe("completed");
283
+ expect(result?.lastAttemptAt).toBeInstanceOf(Date);
284
+ });
285
+
286
+ it("should mark a hook event as processing", async () => {
287
+ const nonce = "test-nonce-3";
288
+ let eventId: FragnoId;
289
+
290
+ await fragment.inContext(async function () {
291
+ return await this.uow(async ({ forSchema, executeMutate }) => {
292
+ const uow = forSchema(internalSchema);
293
+ eventId = uow.create("fragno_hooks", {
294
+ namespace: "test-namespace",
295
+ hookName: "onProcess",
296
+ payload: { test: "data" },
297
+ status: "pending",
298
+ attempts: 0,
299
+ maxAttempts: 5,
300
+ lastAttemptAt: null,
301
+ nextRetryAt: null,
302
+ error: null,
303
+ nonce,
304
+ });
305
+ await executeMutate();
306
+ });
307
+ });
308
+
309
+ await fragment.inContext(async function () {
310
+ return await this.uow(async ({ executeMutate }) => {
311
+ fragment.services.hookService.markHookProcessing(eventId);
312
+ await executeMutate();
313
+ });
314
+ });
315
+
316
+ const result = await fragment.inContext(async function () {
317
+ return await this.uow(async ({ forSchema, executeRetrieve }) => {
318
+ const uow = forSchema(internalSchema);
319
+ const findUow = uow.find("fragno_hooks", (b) =>
320
+ b.whereIndex("primary", (eb) => eb("id", "=", eventId)),
321
+ );
322
+ await executeRetrieve();
323
+ const [events] = await findUow.retrievalPhase;
324
+ return events?.[0];
325
+ });
326
+ });
327
+
328
+ expect(result).toBeDefined();
329
+ expect(result?.status).toBe("processing");
330
+ expect(result?.lastAttemptAt).toBeInstanceOf(Date);
331
+ });
332
+
333
+ it("should mark a hook event as failed with retry scheduled", async () => {
334
+ const nonce = "test-nonce-4";
335
+ let eventId: FragnoId;
336
+
337
+ await fragment.inContext(async function () {
338
+ return await this.uow(async ({ forSchema, executeMutate }) => {
339
+ const uow = forSchema(internalSchema);
340
+ eventId = uow.create("fragno_hooks", {
341
+ namespace: "test-namespace",
342
+ hookName: "onFail",
343
+ payload: { test: "data" },
344
+ status: "pending",
345
+ attempts: 0,
346
+ maxAttempts: 5,
347
+ lastAttemptAt: null,
348
+ nextRetryAt: null,
349
+ error: null,
350
+ nonce,
351
+ });
352
+ await executeMutate();
353
+ });
354
+ });
355
+
356
+ const retryPolicy = new ExponentialBackoffRetryPolicy({ maxRetries: 3 });
357
+
358
+ await fragment.inContext(async function () {
359
+ return await this.uow(async ({ executeMutate }) => {
360
+ fragment.services.hookService.markHookFailed(eventId, "Test error", 0, retryPolicy);
361
+ await executeMutate();
362
+ });
363
+ });
364
+
365
+ const result = await fragment.inContext(async function () {
366
+ return await this.uow(async ({ forSchema, executeRetrieve }) => {
367
+ const uow = forSchema(internalSchema);
368
+ const findUow = uow.find("fragno_hooks", (b) =>
369
+ b.whereIndex("primary", (eb) => eb("id", "=", eventId)),
370
+ );
371
+ await executeRetrieve();
372
+ const [events] = await findUow.retrievalPhase;
373
+ return events?.[0];
374
+ });
375
+ });
376
+
377
+ expect(result).toBeDefined();
378
+ expect(result?.status).toBe("pending");
379
+ expect(result?.attempts).toBe(1);
380
+ expect(result?.error).toBe("Test error");
381
+ expect(result?.nextRetryAt).toBeInstanceOf(Date);
382
+ expect(result?.lastAttemptAt).toBeInstanceOf(Date);
383
+ });
384
+
385
+ it("should mark a hook event as permanently failed when max attempts reached", async () => {
386
+ const nonce = "test-nonce-5";
387
+ let eventId: FragnoId;
388
+
389
+ await fragment.inContext(async function () {
390
+ return await this.uow(async ({ forSchema, executeMutate }) => {
391
+ const uow = forSchema(internalSchema);
392
+ eventId = uow.create("fragno_hooks", {
393
+ namespace: "test-namespace",
394
+ hookName: "onMaxFail",
395
+ payload: { test: "data" },
396
+ status: "pending",
397
+ attempts: 0,
398
+ maxAttempts: 1,
399
+ lastAttemptAt: null,
400
+ nextRetryAt: null,
401
+ error: null,
402
+ nonce,
403
+ });
404
+ await executeMutate();
405
+ });
406
+ });
407
+
408
+ const retryPolicy = new NoRetryPolicy();
409
+
410
+ await fragment.inContext(async function () {
411
+ return await this.uow(async ({ executeMutate }) => {
412
+ fragment.services.hookService.markHookFailed(
413
+ eventId,
414
+ "Max attempts reached",
415
+ 0,
416
+ retryPolicy,
417
+ );
418
+ await executeMutate();
419
+ });
420
+ });
421
+
422
+ const result = await fragment.inContext(async function () {
423
+ return await this.uow(async ({ forSchema, executeRetrieve }) => {
424
+ const uow = forSchema(internalSchema);
425
+ const findUow = uow.find("fragno_hooks", (b) =>
426
+ b.whereIndex("primary", (eb) => eb("id", "=", eventId)),
427
+ );
428
+ await executeRetrieve();
429
+ const [events] = await findUow.retrievalPhase;
430
+ return events?.[0];
431
+ });
432
+ });
433
+
434
+ expect(result).toBeDefined();
435
+ expect(result?.status).toBe("failed");
436
+ expect(result?.attempts).toBe(1);
437
+ expect(result?.error).toBe("Max attempts reached");
438
+ });
439
+
440
+ it("should retrieve stale events ready for retry", async () => {
441
+ const nonce = "test-nonce-6";
442
+ let eventId: FragnoId;
443
+
444
+ const pastTime = new Date(Date.now() - 10000);
445
+
446
+ await fragment.inContext(async function () {
447
+ return await this.uow(async ({ forSchema, executeMutate }) => {
448
+ const uow = forSchema(internalSchema);
449
+ eventId = uow.create("fragno_hooks", {
450
+ namespace: "test-namespace",
451
+ hookName: "onStale",
452
+ payload: { test: "stale" },
453
+ status: "pending",
454
+ attempts: 1,
455
+ maxAttempts: 5,
456
+ lastAttemptAt: pastTime,
457
+ nextRetryAt: pastTime,
458
+ error: "Previous error",
459
+ nonce,
460
+ });
461
+ await executeMutate();
462
+ });
463
+ });
464
+
465
+ const events = await fragment.inContext(async function () {
466
+ return await this.uow(async ({ executeRetrieve }) => {
467
+ const eventsPromise = fragment.services.hookService.getPendingHookEvents("test-namespace");
468
+ await executeRetrieve();
469
+ return await eventsPromise;
470
+ });
471
+ });
472
+
473
+ const staleEvent = events.find((e) => e.id.externalId === eventId.externalId);
474
+ expect(staleEvent).toBeDefined();
475
+ expect(staleEvent?.hookName).toBe("onStale");
476
+ expect(staleEvent?.attempts).toBe(1);
477
+ });
478
+
479
+ it("should not retrieve events from different namespace", async () => {
480
+ const nonce = "test-nonce-7";
481
+
482
+ await fragment.inContext(async function () {
483
+ return await this.uow(async ({ forSchema, executeMutate }) => {
484
+ const uow = forSchema(internalSchema);
485
+ uow.create("fragno_hooks", {
486
+ namespace: "other-namespace",
487
+ hookName: "onOther",
488
+ payload: { test: "other" },
489
+ status: "pending",
490
+ attempts: 0,
491
+ maxAttempts: 5,
492
+ lastAttemptAt: null,
493
+ nextRetryAt: null,
494
+ error: null,
495
+ nonce,
496
+ });
497
+ await executeMutate();
498
+ });
499
+ });
500
+
501
+ const events = await fragment.inContext(async function () {
502
+ return await this.uow(async ({ executeRetrieve }) => {
503
+ const eventsPromise = fragment.services.hookService.getPendingHookEvents("test-namespace");
504
+ await executeRetrieve();
505
+ return await eventsPromise;
506
+ });
507
+ });
508
+
509
+ const otherEvent = events.find((e) => e.hookName === "onOther");
510
+ expect(otherEvent).toBeUndefined();
511
+ });
512
+
513
+ it("should not retrieve events not yet ready for retry", async () => {
514
+ const nonce = "test-nonce-8";
515
+ let eventId: FragnoId;
516
+
517
+ const futureTime = new Date(Date.now() + 60000);
518
+
519
+ await fragment.inContext(async function () {
520
+ return await this.uow(async ({ forSchema, executeMutate }) => {
521
+ const uow = forSchema(internalSchema);
522
+ eventId = uow.create("fragno_hooks", {
523
+ namespace: "test-namespace",
524
+ hookName: "onFuture",
525
+ payload: { test: "future" },
526
+ status: "pending",
527
+ attempts: 1,
528
+ maxAttempts: 5,
529
+ lastAttemptAt: new Date(),
530
+ nextRetryAt: futureTime,
531
+ error: "Previous error",
532
+ nonce,
533
+ });
534
+ await executeMutate();
535
+ });
536
+ });
537
+
538
+ const events = await fragment.inContext(async function () {
539
+ return await this.uow(async ({ executeRetrieve }) => {
540
+ const eventsPromise = fragment.services.hookService.getPendingHookEvents("test-namespace");
541
+ await executeRetrieve();
542
+ return await eventsPromise;
543
+ });
544
+ });
545
+
546
+ const futureEvent = events.find((e) => e.id.externalId === eventId.externalId);
547
+ expect(futureEvent).toBeUndefined();
548
+ });
549
+ });