@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,737 @@
1
+ import type { AnySchema } from "./schema/create";
2
+ import type { SimpleQueryInterface } from "./query/simple-query-interface";
3
+ import type { DatabaseAdapter } from "./adapters/adapters";
4
+ import type { IUnitOfWork } from "./query/unit-of-work/unit-of-work";
5
+ import { TypedUnitOfWork, UnitOfWork } from "./query/unit-of-work/unit-of-work";
6
+ import type {
7
+ RequestThisContext,
8
+ FragnoPublicConfig,
9
+ AnyFragnoInstantiatedFragment,
10
+ } from "@fragno-dev/core";
11
+ import {
12
+ FragmentDefinitionBuilder,
13
+ type FragmentDefinition,
14
+ type ServiceConstructorFn,
15
+ } from "@fragno-dev/core";
16
+ import {
17
+ executeRestrictedUnitOfWork,
18
+ type AwaitedPromisesInObject,
19
+ type ExecuteRestrictedUnitOfWorkOptions,
20
+ } from "./query/unit-of-work/execute-unit-of-work";
21
+ import {
22
+ prepareHookMutations,
23
+ processHooks,
24
+ type HooksMap,
25
+ type HookFn,
26
+ type HookContext,
27
+ } from "./hooks/hooks";
28
+ import type { InternalFragmentInstance } from "./fragments/internal-fragment";
29
+
30
+ /**
31
+ * Extended FragnoPublicConfig that includes a database adapter.
32
+ * Use this type when creating fragments with database support.
33
+ */
34
+ export type FragnoPublicConfigWithDatabase = FragnoPublicConfig & {
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
+ databaseAdapter: DatabaseAdapter<any>;
37
+ };
38
+
39
+ /**
40
+ * Implicit dependencies that database fragments get automatically.
41
+ * These are injected without requiring explicit configuration.
42
+ */
43
+ export type ImplicitDatabaseDependencies<TSchema extends AnySchema> = {
44
+ /**
45
+ * Database query engine for the fragment's schema.
46
+ */
47
+ db: SimpleQueryInterface<TSchema>;
48
+ /**
49
+ * The schema definition for this fragment.
50
+ */
51
+ schema: TSchema;
52
+ /**
53
+ * The database namespace for this fragment.
54
+ */
55
+ namespace: string;
56
+ /**
57
+ * Create a new Unit of Work for database operations.
58
+ */
59
+ createUnitOfWork: () => IUnitOfWork;
60
+ };
61
+
62
+ /**
63
+ * Service context for database fragments - provides restricted UOW access without execute methods.
64
+ */
65
+ export type DatabaseServiceContext<THooks extends HooksMap> = RequestThisContext & {
66
+ /**
67
+ * Get a typed, restricted Unit of Work for the given schema.
68
+ * @param schema - Schema to get a typed view for
69
+ * @returns TypedUnitOfWork (restricted version without execute methods)
70
+ */
71
+ uow<TSchema extends AnySchema>(schema: TSchema): TypedUnitOfWork<TSchema, [], unknown, THooks>;
72
+ };
73
+
74
+ /**
75
+ * Handler context for database fragments - provides UOW execution with automatic retry support.
76
+ */
77
+ export type DatabaseHandlerContext<THooks extends HooksMap = {}> = RequestThisContext & {
78
+ /**
79
+ * Execute a Unit of Work with explicit phase control and automatic retry support.
80
+ * This method provides an API where users call forSchema to create a schema-specific
81
+ * UOW, then call executeRetrieve() and executeMutate() to execute the phases. The entire
82
+ * callback is re-executed on optimistic concurrency conflicts, ensuring retries work properly.
83
+ * Automatically provides the UOW factory from context.
84
+ * Promises in the returned object are awaited 1 level deep.
85
+ *
86
+ * @param callback - Async function that receives a context with forSchema, executeRetrieve, executeMutate, nonce, and currentAttempt
87
+ * @param options - Optional configuration for retry policy and abort signal
88
+ * @returns Promise resolving to the callback's return value with promises awaited 1 level deep
89
+ * @throws Error if retries are exhausted or callback throws an error
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * const result = await this.uow(async ({ forSchema, executeRetrieve, executeMutate, nonce, currentAttempt }) => {
94
+ * const uow = forSchema(schema);
95
+ * const userId = uow.create("users", { name: "John" });
96
+ *
97
+ * // Execute retrieval phase
98
+ * await executeRetrieve();
99
+ *
100
+ * const profileId = uow.create("profiles", { userId });
101
+ *
102
+ * // Execute mutation phase
103
+ * await executeMutate();
104
+ *
105
+ * return { userId, profileId };
106
+ * });
107
+ * ```
108
+ */
109
+ uow<TResult>(
110
+ callback: (context: {
111
+ forSchema: <TSchema extends AnySchema, H extends HooksMap = THooks>(
112
+ schema: TSchema,
113
+ hooks?: H,
114
+ ) => TypedUnitOfWork<TSchema, [], unknown, H>;
115
+ executeRetrieve: () => Promise<void>;
116
+ executeMutate: () => Promise<void>;
117
+ nonce: string;
118
+ currentAttempt: number;
119
+ }) => Promise<TResult> | TResult,
120
+ options?: Omit<ExecuteRestrictedUnitOfWorkOptions, "createUnitOfWork">,
121
+ ): Promise<AwaitedPromisesInObject<TResult>>;
122
+ };
123
+
124
+ /**
125
+ * Database fragment context provided to user callbacks.
126
+ */
127
+ export type DatabaseFragmentContext<TSchema extends AnySchema> = {
128
+ /**
129
+ * Database adapter instance.
130
+ */
131
+ databaseAdapter: DatabaseAdapter<any>; // eslint-disable-line @typescript-eslint/no-explicit-any
132
+ /**
133
+ * ORM query engine for the fragment's schema.
134
+ */
135
+ db: SimpleQueryInterface<TSchema>;
136
+ };
137
+
138
+ /**
139
+ * Create database context from options.
140
+ * This extracts the database adapter and creates the ORM instance.
141
+ */
142
+ function createDatabaseContext<TSchema extends AnySchema>(
143
+ options: FragnoPublicConfigWithDatabase,
144
+ schema: TSchema,
145
+ namespace: string,
146
+ ): DatabaseFragmentContext<TSchema> {
147
+ const databaseAdapter = options.databaseAdapter;
148
+
149
+ if (!databaseAdapter) {
150
+ throw new Error(
151
+ "Database fragment requires a database adapter to be provided in options.databaseAdapter",
152
+ );
153
+ }
154
+
155
+ const db = databaseAdapter.createQueryEngine(schema, namespace);
156
+
157
+ return { databaseAdapter, db };
158
+ }
159
+
160
+ /**
161
+ * Storage type for database fragments - stores the Unit of Work.
162
+ */
163
+ export type DatabaseRequestStorage = {
164
+ uow: IUnitOfWork;
165
+ };
166
+
167
+ /**
168
+ * Builder for database fragments that wraps the core fragment builder
169
+ * and provides database-specific functionality.
170
+ *
171
+ * Database fragments always require FragnoPublicConfigWithDatabase (which includes databaseAdapter).
172
+ */
173
+ export class DatabaseFragmentDefinitionBuilder<
174
+ TSchema extends AnySchema,
175
+ TConfig,
176
+ TDeps,
177
+ TBaseServices,
178
+ TServices,
179
+ TServiceDependencies,
180
+ TPrivateServices,
181
+ THooks extends HooksMap = {},
182
+ TServiceThisContext extends RequestThisContext = DatabaseHandlerContext,
183
+ THandlerThisContext extends RequestThisContext = DatabaseHandlerContext,
184
+ TLinkedFragments extends Record<string, AnyFragnoInstantiatedFragment> = {},
185
+ > {
186
+ // Store the base builder - we'll replace its storage and context setup when building
187
+ #baseBuilder: FragmentDefinitionBuilder<
188
+ TConfig,
189
+ FragnoPublicConfigWithDatabase,
190
+ TDeps,
191
+ TBaseServices,
192
+ TServices,
193
+ TServiceDependencies,
194
+ TPrivateServices,
195
+ TServiceThisContext,
196
+ THandlerThisContext,
197
+ DatabaseRequestStorage,
198
+ TLinkedFragments
199
+ >;
200
+ #schema: TSchema;
201
+ #namespace: string;
202
+ #hooksFactory?: (context: { config: TConfig; options: FragnoPublicConfigWithDatabase }) => THooks;
203
+
204
+ constructor(
205
+ baseBuilder: FragmentDefinitionBuilder<
206
+ TConfig,
207
+ FragnoPublicConfigWithDatabase,
208
+ TDeps,
209
+ TBaseServices,
210
+ TServices,
211
+ TServiceDependencies,
212
+ TPrivateServices,
213
+ TServiceThisContext,
214
+ THandlerThisContext,
215
+ DatabaseRequestStorage,
216
+ TLinkedFragments
217
+ >,
218
+ schema: TSchema,
219
+ namespace?: string,
220
+ hooksFactory?: (context: {
221
+ config: TConfig;
222
+ options: FragnoPublicConfigWithDatabase;
223
+ }) => THooks,
224
+ ) {
225
+ this.#baseBuilder = baseBuilder;
226
+ this.#schema = schema;
227
+ this.#namespace = namespace ?? baseBuilder.name;
228
+ this.#hooksFactory = hooksFactory;
229
+ }
230
+
231
+ /**
232
+ * Define dependencies for this database fragment.
233
+ * The context includes database adapter and ORM instance.
234
+ */
235
+ withDependencies<TNewDeps>(
236
+ fn: (context: {
237
+ config: TConfig;
238
+ options: FragnoPublicConfigWithDatabase;
239
+ db: SimpleQueryInterface<TSchema>;
240
+ databaseAdapter: DatabaseAdapter<any>; // eslint-disable-line @typescript-eslint/no-explicit-any
241
+ }) => TNewDeps,
242
+ ): DatabaseFragmentDefinitionBuilder<
243
+ TSchema,
244
+ TConfig,
245
+ TNewDeps & ImplicitDatabaseDependencies<TSchema>,
246
+ {},
247
+ {},
248
+ TServiceDependencies,
249
+ {},
250
+ THooks,
251
+ TServiceThisContext,
252
+ THandlerThisContext,
253
+ TLinkedFragments
254
+ > {
255
+ // Wrap user function to inject DB context
256
+ const wrappedFn = (context: { config: TConfig; options: FragnoPublicConfigWithDatabase }) => {
257
+ const dbContext = createDatabaseContext(context.options, this.#schema, this.#namespace);
258
+
259
+ // Call user function with enriched context
260
+ const userDeps = fn({
261
+ config: context.config,
262
+ options: context.options,
263
+ db: dbContext.db,
264
+ databaseAdapter: dbContext.databaseAdapter,
265
+ });
266
+
267
+ // Create implicit dependencies
268
+ const createUow = () => dbContext.db.createUnitOfWork();
269
+ const implicitDeps: ImplicitDatabaseDependencies<TSchema> = {
270
+ db: dbContext.db,
271
+ schema: this.#schema,
272
+ namespace: this.#namespace,
273
+ createUnitOfWork: createUow,
274
+ };
275
+
276
+ return {
277
+ ...userDeps,
278
+ ...implicitDeps,
279
+ };
280
+ };
281
+
282
+ // Create new base builder with wrapped function
283
+ const newBaseBuilder = this.#baseBuilder.withDependencies(wrappedFn);
284
+
285
+ return new DatabaseFragmentDefinitionBuilder(
286
+ newBaseBuilder,
287
+ this.#schema,
288
+ this.#namespace,
289
+ this.#hooksFactory,
290
+ );
291
+ }
292
+
293
+ providesBaseService<TNewService>(
294
+ fn: ServiceConstructorFn<
295
+ TConfig,
296
+ FragnoPublicConfigWithDatabase,
297
+ TDeps,
298
+ TServiceDependencies,
299
+ TPrivateServices,
300
+ TNewService,
301
+ TServiceThisContext
302
+ >,
303
+ ): DatabaseFragmentDefinitionBuilder<
304
+ TSchema,
305
+ TConfig,
306
+ TDeps,
307
+ TNewService,
308
+ TServices,
309
+ TServiceDependencies,
310
+ TPrivateServices,
311
+ THooks,
312
+ TServiceThisContext,
313
+ THandlerThisContext,
314
+ TLinkedFragments
315
+ > {
316
+ const newBaseBuilder = this.#baseBuilder.providesBaseService<TNewService>(fn);
317
+
318
+ return new DatabaseFragmentDefinitionBuilder(
319
+ newBaseBuilder,
320
+ this.#schema,
321
+ this.#namespace,
322
+ this.#hooksFactory,
323
+ );
324
+ }
325
+
326
+ providesService<TServiceName extends string, TService>(
327
+ serviceName: TServiceName,
328
+ fn: ServiceConstructorFn<
329
+ TConfig,
330
+ FragnoPublicConfigWithDatabase,
331
+ TDeps,
332
+ TServiceDependencies,
333
+ TPrivateServices,
334
+ TService,
335
+ TServiceThisContext
336
+ >,
337
+ ): DatabaseFragmentDefinitionBuilder<
338
+ TSchema,
339
+ TConfig,
340
+ TDeps,
341
+ TBaseServices,
342
+ TServices & { [K in TServiceName]: TService },
343
+ TServiceDependencies,
344
+ TPrivateServices,
345
+ THooks,
346
+ TServiceThisContext,
347
+ THandlerThisContext,
348
+ TLinkedFragments
349
+ > {
350
+ const newBaseBuilder = this.#baseBuilder.providesService<TServiceName, TService>(
351
+ serviceName,
352
+ fn,
353
+ );
354
+
355
+ return new DatabaseFragmentDefinitionBuilder(
356
+ newBaseBuilder,
357
+ this.#schema,
358
+ this.#namespace,
359
+ this.#hooksFactory,
360
+ );
361
+ }
362
+
363
+ /**
364
+ * Provide a private service that is only accessible to the fragment author.
365
+ * Private services are NOT exposed on the fragment instance, but can be used
366
+ * when defining other services (baseServices, namedServices, and other privateServices).
367
+ * Private services are instantiated in order, so earlier private services are available
368
+ * to later ones.
369
+ */
370
+ providesPrivateService<TServiceName extends string, TService>(
371
+ serviceName: TServiceName,
372
+ fn: ServiceConstructorFn<
373
+ TConfig,
374
+ FragnoPublicConfigWithDatabase,
375
+ TDeps,
376
+ TServiceDependencies,
377
+ TPrivateServices,
378
+ TService,
379
+ TServiceThisContext
380
+ >,
381
+ ): DatabaseFragmentDefinitionBuilder<
382
+ TSchema,
383
+ TConfig,
384
+ TDeps,
385
+ TBaseServices,
386
+ TServices,
387
+ TServiceDependencies,
388
+ TPrivateServices & { [K in TServiceName]: TService },
389
+ THooks,
390
+ TServiceThisContext,
391
+ THandlerThisContext,
392
+ TLinkedFragments
393
+ > {
394
+ const newBaseBuilder = this.#baseBuilder.providesPrivateService<TServiceName, TService>(
395
+ serviceName,
396
+ fn,
397
+ );
398
+
399
+ return new DatabaseFragmentDefinitionBuilder(
400
+ newBaseBuilder,
401
+ this.#schema,
402
+ this.#namespace,
403
+ this.#hooksFactory,
404
+ );
405
+ }
406
+
407
+ /**
408
+ * Define durable hooks for this fragment.
409
+ * Hooks are automatically persisted and retried on failure.
410
+ *
411
+ * @param fn - Function that receives defineHook helper and returns a hooks map
412
+ * @returns Builder with hooks type set
413
+ *
414
+ * @example
415
+ * ```ts
416
+ * .provideHooks(({ defineHook, config }) => ({
417
+ * onSubscribe: defineHook(async function (payload: { email: string }) {
418
+ * // 'this' context available (HookServiceContext with nonce)
419
+ * await config.onSubscribe?.(payload.email);
420
+ * }),
421
+ * }))
422
+ * ```
423
+ */
424
+ provideHooks<TNewHooks extends HooksMap>(
425
+ fn: (context: {
426
+ config: TConfig;
427
+ options: FragnoPublicConfigWithDatabase;
428
+ defineHook: <TPayload>(
429
+ hook: (this: HookContext, payload: TPayload) => void | Promise<void>,
430
+ ) => HookFn<TPayload>;
431
+ }) => TNewHooks,
432
+ ): DatabaseFragmentDefinitionBuilder<
433
+ TSchema,
434
+ TConfig,
435
+ TDeps,
436
+ TBaseServices,
437
+ TServices,
438
+ TServiceDependencies,
439
+ TPrivateServices,
440
+ TNewHooks,
441
+ DatabaseServiceContext<TNewHooks>,
442
+ THandlerThisContext,
443
+ TLinkedFragments
444
+ > {
445
+ const defineHook = <TPayload>(
446
+ hook: (this: HookContext, payload: TPayload) => void | Promise<void>,
447
+ ): HookFn<TPayload> => {
448
+ return hook;
449
+ };
450
+
451
+ // Store the hooks factory - it will be called in build() with config/options
452
+ const hooksFactory = (context: {
453
+ config: TConfig;
454
+ options: FragnoPublicConfigWithDatabase;
455
+ }) => {
456
+ return fn({
457
+ config: context.config,
458
+ options: context.options,
459
+ defineHook,
460
+ });
461
+ };
462
+
463
+ // Create new builder with hooks factory stored
464
+ // Cast is safe: we're only changing THooks and TServiceThisContext type parameters
465
+ const newBuilder = new DatabaseFragmentDefinitionBuilder(
466
+ this.#baseBuilder,
467
+ this.#schema,
468
+ this.#namespace,
469
+ ) as unknown as DatabaseFragmentDefinitionBuilder<
470
+ TSchema,
471
+ TConfig,
472
+ TDeps,
473
+ TBaseServices,
474
+ TServices,
475
+ TServiceDependencies,
476
+ TPrivateServices,
477
+ TNewHooks,
478
+ DatabaseServiceContext<TNewHooks>,
479
+ THandlerThisContext,
480
+ TLinkedFragments
481
+ >;
482
+
483
+ newBuilder.#hooksFactory = hooksFactory;
484
+
485
+ return newBuilder;
486
+ }
487
+
488
+ /**
489
+ * Declare that this fragment uses a required service provided by the runtime.
490
+ * Delegates to the base builder.
491
+ */
492
+ usesService<TServiceName extends string, TService>(
493
+ serviceName: TServiceName,
494
+ ): DatabaseFragmentDefinitionBuilder<
495
+ TSchema,
496
+ TConfig,
497
+ TDeps,
498
+ TBaseServices,
499
+ TServices,
500
+ TServiceDependencies & { [K in TServiceName]: TService },
501
+ TPrivateServices,
502
+ THooks,
503
+ TServiceThisContext,
504
+ THandlerThisContext,
505
+ TLinkedFragments
506
+ > {
507
+ const newBaseBuilder = this.#baseBuilder.usesService<TServiceName, TService>(serviceName);
508
+
509
+ return new DatabaseFragmentDefinitionBuilder(
510
+ newBaseBuilder,
511
+ this.#schema,
512
+ this.#namespace,
513
+ this.#hooksFactory,
514
+ );
515
+ }
516
+
517
+ /**
518
+ * Declare that this fragment uses an optional service provided by the runtime.
519
+ * Delegates to the base builder.
520
+ */
521
+ usesOptionalService<TServiceName extends string, TService>(
522
+ serviceName: TServiceName,
523
+ ): DatabaseFragmentDefinitionBuilder<
524
+ TSchema,
525
+ TConfig,
526
+ TDeps,
527
+ TBaseServices,
528
+ TServices,
529
+ TServiceDependencies & { [K in TServiceName]: TService | undefined },
530
+ TPrivateServices,
531
+ THooks,
532
+ TServiceThisContext,
533
+ THandlerThisContext,
534
+ TLinkedFragments
535
+ > {
536
+ const newBaseBuilder = this.#baseBuilder.usesOptionalService<TServiceName, TService>(
537
+ serviceName,
538
+ );
539
+
540
+ return new DatabaseFragmentDefinitionBuilder(
541
+ newBaseBuilder,
542
+ this.#schema,
543
+ this.#namespace,
544
+ this.#hooksFactory,
545
+ );
546
+ }
547
+
548
+ /**
549
+ * Build the final database fragment definition.
550
+ * This includes the request context setup for UnitOfWork management.
551
+ * Note: TDeps already includes ImplicitDatabaseDependencies from withDatabase().
552
+ */
553
+ build(): FragmentDefinition<
554
+ TConfig,
555
+ FragnoPublicConfigWithDatabase,
556
+ TDeps,
557
+ TBaseServices,
558
+ TServices,
559
+ TServiceDependencies,
560
+ TPrivateServices,
561
+ DatabaseServiceContext<THooks>,
562
+ DatabaseHandlerContext<THooks>,
563
+ DatabaseRequestStorage,
564
+ TLinkedFragments
565
+ > {
566
+ const baseDef = this.#baseBuilder.build();
567
+
568
+ // Ensure dependencies callback always exists for database fragments
569
+ // If no user dependencies were defined, create a minimal one that only adds implicit deps
570
+ const dependencies = (context: {
571
+ config: TConfig;
572
+ options: FragnoPublicConfigWithDatabase;
573
+ }): TDeps => {
574
+ // In dry run mode, allow user deps to fail gracefully.
575
+ // This is critical for database fragments because the CLI needs access to the schema
576
+ // even when user dependencies (like API clients) can't be initialized.
577
+ // Without this, if user deps fail, we'd lose the implicit database dependencies
578
+ // (including schema), and the CLI couldn't extract schema information.
579
+ let userDeps;
580
+ try {
581
+ userDeps = baseDef.dependencies?.(context);
582
+ } catch (error) {
583
+ if (process.env["FRAGNO_INIT_DRY_RUN"] === "true") {
584
+ console.warn(
585
+ "Warning: Failed to initialize user dependencies in dry run mode:",
586
+ error instanceof Error ? error.message : String(error),
587
+ );
588
+ userDeps = {};
589
+ } else {
590
+ throw error;
591
+ }
592
+ }
593
+
594
+ const { db } = createDatabaseContext(context.options, this.#schema, this.#namespace);
595
+
596
+ const implicitDeps: ImplicitDatabaseDependencies<TSchema> = {
597
+ db,
598
+ schema: this.#schema,
599
+ namespace: this.#namespace,
600
+ createUnitOfWork: () => db.createUnitOfWork(),
601
+ };
602
+
603
+ return {
604
+ ...userDeps,
605
+ ...implicitDeps,
606
+ } as TDeps;
607
+ };
608
+
609
+ // Use the adapter's shared context storage (all fragments using the same adapter share this storage)
610
+ const builderWithExternalStorage = this.#baseBuilder.withExternalRequestStorage(
611
+ ({ options }) => {
612
+ const dbContext = createDatabaseContext(options, this.#schema, this.#namespace);
613
+ return dbContext.databaseAdapter.contextStorage;
614
+ },
615
+ );
616
+
617
+ // Set up request storage to initialize the Unit of Work
618
+ const builderWithStorage = builderWithExternalStorage.withRequestStorage(
619
+ ({ options }): DatabaseRequestStorage => {
620
+ // Create database context - needed here to create the UOW
621
+ const dbContextForStorage = createDatabaseContext(options, this.#schema, this.#namespace);
622
+
623
+ // Create a new Unit of Work for this request
624
+ const uow: IUnitOfWork = dbContextForStorage.db.createUnitOfWork();
625
+
626
+ return { uow };
627
+ },
628
+ );
629
+
630
+ // Get the internal fragment factory from linked fragments (added by withDatabase)
631
+ // Cast is safe: withDatabase() guarantees this fragment exists and has the correct type
632
+ const internalFragmentFactory = baseDef.linkedFragments?.["_fragno_internal"] as (context: {
633
+ config: TConfig;
634
+ options: FragnoPublicConfigWithDatabase;
635
+ }) => InternalFragmentInstance;
636
+
637
+ const builderWithContext = builderWithStorage.withThisContext<
638
+ DatabaseServiceContext<THooks>,
639
+ DatabaseHandlerContext<THooks>
640
+ >(({ storage, config, options }) => {
641
+ // Create hooks config if hooks factory is defined
642
+ const hooksConfig = this.#hooksFactory
643
+ ? {
644
+ hooks: this.#hooksFactory({ config, options }),
645
+ namespace: this.#namespace,
646
+ internalFragment: internalFragmentFactory({ config, options }),
647
+ }
648
+ : undefined;
649
+
650
+ function forSchema<TSchema extends AnySchema>(
651
+ schema: TSchema,
652
+ ): TypedUnitOfWork<TSchema, [], unknown, THooks> {
653
+ const uow = storage.getStore()?.uow;
654
+ if (!uow) {
655
+ throw new Error(
656
+ "No UnitOfWork in context. Service must be called within a route handler OR using `withUnitOfWork`.",
657
+ );
658
+ }
659
+
660
+ return uow.restrict().forSchema<TSchema, THooks>(schema);
661
+ }
662
+
663
+ const serviceContext: DatabaseServiceContext<THooks> = {
664
+ uow: forSchema,
665
+ };
666
+
667
+ async function uow<TResult>(
668
+ callback: (context: {
669
+ forSchema: <S extends AnySchema, H extends HooksMap = THooks>(
670
+ schema: S,
671
+ hooks?: H,
672
+ ) => TypedUnitOfWork<S, [], unknown, H>;
673
+ executeRetrieve: () => Promise<void>;
674
+ executeMutate: () => Promise<void>;
675
+ nonce: string;
676
+ currentAttempt: number;
677
+ }) => Promise<TResult> | TResult,
678
+ execOptions?: Omit<
679
+ ExecuteRestrictedUnitOfWorkOptions,
680
+ "createUnitOfWork" | "onBeforeMutate" | "onSuccess"
681
+ >,
682
+ ): Promise<AwaitedPromisesInObject<TResult>> {
683
+ const currentStorage = storage.getStore();
684
+ if (!currentStorage) {
685
+ throw new Error(
686
+ "No storage in context. Handler must be called within a request context.",
687
+ );
688
+ }
689
+
690
+ const wrappedCallback = async (context: {
691
+ forSchema: <S extends AnySchema, H extends HooksMap = THooks>(
692
+ schema: S,
693
+ hooks?: H,
694
+ ) => TypedUnitOfWork<S, [], unknown, H>;
695
+ executeRetrieve: () => Promise<void>;
696
+ executeMutate: () => Promise<void>;
697
+ nonce: string;
698
+ currentAttempt: number;
699
+ }): Promise<TResult> => {
700
+ return callback(context);
701
+ };
702
+
703
+ return executeRestrictedUnitOfWork(wrappedCallback, {
704
+ ...execOptions,
705
+ createUnitOfWork: () => {
706
+ currentStorage.uow.reset();
707
+ // Register internal schema for hook mutations
708
+ if (hooksConfig) {
709
+ currentStorage.uow.registerSchema(
710
+ hooksConfig.internalFragment.$internal.deps.schema,
711
+ hooksConfig.internalFragment.$internal.deps.namespace,
712
+ );
713
+ }
714
+ return currentStorage.uow as UnitOfWork;
715
+ },
716
+ onBeforeMutate: hooksConfig ? (uow) => prepareHookMutations(uow, hooksConfig) : undefined,
717
+ onSuccess: hooksConfig ? () => processHooks(hooksConfig) : undefined,
718
+ });
719
+ }
720
+
721
+ const handlerContext: DatabaseHandlerContext<THooks> = {
722
+ uow,
723
+ };
724
+
725
+ return { serviceContext, handlerContext };
726
+ });
727
+
728
+ // Build the final definition
729
+ const finalDef = builderWithContext.build();
730
+
731
+ // Return the complete definition with proper typing and dependencies
732
+ return {
733
+ ...finalDef,
734
+ dependencies,
735
+ };
736
+ }
737
+ }