@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 @@
1
+ {"version":3,"file":"internal-fragment.d.ts","names":[],"sources":["../../src/fragments/internal-fragment.ts"],"sourcesContent":[],"mappings":"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"}
@@ -0,0 +1,111 @@
1
+ import { column, idColumn, schema } from "../schema/create.js";
2
+ import { FragmentDefinitionBuilder } from "../packages/fragno/dist/api/fragment-definition-builder.js";
3
+ import { DatabaseFragmentDefinitionBuilder } from "../db-fragment-definition-builder.js";
4
+
5
+ //#region src/fragments/internal-fragment.ts
6
+ const SETTINGS_TABLE_NAME = "fragno_db_settings";
7
+ const SETTINGS_NAMESPACE = "fragno-db-settings";
8
+ const internalSchema = schema((s) => {
9
+ return s.addTable(SETTINGS_TABLE_NAME, (t) => {
10
+ return t.addColumn("id", idColumn()).addColumn("key", column("string")).addColumn("value", column("string")).createIndex("unique_key", ["key"], { unique: true });
11
+ }).addTable("fragno_hooks", (t) => {
12
+ return t.addColumn("id", idColumn()).addColumn("namespace", column("string")).addColumn("hookName", column("string")).addColumn("payload", column("json")).addColumn("status", column("string")).addColumn("attempts", column("integer").defaultTo(0)).addColumn("maxAttempts", column("integer").defaultTo(5)).addColumn("lastAttemptAt", column("timestamp").nullable()).addColumn("nextRetryAt", column("timestamp").nullable()).addColumn("error", column("string").nullable()).addColumn("createdAt", column("timestamp").defaultTo((b) => b.now())).addColumn("nonce", column("string")).createIndex("idx_namespace_status_retry", [
13
+ "namespace",
14
+ "status",
15
+ "nextRetryAt"
16
+ ]).createIndex("idx_nonce", ["nonce"]);
17
+ });
18
+ });
19
+ const internalFragmentDef = new DatabaseFragmentDefinitionBuilder(new FragmentDefinitionBuilder("$fragno-internal-fragment"), internalSchema, "").providesService("settingsService", ({ defineService }) => {
20
+ return defineService({
21
+ async get(namespace, key) {
22
+ const fullKey = `${namespace}.${key}`;
23
+ const [results] = await this.uow(internalSchema).find(SETTINGS_TABLE_NAME, (b) => b.whereIndex("unique_key", (eb) => eb("key", "=", fullKey))).retrievalPhase;
24
+ return results?.[0];
25
+ },
26
+ async set(namespace, key, value) {
27
+ const fullKey = `${namespace}.${key}`;
28
+ const uow = this.uow(internalSchema);
29
+ const [existing] = await uow.find(SETTINGS_TABLE_NAME, (b) => b.whereIndex("unique_key", (eb) => eb("key", "=", fullKey))).retrievalPhase;
30
+ if (existing?.[0]) uow.update(SETTINGS_TABLE_NAME, existing[0].id, (b) => b.set({ value }).check());
31
+ else uow.create(SETTINGS_TABLE_NAME, {
32
+ key: fullKey,
33
+ value
34
+ });
35
+ await uow.mutationPhase;
36
+ },
37
+ async delete(id) {
38
+ const uow = this.uow(internalSchema);
39
+ uow.delete(SETTINGS_TABLE_NAME, id);
40
+ await uow.mutationPhase;
41
+ }
42
+ });
43
+ }).providesService("hookService", ({ defineService }) => {
44
+ return defineService({
45
+ async getPendingHookEvents(namespace) {
46
+ const [events] = await this.uow(internalSchema).find("fragno_hooks", (b) => b.whereIndex("idx_namespace_status_retry", (eb) => eb.and(eb("namespace", "=", namespace), eb("status", "=", "pending")))).retrievalPhase;
47
+ const now = /* @__PURE__ */ new Date();
48
+ return events.filter((event) => {
49
+ if (!event.nextRetryAt) return true;
50
+ return event.nextRetryAt <= now;
51
+ }).map((event) => ({
52
+ id: event.id,
53
+ hookName: event.hookName,
54
+ payload: event.payload,
55
+ attempts: event.attempts,
56
+ maxAttempts: event.maxAttempts,
57
+ nonce: event.nonce
58
+ }));
59
+ },
60
+ markHookCompleted(eventId) {
61
+ this.uow(internalSchema).update("fragno_hooks", eventId, (b) => b.set({
62
+ status: "completed",
63
+ lastAttemptAt: /* @__PURE__ */ new Date()
64
+ }).check());
65
+ },
66
+ markHookFailed(eventId, error, attempts, retryPolicy) {
67
+ const uow = this.uow(internalSchema);
68
+ const newAttempts = attempts + 1;
69
+ if (retryPolicy.shouldRetry(newAttempts - 1)) {
70
+ const delayMs = retryPolicy.getDelayMs(newAttempts - 1);
71
+ const nextRetryAt = new Date(Date.now() + delayMs);
72
+ uow.update("fragno_hooks", eventId, (b) => b.set({
73
+ status: "pending",
74
+ attempts: newAttempts,
75
+ lastAttemptAt: /* @__PURE__ */ new Date(),
76
+ nextRetryAt,
77
+ error
78
+ }).check());
79
+ } else uow.update("fragno_hooks", eventId, (b) => b.set({
80
+ status: "failed",
81
+ attempts: newAttempts,
82
+ lastAttemptAt: /* @__PURE__ */ new Date(),
83
+ error
84
+ }).check());
85
+ },
86
+ markHookProcessing(eventId) {
87
+ this.uow(internalSchema).update("fragno_hooks", eventId, (b) => b.set({
88
+ status: "processing",
89
+ lastAttemptAt: /* @__PURE__ */ new Date()
90
+ }).check());
91
+ }
92
+ });
93
+ }).build();
94
+ async function getSchemaVersionFromDatabase(fragment, namespace) {
95
+ try {
96
+ return await fragment.inContext(async function() {
97
+ const version = await this.uow(async ({ executeRetrieve }) => {
98
+ const version$1 = fragment.services.settingsService.get(namespace, "schema_version");
99
+ await executeRetrieve();
100
+ return version$1;
101
+ });
102
+ return version ? parseInt(version.value, 10) : 0;
103
+ });
104
+ } catch {
105
+ return 0;
106
+ }
107
+ }
108
+
109
+ //#endregion
110
+ export { SETTINGS_NAMESPACE, SETTINGS_TABLE_NAME, getSchemaVersionFromDatabase, internalFragmentDef, internalSchema };
111
+ //# sourceMappingURL=internal-fragment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal-fragment.js","names":["version"],"sources":["../../src/fragments/internal-fragment.ts"],"sourcesContent":["import { FragmentDefinitionBuilder } from \"@fragno-dev/core\";\nimport type { InstantiatedFragmentFromDefinition } from \"@fragno-dev/core\";\nimport {\n DatabaseFragmentDefinitionBuilder,\n type DatabaseHandlerContext,\n type DatabaseRequestStorage,\n type DatabaseServiceContext,\n type FragnoPublicConfigWithDatabase,\n type ImplicitDatabaseDependencies,\n} from \"../db-fragment-definition-builder\";\nimport type { FragnoId } from \"../schema/create\";\nimport { schema, idColumn, column } from \"../schema/create\";\nimport type { RetryPolicy } from \"../query/unit-of-work/retry-policy\";\n\n// Constants for Fragno's internal settings table\nexport const SETTINGS_TABLE_NAME = \"fragno_db_settings\" as const;\n// FIXME: In some places we simply use empty string \"\" as namespace, which is not correct.\nexport const SETTINGS_NAMESPACE = \"fragno-db-settings\" as const;\n\nexport const internalSchema = schema((s) => {\n return s\n .addTable(SETTINGS_TABLE_NAME, (t) => {\n return t\n .addColumn(\"id\", idColumn())\n .addColumn(\"key\", column(\"string\"))\n .addColumn(\"value\", column(\"string\"))\n .createIndex(\"unique_key\", [\"key\"], { unique: true });\n })\n .addTable(\"fragno_hooks\", (t) => {\n return t\n .addColumn(\"id\", idColumn())\n .addColumn(\"namespace\", column(\"string\"))\n .addColumn(\"hookName\", column(\"string\"))\n .addColumn(\"payload\", column(\"json\"))\n .addColumn(\"status\", column(\"string\")) // \"pending\" | \"processing\" | \"completed\" | \"failed\"\n .addColumn(\"attempts\", column(\"integer\").defaultTo(0))\n .addColumn(\"maxAttempts\", column(\"integer\").defaultTo(5))\n .addColumn(\"lastAttemptAt\", column(\"timestamp\").nullable())\n .addColumn(\"nextRetryAt\", column(\"timestamp\").nullable())\n .addColumn(\"error\", column(\"string\").nullable())\n .addColumn(\n \"createdAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n )\n .addColumn(\"nonce\", column(\"string\"))\n .createIndex(\"idx_namespace_status_retry\", [\"namespace\", \"status\", \"nextRetryAt\"])\n .createIndex(\"idx_nonce\", [\"nonce\"]);\n });\n});\n\n// This uses DatabaseFragmentDefinitionBuilder directly\n// to avoid circular dependency (it doesn't need to link to itself)\nexport const internalFragmentDef = new DatabaseFragmentDefinitionBuilder(\n new FragmentDefinitionBuilder<\n {},\n FragnoPublicConfigWithDatabase,\n ImplicitDatabaseDependencies<typeof internalSchema>,\n {},\n {},\n {},\n {},\n DatabaseServiceContext<{}>,\n DatabaseHandlerContext,\n DatabaseRequestStorage\n >(\"$fragno-internal-fragment\"),\n internalSchema,\n \"\", // intentionally blank namespace so there is no prefix\n)\n .providesService(\"settingsService\", ({ defineService }) => {\n return defineService({\n async get(\n namespace: string,\n key: string,\n ): Promise<{ id: FragnoId; key: string; value: string } | undefined> {\n const fullKey = `${namespace}.${key}`;\n const uow = this.uow(internalSchema).find(SETTINGS_TABLE_NAME, (b) =>\n b.whereIndex(\"unique_key\", (eb) => eb(\"key\", \"=\", fullKey)),\n );\n const [results] = await uow.retrievalPhase;\n return results?.[0];\n },\n\n async set(namespace: string, key: string, value: string) {\n const fullKey = `${namespace}.${key}`;\n const uow = this.uow(internalSchema);\n\n // First, find if the key already exists\n const findUow = uow.find(SETTINGS_TABLE_NAME, (b) =>\n b.whereIndex(\"unique_key\", (eb) => eb(\"key\", \"=\", fullKey)),\n );\n const [existing] = await findUow.retrievalPhase;\n\n if (existing?.[0]) {\n uow.update(SETTINGS_TABLE_NAME, existing[0].id, (b) => b.set({ value }).check());\n } else {\n uow.create(SETTINGS_TABLE_NAME, {\n key: fullKey,\n value,\n });\n }\n\n // Await mutation phase - will throw if mutation fails\n await uow.mutationPhase;\n },\n\n async delete(id: FragnoId) {\n const uow = this.uow(internalSchema);\n uow.delete(SETTINGS_TABLE_NAME, id);\n await uow.mutationPhase;\n },\n });\n })\n .providesService(\"hookService\", ({ defineService }) => {\n // TODO(Wilco): re-implement this better\n return defineService({\n /**\n * Get pending hook events for processing.\n * Returns all pending events for the given namespace that are ready to be processed.\n */\n async getPendingHookEvents(namespace: string): Promise<\n {\n id: FragnoId;\n hookName: string;\n payload: unknown;\n attempts: number;\n maxAttempts: number;\n nonce: string;\n }[]\n > {\n const uow = this.uow(internalSchema).find(\"fragno_hooks\", (b) =>\n b.whereIndex(\"idx_namespace_status_retry\", (eb) =>\n eb.and(eb(\"namespace\", \"=\", namespace), eb(\"status\", \"=\", \"pending\")),\n ),\n );\n\n const [events] = await uow.retrievalPhase;\n\n // Filter for pending status and events ready for retry\n const now = new Date();\n const ready = events.filter((event) => {\n // FIXME(Wilco): this should be handled by the database query, but there seems to be an issue.\n if (!event.nextRetryAt) {\n return true; // Newly created events (nextRetryAt = null) are ready\n }\n return event.nextRetryAt <= now; // Only include if retry time has passed\n });\n\n return ready.map((event) => ({\n id: event.id,\n hookName: event.hookName,\n payload: event.payload,\n attempts: event.attempts,\n maxAttempts: event.maxAttempts,\n nonce: event.nonce,\n }));\n },\n\n /**\n * Mark a hook event as completed.\n */\n markHookCompleted(eventId: FragnoId): void {\n const uow = this.uow(internalSchema);\n uow.update(\"fragno_hooks\", eventId, (b) =>\n b.set({ status: \"completed\", lastAttemptAt: new Date() }).check(),\n );\n },\n\n /**\n * Mark a hook event as failed and schedule next retry.\n */\n markHookFailed(\n eventId: FragnoId,\n error: string,\n attempts: number,\n retryPolicy: RetryPolicy,\n ): void {\n const uow = this.uow(internalSchema);\n\n const newAttempts = attempts + 1;\n const shouldRetry = retryPolicy.shouldRetry(newAttempts - 1);\n\n if (shouldRetry) {\n const delayMs = retryPolicy.getDelayMs(newAttempts - 1);\n const nextRetryAt = new Date(Date.now() + delayMs);\n uow.update(\"fragno_hooks\", eventId, (b) =>\n b\n .set({\n status: \"pending\",\n attempts: newAttempts,\n lastAttemptAt: new Date(),\n nextRetryAt,\n error,\n })\n .check(),\n );\n } else {\n uow.update(\"fragno_hooks\", eventId, (b) =>\n b\n .set({\n status: \"failed\",\n attempts: newAttempts,\n lastAttemptAt: new Date(),\n error,\n })\n .check(),\n );\n }\n },\n\n /**\n * Mark a hook event as processing (to prevent concurrent execution).\n */\n markHookProcessing(eventId: FragnoId): void {\n const uow = this.uow(internalSchema);\n uow.update(\"fragno_hooks\", eventId, (b) =>\n b.set({ status: \"processing\", lastAttemptAt: new Date() }).check(),\n );\n },\n });\n })\n .build();\n\n/**\n * Type representing an instantiated internal fragment.\n * This is the fragment that manages Fragno's internal settings table.\n */\nexport type InternalFragmentInstance = InstantiatedFragmentFromDefinition<\n typeof internalFragmentDef\n>;\n\nexport async function getSchemaVersionFromDatabase(\n fragment: InternalFragmentInstance,\n namespace: string,\n): Promise<number> {\n try {\n const version = await fragment.inContext(async function () {\n const version = await this.uow(async ({ executeRetrieve }) => {\n const version = fragment.services.settingsService.get(namespace, \"schema_version\");\n await executeRetrieve();\n return version;\n });\n\n return version ? parseInt(version.value, 10) : 0;\n });\n return version;\n } catch {\n return 0;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import { RetryPolicy } from "../query/unit-of-work/retry-policy.js";
2
+
3
+ //#region src/hooks/hooks.d.ts
4
+
5
+ /**
6
+ * Context available in hook functions via `this`.
7
+ * Contains the nonce for idempotency and database access.
8
+ */
9
+ interface HookContext {
10
+ /**
11
+ * Unique nonce for this transaction.
12
+ * Use this for idempotency checks in your hook implementation.
13
+ */
14
+ nonce: string;
15
+ }
16
+ /**
17
+ * A hook function signature.
18
+ * Hooks receive a typed payload and access context via `this`.
19
+ */
20
+ type HookFn<TPayload = unknown> = (payload: TPayload) => void | Promise<void>;
21
+ /**
22
+ * Map of hook names to hook functions.
23
+ * Used for type-safe hook definitions and triggering.
24
+ */
25
+ type HooksMap = Record<string, HookFn<any>>;
26
+ /**
27
+ * Extract the payload type from a hook function.
28
+ */
29
+ type HookPayload<T> = T extends HookFn<infer P> ? P : never;
30
+ /**
31
+ * Options for triggering a hook.
32
+ */
33
+ interface TriggerHookOptions {
34
+ /**
35
+ * Optional retry policy override for this specific hook trigger.
36
+ * If not provided, uses the default retry policy.
37
+ */
38
+ retryPolicy?: RetryPolicy;
39
+ }
40
+ /**
41
+ * Internal representation of a triggered hook.
42
+ * Stored in the Unit of Work before execution.
43
+ */
44
+ interface TriggeredHook {
45
+ hookName: string;
46
+ payload: unknown;
47
+ options?: TriggerHookOptions;
48
+ }
49
+ //#endregion
50
+ export { HookContext, HookFn, HookPayload, HooksMap, TriggerHookOptions, TriggeredHook };
51
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","names":[],"sources":["../../src/hooks/hooks.ts"],"sourcesContent":[],"mappings":";;;;AASA;AAYA;AAOA;AAKA;AAA6B,UAxBZ,WAAA,CAwBY;EAAU;;;AAKvC;EAYiB,KAAA,EAAA,MAAA;;;;;;KA7BL,uCAAuC,oBAAoB;;;;;KAO3D,QAAA,GAAW,eAAe;;;;KAK1B,iBAAiB,UAAU,kBAAkB;;;;UAKxC,kBAAA;;;;;gBAKD;;;;;;UAOC,aAAA;;;YAGL"}
@@ -0,0 +1,88 @@
1
+ import { ExponentialBackoffRetryPolicy } from "../query/unit-of-work/retry-policy.js";
2
+
3
+ //#region src/hooks/hooks.ts
4
+ /**
5
+ * Add hook events as mutation operations to the UOW.
6
+ * This should be called before executeMutations() so hook records are created
7
+ * in the same transaction as the user's mutations.
8
+ */
9
+ function prepareHookMutations(uow, config) {
10
+ const { namespace, internalFragment, defaultRetryPolicy } = config;
11
+ const retryPolicy = defaultRetryPolicy ?? new ExponentialBackoffRetryPolicy({ maxRetries: 5 });
12
+ const triggeredHooks = uow.getTriggeredHooks();
13
+ if (triggeredHooks.length === 0) return;
14
+ const internalSchema = internalFragment.$internal.deps.schema;
15
+ const internalUow = uow.forSchema(internalSchema);
16
+ for (const hook of triggeredHooks) {
17
+ const maxAttempts = (hook.options?.retryPolicy ?? retryPolicy).shouldRetry(4) ? 5 : 1;
18
+ internalUow.create("fragno_hooks", {
19
+ namespace,
20
+ hookName: hook.hookName,
21
+ payload: hook.payload,
22
+ status: "pending",
23
+ attempts: 0,
24
+ maxAttempts,
25
+ lastAttemptAt: null,
26
+ nextRetryAt: null,
27
+ error: null,
28
+ nonce: uow.nonce
29
+ });
30
+ }
31
+ }
32
+ /**
33
+ * Process pending hook events after the transaction has committed.
34
+ * This should be called in the onSuccess callback after executeMutations().
35
+ */
36
+ async function processHooks(config) {
37
+ const { hooks, namespace, internalFragment, defaultRetryPolicy } = config;
38
+ const retryPolicy = defaultRetryPolicy ?? new ExponentialBackoffRetryPolicy({ maxRetries: 5 });
39
+ await internalFragment.inContext(async function() {
40
+ return await this.uow(async ({ executeRetrieve, executeMutate }) => {
41
+ const pendingEventsPromise = internalFragment.services.hookService.getPendingHookEvents(namespace);
42
+ await executeRetrieve();
43
+ const pendingEvents = await pendingEventsPromise;
44
+ if (pendingEvents.length === 0) return;
45
+ const processedEvents = await Promise.allSettled(pendingEvents.map(async (event) => {
46
+ const hookFn = hooks[event.hookName];
47
+ if (!hookFn) return {
48
+ eventId: event.id,
49
+ status: "failed",
50
+ error: `Hook '${event.hookName}' not found in hooks map`,
51
+ attempts: event.attempts,
52
+ maxAttempts: event.maxAttempts
53
+ };
54
+ try {
55
+ const hookContext = { nonce: event.nonce };
56
+ await hookFn.call(hookContext, event.payload);
57
+ return {
58
+ eventId: event.id,
59
+ status: "completed"
60
+ };
61
+ } catch (error) {
62
+ const errorMessage = error instanceof Error ? error.message : String(error);
63
+ return {
64
+ eventId: event.id,
65
+ status: "failed",
66
+ error: errorMessage,
67
+ attempts: event.attempts,
68
+ maxAttempts: event.maxAttempts
69
+ };
70
+ }
71
+ }));
72
+ for (const processedEvent of processedEvents) {
73
+ if (processedEvent.status === "rejected") continue;
74
+ const { eventId, status } = processedEvent.value;
75
+ if (status === "completed") internalFragment.services.hookService.markHookCompleted(eventId);
76
+ else if (status === "failed") {
77
+ const { error, attempts } = processedEvent.value;
78
+ internalFragment.services.hookService.markHookFailed(eventId, error, attempts, retryPolicy);
79
+ }
80
+ }
81
+ await executeMutate();
82
+ });
83
+ });
84
+ }
85
+
86
+ //#endregion
87
+ export { prepareHookMutations, processHooks };
88
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","names":["hookContext: HookContext"],"sources":["../../src/hooks/hooks.ts"],"sourcesContent":["import type { RetryPolicy } from \"../query/unit-of-work/retry-policy\";\nimport { ExponentialBackoffRetryPolicy } from \"../query/unit-of-work/retry-policy\";\nimport type { IUnitOfWork } from \"../query/unit-of-work/unit-of-work\";\nimport type { InternalFragmentInstance } from \"../fragments/internal-fragment\";\n\n/**\n * Context available in hook functions via `this`.\n * Contains the nonce for idempotency and database access.\n */\nexport interface HookContext {\n /**\n * Unique nonce for this transaction.\n * Use this for idempotency checks in your hook implementation.\n */\n nonce: string;\n}\n\n/**\n * A hook function signature.\n * Hooks receive a typed payload and access context via `this`.\n */\nexport type HookFn<TPayload = unknown> = (payload: TPayload) => void | Promise<void>;\n\n/**\n * Map of hook names to hook functions.\n * Used for type-safe hook definitions and triggering.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type HooksMap = Record<string, HookFn<any>>;\n\n/**\n * Extract the payload type from a hook function.\n */\nexport type HookPayload<T> = T extends HookFn<infer P> ? P : never;\n\n/**\n * Options for triggering a hook.\n */\nexport interface TriggerHookOptions {\n /**\n * Optional retry policy override for this specific hook trigger.\n * If not provided, uses the default retry policy.\n */\n retryPolicy?: RetryPolicy;\n}\n\n/**\n * Internal representation of a triggered hook.\n * Stored in the Unit of Work before execution.\n */\nexport interface TriggeredHook {\n hookName: string;\n payload: unknown;\n options?: TriggerHookOptions;\n}\n\n/**\n * Configuration for hook processing.\n */\nexport interface HookProcessorConfig {\n hooks: HooksMap;\n namespace: string;\n internalFragment: InternalFragmentInstance;\n defaultRetryPolicy?: RetryPolicy;\n}\n\n/**\n * Add hook events as mutation operations to the UOW.\n * This should be called before executeMutations() so hook records are created\n * in the same transaction as the user's mutations.\n */\nexport function prepareHookMutations(uow: IUnitOfWork, config: HookProcessorConfig): void {\n const { namespace, internalFragment, defaultRetryPolicy } = config;\n const retryPolicy = defaultRetryPolicy ?? new ExponentialBackoffRetryPolicy({ maxRetries: 5 });\n\n const triggeredHooks = uow.getTriggeredHooks();\n\n if (triggeredHooks.length === 0) {\n return;\n }\n\n const internalSchema = internalFragment.$internal.deps.schema;\n const internalUow = uow.forSchema(internalSchema);\n\n for (const hook of triggeredHooks) {\n const hookRetryPolicy = hook.options?.retryPolicy ?? retryPolicy;\n const maxAttempts = hookRetryPolicy.shouldRetry(4) ? 5 : 1;\n internalUow.create(\"fragno_hooks\", {\n namespace,\n hookName: hook.hookName,\n payload: hook.payload,\n status: \"pending\",\n attempts: 0,\n maxAttempts,\n lastAttemptAt: null,\n nextRetryAt: null,\n error: null,\n nonce: uow.nonce,\n });\n }\n}\n\n/**\n * Process pending hook events after the transaction has committed.\n * This should be called in the onSuccess callback after executeMutations().\n */\nexport async function processHooks(config: HookProcessorConfig): Promise<void> {\n const { hooks, namespace, internalFragment, defaultRetryPolicy } = config;\n const retryPolicy = defaultRetryPolicy ?? new ExponentialBackoffRetryPolicy({ maxRetries: 5 });\n\n await internalFragment.inContext(async function () {\n return await this.uow(async ({ executeRetrieve, executeMutate }) => {\n const pendingEventsPromise =\n internalFragment.services.hookService.getPendingHookEvents(namespace);\n await executeRetrieve();\n\n const pendingEvents = await pendingEventsPromise;\n\n if (pendingEvents.length === 0) {\n return;\n }\n\n const processedEvents = await Promise.allSettled(\n pendingEvents.map(async (event) => {\n const hookFn = hooks[event.hookName];\n if (!hookFn) {\n return {\n eventId: event.id,\n status: \"failed\" as const,\n error: `Hook '${event.hookName}' not found in hooks map`,\n attempts: event.attempts,\n maxAttempts: event.maxAttempts,\n };\n }\n\n try {\n const hookContext: HookContext = { nonce: event.nonce };\n await hookFn.call(hookContext, event.payload);\n return {\n eventId: event.id,\n status: \"completed\" as const,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n eventId: event.id,\n status: \"failed\" as const,\n error: errorMessage,\n attempts: event.attempts,\n maxAttempts: event.maxAttempts,\n };\n }\n }),\n );\n\n for (const processedEvent of processedEvents) {\n if (processedEvent.status === \"rejected\") {\n continue;\n }\n\n const { eventId, status } = processedEvent.value;\n\n if (status === \"completed\") {\n internalFragment.services.hookService.markHookCompleted(eventId);\n } else if (status === \"failed\") {\n const { error, attempts } = processedEvent.value;\n internalFragment.services.hookService.markHookFailed(\n eventId,\n error,\n attempts,\n retryPolicy,\n );\n }\n }\n\n await executeMutate();\n });\n });\n}\n"],"mappings":";;;;;;;;AAuEA,SAAgB,qBAAqB,KAAkB,QAAmC;CACxF,MAAM,EAAE,WAAW,kBAAkB,uBAAuB;CAC5D,MAAM,cAAc,sBAAsB,IAAI,8BAA8B,EAAE,YAAY,GAAG,CAAC;CAE9F,MAAM,iBAAiB,IAAI,mBAAmB;AAE9C,KAAI,eAAe,WAAW,EAC5B;CAGF,MAAM,iBAAiB,iBAAiB,UAAU,KAAK;CACvD,MAAM,cAAc,IAAI,UAAU,eAAe;AAEjD,MAAK,MAAM,QAAQ,gBAAgB;EAEjC,MAAM,eADkB,KAAK,SAAS,eAAe,aACjB,YAAY,EAAE,GAAG,IAAI;AACzD,cAAY,OAAO,gBAAgB;GACjC;GACA,UAAU,KAAK;GACf,SAAS,KAAK;GACd,QAAQ;GACR,UAAU;GACV;GACA,eAAe;GACf,aAAa;GACb,OAAO;GACP,OAAO,IAAI;GACZ,CAAC;;;;;;;AAQN,eAAsB,aAAa,QAA4C;CAC7E,MAAM,EAAE,OAAO,WAAW,kBAAkB,uBAAuB;CACnE,MAAM,cAAc,sBAAsB,IAAI,8BAA8B,EAAE,YAAY,GAAG,CAAC;AAE9F,OAAM,iBAAiB,UAAU,iBAAkB;AACjD,SAAO,MAAM,KAAK,IAAI,OAAO,EAAE,iBAAiB,oBAAoB;GAClE,MAAM,uBACJ,iBAAiB,SAAS,YAAY,qBAAqB,UAAU;AACvE,SAAM,iBAAiB;GAEvB,MAAM,gBAAgB,MAAM;AAE5B,OAAI,cAAc,WAAW,EAC3B;GAGF,MAAM,kBAAkB,MAAM,QAAQ,WACpC,cAAc,IAAI,OAAO,UAAU;IACjC,MAAM,SAAS,MAAM,MAAM;AAC3B,QAAI,CAAC,OACH,QAAO;KACL,SAAS,MAAM;KACf,QAAQ;KACR,OAAO,SAAS,MAAM,SAAS;KAC/B,UAAU,MAAM;KAChB,aAAa,MAAM;KACpB;AAGH,QAAI;KACF,MAAMA,cAA2B,EAAE,OAAO,MAAM,OAAO;AACvD,WAAM,OAAO,KAAK,aAAa,MAAM,QAAQ;AAC7C,YAAO;MACL,SAAS,MAAM;MACf,QAAQ;MACT;aACM,OAAO;KACd,MAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AAC3E,YAAO;MACL,SAAS,MAAM;MACf,QAAQ;MACR,OAAO;MACP,UAAU,MAAM;MAChB,aAAa,MAAM;MACpB;;KAEH,CACH;AAED,QAAK,MAAM,kBAAkB,iBAAiB;AAC5C,QAAI,eAAe,WAAW,WAC5B;IAGF,MAAM,EAAE,SAAS,WAAW,eAAe;AAE3C,QAAI,WAAW,YACb,kBAAiB,SAAS,YAAY,kBAAkB,QAAQ;aACvD,WAAW,UAAU;KAC9B,MAAM,EAAE,OAAO,aAAa,eAAe;AAC3C,sBAAiB,SAAS,YAAY,eACpC,SACA,OACA,UACA,YACD;;;AAIL,SAAM,eAAe;IACrB;GACF"}
@@ -1,5 +1,4 @@
1
1
  import { AnySchema } from "../schema/create.js";
