@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,549 @@
1
+ import SQLite from "better-sqlite3";
2
+ import { SqliteDialect } from "kysely";
3
+ import { beforeAll, describe, expect, it } from "vitest";
4
+ import { instantiate } from "@fragno-dev/core";
5
+ import { internalFragmentDef, internalSchema, SETTINGS_NAMESPACE } from "./internal-fragment";
6
+ import type { FragnoPublicConfigWithDatabase } from "../db-fragment-definition-builder";
7
+ import { DrizzleAdapter } from "../adapters/drizzle/drizzle-adapter";
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";
11
+
12
+ describe("Internal Fragment", () => {
13
+ let sqliteDatabase: SQLite.Database;
14
+ let adapter: DrizzleAdapter;
15
+ let fragment: ReturnType<typeof instantiateFragment>;
16
+
17
+ function instantiateFragment(options: FragnoPublicConfigWithDatabase) {
18
+ return instantiate(internalFragmentDef).withConfig({}).withOptions(options).build();
19
+ }
20
+
21
+ beforeAll(async () => {
22
+ sqliteDatabase = new SQLite(":memory:");
23
+
24
+ const dialect = new SqliteDialect({
25
+ database: sqliteDatabase,
26
+ });
27
+
28
+ adapter = new DrizzleAdapter({
29
+ dialect,
30
+ driverConfig: new BetterSQLite3DriverConfig(),
31
+ });
32
+
33
+ {
34
+ const migrations = adapter.prepareMigrations(internalSchema, "");
35
+ await migrations.executeWithDriver(adapter.driver, 0);
36
+ }
37
+
38
+ // Instantiate fragment with shared database adapter
39
+ const options: FragnoPublicConfigWithDatabase = {
40
+ databaseAdapter: adapter,
41
+ };
42
+
43
+ fragment = instantiateFragment(options);
44
+
45
+ return async () => {
46
+ await adapter.close();
47
+ };
48
+ }, 12000);
49
+
50
+ it("should get undefined for non-existent key", async () => {
51
+ const result = await fragment.inContext(async function () {
52
+ return await this.uow(async ({ executeRetrieve }) => {
53
+ const valuePromise = fragment.services.settingsService.get(SETTINGS_NAMESPACE, "test-key");
54
+ await executeRetrieve();
55
+ return await valuePromise;
56
+ });
57
+ });
58
+
59
+ expect(result).toBeUndefined();
60
+ });
61
+
62
+ it("should set and get a value", async () => {
63
+ await fragment.inContext(async function () {
64
+ return await this.uow(async ({ executeMutate }) => {
65
+ const setPromise = fragment.services.settingsService.set(
66
+ SETTINGS_NAMESPACE,
67
+ "test-key",
68
+ "test-value",
69
+ );
70
+ await executeMutate();
71
+ await setPromise;
72
+ });
73
+ });
74
+
75
+ const result = await fragment.inContext(async function () {
76
+ return await this.uow(async ({ executeRetrieve }) => {
77
+ const valuePromise = fragment.services.settingsService.get(SETTINGS_NAMESPACE, "test-key");
78
+ await executeRetrieve();
79
+ return await valuePromise;
80
+ });
81
+ });
82
+
83
+ expect(result).toMatchObject({
84
+ key: "fragno-db-settings.test-key",
85
+ value: "test-value",
86
+ });
87
+ });
88
+
89
+ it("should update an existing value", async () => {
90
+ await fragment.inContext(async function () {
91
+ return await this.uow(async ({ executeMutate }) => {
92
+ const setPromise = fragment.services.settingsService.set(
93
+ SETTINGS_NAMESPACE,
94
+ "test-key",
95
+ "updated-value",
96
+ );
97
+ await executeMutate();
98
+ await setPromise;
99
+ });
100
+ });
101
+
102
+ const result = await fragment.inContext(async function () {
103
+ return await this.uow(async ({ executeRetrieve }) => {
104
+ const valuePromise = fragment.services.settingsService.get(SETTINGS_NAMESPACE, "test-key");
105
+ await executeRetrieve();
106
+ return await valuePromise;
107
+ });
108
+ });
109
+
110
+ expect(result).toMatchObject({
111
+ key: "fragno-db-settings.test-key",
112
+ value: "updated-value",
113
+ });
114
+ });
115
+
116
+ it("should delete a value", async () => {
117
+ // First get the ID
118
+ const setting = await fragment.inContext(async function () {
119
+ return await this.uow(async ({ executeRetrieve }) => {
120
+ const valuePromise = fragment.services.settingsService.get(SETTINGS_NAMESPACE, "test-key");
121
+ await executeRetrieve();
122
+ return await valuePromise;
123
+ });
124
+ });
125
+
126
+ expect(setting).toBeDefined();
127
+
128
+ // Delete it
129
+ await fragment.inContext(async function () {
130
+ return await this.uow(async ({ executeMutate }) => {
131
+ const deletePromise = fragment.services.settingsService.delete(setting!.id);
132
+ await executeMutate();
133
+ await deletePromise;
134
+ });
135
+ });
136
+
137
+ // Verify it's gone
138
+ const result = await fragment.inContext(async function () {
139
+ return await this.uow(async ({ executeRetrieve }) => {
140
+ const valuePromise = fragment.services.settingsService.get(SETTINGS_NAMESPACE, "test-key");
141
+ await executeRetrieve();
142
+ return await valuePromise;
143
+ });
144
+ });
145
+
146
+ expect(result).toBeUndefined();
147
+ });
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
+ });