2
- import { PreparedMigration } from "./create.js";
3
2
  import { FragnoDatabase } from "../mod.js";
4
3
 
5
4
  //#region src/migration-engine/generation-engine.d.ts
@@ -14,7 +13,6 @@ interface GenerationInternalResult {
14
13
  namespace: string;
15
14
  fromVersion: number;
16
15
  toVersion: number;
17
- preparedMigration?: PreparedMigration;
18
16
  }
19
17
  interface ExecuteMigrationResult {
20
18
  namespace: string;
@@ -1 +1 @@
1
- {"version":3,"file":"generation-engine.d.ts","names":[],"sources":["../../src/migration-engine/generation-engine.ts"],"sourcesContent":[],"mappings":";;;;;UAaiB,sBAAA;;EAAA,IAAA,EAAA,MAAA;EAMA,SAAA,EAAA,MAAA;AASjB;AAOsB,UAhBL,wBAAA,CAgB+B;EAEN,MAAA,EAAA,MAAA;EAAf,IAAA,EAAA,MAAA;EAEd,SAAA,EAAA,MAAA;EAMF,WAAA,EAAA,MAAA;EAAR,SAAA,EAAA,MAAA;EAAO,iBAAA,CAAA,EApBY,iBAoBZ;AAiJV;AAAgF,UAlK/D,sBAAA,CAkK+D;EAAf,SAAA,EAAA,MAAA;EACpD,UAAA,EAAA,OAAA;EACF,WAAA,EAAA,MAAA;EAAR,SAAA,EAAA,MAAA;;AAyIa,iBAtSM,0BAuSb,CAAA,yBArSkB,cAsSxB,CAtSuC,SAsSjB,EAAA,GAAA,CAAA,EAAA,CAAA,CAAA,SAAA,EApSZ,UAoSY,EAAA,QAAA,EAAA;;;;IA9RtB,QAAQ;;;;;;;;iBAiJW,2CAA2C,eAAe,yBACnE,aACV,QAAQ;;;;;;;;;;;iBAyIK,6BAAA,QACP,6BACN"}
1
+ {"version":3,"file":"generation-engine.d.ts","names":[],"sources":["../../src/migration-engine/generation-engine.ts"],"sourcesContent":[],"mappings":";;;;UAciB,sBAAA;;EAAA,IAAA,EAAA,MAAA;EAMA,SAAA,EAAA,MAAA;AAQjB;AAOsB,UAfL,wBAAA,CAe+B;EAEN,MAAA,EAAA,MAAA;EAAf,IAAA,EAAA,MAAA;EAEd,SAAA,EAAA,MAAA;EAMF,WAAA,EAAA,MAAA;EAAR,SAAA,EAAA,MAAA;;AA2ImB,UA5JL,sBAAA,CA4JsB;EAAyC,SAAA,EAAA,MAAA;EAAf,UAAA,EAAA,OAAA;EACpD,WAAA,EAAA,MAAA;EACF,SAAA,EAAA,MAAA;;AAAD,iBAvJY,0BAuJZ,CAAA,yBArJiB,cAqJjB,CArJgC,SAqJhC,EAAA,GAAA,CAAA,EAAA,CAAA,CAAA,SAAA,EAnJG,UAmJH,EAAA,QAAA,EAAA;EAiJM,IAAA,CAAA,EAAA,MAAA;;;IA9Rb,QAAQ;;;;;;;;iBA2IW,2CAA2C,eAAe,yBACnE,aACV,QAAQ;;;;;;;;;;;iBAiJK,6BAAA,QACP,6BACN"}
@@ -1,5 +1,6 @@
1
+ import { instantiate } from "../packages/fragno/dist/api/fragment-instantiator.js";
2
+ import { SETTINGS_NAMESPACE, getSchemaVersionFromDatabase, internalFragmentDef, internalSchema } from "../fragments/internal-fragment.js";
1
3
  import { fragnoDatabaseAdapterNameFakeSymbol, fragnoDatabaseAdapterVersionFakeSymbol } from "../adapters/adapters.js";
2
- import { SETTINGS_NAMESPACE, createSettingsManager, settingsSchema } from "../shared/settings-schema.js";
3
4
 
4
5
  //#region src/migration-engine/generation-engine.ts
5
6
  async function generateMigrationsOrSchema(databases, options) {
@@ -8,56 +9,48 @@ async function generateMigrationsOrSchema(databases, options) {
8
9
  const adapter = firstDb.adapter;
9
10
  if (adapter.createSchemaGenerator) {
10
11
  if (options?.toVersion !== void 0 || options?.fromVersion !== void 0) console.warn("⚠️ Warning: --from and --to version options are not supported when generating schemas for multiple fragments and will be ignored.");
11
- const fragments = databases.map((db) => ({
12
+ const fragmentsMap = /* @__PURE__ */ new Map();
13
+ fragmentsMap.set("", {
14
+ schema: internalSchema,
15
+ namespace: ""
16
+ });
17
+ for (const db of databases) if (!fragmentsMap.has(db.namespace)) fragmentsMap.set(db.namespace, {
12
18
  schema: db.schema,
13
19
  namespace: db.namespace
14
- }));
20
+ });
21
+ const allFragments = Array.from(fragmentsMap.values());
15
22
  return [{
16
- ...adapter.createSchemaGenerator(fragments, { path: options?.path }).generateSchema(),
23
+ ...adapter.createSchemaGenerator(allFragments, { path: options?.path }).generateSchema(),
17
24
  namespace: firstDb.namespace
18
25
  }];
19
26
  }
20
- if (!adapter.createMigrationEngine) throw new Error("Adapter does not support migration-based schema generation. Ensure your adapter implements createMigrationEngine.");
27
+ if (!adapter.prepareMigrations) throw new Error("Adapter does not support migration-based schema generation. Ensure your adapter implements prepareMigrations.");
21
28
  if (!await adapter.isConnectionHealthy()) throw new Error("Database connection is not healthy. Please check your database connection and try again.");
22
- const settingsManager = createSettingsManager(adapter.createQueryEngine(settingsSchema, ""), SETTINGS_NAMESPACE);
23
- let settingsSourceVersion;
24
- try {
25
- const result = await settingsManager.get("version");
26
- if (!result) settingsSourceVersion = 0;
27
- else settingsSourceVersion = parseInt(result.value);
28
- } catch {
29
- settingsSourceVersion = 0;
30
- }
29
+ const settingsSourceVersion = await getSchemaVersionFromDatabase(instantiate(internalFragmentDef).withConfig({}).withOptions({ databaseAdapter: adapter }).build(), SETTINGS_NAMESPACE);
31
30
  const generatedFiles = [];
32
- const settingsMigrator = adapter.createMigrationEngine(settingsSchema, SETTINGS_NAMESPACE);
33
- const settingsTargetVersion = settingsSchema.version;
34
- const settingsMigration = await settingsMigrator.prepareMigrationTo(settingsTargetVersion, { fromVersion: settingsSourceVersion });
35
- if (!settingsMigration.getSQL) throw new Error("Migration engine does not support SQL generation. Ensure your adapter's migration engine provides getSQL().");
36
- const settingsSql = settingsMigration.getSQL();
31
+ const settingsPreparedMigrations = adapter.prepareMigrations(internalSchema, "");
32
+ const settingsTargetVersion = internalSchema.version;
33
+ const settingsSql = settingsPreparedMigrations.getSQL(settingsSourceVersion, settingsTargetVersion);
37
34
  if (settingsSql.trim()) generatedFiles.push({
38
35
  schema: settingsSql,
39
36
  path: "settings-migration.sql",
40
- namespace: SETTINGS_NAMESPACE,
37
+ namespace: "",
41
38
  fromVersion: settingsSourceVersion,
42
- toVersion: settingsTargetVersion,
43
- preparedMigration: settingsMigration
39
+ toVersion: settingsTargetVersion
44
40
  });
45
41
  for (const db of databases) {
46
42
  const dbAdapter = db.adapter;
47
- if (!dbAdapter.createMigrationEngine) throw new Error(`Adapter for ${db.namespace} does not support schema generation. Ensure your adapter implements either createSchemaGenerator or createMigrationEngine.`);
48
- const migrator = dbAdapter.createMigrationEngine(db.schema, db.namespace);
43
+ if (!dbAdapter.prepareMigrations) throw new Error(`Adapter for ${db.namespace} does not support schema generation. Ensure your adapter implements either createSchemaGenerator or prepareMigrations.`);
44
+ const preparedMigrations = dbAdapter.prepareMigrations(db.schema, db.namespace);
49
45
  const targetVersion = options?.toVersion ?? db.schema.version;
50
46
  const sourceVersion = options?.fromVersion ?? 0;
51
- const preparedMigration = await migrator.prepareMigrationTo(targetVersion, { fromVersion: sourceVersion });
52
- if (!preparedMigration.getSQL) throw new Error("Migration engine does not support SQL generation. Ensure your adapter's migration engine provides getSQL().");
53
- const sql = preparedMigration.getSQL();
47
+ const sql = preparedMigrations.getSQL(sourceVersion, targetVersion);
54
48
  if (sql.trim()) generatedFiles.push({
55
49
  schema: sql,
56
50
  path: "schema.sql",
57
51
  namespace: db.namespace,
58
52
  fromVersion: sourceVersion,
59
- toVersion: targetVersion,
60
- preparedMigration
53
+ toVersion: targetVersion
61
54
  });
62
55
  }
63
56
  return postProcessMigrationFilenames(generatedFiles);
@@ -72,7 +65,7 @@ async function generateMigrationsOrSchema(databases, options) {
72
65
  async function executeMigrations(databases) {
73
66
  if (databases.length === 0) throw new Error("No databases provided for migration");
74
67
  const adapter = databases[0].adapter;
75
- if (!adapter.createMigrationEngine) throw new Error("Adapter does not support running migrations. The adapter only supports schema generation.\nTry using 'generateMigrationsOrSchema' instead to generate schema files.");
68
+ if (!adapter.prepareMigrations) throw new Error("Adapter does not support running migrations. The adapter only supports schema generation.\nTry using 'generateMigrationsOrSchema' instead to generate schema files.");
76
69
  const firstAdapterName = adapter[fragnoDatabaseAdapterNameFakeSymbol];
77
70
  const firstAdapterVersion = adapter[fragnoDatabaseAdapterVersionFakeSymbol];
78
71
  for (const db of databases) {
@@ -83,45 +76,34 @@ async function executeMigrations(databases) {
83
76
  if (!await adapter.isConnectionHealthy()) throw new Error("Database connection is not healthy. Please check your database connection and try again.");
84
77
  const results = [];
85
78
  const migrationsToExecute = [];
86
- const settingsManager = createSettingsManager(adapter.createQueryEngine(settingsSchema, ""), SETTINGS_NAMESPACE);
87
- let settingsSourceVersion;
88
- try {
89
- const result = await settingsManager.get("version");
90
- settingsSourceVersion = result ? parseInt(result.value) : 0;
91
- } catch {
92
- settingsSourceVersion = 0;
93
- }
94
- const settingsMigrator = adapter.createMigrationEngine(settingsSchema, SETTINGS_NAMESPACE);
95
- const settingsTargetVersion = settingsSchema.version;
79
+ const internalFragment = instantiate(internalFragmentDef).withConfig({}).withOptions({ databaseAdapter: adapter }).build();
80
+ const settingsSourceVersion = await getSchemaVersionFromDatabase(internalFragment, SETTINGS_NAMESPACE);
81
+ const settingsPreparedMigrations = adapter.prepareMigrations(internalSchema, "");
82
+ const settingsTargetVersion = internalSchema.version;
96
83
  if (settingsSourceVersion < settingsTargetVersion) {
97
- const settingsMigration = await settingsMigrator.prepareMigrationTo(settingsTargetVersion, {
98
- fromVersion: settingsSourceVersion,
99
- updateSettings: true
100
- });
101
- if (settingsMigration.operations.length > 0) migrationsToExecute.push({
102
- namespace: SETTINGS_NAMESPACE,
84
+ if (settingsPreparedMigrations.compile(settingsSourceVersion, settingsTargetVersion, { updateVersionInMigration: true }).statements.length > 0) migrationsToExecute.push({
85
+ namespace: "",
103
86
  fromVersion: settingsSourceVersion,
104
87
  toVersion: settingsTargetVersion,
105
- preparedMigration: settingsMigration
88
+ execute: () => settingsPreparedMigrations.execute(settingsSourceVersion, settingsTargetVersion, { updateVersionInMigration: true })
106
89
  });
107
90
  }
108
91
  const sortedDatabases = [...databases].sort((a, b) => a.namespace.localeCompare(b.namespace));
109
92
  for (const fragnoDb of sortedDatabases) {
110
- const migrator = adapter.createMigrationEngine(fragnoDb.schema, fragnoDb.namespace);
111
- const currentVersion = await migrator.getVersion();
93
+ const preparedMigrations = adapter.prepareMigrations(fragnoDb.schema, fragnoDb.namespace);
94
+ const currentVersion = await getSchemaVersionFromDatabase(internalFragment, fragnoDb.namespace);
112
95
  const targetVersion = fragnoDb.schema.version;
113
96
  if (currentVersion < targetVersion) {
114
- const preparedMigration = await migrator.prepareMigrationTo(targetVersion, { updateSettings: true });
115
- if (preparedMigration.operations.length > 0) migrationsToExecute.push({
97
+ if (preparedMigrations.compile(currentVersion, targetVersion, { updateVersionInMigration: true }).statements.length > 0) migrationsToExecute.push({
116
98
  namespace: fragnoDb.namespace,
117
99
  fromVersion: currentVersion,
118
100
  toVersion: targetVersion,
119
- preparedMigration
101
+ execute: () => preparedMigrations.execute(currentVersion, targetVersion, { updateVersionInMigration: true })
120
102
  });
121
103
  }
122
104
  }
123
105
  for (const migration of migrationsToExecute) {
124
- await migration.preparedMigration.execute();
106
+ await migration.execute();
125
107
  results.push({
126
108
  namespace: migration.namespace,
127
109
  didMigrate: true,
@@ -150,15 +132,15 @@ async function executeMigrations(databases) {
150
132
  function postProcessMigrationFilenames(files) {
151
133
  if (files.length === 0) return [];
152
134
  const sortedFiles = [...files].sort((a, b) => {
153
- if (a.namespace === SETTINGS_NAMESPACE) return -1;
154
- if (b.namespace === SETTINGS_NAMESPACE) return 1;
135
+ if (a.namespace === "") return -1;
136
+ if (b.namespace === "") return 1;
155
137
  return a.namespace.localeCompare(b.namespace);
156
138
  });
157
139
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0].replace(/-/g, "");
158
140
  return sortedFiles.map((file, index) => {
159
141
  const fromVersion = file.fromVersion ?? 0;
160
142
  const toVersion = file.toVersion ?? 0;
161
- const newPath = `${date}_${(index + 1).toString().padStart(3, "0")}_f${fromVersion.toString().padStart(3, "0")}_t${toVersion.toString().padStart(3, "0")}_${file.namespace.replace(/[^a-z0-9-]/gi, "_")}.sql`;
143
+ const newPath = `${date}_${(index + 1).toString().padStart(3, "0")}_f${fromVersion.toString().padStart(3, "0")}_t${toVersion.toString().padStart(3, "0")}_${file.namespace === "" ? "fragno_db_settings" : file.namespace.replace(/[^a-z0-9-]/gi, "_")}.sql`;
162
144
  return {
163
145
  schema: file.schema,
164
146
  path: newPath,
@@ -1 +1 @@
1
- {"version":3,"file":"generation-engine.js","names":["settingsSourceVersion: number","generatedFiles: GenerationInternalResult[]","results: ExecuteMigrationResult[]","migrationsToExecute: Array<{\n namespace: string;\n fromVersion: number;\n toVersion: number;\n preparedMigration: PreparedMigration;\n }>"],"sources":["../../src/migration-engine/generation-engine.ts"],"sourcesContent":["import type { FragnoDatabase } from \"../mod\";\nimport type { AnySchema } from \"../schema/create\";\nimport type { PreparedMigration } from \"./create\";\nimport {\n settingsSchema,\n SETTINGS_NAMESPACE,\n createSettingsManager,\n} from \"../shared/settings-schema\";\nimport {\n fragnoDatabaseAdapterNameFakeSymbol,\n fragnoDatabaseAdapterVersionFakeSymbol,\n} from \"../adapters/adapters\";\n\nexport interface GenerationEngineResult {\n schema: string;\n path: string;\n namespace: string;\n}\n\nexport interface GenerationInternalResult {\n schema: string;\n path: string;\n namespace: string;\n fromVersion: number;\n toVersion: number;\n preparedMigration?: PreparedMigration;\n}\n\nexport interface ExecuteMigrationResult {\n namespace: string;\n didMigrate: boolean;\n fromVersion: number;\n toVersion: number;\n}\n\nexport async function generateMigrationsOrSchema<\n // oxlint-disable-next-line no-explicit-any\n const TDatabases extends FragnoDatabase<AnySchema, any>[],\n>(\n databases: TDatabases,\n options?: {\n path?: string;\n toVersion?: number;\n fromVersion?: number;\n },\n): Promise<GenerationEngineResult[]> {\n if (databases.length === 0) {\n throw new Error(\"No databases provided for schema generation\");\n }\n\n const firstDb = databases[0];\n const adapter = firstDb.adapter;\n\n // If adapter has createSchemaGenerator, use it for combined generation (e.g., Drizzle)\n if (adapter.createSchemaGenerator) {\n if (options?.toVersion !== undefined || options?.fromVersion !== undefined) {\n console.warn(\n \"⚠️ Warning: --from and --to version options are not supported when generating schemas for multiple fragments and will be ignored.\",\n );\n }\n\n const fragments = databases.map((db) => ({\n schema: db.schema,\n namespace: db.namespace,\n }));\n\n const generator = adapter.createSchemaGenerator(fragments, {\n path: options?.path,\n });\n\n return [\n {\n ...generator.generateSchema(),\n namespace: firstDb.namespace,\n },\n ];\n }\n\n // Otherwise, use migration engine for individual generation (e.g., Kysely)\n if (!adapter.createMigrationEngine) {\n throw new Error(\n \"Adapter does not support migration-based schema generation. Ensure your adapter implements createMigrationEngine.\",\n );\n }\n\n if (!(await adapter.isConnectionHealthy())) {\n throw new Error(\n \"Database connection is not healthy. Please check your database connection and try again.\",\n );\n }\n\n const settingsQueryEngine = adapter.createQueryEngine(settingsSchema, \"\");\n const settingsManager = createSettingsManager(settingsQueryEngine, SETTINGS_NAMESPACE);\n\n let settingsSourceVersion: number;\n try {\n const result = await settingsManager.get(\"version\");\n\n if (!result) {\n settingsSourceVersion = 0;\n } else {\n settingsSourceVersion = parseInt(result.value);\n }\n } catch {\n // We don't really have a way to verify this error happens because the key doesn't exist in the database\n settingsSourceVersion = 0;\n }\n\n const generatedFiles: GenerationInternalResult[] = [];\n\n const settingsMigrator = adapter.createMigrationEngine(settingsSchema, SETTINGS_NAMESPACE);\n const settingsTargetVersion = settingsSchema.version;\n\n // Generate settings table migration\n const settingsMigration = await settingsMigrator.prepareMigrationTo(settingsTargetVersion, {\n fromVersion: settingsSourceVersion,\n });\n\n if (!settingsMigration.getSQL) {\n throw new Error(\n \"Migration engine does not support SQL generation. Ensure your adapter's migration engine provides getSQL().\",\n );\n }\n\n const settingsSql = settingsMigration.getSQL();\n\n if (settingsSql.trim()) {\n generatedFiles.push({\n schema: settingsSql,\n path: \"settings-migration.sql\", // Placeholder, will be renamed in post-processing\n namespace: SETTINGS_NAMESPACE,\n fromVersion: settingsSourceVersion,\n toVersion: settingsTargetVersion,\n preparedMigration: settingsMigration,\n });\n }\n\n // Generate migration for each fragment\n for (const db of databases) {\n const dbAdapter = db.adapter;\n\n // Use migration engine\n if (!dbAdapter.createMigrationEngine) {\n throw new Error(\n `Adapter for ${db.namespace} does not support schema generation. ` +\n `Ensure your adapter implements either createSchemaGenerator or createMigrationEngine.`,\n );\n }\n\n const migrator = dbAdapter.createMigrationEngine(db.schema, db.namespace);\n const targetVersion = options?.toVersion ?? db.schema.version;\n const sourceVersion = options?.fromVersion ?? 0;\n\n // Generate migration from source to target version\n const preparedMigration = await migrator.prepareMigrationTo(targetVersion, {\n fromVersion: sourceVersion,\n });\n\n if (!preparedMigration.getSQL) {\n throw new Error(\n \"Migration engine does not support SQL generation. Ensure your adapter's migration engine provides getSQL().\",\n );\n }\n\n const sql = preparedMigration.getSQL();\n\n // If no migrations needed, skip this fragment\n if (sql.trim()) {\n generatedFiles.push({\n schema: sql,\n path: \"schema.sql\", // Placeholder, will be renamed in post-processing\n namespace: db.namespace,\n fromVersion: sourceVersion,\n toVersion: targetVersion,\n preparedMigration: preparedMigration,\n });\n }\n }\n\n // Post-process filenames with ordering\n return postProcessMigrationFilenames(generatedFiles);\n}\n\n/**\n * Execute migrations for all fragments in the correct order.\n * Migrates settings table first, then fragments alphabetically.\n *\n * @param databases - Array of FragnoDatabase instances to migrate\n * @returns Array of execution results for each migration\n */\nexport async function executeMigrations<const TDatabases extends FragnoDatabase<AnySchema>[]>(\n databases: TDatabases,\n): Promise<ExecuteMigrationResult[]> {\n if (databases.length === 0) {\n throw new Error(\"No databases provided for migration\");\n }\n\n const firstDb = databases[0];\n const adapter = firstDb.adapter;\n\n // Validate adapter supports migrations\n if (!adapter.createMigrationEngine) {\n throw new Error(\n \"Adapter does not support running migrations. The adapter only supports schema generation.\\n\" +\n \"Try using 'generateMigrationsOrSchema' instead to generate schema files.\",\n );\n }\n\n // Validate all use same adapter name and version\n const firstAdapterName = adapter[fragnoDatabaseAdapterNameFakeSymbol];\n const firstAdapterVersion = adapter[fragnoDatabaseAdapterVersionFakeSymbol];\n\n for (const db of databases) {\n const dbAdapterName = db.adapter[fragnoDatabaseAdapterNameFakeSymbol];\n const dbAdapterVersion = db.adapter[fragnoDatabaseAdapterVersionFakeSymbol];\n\n if (dbAdapterName !== firstAdapterName || dbAdapterVersion !== firstAdapterVersion) {\n throw new Error(\n `All fragments must use the same database adapter. ` +\n `Found: ${firstAdapterName}@${firstAdapterVersion} and ${dbAdapterName}@${dbAdapterVersion}`,\n );\n }\n }\n\n if (!(await adapter.isConnectionHealthy())) {\n throw new Error(\n \"Database connection is not healthy. Please check your database connection and try again.\",\n );\n }\n\n const results: ExecuteMigrationResult[] = [];\n const migrationsToExecute: Array<{\n namespace: string;\n fromVersion: number;\n toVersion: number;\n preparedMigration: PreparedMigration;\n }> = [];\n\n // 1. Prepare settings table migration\n const settingsQueryEngine = adapter.createQueryEngine(settingsSchema, \"\");\n const settingsManager = createSettingsManager(settingsQueryEngine, SETTINGS_NAMESPACE);\n\n let settingsSourceVersion: number;\n try {\n const result = await settingsManager.get(\"version\");\n settingsSourceVersion = result ? parseInt(result.value) : 0;\n } catch {\n settingsSourceVersion = 0;\n }\n\n const settingsMigrator = adapter.createMigrationEngine(settingsSchema, SETTINGS_NAMESPACE);\n const settingsTargetVersion = settingsSchema.version;\n\n if (settingsSourceVersion < settingsTargetVersion) {\n const settingsMigration = await settingsMigrator.prepareMigrationTo(settingsTargetVersion, {\n fromVersion: settingsSourceVersion,\n updateSettings: true,\n });\n\n if (settingsMigration.operations.length > 0) {\n migrationsToExecute.push({\n namespace: SETTINGS_NAMESPACE,\n fromVersion: settingsSourceVersion,\n toVersion: settingsTargetVersion,\n preparedMigration: settingsMigration,\n });\n }\n }\n\n // 2. Prepare fragment migrations (sorted alphabetically)\n const sortedDatabases = [...databases].sort((a, b) => a.namespace.localeCompare(b.namespace));\n\n for (const fragnoDb of sortedDatabases) {\n const migrator = adapter.createMigrationEngine(fragnoDb.schema, fragnoDb.namespace);\n const currentVersion = await migrator.getVersion();\n const targetVersion = fragnoDb.schema.version;\n\n if (currentVersion < targetVersion) {\n const preparedMigration = await migrator.prepareMigrationTo(targetVersion, {\n updateSettings: true,\n });\n\n if (preparedMigration.operations.length > 0) {\n migrationsToExecute.push({\n namespace: fragnoDb.namespace,\n fromVersion: currentVersion,\n toVersion: targetVersion,\n preparedMigration: preparedMigration,\n });\n }\n }\n }\n\n // 3. Execute all migrations in order\n for (const migration of migrationsToExecute) {\n await migration.preparedMigration.execute();\n results.push({\n namespace: migration.namespace,\n didMigrate: true,\n fromVersion: migration.fromVersion,\n toVersion: migration.toVersion,\n });\n }\n\n // 4. Add skipped migrations (already up-to-date)\n for (const fragnoDb of databases) {\n if (!results.find((r) => r.namespace === fragnoDb.namespace)) {\n results.push({\n namespace: fragnoDb.namespace,\n didMigrate: false,\n fromVersion: fragnoDb.schema.version,\n toVersion: fragnoDb.schema.version,\n });\n }\n }\n\n return results;\n}\n\n/**\n * Post-processes migration files to add ordering and standardize naming.\n *\n * Sorts files with settings namespace first, then alphabetically by namespace,\n * and assigns ordering numbers. Transforms filenames to format:\n * `<date>_<n>_f<from>_t<to>_<namespace>.sql`\n *\n * @param files - Array of generated migration files with version information\n * @returns Array of files with standardized paths and ordering\n */\nexport function postProcessMigrationFilenames(\n files: GenerationInternalResult[],\n): GenerationEngineResult[] {\n if (files.length === 0) {\n return [];\n }\n\n // Sort files: settings namespace first, then alphabetically by namespace\n const sortedFiles = [...files].sort((a, b) => {\n if (a.namespace === SETTINGS_NAMESPACE) {\n return -1;\n }\n if (b.namespace === SETTINGS_NAMESPACE) {\n return 1;\n }\n return a.namespace.localeCompare(b.namespace);\n });\n\n // Generate date prefix for filenames\n const date = new Date().toISOString().split(\"T\")[0].replace(/-/g, \"\");\n\n // Rename files with ordering\n return sortedFiles.map((file, index) => {\n const fromVersion = file.fromVersion ?? 0;\n const toVersion = file.toVersion ?? 0;\n\n // Create new filename with ordering\n const orderNum = (index + 1).toString().padStart(3, \"0\");\n const fromPadded = fromVersion.toString().padStart(3, \"0\");\n const toPadded = toVersion.toString().padStart(3, \"0\");\n const safeName = file.namespace.replace(/[^a-z0-9-]/gi, \"_\");\n const newPath = `${date}_${orderNum}_f${fromPadded}_t${toPadded}_${safeName}.sql`;\n\n return {\n schema: file.schema,\n path: newPath,\n namespace: file.namespace,\n };\n });\n}\n"],"mappings":";;;;AAmCA,eAAsB,2BAIpB,WACA,SAKmC;AACnC,KAAI,UAAU,WAAW,EACvB,OAAM,IAAI,MAAM,8CAA8C;CAGhE,MAAM,UAAU,UAAU;CAC1B,MAAM,UAAU,QAAQ;AAGxB,KAAI,QAAQ,uBAAuB;AACjC,MAAI,SAAS,cAAc,UAAa,SAAS,gBAAgB,OAC/D,SAAQ,KACN,oIACD;EAGH,MAAM,YAAY,UAAU,KAAK,QAAQ;GACvC,QAAQ,GAAG;GACX,WAAW,GAAG;GACf,EAAE;AAMH,SAAO,CACL;GACE,GANc,QAAQ,sBAAsB,WAAW,EACzD,MAAM,SAAS,MAChB,CAAC,CAIe,gBAAgB;GAC7B,WAAW,QAAQ;GACpB,CACF;;AAIH,KAAI,CAAC,QAAQ,sBACX,OAAM,IAAI,MACR,oHACD;AAGH,KAAI,CAAE,MAAM,QAAQ,qBAAqB,CACvC,OAAM,IAAI,MACR,2FACD;CAIH,MAAM,kBAAkB,sBADI,QAAQ,kBAAkB,gBAAgB,GAAG,EACN,mBAAmB;CAEtF,IAAIA;AACJ,KAAI;EACF,MAAM,SAAS,MAAM,gBAAgB,IAAI,UAAU;AAEnD,MAAI,CAAC,OACH,yBAAwB;MAExB,yBAAwB,SAAS,OAAO,MAAM;SAE1C;AAEN,0BAAwB;;CAG1B,MAAMC,iBAA6C,EAAE;CAErD,MAAM,mBAAmB,QAAQ,sBAAsB,gBAAgB,mBAAmB;CAC1F,MAAM,wBAAwB,eAAe;CAG7C,MAAM,oBAAoB,MAAM,iBAAiB,mBAAmB,uBAAuB,EACzF,aAAa,uBACd,CAAC;AAEF,KAAI,CAAC,kBAAkB,OACrB,OAAM,IAAI,MACR,8GACD;CAGH,MAAM,cAAc,kBAAkB,QAAQ;AAE9C,KAAI,YAAY,MAAM,CACpB,gBAAe,KAAK;EAClB,QAAQ;EACR,MAAM;EACN,WAAW;EACX,aAAa;EACb,WAAW;EACX,mBAAmB;EACpB,CAAC;AAIJ,MAAK,MAAM,MAAM,WAAW;EAC1B,MAAM,YAAY,GAAG;AAGrB,MAAI,CAAC,UAAU,sBACb,OAAM,IAAI,MACR,eAAe,GAAG,UAAU,4HAE7B;EAGH,MAAM,WAAW,UAAU,sBAAsB,GAAG,QAAQ,GAAG,UAAU;EACzE,MAAM,gBAAgB,SAAS,aAAa,GAAG,OAAO;EACtD,MAAM,gBAAgB,SAAS,eAAe;EAG9C,MAAM,oBAAoB,MAAM,SAAS,mBAAmB,eAAe,EACzE,aAAa,eACd,CAAC;AAEF,MAAI,CAAC,kBAAkB,OACrB,OAAM,IAAI,MACR,8GACD;EAGH,MAAM,MAAM,kBAAkB,QAAQ;AAGtC,MAAI,IAAI,MAAM,CACZ,gBAAe,KAAK;GAClB,QAAQ;GACR,MAAM;GACN,WAAW,GAAG;GACd,aAAa;GACb,WAAW;GACQ;GACpB,CAAC;;AAKN,QAAO,8BAA8B,eAAe;;;;;;;;;AAUtD,eAAsB,kBACpB,WACmC;AACnC,KAAI,UAAU,WAAW,EACvB,OAAM,IAAI,MAAM,sCAAsC;CAIxD,MAAM,UADU,UAAU,GACF;AAGxB,KAAI,CAAC,QAAQ,sBACX,OAAM,IAAI,MACR,sKAED;CAIH,MAAM,mBAAmB,QAAQ;CACjC,MAAM,sBAAsB,QAAQ;AAEpC,MAAK,MAAM,MAAM,WAAW;EAC1B,MAAM,gBAAgB,GAAG,QAAQ;EACjC,MAAM,mBAAmB,GAAG,QAAQ;AAEpC,MAAI,kBAAkB,oBAAoB,qBAAqB,oBAC7D,OAAM,IAAI,MACR,4DACY,iBAAiB,GAAG,oBAAoB,OAAO,cAAc,GAAG,mBAC7E;;AAIL,KAAI,CAAE,MAAM,QAAQ,qBAAqB,CACvC,OAAM,IAAI,MACR,2FACD;CAGH,MAAMC,UAAoC,EAAE;CAC5C,MAAMC,sBAKD,EAAE;CAIP,MAAM,kBAAkB,sBADI,QAAQ,kBAAkB,gBAAgB,GAAG,EACN,mBAAmB;CAEtF,IAAIH;AACJ,KAAI;EACF,MAAM,SAAS,MAAM,gBAAgB,IAAI,UAAU;AACnD,0BAAwB,SAAS,SAAS,OAAO,MAAM,GAAG;SACpD;AACN,0BAAwB;;CAG1B,MAAM,mBAAmB,QAAQ,sBAAsB,gBAAgB,mBAAmB;CAC1F,MAAM,wBAAwB,eAAe;AAE7C,KAAI,wBAAwB,uBAAuB;EACjD,MAAM,oBAAoB,MAAM,iBAAiB,mBAAmB,uBAAuB;GACzF,aAAa;GACb,gBAAgB;GACjB,CAAC;AAEF,MAAI,kBAAkB,WAAW,SAAS,EACxC,qBAAoB,KAAK;GACvB,WAAW;GACX,aAAa;GACb,WAAW;GACX,mBAAmB;GACpB,CAAC;;CAKN,MAAM,kBAAkB,CAAC,GAAG,UAAU,CAAC,MAAM,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,UAAU,CAAC;AAE7F,MAAK,MAAM,YAAY,iBAAiB;EACtC,MAAM,WAAW,QAAQ,sBAAsB,SAAS,QAAQ,SAAS,UAAU;EACnF,MAAM,iBAAiB,MAAM,SAAS,YAAY;EAClD,MAAM,gBAAgB,SAAS,OAAO;AAEtC,MAAI,iBAAiB,eAAe;GAClC,MAAM,oBAAoB,MAAM,SAAS,mBAAmB,eAAe,EACzE,gBAAgB,MACjB,CAAC;AAEF,OAAI,kBAAkB,WAAW,SAAS,EACxC,qBAAoB,KAAK;IACvB,WAAW,SAAS;IACpB,aAAa;IACb,WAAW;IACQ;IACpB,CAAC;;;AAMR,MAAK,MAAM,aAAa,qBAAqB;AAC3C,QAAM,UAAU,kBAAkB,SAAS;AAC3C,UAAQ,KAAK;GACX,WAAW,UAAU;GACrB,YAAY;GACZ,aAAa,UAAU;GACvB,WAAW,UAAU;GACtB,CAAC;;AAIJ,MAAK,MAAM,YAAY,UACrB,KAAI,CAAC,QAAQ,MAAM,MAAM,EAAE,cAAc,SAAS,UAAU,CAC1D,SAAQ,KAAK;EACX,WAAW,SAAS;EACpB,YAAY;EACZ,aAAa,SAAS,OAAO;EAC7B,WAAW,SAAS,OAAO;EAC5B,CAAC;AAIN,QAAO;;;;;;;;;;;;AAaT,SAAgB,8BACd,OAC0B;AAC1B,KAAI,MAAM,WAAW,EACnB,QAAO,EAAE;CAIX,MAAM,cAAc,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM;AAC5C,MAAI,EAAE,cAAc,mBAClB,QAAO;AAET,MAAI,EAAE,cAAc,mBAClB,QAAO;AAET,SAAO,EAAE,UAAU,cAAc,EAAE,UAAU;GAC7C;CAGF,MAAM,wBAAO,IAAI,MAAM,EAAC,aAAa,CAAC,MAAM,IAAI,CAAC,GAAG,QAAQ,MAAM,GAAG;AAGrE,QAAO,YAAY,KAAK,MAAM,UAAU;EACtC,MAAM,cAAc,KAAK,eAAe;EACxC,MAAM,YAAY,KAAK,aAAa;EAOpC,MAAM,UAAU,GAAG,KAAK,IAJN,QAAQ,GAAG,UAAU,CAAC,SAAS,GAAG,IAAI,CAIpB,IAHjB,YAAY,UAAU,CAAC,SAAS,GAAG,IAAI,CAGP,IAFlC,UAAU,UAAU,CAAC,SAAS,GAAG,IAAI,CAEU,GAD/C,KAAK,UAAU,QAAQ,gBAAgB,IAAI,CACgB;AAE5E,SAAO;GACL,QAAQ,KAAK;GACb,MAAM;GACN,WAAW,KAAK;GACjB;GACD"}
1
+ {"version":3,"file":"generation-engine.js","names":["generatedFiles: GenerationInternalResult[]","results: ExecuteMigrationResult[]","migrationsToExecute: Array<{\n namespace: string;\n fromVersion: number;\n toVersion: number;\n execute: () => Promise<void>;\n }>"],"sources":["../../src/migration-engine/generation-engine.ts"],"sourcesContent":["import type { FragnoDatabase } from \"../mod\";\nimport type { AnySchema } from \"../schema/create\";\nimport {\n fragnoDatabaseAdapterNameFakeSymbol,\n fragnoDatabaseAdapterVersionFakeSymbol,\n} from \"../adapters/adapters\";\nimport {\n internalFragmentDef,\n internalSchema,\n SETTINGS_NAMESPACE,\n getSchemaVersionFromDatabase,\n} from \"../fragments/internal-fragment\";\nimport { instantiate } from \"@fragno-dev/core\";\n\nexport interface GenerationEngineResult {\n schema: string;\n path: string;\n namespace: string;\n}\n\nexport interface GenerationInternalResult {\n schema: string;\n path: string;\n namespace: string;\n fromVersion: number;\n toVersion: number;\n}\n\nexport interface ExecuteMigrationResult {\n namespace: string;\n didMigrate: boolean;\n fromVersion: number;\n toVersion: number;\n}\n\nexport async function generateMigrationsOrSchema<\n // oxlint-disable-next-line no-explicit-any\n const TDatabases extends FragnoDatabase<AnySchema, any>[],\n>(\n databases: TDatabases,\n options?: {\n path?: string;\n toVersion?: number;\n fromVersion?: number;\n },\n): Promise<GenerationEngineResult[]> {\n if (databases.length === 0) {\n throw new Error(\"No databases provided for schema generation\");\n }\n\n const firstDb = databases[0];\n const adapter = firstDb.adapter;\n\n // If adapter has createSchemaGenerator, use it for combined generation (e.g., Drizzle)\n if (adapter.createSchemaGenerator) {\n if (options?.toVersion !== undefined || options?.fromVersion !== undefined) {\n console.warn(\n \"⚠️ Warning: --from and --to version options are not supported when generating schemas for multiple fragments and will be ignored.\",\n );\n }\n\n // Collect all schemas, de-duplicating by namespace.\n // The internal fragment (settings schema) is always included first since all database\n // fragments automatically link to it via withDatabase().\n const fragmentsMap = new Map<string, { schema: AnySchema; namespace: string }>();\n\n // Include internal fragment first with empty namespace (settings table has no prefix)\n fragmentsMap.set(\"\", {\n schema: internalSchema,\n namespace: \"\",\n });\n\n // Add user fragments, de-duplicating by namespace\n // Each FragnoDatabase has a unique namespace, so this prevents duplicate schema generation\n for (const db of databases) {\n if (!fragmentsMap.has(db.namespace)) {\n fragmentsMap.set(db.namespace, {\n schema: db.schema,\n namespace: db.namespace,\n });\n }\n }\n\n const allFragments = Array.from(fragmentsMap.values());\n const generator = adapter.createSchemaGenerator(allFragments, {\n path: options?.path,\n });\n\n return [\n {\n ...generator.generateSchema(),\n namespace: firstDb.namespace,\n },\n ];\n }\n\n // Otherwise, use migration engine for individual generation (e.g., Kysely, GenericSQL)\n if (!adapter.prepareMigrations) {\n throw new Error(\n \"Adapter does not support migration-based schema generation. Ensure your adapter implements prepareMigrations.\",\n );\n }\n\n if (!(await adapter.isConnectionHealthy())) {\n throw new Error(\n \"Database connection is not healthy. Please check your database connection and try again.\",\n );\n }\n\n // Use the internal fragment for settings management\n const internalFragment = instantiate(internalFragmentDef)\n .withConfig({})\n .withOptions({ databaseAdapter: adapter })\n .build();\n\n const settingsSourceVersion = await getSchemaVersionFromDatabase(\n internalFragment,\n SETTINGS_NAMESPACE,\n );\n\n const generatedFiles: GenerationInternalResult[] = [];\n\n // Use empty namespace for settings (SETTINGS_NAMESPACE is for prefixing keys, not the database namespace)\n const settingsPreparedMigrations = adapter.prepareMigrations(internalSchema, \"\");\n const settingsTargetVersion = internalSchema.version;\n\n // Generate settings table migration\n const settingsSql = settingsPreparedMigrations.getSQL(\n settingsSourceVersion,\n settingsTargetVersion,\n );\n\n if (settingsSql.trim()) {\n generatedFiles.push({\n schema: settingsSql,\n path: \"settings-migration.sql\", // Placeholder, will be renamed in post-processing\n namespace: \"\", // Empty namespace for settings table\n fromVersion: settingsSourceVersion,\n toVersion: settingsTargetVersion,\n });\n }\n\n // Generate migration for each fragment\n for (const db of databases) {\n const dbAdapter = db.adapter;\n\n // Use migration engine\n if (!dbAdapter.prepareMigrations) {\n throw new Error(\n `Adapter for ${db.namespace} does not support schema generation. ` +\n `Ensure your adapter implements either createSchemaGenerator or prepareMigrations.`,\n );\n }\n\n const preparedMigrations = dbAdapter.prepareMigrations(db.schema, db.namespace);\n const targetVersion = options?.toVersion ?? db.schema.version;\n const sourceVersion = options?.fromVersion ?? 0;\n\n // Generate migration from source to target version\n const sql = preparedMigrations.getSQL(sourceVersion, targetVersion);\n\n // If no migrations needed, skip this fragment\n if (sql.trim()) {\n generatedFiles.push({\n schema: sql,\n path: \"schema.sql\", // Placeholder, will be renamed in post-processing\n namespace: db.namespace,\n fromVersion: sourceVersion,\n toVersion: targetVersion,\n });\n }\n }\n\n // Post-process filenames with ordering\n return postProcessMigrationFilenames(generatedFiles);\n}\n\n/**\n * Execute migrations for all fragments in the correct order.\n * Migrates settings table first, then fragments alphabetically.\n *\n * @param databases - Array of FragnoDatabase instances to migrate\n * @returns Array of execution results for each migration\n */\nexport async function executeMigrations<const TDatabases extends FragnoDatabase<AnySchema>[]>(\n databases: TDatabases,\n): Promise<ExecuteMigrationResult[]> {\n if (databases.length === 0) {\n throw new Error(\"No databases provided for migration\");\n }\n\n const firstDb = databases[0];\n const adapter = firstDb.adapter;\n\n // Validate adapter supports migrations\n if (!adapter.prepareMigrations) {\n throw new Error(\n \"Adapter does not support running migrations. The adapter only supports schema generation.\\n\" +\n \"Try using 'generateMigrationsOrSchema' instead to generate schema files.\",\n );\n }\n\n // Validate all use same adapter name and version\n const firstAdapterName = adapter[fragnoDatabaseAdapterNameFakeSymbol];\n const firstAdapterVersion = adapter[fragnoDatabaseAdapterVersionFakeSymbol];\n\n for (const db of databases) {\n const dbAdapterName = db.adapter[fragnoDatabaseAdapterNameFakeSymbol];\n const dbAdapterVersion = db.adapter[fragnoDatabaseAdapterVersionFakeSymbol];\n\n if (dbAdapterName !== firstAdapterName || dbAdapterVersion !== firstAdapterVersion) {\n throw new Error(\n `All fragments must use the same database adapter. ` +\n `Found: ${firstAdapterName}@${firstAdapterVersion} and ${dbAdapterName}@${dbAdapterVersion}`,\n );\n }\n }\n\n if (!(await adapter.isConnectionHealthy())) {\n throw new Error(\n \"Database connection is not healthy. Please check your database connection and try again.\",\n );\n }\n\n const results: ExecuteMigrationResult[] = [];\n const migrationsToExecute: Array<{\n namespace: string;\n fromVersion: number;\n toVersion: number;\n execute: () => Promise<void>;\n }> = [];\n\n // 1. Prepare settings table migration\n // Use the internal fragment for settings management\n const internalFragment = instantiate(internalFragmentDef)\n .withConfig({})\n .withOptions({ databaseAdapter: adapter })\n .build();\n\n const settingsSourceVersion = await getSchemaVersionFromDatabase(\n internalFragment,\n SETTINGS_NAMESPACE,\n );\n\n // Use empty namespace for settings (SETTINGS_NAMESPACE is for prefixing keys, not the database namespace)\n const settingsPreparedMigrations = adapter.prepareMigrations(internalSchema, \"\");\n const settingsTargetVersion = internalSchema.version;\n\n if (settingsSourceVersion < settingsTargetVersion) {\n const compiledMigration = settingsPreparedMigrations.compile(\n settingsSourceVersion,\n settingsTargetVersion,\n { updateVersionInMigration: true },\n );\n\n if (compiledMigration.statements.length > 0) {\n migrationsToExecute.push({\n namespace: \"\", // Empty namespace for settings table\n fromVersion: settingsSourceVersion,\n toVersion: settingsTargetVersion,\n execute: () =>\n settingsPreparedMigrations.execute(settingsSourceVersion, settingsTargetVersion, {\n updateVersionInMigration: true,\n }),\n });\n }\n }\n\n // 2. Prepare fragment migrations (sorted alphabetically)\n const sortedDatabases = [...databases].sort((a, b) => a.namespace.localeCompare(b.namespace));\n\n for (const fragnoDb of sortedDatabases) {\n const preparedMigrations = adapter.prepareMigrations(fragnoDb.schema, fragnoDb.namespace);\n const currentVersion = await getSchemaVersionFromDatabase(internalFragment, fragnoDb.namespace);\n const targetVersion = fragnoDb.schema.version;\n\n if (currentVersion < targetVersion) {\n const compiledMigration = preparedMigrations.compile(currentVersion, targetVersion, {\n updateVersionInMigration: true,\n });\n\n if (compiledMigration.statements.length > 0) {\n migrationsToExecute.push({\n namespace: fragnoDb.namespace,\n fromVersion: currentVersion,\n toVersion: targetVersion,\n execute: () =>\n preparedMigrations.execute(currentVersion, targetVersion, {\n updateVersionInMigration: true,\n }),\n });\n }\n }\n }\n\n // 3. Execute all migrations in order\n for (const migration of migrationsToExecute) {\n await migration.execute();\n results.push({\n namespace: migration.namespace,\n didMigrate: true,\n fromVersion: migration.fromVersion,\n toVersion: migration.toVersion,\n });\n }\n\n // 4. Add skipped migrations (already up-to-date)\n for (const fragnoDb of databases) {\n if (!results.find((r) => r.namespace === fragnoDb.namespace)) {\n results.push({\n namespace: fragnoDb.namespace,\n didMigrate: false,\n fromVersion: fragnoDb.schema.version,\n toVersion: fragnoDb.schema.version,\n });\n }\n }\n\n return results;\n}\n\n/**\n * Post-processes migration files to add ordering and standardize naming.\n *\n * Sorts files with settings namespace first, then alphabetically by namespace,\n * and assigns ordering numbers. Transforms filenames to format:\n * `<date>_<n>_f<from>_t<to>_<namespace>.sql`\n *\n * @param files - Array of generated migration files with version information\n * @returns Array of files with standardized paths and ordering\n */\nexport function postProcessMigrationFilenames(\n files: GenerationInternalResult[],\n): GenerationEngineResult[] {\n if (files.length === 0) {\n return [];\n }\n\n // Sort files: settings namespace first (empty string), then alphabetically by namespace\n const sortedFiles = [...files].sort((a, b) => {\n // Settings table has empty namespace - sort it first\n if (a.namespace === \"\") {\n return -1;\n }\n if (b.namespace === \"\") {\n return 1;\n }\n return a.namespace.localeCompare(b.namespace);\n });\n\n // Generate date prefix for filenames\n const date = new Date().toISOString().split(\"T\")[0].replace(/-/g, \"\");\n\n // Rename files with ordering\n return sortedFiles.map((file, index) => {\n const fromVersion = file.fromVersion ?? 0;\n const toVersion = file.toVersion ?? 0;\n\n // Create new filename with ordering\n const orderNum = (index + 1).toString().padStart(3, \"0\");\n const fromPadded = fromVersion.toString().padStart(3, \"0\");\n const toPadded = toVersion.toString().padStart(3, \"0\");\n\n // For settings table (empty namespace), use \"fragno_db_settings\" in the filename\n // For other tables, use their namespace\n const safeName =\n file.namespace === \"\" ? \"fragno_db_settings\" : file.namespace.replace(/[^a-z0-9-]/gi, \"_\");\n const newPath = `${date}_${orderNum}_f${fromPadded}_t${toPadded}_${safeName}.sql`;\n\n return {\n schema: file.schema,\n path: newPath,\n namespace: file.namespace,\n };\n });\n}\n"],"mappings":"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"}