@fragno-dev/db 0.2.1 → 0.3.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 (362) hide show
  1. package/.turbo/turbo-build.log +206 -140
  2. package/CHANGELOG.md +67 -0
  3. package/README.md +30 -9
  4. package/dist/adapters/adapters.d.ts +23 -21
  5. package/dist/adapters/adapters.d.ts.map +1 -1
  6. package/dist/adapters/adapters.js.map +1 -1
  7. package/dist/adapters/generic-sql/driver-config.d.ts +16 -1
  8. package/dist/adapters/generic-sql/driver-config.d.ts.map +1 -1
  9. package/dist/adapters/generic-sql/driver-config.js +23 -1
  10. package/dist/adapters/generic-sql/driver-config.js.map +1 -1
  11. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts +27 -9
  12. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -1
  13. package/dist/adapters/generic-sql/generic-sql-adapter.js +55 -16
  14. package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -1
  15. package/dist/adapters/generic-sql/generic-sql-uow-executor.js +129 -3
  16. package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -1
  17. package/dist/adapters/generic-sql/migration/dialect/mysql.js +24 -5
  18. package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -1
  19. package/dist/adapters/generic-sql/migration/dialect/postgres.js +6 -5
  20. package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -1
  21. package/dist/adapters/generic-sql/migration/dialect/sqlite.js +21 -10
  22. package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -1
  23. package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -1
  24. package/dist/adapters/generic-sql/migration/prepared-migrations.js +8 -8
  25. package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -1
  26. package/dist/adapters/generic-sql/migration/sql-generator.js +74 -51
  27. package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -1
  28. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +6 -5
  29. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -1
  30. package/dist/adapters/generic-sql/query/cursor-utils.js +42 -4
  31. package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -1
  32. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +25 -17
  33. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -1
  34. package/dist/adapters/generic-sql/query/select-builder.js +5 -3
  35. package/dist/adapters/generic-sql/query/select-builder.js.map +1 -1
  36. package/dist/adapters/generic-sql/query/sql-query-compiler.js +15 -12
  37. package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -1
  38. package/dist/adapters/generic-sql/query/where-builder.js +38 -28
  39. package/dist/adapters/generic-sql/query/where-builder.js.map +1 -1
  40. package/dist/adapters/generic-sql/sqlite-storage.d.ts +13 -0
  41. package/dist/adapters/generic-sql/sqlite-storage.d.ts.map +1 -0
  42. package/dist/adapters/generic-sql/sqlite-storage.js +15 -0
  43. package/dist/adapters/generic-sql/sqlite-storage.js.map +1 -0
  44. package/dist/adapters/generic-sql/uow-decoder.js +7 -3
  45. package/dist/adapters/generic-sql/uow-decoder.js.map +1 -1
  46. package/dist/adapters/generic-sql/uow-encoder.js +28 -8
  47. package/dist/adapters/generic-sql/uow-encoder.js.map +1 -1
  48. package/dist/adapters/in-memory/condition-evaluator.js +131 -0
  49. package/dist/adapters/in-memory/condition-evaluator.js.map +1 -0
  50. package/dist/adapters/in-memory/errors.d.ts +13 -0
  51. package/dist/adapters/in-memory/errors.d.ts.map +1 -0
  52. package/dist/adapters/in-memory/errors.js +23 -0
  53. package/dist/adapters/in-memory/errors.js.map +1 -0
  54. package/dist/adapters/in-memory/in-memory-adapter.d.ts +27 -0
  55. package/dist/adapters/in-memory/in-memory-adapter.d.ts.map +1 -0
  56. package/dist/adapters/in-memory/in-memory-adapter.js +176 -0
  57. package/dist/adapters/in-memory/in-memory-adapter.js.map +1 -0
  58. package/dist/adapters/in-memory/in-memory-uow.js +648 -0
  59. package/dist/adapters/in-memory/in-memory-uow.js.map +1 -0
  60. package/dist/adapters/in-memory/index.d.ts +4 -0
  61. package/dist/adapters/in-memory/index.js +4 -0
  62. package/dist/adapters/in-memory/options.d.ts +28 -0
  63. package/dist/adapters/in-memory/options.d.ts.map +1 -0
  64. package/dist/adapters/in-memory/options.js +61 -0
  65. package/dist/adapters/in-memory/options.js.map +1 -0
  66. package/dist/adapters/in-memory/reference-resolution.js +26 -0
  67. package/dist/adapters/in-memory/reference-resolution.js.map +1 -0
  68. package/dist/adapters/in-memory/sorted-array-index.js +129 -0
  69. package/dist/adapters/in-memory/sorted-array-index.js.map +1 -0
  70. package/dist/adapters/in-memory/store.js +71 -0
  71. package/dist/adapters/in-memory/store.js.map +1 -0
  72. package/dist/adapters/in-memory/value-comparison.js +28 -0
  73. package/dist/adapters/in-memory/value-comparison.js.map +1 -0
  74. package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -1
  75. package/dist/adapters/shared/uow-operation-compiler.js +11 -11
  76. package/dist/adapters/shared/uow-operation-compiler.js.map +1 -1
  77. package/dist/adapters/sql/index.d.ts +5 -0
  78. package/dist/adapters/sql/index.js +4 -0
  79. package/dist/db-fragment-definition-builder.d.ts +45 -96
  80. package/dist/db-fragment-definition-builder.d.ts.map +1 -1
  81. package/dist/db-fragment-definition-builder.js +121 -99
  82. package/dist/db-fragment-definition-builder.js.map +1 -1
  83. package/dist/dispatchers/cloudflare-do/index.d.ts +26 -0
  84. package/dist/dispatchers/cloudflare-do/index.d.ts.map +1 -0
  85. package/dist/dispatchers/cloudflare-do/index.js +63 -0
  86. package/dist/dispatchers/cloudflare-do/index.js.map +1 -0
  87. package/dist/dispatchers/node/index.d.ts +17 -0
  88. package/dist/dispatchers/node/index.d.ts.map +1 -0
  89. package/dist/dispatchers/node/index.js +59 -0
  90. package/dist/dispatchers/node/index.js.map +1 -0
  91. package/dist/fragments/internal-fragment.d.ts +172 -9
  92. package/dist/fragments/internal-fragment.d.ts.map +1 -1
  93. package/dist/fragments/internal-fragment.js +193 -74
  94. package/dist/fragments/internal-fragment.js.map +1 -1
  95. package/dist/fragments/internal-fragment.routes.js +29 -0
  96. package/dist/fragments/internal-fragment.routes.js.map +1 -0
  97. package/dist/fragments/internal-fragment.schema.d.ts +9 -0
  98. package/dist/fragments/internal-fragment.schema.d.ts.map +1 -0
  99. package/dist/fragments/internal-fragment.schema.js +22 -0
  100. package/dist/fragments/internal-fragment.schema.js.map +1 -0
  101. package/dist/hooks/durable-hooks-processor.d.ts +14 -0
  102. package/dist/hooks/durable-hooks-processor.d.ts.map +1 -0
  103. package/dist/hooks/durable-hooks-processor.js +32 -0
  104. package/dist/hooks/durable-hooks-processor.js.map +1 -0
  105. package/dist/hooks/hooks.d.ts +47 -4
  106. package/dist/hooks/hooks.d.ts.map +1 -1
  107. package/dist/hooks/hooks.js +106 -39
  108. package/dist/hooks/hooks.js.map +1 -1
  109. package/dist/migration-engine/auto-from-schema.js +14 -11
  110. package/dist/migration-engine/auto-from-schema.js.map +1 -1
  111. package/dist/migration-engine/generation-engine.d.ts +16 -10
  112. package/dist/migration-engine/generation-engine.d.ts.map +1 -1
  113. package/dist/migration-engine/generation-engine.js +72 -33
  114. package/dist/migration-engine/generation-engine.js.map +1 -1
  115. package/dist/migration-engine/shared.js.map +1 -1
  116. package/dist/mod.d.ts +17 -10
  117. package/dist/mod.d.ts.map +1 -1
  118. package/dist/mod.js +14 -8
  119. package/dist/mod.js.map +1 -1
  120. package/dist/naming/sql-naming.d.ts +19 -0
  121. package/dist/naming/sql-naming.d.ts.map +1 -0
  122. package/dist/naming/sql-naming.js +116 -0
  123. package/dist/naming/sql-naming.js.map +1 -0
  124. package/dist/node_modules/.pnpm/{rou3@0.7.10 → rou3@0.7.12}/node_modules/rou3/dist/index.js +8 -5
  125. package/dist/node_modules/.pnpm/rou3@0.7.12/node_modules/rou3/dist/index.js.map +1 -0
  126. package/dist/outbox/outbox-builder.js +156 -0
  127. package/dist/outbox/outbox-builder.js.map +1 -0
  128. package/dist/outbox/outbox.d.ts +52 -0
  129. package/dist/outbox/outbox.d.ts.map +1 -0
  130. package/dist/outbox/outbox.js +37 -0
  131. package/dist/outbox/outbox.js.map +1 -0
  132. package/dist/packages/fragno/dist/api/fragment-definition-builder.js +3 -2
  133. package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +1 -1
  134. package/dist/packages/fragno/dist/api/fragment-instantiator.js +164 -20
  135. package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -1
  136. package/dist/packages/fragno/dist/api/request-input-context.js +67 -0
  137. package/dist/packages/fragno/dist/api/request-input-context.js.map +1 -1
  138. package/dist/packages/fragno/dist/api/route.js +14 -1
  139. package/dist/packages/fragno/dist/api/route.js.map +1 -1
  140. package/dist/packages/fragno/dist/internal/trace-context.js +12 -0
  141. package/dist/packages/fragno/dist/internal/trace-context.js.map +1 -0
  142. package/dist/query/column-defaults.js +20 -4
  143. package/dist/query/column-defaults.js.map +1 -1
  144. package/dist/query/cursor.d.ts +3 -1
  145. package/dist/query/cursor.d.ts.map +1 -1
  146. package/dist/query/cursor.js +45 -14
  147. package/dist/query/cursor.js.map +1 -1
  148. package/dist/query/db-now.d.ts +8 -0
  149. package/dist/query/db-now.d.ts.map +1 -0
  150. package/dist/query/db-now.js +7 -0
  151. package/dist/query/db-now.js.map +1 -0
  152. package/dist/query/serialize/create-sql-serializer.js +3 -2
  153. package/dist/query/serialize/create-sql-serializer.js.map +1 -1
  154. package/dist/query/serialize/dialect/mysql-serializer.js +12 -6
  155. package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -1
  156. package/dist/query/serialize/dialect/postgres-serializer.js +25 -7
  157. package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -1
  158. package/dist/query/serialize/dialect/sqlite-serializer.js +55 -11
  159. package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -1
  160. package/dist/query/serialize/sql-serializer.js +2 -2
  161. package/dist/query/serialize/sql-serializer.js.map +1 -1
  162. package/dist/query/simple-query-interface.d.ts +6 -1
  163. package/dist/query/simple-query-interface.d.ts.map +1 -1
  164. package/dist/query/unit-of-work/execute-unit-of-work.d.ts +351 -100
  165. package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -1
  166. package/dist/query/unit-of-work/execute-unit-of-work.js +440 -267
  167. package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -1
  168. package/dist/query/unit-of-work/unit-of-work.d.ts +67 -22
  169. package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
  170. package/dist/query/unit-of-work/unit-of-work.js +110 -13
  171. package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
  172. package/dist/query/value-decoding.js +8 -5
  173. package/dist/query/value-decoding.js.map +1 -1
  174. package/dist/query/value-encoding.js +29 -9
  175. package/dist/query/value-encoding.js.map +1 -1
  176. package/dist/schema/create.d.ts +40 -14
  177. package/dist/schema/create.d.ts.map +1 -1
  178. package/dist/schema/create.js +82 -42
  179. package/dist/schema/create.js.map +1 -1
  180. package/dist/schema/generate-id.d.ts +20 -0
  181. package/dist/schema/generate-id.d.ts.map +1 -0
  182. package/dist/schema/generate-id.js +28 -0
  183. package/dist/schema/generate-id.js.map +1 -0
  184. package/dist/schema/type-conversion/create-sql-type-mapper.js +3 -2
  185. package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -1
  186. package/dist/schema/type-conversion/dialect/sqlite.js +9 -0
  187. package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -1
  188. package/dist/schema/validator.d.ts +10 -0
  189. package/dist/schema/validator.d.ts.map +1 -0
  190. package/dist/schema/validator.js +123 -0
  191. package/dist/schema/validator.js.map +1 -0
  192. package/dist/schema-output/drizzle.d.ts +30 -0
  193. package/dist/schema-output/drizzle.d.ts.map +1 -0
  194. package/dist/{adapters/drizzle/generate.js → schema-output/drizzle.js} +82 -56
  195. package/dist/schema-output/drizzle.js.map +1 -0
  196. package/dist/schema-output/prisma.d.ts +17 -0
  197. package/dist/schema-output/prisma.d.ts.map +1 -0
  198. package/dist/schema-output/prisma.js +296 -0
  199. package/dist/schema-output/prisma.js.map +1 -0
  200. package/dist/util/default-database-adapter.js +61 -0
  201. package/dist/util/default-database-adapter.js.map +1 -0
  202. package/dist/with-database.d.ts +1 -1
  203. package/dist/with-database.d.ts.map +1 -1
  204. package/dist/with-database.js +12 -3
  205. package/dist/with-database.js.map +1 -1
  206. package/package.json +43 -28
  207. package/src/adapters/adapters.ts +30 -24
  208. package/src/adapters/drizzle/migrate-drizzle.test.ts +54 -33
  209. package/src/adapters/drizzle/migration-parity-drizzle-kit.test.ts +599 -0
  210. package/src/adapters/drizzle/test-utils.ts +12 -8
  211. package/src/adapters/generic-sql/driver-config.ts +38 -0
  212. package/src/adapters/generic-sql/generic-sql-adapter.test.ts +5 -5
  213. package/src/adapters/generic-sql/generic-sql-adapter.ts +110 -24
  214. package/src/adapters/generic-sql/generic-sql-uow-executor.test.ts +54 -0
  215. package/src/adapters/generic-sql/generic-sql-uow-executor.ts +231 -3
  216. package/src/adapters/generic-sql/migration/adapter-migration-parity.test.ts +118 -0
  217. package/src/adapters/generic-sql/migration/dialect/mysql.test.ts +26 -8
  218. package/src/adapters/generic-sql/migration/dialect/mysql.ts +46 -8
  219. package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +25 -7
  220. package/src/adapters/generic-sql/migration/dialect/postgres.ts +8 -4
  221. package/src/adapters/generic-sql/migration/dialect/sqlite.test.ts +47 -8
  222. package/src/adapters/generic-sql/migration/dialect/sqlite.ts +27 -12
  223. package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +128 -39
  224. package/src/adapters/generic-sql/migration/prepared-migrations.ts +15 -8
  225. package/src/adapters/generic-sql/migration/sql-generator.ts +142 -65
  226. package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +9 -6
  227. package/src/adapters/generic-sql/query/cursor-utils.test.ts +271 -0
  228. package/src/adapters/generic-sql/query/cursor-utils.ts +41 -6
  229. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +27 -27
  230. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +38 -24
  231. package/src/adapters/generic-sql/query/select-builder.test.ts +15 -11
  232. package/src/adapters/generic-sql/query/select-builder.ts +6 -2
  233. package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +52 -2
  234. package/src/adapters/generic-sql/query/sql-query-compiler.ts +50 -15
  235. package/src/adapters/generic-sql/query/where-builder.test.ts +91 -17
  236. package/src/adapters/generic-sql/query/where-builder.ts +90 -38
  237. package/src/adapters/{kysely/kysely-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-migrations.test.ts} +6 -6
  238. package/src/adapters/generic-sql/sql-adapter-pglite-pagination.test.ts +806 -0
  239. package/src/adapters/{drizzle/drizzle-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-queries.test.ts} +11 -11
  240. package/src/adapters/generic-sql/{test/generic-drizzle-adapter-sqlite3.test.ts → sql-adapter-sqlite3-driver.test.ts} +49 -35
  241. package/src/adapters/{drizzle/drizzle-adapter-sqlite3.test.ts → generic-sql/sql-adapter-sqlite3-uow.test.ts} +48 -32
  242. package/src/adapters/{kysely/kysely-adapter-sqlocal.test.ts → generic-sql/sql-adapter-sqlocal.test.ts} +6 -6
  243. package/src/adapters/generic-sql/sqlite-storage.ts +20 -0
  244. package/src/adapters/generic-sql/uow-decoder.test.ts +1 -1
  245. package/src/adapters/generic-sql/uow-decoder.ts +21 -3
  246. package/src/adapters/generic-sql/uow-encoder.test.ts +33 -2
  247. package/src/adapters/generic-sql/uow-encoder.ts +50 -11
  248. package/src/adapters/in-memory/condition-evaluator.test.ts +193 -0
  249. package/src/adapters/in-memory/condition-evaluator.ts +275 -0
  250. package/src/adapters/in-memory/errors.ts +20 -0
  251. package/src/adapters/in-memory/in-memory-adapter.ts +277 -0
  252. package/src/adapters/in-memory/in-memory-uow.mutations.test.ts +296 -0
  253. package/src/adapters/in-memory/in-memory-uow.retrieval.test.ts +100 -0
  254. package/src/adapters/in-memory/in-memory-uow.ts +1348 -0
  255. package/src/adapters/in-memory/index.ts +3 -0
  256. package/src/adapters/in-memory/options.test.ts +41 -0
  257. package/src/adapters/in-memory/options.ts +87 -0
  258. package/src/adapters/in-memory/reference-resolution.test.ts +50 -0
  259. package/src/adapters/in-memory/reference-resolution.ts +67 -0
  260. package/src/adapters/in-memory/sorted-array-index.test.ts +123 -0
  261. package/src/adapters/in-memory/sorted-array-index.ts +228 -0
  262. package/src/adapters/in-memory/store.test.ts +68 -0
  263. package/src/adapters/in-memory/store.ts +145 -0
  264. package/src/adapters/in-memory/value-comparison.ts +53 -0
  265. package/src/adapters/in-memory/value-normalization.test.ts +57 -0
  266. package/src/adapters/prisma/prisma-adapter-sqlite3.test.ts +1163 -0
  267. package/src/adapters/shared/from-unit-of-work-compiler.ts +3 -1
  268. package/src/adapters/shared/uow-operation-compiler.ts +26 -16
  269. package/src/adapters/sql/index.ts +12 -0
  270. package/src/db-fragment-definition-builder.test.ts +88 -54
  271. package/src/db-fragment-definition-builder.ts +201 -322
  272. package/src/db-fragment-instantiator.test.ts +169 -101
  273. package/src/db-fragment-integration.test.ts +301 -149
  274. package/src/dispatchers/cloudflare-do/index.test.ts +73 -0
  275. package/src/dispatchers/cloudflare-do/index.ts +104 -0
  276. package/src/dispatchers/node/index.test.ts +91 -0
  277. package/src/dispatchers/node/index.ts +87 -0
  278. package/src/fragments/internal-fragment.routes.ts +42 -0
  279. package/src/fragments/internal-fragment.schema.ts +51 -0
  280. package/src/fragments/internal-fragment.test.ts +730 -274
  281. package/src/fragments/internal-fragment.ts +447 -154
  282. package/src/hooks/durable-hooks-processor.test.ts +117 -0
  283. package/src/hooks/durable-hooks-processor.ts +67 -0
  284. package/src/hooks/hooks.test.ts +411 -259
  285. package/src/hooks/hooks.ts +265 -66
  286. package/src/migration-engine/auto-from-schema.test.ts +14 -14
  287. package/src/migration-engine/auto-from-schema.ts +5 -2
  288. package/src/migration-engine/create.test.ts +2 -2
  289. package/src/migration-engine/generation-engine.test.ts +229 -104
  290. package/src/migration-engine/generation-engine.ts +94 -64
  291. package/src/migration-engine/shared.ts +1 -0
  292. package/src/mod.ts +78 -30
  293. package/src/naming/sql-naming.ts +180 -0
  294. package/src/outbox/outbox-builder.ts +241 -0
  295. package/src/outbox/outbox.test.ts +253 -0
  296. package/src/outbox/outbox.ts +137 -0
  297. package/src/query/column-defaults.ts +41 -3
  298. package/src/query/condition-builder.test.ts +3 -3
  299. package/src/query/cursor.test.ts +116 -18
  300. package/src/query/cursor.ts +75 -26
  301. package/src/query/db-now.ts +6 -0
  302. package/src/query/query-type.test.ts +2 -2
  303. package/src/query/serialize/create-sql-serializer.ts +7 -2
  304. package/src/query/serialize/dialect/mysql-serializer.ts +12 -4
  305. package/src/query/serialize/dialect/postgres-serializer.ts +34 -4
  306. package/src/query/serialize/dialect/sqlite-serializer.test.ts +51 -1
  307. package/src/query/serialize/dialect/sqlite-serializer.ts +92 -9
  308. package/src/query/serialize/sql-serializer.ts +4 -4
  309. package/src/query/simple-query-interface.ts +5 -0
  310. package/src/query/unit-of-work/execute-unit-of-work.test.ts +1512 -1458
  311. package/src/query/unit-of-work/execute-unit-of-work.ts +1708 -596
  312. package/src/query/unit-of-work/tx-builder.test.ts +1041 -0
  313. package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +32 -32
  314. package/src/query/unit-of-work/unit-of-work-types.test.ts +1 -1
  315. package/src/query/unit-of-work/unit-of-work.test.ts +231 -36
  316. package/src/query/unit-of-work/unit-of-work.ts +229 -31
  317. package/src/query/value-decoding.test.ts +13 -2
  318. package/src/query/value-decoding.ts +17 -4
  319. package/src/query/value-encoding.test.ts +85 -2
  320. package/src/query/value-encoding.ts +56 -6
  321. package/src/schema/create.test.ts +129 -42
  322. package/src/schema/create.ts +187 -47
  323. package/src/schema/generate-id.test.ts +57 -0
  324. package/src/schema/generate-id.ts +38 -0
  325. package/src/schema/serialize.test.ts +14 -2
  326. package/src/schema/type-conversion/create-sql-type-mapper.ts +7 -2
  327. package/src/schema/type-conversion/dialect/sqlite.ts +18 -0
  328. package/src/schema/type-conversion/type-mapping.test.ts +25 -1
  329. package/src/schema/validator.test.ts +197 -0
  330. package/src/schema/validator.ts +231 -0
  331. package/src/{adapters/drizzle/generate.test.ts → schema-output/drizzle.test.ts} +179 -129
  332. package/src/{adapters/drizzle/generate.ts → schema-output/drizzle.ts} +143 -93
  333. package/src/schema-output/prisma.test.ts +536 -0
  334. package/src/schema-output/prisma.ts +573 -0
  335. package/src/util/default-database-adapter.ts +106 -0
  336. package/src/with-database.ts +22 -3
  337. package/tsdown.config.ts +6 -4
  338. package/dist/adapters/drizzle/drizzle-adapter.d.ts +0 -20
  339. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +0 -1
  340. package/dist/adapters/drizzle/drizzle-adapter.js +0 -27
  341. package/dist/adapters/drizzle/drizzle-adapter.js.map +0 -1
  342. package/dist/adapters/drizzle/generate.d.ts +0 -30
  343. package/dist/adapters/drizzle/generate.d.ts.map +0 -1
  344. package/dist/adapters/drizzle/generate.js.map +0 -1
  345. package/dist/adapters/kysely/kysely-adapter.d.ts +0 -19
  346. package/dist/adapters/kysely/kysely-adapter.d.ts.map +0 -1
  347. package/dist/adapters/kysely/kysely-adapter.js +0 -17
  348. package/dist/adapters/kysely/kysely-adapter.js.map +0 -1
  349. package/dist/adapters/shared/table-name-mapper.d.ts +0 -12
  350. package/dist/adapters/shared/table-name-mapper.d.ts.map +0 -1
  351. package/dist/adapters/shared/table-name-mapper.js +0 -43
  352. package/dist/adapters/shared/table-name-mapper.js.map +0 -1
  353. package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js.map +0 -1
  354. package/dist/schema-generator/schema-generator.d.ts +0 -15
  355. package/dist/schema-generator/schema-generator.d.ts.map +0 -1
  356. package/src/adapters/drizzle/drizzle-adapter.ts +0 -39
  357. package/src/adapters/kysely/kysely-adapter.ts +0 -27
  358. package/src/adapters/shared/table-name-mapper.ts +0 -50
  359. package/src/schema-generator/schema-generator.ts +0 -12
  360. package/src/shared/config.ts +0 -10
  361. package/src/shared/connection-pool.ts +0 -24
  362. package/src/shared/prisma.ts +0 -45
@@ -1 +1 @@
1
- {"version":3,"file":"auto-from-schema.js","names":["migrationOperations: MigrationOperation[]","columns: ColumnInfo[]"],"sources":["../../src/migration-engine/auto-from-schema.ts"],"sourcesContent":["import { type AnySchema } from \"../schema/create\";\nimport type { MigrationOperation, ColumnInfo } from \"./shared\";\n\n/**\n * Generate migration operations from a schema's operation history\n *\n * The schema version number represents the cumulative number of operations applied.\n * This function takes operations from the schema between fromVersion and toVersion,\n * and converts them into migration operations.\n *\n * @param targetSchema - The schema containing the operations history\n * @param fromVersion - The current database version (e.g., 0)\n * @param toVersion - The target version to migrate to (e.g., 5)\n * @param options - Migration generation options\n * @returns Array of migration operations to apply\n *\n * @example\n * ```ts\n * const mySchema = schema(s => s\n * .addTable(\"users\", t => t.addColumn(\"id\", idColumn())) // version 1\n * .addTable(\"posts\", t => t.addColumn(\"id\", idColumn())) // version 2\n * );\n *\n * // Generate operations from version 0 to 1 (only creates users table)\n * const operations = generateMigrationFromSchema(mySchema, 0, 1);\n * ```\n */\nexport function generateMigrationFromSchema(\n targetSchema: AnySchema,\n fromVersion: number,\n toVersion: number,\n): MigrationOperation[] {\n if (fromVersion < 0) {\n throw new Error(`fromVersion cannot be negative: ${fromVersion}`);\n }\n\n if (fromVersion > targetSchema.version) {\n throw new Error(\n `fromVersion (${fromVersion}) exceeds schema version (${targetSchema.version})`,\n );\n }\n\n if (toVersion > targetSchema.version) {\n throw new Error(`toVersion (${toVersion}) exceeds schema version (${targetSchema.version})`);\n }\n\n if (toVersion < fromVersion) {\n throw new Error(\n `Cannot migrate backwards: toVersion (${toVersion}) < fromVersion (${fromVersion})`,\n );\n }\n\n // Get operations between fromVersion and toVersion\n // Operations are 1-indexed (operation 0 is version 0→1)\n const relevantOperations = targetSchema.operations.slice(fromVersion, toVersion);\n\n // Convert schema operations to migration operations\n const migrationOperations: MigrationOperation[] = [];\n\n for (const op of relevantOperations) {\n if (op.type === \"add-table\") {\n // Collect columns for create-table operation\n const columns: ColumnInfo[] = [];\n\n for (const subOp of op.operations) {\n if (subOp.type === \"add-column\") {\n const col = subOp.column;\n columns.push({\n name: subOp.columnName,\n type: col.type,\n isNullable: col.isNullable,\n role: col.role,\n default: col.default\n ? \"value\" in col.default\n ? { value: col.default.value }\n : \"dbSpecial\" in col.default\n ? { dbSpecial: col.default.dbSpecial }\n : \"runtime\" in col.default && typeof col.default.runtime === \"string\"\n ? { runtime: col.default.runtime }\n : undefined\n : undefined,\n });\n }\n }\n\n migrationOperations.push({\n type: \"create-table\",\n name: op.tableName,\n columns,\n });\n\n // Add indexes and foreign keys as separate operations\n for (const subOp of op.operations) {\n if (subOp.type === \"add-index\") {\n migrationOperations.push({\n type: \"add-index\",\n table: op.tableName,\n name: subOp.name,\n columns: subOp.columns,\n unique: subOp.unique,\n });\n } else if (subOp.type === \"add-foreign-key\") {\n migrationOperations.push({\n type: \"add-foreign-key\",\n table: op.tableName,\n value: {\n name: subOp.name,\n columns: subOp.columns,\n referencedTable: subOp.referencedTable,\n referencedColumns: subOp.referencedColumns,\n },\n });\n }\n }\n } else if (op.type === \"alter-table\") {\n const columnOps = op.operations.filter((o) => o.type === \"add-column\");\n\n if (columnOps.length > 0) {\n migrationOperations.push({\n type: \"alter-table\",\n name: op.tableName,\n value: columnOps.map((o) => {\n const col = o.column;\n return {\n type: \"create-column\" as const,\n value: {\n name: o.columnName,\n type: col.type,\n isNullable: col.isNullable,\n role: col.role,\n default: col.default\n ? \"value\" in col.default\n ? { value: col.default.value }\n : \"dbSpecial\" in col.default\n ? { dbSpecial: col.default.dbSpecial }\n : \"runtime\" in col.default && typeof col.default.runtime === \"string\"\n ? { runtime: col.default.runtime }\n : undefined\n : undefined,\n },\n };\n }),\n });\n }\n\n // Add indexes as separate operations\n for (const subOp of op.operations) {\n if (subOp.type === \"add-index\") {\n migrationOperations.push({\n type: \"add-index\",\n table: op.tableName,\n name: subOp.name,\n columns: subOp.columns,\n unique: subOp.unique,\n });\n }\n }\n } else if (op.type === \"add-reference\") {\n migrationOperations.push({\n type: \"add-foreign-key\",\n table: op.tableName,\n value: {\n name: `${op.tableName}_${op.config.to.table}_${op.referenceName}_fk`,\n columns: [op.config.from.column],\n referencedTable: op.config.to.table,\n referencedColumns: [op.config.to.column],\n },\n });\n }\n }\n\n return migrationOperations;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"auto-from-schema.js","names":["migrationOperations: MigrationOperation[]","columns: ColumnInfo[]"],"sources":["../../src/migration-engine/auto-from-schema.ts"],"sourcesContent":["import { type AnySchema } from \"../schema/create\";\nimport type { MigrationOperation, ColumnInfo } from \"./shared\";\n\n/**\n * Generate migration operations from a schema's operation history\n *\n * The schema version number represents the cumulative number of operations applied.\n * This function takes operations from the schema between fromVersion and toVersion,\n * and converts them into migration operations.\n *\n * @param targetSchema - The schema containing the operations history\n * @param fromVersion - The current database version (e.g., 0)\n * @param toVersion - The target version to migrate to (e.g., 5)\n * @param options - Migration generation options\n * @returns Array of migration operations to apply\n *\n * @example\n * ```ts\n * const mySchema = schema(\"my\", s => s\n * .addTable(\"users\", t => t.addColumn(\"id\", idColumn())) // version 1\n * .addTable(\"posts\", t => t.addColumn(\"id\", idColumn())) // version 2\n * );\n *\n * // Generate operations from version 0 to 1 (only creates users table)\n * const operations = generateMigrationFromSchema(mySchema, 0, 1);\n * ```\n */\nexport function generateMigrationFromSchema(\n targetSchema: AnySchema,\n fromVersion: number,\n toVersion: number,\n): MigrationOperation[] {\n if (fromVersion < 0) {\n throw new Error(`fromVersion cannot be negative: ${fromVersion}`);\n }\n\n if (fromVersion > targetSchema.version) {\n throw new Error(\n `fromVersion (${fromVersion}) exceeds schema version (${targetSchema.version})`,\n );\n }\n\n if (toVersion > targetSchema.version) {\n throw new Error(`toVersion (${toVersion}) exceeds schema version (${targetSchema.version})`);\n }\n\n if (toVersion < fromVersion) {\n throw new Error(\n `Cannot migrate backwards: toVersion (${toVersion}) < fromVersion (${fromVersion})`,\n );\n }\n\n // Get operations between fromVersion and toVersion\n // Operations are 1-indexed (operation 0 is version 0→1)\n const relevantOperations = targetSchema.operations.slice(fromVersion, toVersion);\n\n // Convert schema operations to migration operations\n const migrationOperations: MigrationOperation[] = [];\n\n for (const op of relevantOperations) {\n if (op.type === \"add-table\") {\n // Collect columns for create-table operation\n const columns: ColumnInfo[] = [];\n\n for (const subOp of op.operations) {\n if (subOp.type === \"add-column\") {\n const col = subOp.column;\n columns.push({\n name: subOp.columnName,\n type: col.type,\n isNullable: col.isNullable,\n role: col.role,\n default: col.default\n ? \"value\" in col.default\n ? { value: col.default.value }\n : \"dbSpecial\" in col.default\n ? { dbSpecial: col.default.dbSpecial }\n : \"runtime\" in col.default && typeof col.default.runtime === \"string\"\n ? { runtime: col.default.runtime }\n : undefined\n : undefined,\n });\n }\n }\n\n migrationOperations.push({\n type: \"create-table\",\n name: op.tableName,\n columns,\n });\n\n // Add indexes and foreign keys as separate operations\n for (const subOp of op.operations) {\n if (subOp.type === \"add-index\") {\n migrationOperations.push({\n type: \"add-index\",\n table: op.tableName,\n name: subOp.name,\n columns: subOp.columns,\n unique: subOp.unique,\n });\n } else if (subOp.type === \"add-foreign-key\") {\n migrationOperations.push({\n type: \"add-foreign-key\",\n table: op.tableName,\n value: {\n name: subOp.name,\n columns: subOp.columns,\n referencedTable: subOp.referencedTable,\n referencedColumns: subOp.referencedColumns,\n },\n });\n }\n }\n } else if (op.type === \"alter-table\") {\n const columnOps = op.operations.filter((o) => o.type === \"add-column\");\n\n if (columnOps.length > 0) {\n migrationOperations.push({\n type: \"alter-table\",\n name: op.tableName,\n value: columnOps.map((o) => {\n const col = o.column;\n return {\n type: \"create-column\" as const,\n value: {\n name: o.columnName,\n type: col.type,\n isNullable: col.isNullable,\n role: col.role,\n default: col.default\n ? \"value\" in col.default\n ? { value: col.default.value }\n : \"dbSpecial\" in col.default\n ? { dbSpecial: col.default.dbSpecial }\n : \"runtime\" in col.default && typeof col.default.runtime === \"string\"\n ? { runtime: col.default.runtime }\n : undefined\n : undefined,\n },\n };\n }),\n });\n }\n\n // Add indexes as separate operations\n for (const subOp of op.operations) {\n if (subOp.type === \"add-index\") {\n migrationOperations.push({\n type: \"add-index\",\n table: op.tableName,\n name: subOp.name,\n columns: subOp.columns,\n unique: subOp.unique,\n });\n }\n }\n } else if (op.type === \"add-reference\") {\n if (!op.referenceName || op.referenceName.trim().length === 0) {\n throw new Error(`referenceName is required for add-reference on ${op.tableName}`);\n }\n migrationOperations.push({\n type: \"add-foreign-key\",\n table: op.tableName,\n value: {\n name: op.referenceName,\n columns: [op.config.from.column],\n referencedTable: op.config.to.table,\n referencedColumns: [op.config.to.column],\n },\n });\n }\n }\n\n return migrationOperations;\n}\n"],"mappings":"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"}
@@ -5,26 +5,32 @@ import { FragnoDatabase } from "../mod.js";
5
5
  interface GenerationEngineResult {
6
6
  schema: string;
7
7
  path: string;
8
- namespace: string;
8
+ namespace: string | null;
9
+ }
10
+ type SchemaOutputFormat = "sql" | "drizzle" | "prisma";
11
+ interface GenerateSchemaOptions {
12
+ format?: SchemaOutputFormat;
13
+ path?: string;
14
+ toVersion?: number;
15
+ fromVersion?: number;
9
16
  }
10
17
  interface GenerationInternalResult {
11
18
  schema: string;
12
19
  path: string;
13
- namespace: string;
20
+ namespace: string | null;
21
+ namespaceKey: string;
22
+ schemaName: string;
23
+ isSettings: boolean;
14
24
  fromVersion: number;
15
25
  toVersion: number;
16
26
  }
17
27
  interface ExecuteMigrationResult {
18
- namespace: string;
28
+ namespace: string | null;
19
29
  didMigrate: boolean;
20
30
  fromVersion: number;
21
31
  toVersion: number;
22
32
  }
23
- declare function generateMigrationsOrSchema<const TDatabases extends FragnoDatabase<AnySchema, any>[]>(databases: TDatabases, options?: {
24
- path?: string;
25
- toVersion?: number;
26
- fromVersion?: number;
27
- }): Promise<GenerationEngineResult[]>;
33
+ declare function generateSchemaArtifacts<const TDatabases extends FragnoDatabase<AnySchema, any>[]>(databases: TDatabases, options?: GenerateSchemaOptions): Promise<GenerationEngineResult[]>;
28
34
  /**
29
35
  * Execute migrations for all fragments in the correct order.
30
36
  * Migrates settings table first, then fragments alphabetically.
@@ -36,7 +42,7 @@ declare function executeMigrations<const TDatabases extends FragnoDatabase<AnySc
36
42
  /**
37
43
  * Post-processes migration files to add ordering and standardize naming.
38
44
  *
39
- * Sorts files with settings namespace first, then alphabetically by namespace,
45
+ * Sorts files with settings namespace first, then alphabetically by namespace key,
40
46
  * and assigns ordering numbers. Transforms filenames to format:
41
47
  * `<date>_<n>_f<from>_t<to>_<namespace>.sql`
42
48
  *
@@ -45,5 +51,5 @@ declare function executeMigrations<const TDatabases extends FragnoDatabase<AnySc
45
51
  */
46
52
  declare function postProcessMigrationFilenames(files: GenerationInternalResult[]): GenerationEngineResult[];
47
53
  //#endregion
48
- export { ExecuteMigrationResult, GenerationEngineResult, GenerationInternalResult, executeMigrations, generateMigrationsOrSchema, postProcessMigrationFilenames };
54
+ export { ExecuteMigrationResult, GenerateSchemaOptions, GenerationEngineResult, GenerationInternalResult, SchemaOutputFormat, executeMigrations, generateSchemaArtifacts, postProcessMigrationFilenames };
49
55
  //# sourceMappingURL=generation-engine.d.ts.map
@@ -1 +1 @@
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
+ {"version":3,"file":"generation-engine.d.ts","names":[],"sources":["../../src/migration-engine/generation-engine.ts"],"sourcesContent":[],"mappings":";;;;UAaiB,sBAAA;;EAAA,IAAA,EAAA,MAAA;EAML,SAAA,EAAA,MAAA,GAAA,IAAkB;AAE9B;AAOiB,KATL,kBAAA,GAS6B,KAAA,GAAA,SAAA,GAAA,QAAA;AAWxB,UAlBA,qBAAA,CAkBsB;EAajB,MAAA,CAAA,EA9BX,kBA8BkC;EAEH,IAAA,CAAA,EAAA,MAAA;EAAf,SAAA,CAAA,EAAA,MAAA;EACd,WAAA,CAAA,EAAA,MAAA;;AAAsD,UA3BlD,wBAAA,CA2BkD;EAAR,MAAA,EAAA,MAAA;EAAO,IAAA,EAAA,MAAA;EA4J5C,SAAA,EAAA,MAAA,GAAiB,IAAA;EAAyC,YAAA,EAAA,MAAA;EAAf,UAAA,EAAA,MAAA;EACpD,UAAA,EAAA,OAAA;EACF,WAAA,EAAA,MAAA;EAAR,SAAA,EAAA,MAAA;;AAwJa,UAtUC,sBAAA,CAsU4B;;;;;;iBAzTvB,iDAEK,eAAe,8BAC7B,sBAAsB,wBAAwB,QAAQ;;;;;;;;iBA4J7C,2CAA2C,eAAe,yBACnE,aACV,QAAQ;;;;;;;;;;;iBAwJK,6BAAA,QACP,6BACN"}
@@ -1,32 +1,53 @@
1
1
  import { instantiate } from "../packages/fragno/dist/api/fragment-instantiator.js";
2
- import { SETTINGS_NAMESPACE, getSchemaVersionFromDatabase, internalFragmentDef, internalSchema } from "../fragments/internal-fragment.js";
3
2
  import { fragnoDatabaseAdapterNameFakeSymbol, fragnoDatabaseAdapterVersionFakeSymbol } from "../adapters/adapters.js";
3
+ import { SETTINGS_TABLE_NAME, internalSchema } from "../fragments/internal-fragment.schema.js";
4
+ import { supportedDatabases } from "../adapters/generic-sql/driver-config.js";
5
+ import { getSchemaVersionFromDatabase, internalFragmentDef } from "../fragments/internal-fragment.js";
6
+ import { generateDrizzleSchema } from "../schema-output/drizzle.js";
7
+ import { generatePrismaSchema } from "../schema-output/prisma.js";
4
8
 
5
9
  //#region src/migration-engine/generation-engine.ts
6
- async function generateMigrationsOrSchema(databases, options) {
10
+ const DEFAULT_DRIZZLE_PATH = "fragno-schema.ts";
11
+ const DEFAULT_PRISMA_PATH = "fragno.prisma";
12
+ const isSupportedDatabase = (value) => supportedDatabases.includes(value);
13
+ async function generateSchemaArtifacts(databases, options) {
7
14
  if (databases.length === 0) throw new Error("No databases provided for schema generation");
8
15
  const firstDb = databases[0];
9
16
  const adapter = firstDb.adapter;
10
- if (adapter.createSchemaGenerator) {
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.");
17
+ const format = options?.format ?? "sql";
18
+ if (format !== "sql") {
19
+ if (options?.toVersion !== void 0 || options?.fromVersion !== void 0) throw new Error("--from and --to are only supported when generating SQL migrations.");
20
+ const databaseType = adapter.adapterMetadata?.databaseType;
21
+ if (!databaseType || !isSupportedDatabase(databaseType)) throw new Error("Adapter does not expose databaseType metadata required for schema output generation.");
12
22
  const fragmentsMap = /* @__PURE__ */ new Map();
13
- fragmentsMap.set("", {
23
+ fragmentsMap.set(internalSchema.name, {
14
24
  schema: internalSchema,
15
- namespace: ""
16
- });
17
- for (const db of databases) if (!fragmentsMap.has(db.namespace)) fragmentsMap.set(db.namespace, {
18
- schema: db.schema,
19
- namespace: db.namespace
25
+ namespace: null
20
26
  });
27
+ for (const db of databases) {
28
+ const namespaceKey = db.namespace ?? db.schema.name;
29
+ if (!fragmentsMap.has(namespaceKey)) fragmentsMap.set(namespaceKey, {
30
+ schema: db.schema,
31
+ namespace: db.namespace
32
+ });
33
+ }
21
34
  const allFragments = Array.from(fragmentsMap.values());
35
+ const defaultPath = format === "drizzle" ? DEFAULT_DRIZZLE_PATH : DEFAULT_PRISMA_PATH;
22
36
  return [{
23
- ...adapter.createSchemaGenerator(allFragments, { path: options?.path }).generateSchema(),
37
+ schema: format === "drizzle" ? generateDrizzleSchema(allFragments, databaseType, { namingStrategy: adapter.namingStrategy }) : generatePrismaSchema(allFragments, databaseType, {
38
+ sqliteStorageMode: adapter.adapterMetadata?.sqliteStorageMode,
39
+ namingStrategy: adapter.namingStrategy
40
+ }),
41
+ path: options?.path ?? defaultPath,
24
42
  namespace: firstDb.namespace
25
43
  }];
26
44
  }
27
- if (!adapter.prepareMigrations) throw new Error("Adapter does not support migration-based schema generation. Ensure your adapter implements prepareMigrations.");
45
+ if (!adapter.prepareMigrations) throw new Error("Adapter does not support migration generation. Ensure your adapter implements prepareMigrations.");
28
46
  if (!await adapter.isConnectionHealthy()) throw new Error("Database connection is not healthy. Please check your database connection and try again.");
29
- const settingsSourceVersion = await getSchemaVersionFromDatabase(instantiate(internalFragmentDef).withConfig({}).withOptions({ databaseAdapter: adapter }).build(), SETTINGS_NAMESPACE);
47
+ const settingsSourceVersion = await getSchemaVersionFromDatabase(instantiate(internalFragmentDef).withConfig({}).withOptions({
48
+ databaseAdapter: adapter,
49
+ databaseNamespace: null
50
+ }).build(), "");
30
51
  const generatedFiles = [];
31
52
  const settingsPreparedMigrations = adapter.prepareMigrations(internalSchema, "");
32
53
  const settingsTargetVersion = internalSchema.version;
@@ -34,13 +55,16 @@ async function generateMigrationsOrSchema(databases, options) {
34
55
  if (settingsSql.trim()) generatedFiles.push({
35
56
  schema: settingsSql,
36
57
  path: "settings-migration.sql",
37
- namespace: "",
58
+ namespace: null,
59
+ namespaceKey: SETTINGS_TABLE_NAME,
60
+ schemaName: internalSchema.name,
61
+ isSettings: true,
38
62
  fromVersion: settingsSourceVersion,
39
63
  toVersion: settingsTargetVersion
40
64
  });
41
65
  for (const db of databases) {
42
66
  const dbAdapter = db.adapter;
43
- if (!dbAdapter.prepareMigrations) throw new Error(`Adapter for ${db.namespace} does not support schema generation. Ensure your adapter implements either createSchemaGenerator or prepareMigrations.`);
67
+ if (!dbAdapter.prepareMigrations) throw new Error(`Adapter for ${db.namespace ?? db.schema.name} does not support migration generation. Ensure your adapter implements prepareMigrations.`);
44
68
  const preparedMigrations = dbAdapter.prepareMigrations(db.schema, db.namespace);
45
69
  const targetVersion = options?.toVersion ?? db.schema.version;
46
70
  const sourceVersion = options?.fromVersion ?? 0;
@@ -49,6 +73,9 @@ async function generateMigrationsOrSchema(databases, options) {
49
73
  schema: sql,
50
74
  path: "schema.sql",
51
75
  namespace: db.namespace,
76
+ namespaceKey: db.namespace ?? db.schema.name,
77
+ schemaName: db.schema.name,
78
+ isSettings: false,
52
79
  fromVersion: sourceVersion,
53
80
  toVersion: targetVersion
54
81
  });
@@ -65,7 +92,7 @@ async function generateMigrationsOrSchema(databases, options) {
65
92
  async function executeMigrations(databases) {
66
93
  if (databases.length === 0) throw new Error("No databases provided for migration");
67
94
  const adapter = databases[0].adapter;
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.");
95
+ if (!adapter.prepareMigrations) throw new Error("Adapter does not support running migrations. The adapter only supports schema generation.\nTry using 'generateSchemaArtifacts' instead to generate schema files.");
69
96
  const firstAdapterName = adapter[fragnoDatabaseAdapterNameFakeSymbol];
70
97
  const firstAdapterVersion = adapter[fragnoDatabaseAdapterVersionFakeSymbol];
71
98
  for (const db of databases) {
@@ -76,32 +103,40 @@ async function executeMigrations(databases) {
76
103
  if (!await adapter.isConnectionHealthy()) throw new Error("Database connection is not healthy. Please check your database connection and try again.");
77
104
  const results = [];
78
105
  const migrationsToExecute = [];
79
- const internalFragment = instantiate(internalFragmentDef).withConfig({}).withOptions({ databaseAdapter: adapter }).build();
80
- const settingsSourceVersion = await getSchemaVersionFromDatabase(internalFragment, SETTINGS_NAMESPACE);
106
+ const internalFragment = instantiate(internalFragmentDef).withConfig({}).withOptions({
107
+ databaseAdapter: adapter,
108
+ databaseNamespace: null
109
+ }).build();
110
+ const settingsSourceVersion = await getSchemaVersionFromDatabase(internalFragment, "");
81
111
  const settingsPreparedMigrations = adapter.prepareMigrations(internalSchema, "");
82
112
  const settingsTargetVersion = internalSchema.version;
83
113
  if (settingsSourceVersion < settingsTargetVersion) {
84
114
  if (settingsPreparedMigrations.compile(settingsSourceVersion, settingsTargetVersion, { updateVersionInMigration: true }).statements.length > 0) migrationsToExecute.push({
85
- namespace: "",
115
+ namespace: null,
116
+ namespaceKey: SETTINGS_TABLE_NAME,
86
117
  fromVersion: settingsSourceVersion,
87
118
  toVersion: settingsTargetVersion,
88
119
  execute: () => settingsPreparedMigrations.execute(settingsSourceVersion, settingsTargetVersion, { updateVersionInMigration: true })
89
120
  });
90
121
  }
91
- const sortedDatabases = [...databases].sort((a, b) => a.namespace.localeCompare(b.namespace));
122
+ const getNamespaceKey = (db) => db.namespace ?? db.schema.name;
123
+ const sortedDatabases = [...databases].sort((a, b) => getNamespaceKey(a).localeCompare(getNamespaceKey(b)));
92
124
  for (const fragnoDb of sortedDatabases) {
125
+ const namespaceKey = getNamespaceKey(fragnoDb);
93
126
  const preparedMigrations = adapter.prepareMigrations(fragnoDb.schema, fragnoDb.namespace);
94
- const currentVersion = await getSchemaVersionFromDatabase(internalFragment, fragnoDb.namespace);
127
+ const currentVersion = await getSchemaVersionFromDatabase(internalFragment, namespaceKey);
95
128
  const targetVersion = fragnoDb.schema.version;
96
129
  if (currentVersion < targetVersion) {
97
130
  if (preparedMigrations.compile(currentVersion, targetVersion, { updateVersionInMigration: true }).statements.length > 0) migrationsToExecute.push({
98
131
  namespace: fragnoDb.namespace,
132
+ namespaceKey,
99
133
  fromVersion: currentVersion,
100
134
  toVersion: targetVersion,
101
135
  execute: () => preparedMigrations.execute(currentVersion, targetVersion, { updateVersionInMigration: true })
102
136
  });
103
137
  }
104
138
  }
139
+ const executedNamespaceKeys = /* @__PURE__ */ new Set();
105
140
  for (const migration of migrationsToExecute) {
106
141
  await migration.execute();
107
142
  results.push({
@@ -110,19 +145,23 @@ async function executeMigrations(databases) {
110
145
  fromVersion: migration.fromVersion,
111
146
  toVersion: migration.toVersion
112
147
  });
148
+ executedNamespaceKeys.add(migration.namespaceKey);
149
+ }
150
+ for (const fragnoDb of databases) {
151
+ const namespaceKey = getNamespaceKey(fragnoDb);
152
+ if (!executedNamespaceKeys.has(namespaceKey)) results.push({
153
+ namespace: fragnoDb.namespace,
154
+ didMigrate: false,
155
+ fromVersion: fragnoDb.schema.version,
156
+ toVersion: fragnoDb.schema.version
157
+ });
113
158
  }
114
- for (const fragnoDb of databases) if (!results.find((r) => r.namespace === fragnoDb.namespace)) results.push({
115
- namespace: fragnoDb.namespace,
116
- didMigrate: false,
117
- fromVersion: fragnoDb.schema.version,
118
- toVersion: fragnoDb.schema.version
119
- });
120
159
  return results;
121
160
  }
122
161
  /**
123
162
  * Post-processes migration files to add ordering and standardize naming.
124
163
  *
125
- * Sorts files with settings namespace first, then alphabetically by namespace,
164
+ * Sorts files with settings namespace first, then alphabetically by namespace key,
126
165
  * and assigns ordering numbers. Transforms filenames to format:
127
166
  * `<date>_<n>_f<from>_t<to>_<namespace>.sql`
128
167
  *
@@ -132,15 +171,15 @@ async function executeMigrations(databases) {
132
171
  function postProcessMigrationFilenames(files) {
133
172
  if (files.length === 0) return [];
134
173
  const sortedFiles = [...files].sort((a, b) => {
135
- if (a.namespace === "") return -1;
136
- if (b.namespace === "") return 1;
137
- return a.namespace.localeCompare(b.namespace);
174
+ if (a.isSettings) return -1;
175
+ if (b.isSettings) return 1;
176
+ return a.namespaceKey.localeCompare(b.namespaceKey);
138
177
  });
139
178
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0].replace(/-/g, "");
140
179
  return sortedFiles.map((file, index) => {
141
180
  const fromVersion = file.fromVersion ?? 0;
142
181
  const toVersion = file.toVersion ?? 0;
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`;
182
+ const newPath = `${date}_${(index + 1).toString().padStart(3, "0")}_f${fromVersion.toString().padStart(3, "0")}_t${toVersion.toString().padStart(3, "0")}_${file.namespaceKey.replace(/[^a-z0-9-]/gi, "_")}.sql`;
144
183
  return {
145
184
  schema: file.schema,
146
185
  path: newPath,
@@ -150,5 +189,5 @@ function postProcessMigrationFilenames(files) {
150
189
  }
151
190
 
152
191
  //#endregion
153
- export { executeMigrations, generateMigrationsOrSchema, postProcessMigrationFilenames };
192
+ export { executeMigrations, generateSchemaArtifacts, postProcessMigrationFilenames };
154
193
  //# sourceMappingURL=generation-engine.js.map
@@ -1 +1 @@
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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"}
1
+ {"version":3,"file":"generation-engine.js","names":["generatedFiles: GenerationInternalResult[]","results: ExecuteMigrationResult[]","migrationsToExecute: Array<{\n namespace: string | null;\n namespaceKey: 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 { generateDrizzleSchema } from \"../schema-output/drizzle\";\nimport { generatePrismaSchema } from \"../schema-output/prisma\";\nimport { internalFragmentDef, getSchemaVersionFromDatabase } from \"../fragments/internal-fragment\";\nimport { internalSchema, SETTINGS_TABLE_NAME } from \"../fragments/internal-fragment.schema\";\nimport { instantiate } from \"@fragno-dev/core\";\nimport { supportedDatabases, type SupportedDatabase } from \"../adapters/generic-sql/driver-config\";\n\nexport interface GenerationEngineResult {\n schema: string;\n path: string;\n namespace: string | null;\n}\n\nexport type SchemaOutputFormat = \"sql\" | \"drizzle\" | \"prisma\";\n\nexport interface GenerateSchemaOptions {\n format?: SchemaOutputFormat;\n path?: string;\n toVersion?: number;\n fromVersion?: number;\n}\n\nexport interface GenerationInternalResult {\n schema: string;\n path: string;\n namespace: string | null;\n namespaceKey: string;\n schemaName: string;\n isSettings: boolean;\n fromVersion: number;\n toVersion: number;\n}\n\nexport interface ExecuteMigrationResult {\n namespace: string | null;\n didMigrate: boolean;\n fromVersion: number;\n toVersion: number;\n}\n\nconst DEFAULT_DRIZZLE_PATH = \"fragno-schema.ts\";\nconst DEFAULT_PRISMA_PATH = \"fragno.prisma\";\n\nconst isSupportedDatabase = (value: string): value is SupportedDatabase =>\n supportedDatabases.includes(value as SupportedDatabase);\n\nexport async function generateSchemaArtifacts<\n // oxlint-disable-next-line no-explicit-any\n const TDatabases extends FragnoDatabase<AnySchema, any>[],\n>(databases: TDatabases, options?: GenerateSchemaOptions): 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 const format = options?.format ?? \"sql\";\n\n if (format !== \"sql\") {\n if (options?.toVersion !== undefined || options?.fromVersion !== undefined) {\n throw new Error(\"--from and --to are only supported when generating SQL migrations.\");\n }\n\n const databaseType = adapter.adapterMetadata?.databaseType;\n if (!databaseType || !isSupportedDatabase(databaseType)) {\n throw new Error(\n \"Adapter does not expose databaseType metadata required for schema output generation.\",\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 | null }>();\n\n // Include internal fragment first with empty namespace (settings table has no prefix)\n fragmentsMap.set(internalSchema.name, {\n schema: internalSchema,\n namespace: null,\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 const namespaceKey = db.namespace ?? db.schema.name;\n if (!fragmentsMap.has(namespaceKey)) {\n fragmentsMap.set(namespaceKey, {\n schema: db.schema,\n namespace: db.namespace,\n });\n }\n }\n\n const allFragments = Array.from(fragmentsMap.values());\n const defaultPath = format === \"drizzle\" ? DEFAULT_DRIZZLE_PATH : DEFAULT_PRISMA_PATH;\n const schema =\n format === \"drizzle\"\n ? generateDrizzleSchema(allFragments, databaseType, {\n namingStrategy: adapter.namingStrategy,\n })\n : generatePrismaSchema(allFragments, databaseType, {\n sqliteStorageMode: adapter.adapterMetadata?.sqliteStorageMode,\n namingStrategy: adapter.namingStrategy,\n });\n\n return [\n {\n schema,\n path: options?.path ?? defaultPath,\n namespace: firstDb.namespace,\n },\n ];\n }\n\n // Otherwise, use migration engine for SQL migration generation.\n if (!adapter.prepareMigrations) {\n throw new Error(\n \"Adapter does not support migration 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, databaseNamespace: null })\n .build();\n\n const settingsSourceVersion = await getSchemaVersionFromDatabase(internalFragment, \"\");\n\n const generatedFiles: GenerationInternalResult[] = [];\n\n // Internal fragment uses empty-string namespace: no table suffix, version key is \".schema_version\"\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: null,\n namespaceKey: SETTINGS_TABLE_NAME,\n schemaName: internalSchema.name,\n isSettings: true,\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 ?? db.schema.name} does not support migration generation. ` +\n `Ensure your adapter implements 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 namespaceKey: db.namespace ?? db.schema.name,\n schemaName: db.schema.name,\n isSettings: false,\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 'generateSchemaArtifacts' 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 | null;\n namespaceKey: 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, databaseNamespace: null })\n .build();\n\n const settingsSourceVersion = await getSchemaVersionFromDatabase(internalFragment, \"\");\n\n // Internal fragment uses empty-string namespace: no table suffix, version key is \".schema_version\"\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: null,\n namespaceKey: SETTINGS_TABLE_NAME,\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 getNamespaceKey = (db: FragnoDatabase<AnySchema>) => db.namespace ?? db.schema.name;\n const sortedDatabases = [...databases].sort((a, b) =>\n getNamespaceKey(a).localeCompare(getNamespaceKey(b)),\n );\n\n for (const fragnoDb of sortedDatabases) {\n const namespaceKey = getNamespaceKey(fragnoDb);\n const preparedMigrations = adapter.prepareMigrations(fragnoDb.schema, fragnoDb.namespace);\n const currentVersion = await getSchemaVersionFromDatabase(internalFragment, namespaceKey);\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 namespaceKey,\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 const executedNamespaceKeys = new Set<string>();\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 executedNamespaceKeys.add(migration.namespaceKey);\n }\n\n // 4. Add skipped migrations (already up-to-date)\n for (const fragnoDb of databases) {\n const namespaceKey = getNamespaceKey(fragnoDb);\n if (!executedNamespaceKeys.has(namespaceKey)) {\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 key,\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 first, then alphabetically by namespace key\n const sortedFiles = [...files].sort((a, b) => {\n if (a.isSettings) {\n return -1;\n }\n if (b.isSettings) {\n return 1;\n }\n return a.namespaceKey.localeCompare(b.namespaceKey);\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 const safeName = file.namespaceKey.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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"shared.js","names":[],"sources":["../../src/migration-engine/shared.ts"],"sourcesContent":["export interface ForeignKeyInfo {\n name: string;\n columns: string[];\n referencedTable: string;\n referencedColumns: string[];\n}\n\n/**\n * Provider-specific metadata that can be attached to operations during preprocessing.\n * This allows providers to add additional context without polluting the core operation types.\n */\nexport interface MigrationOperationMetadata {\n [key: string]: unknown;\n}\n\n/**\n * SQLite-specific metadata for create-table operations.\n * Includes foreign keys that should be created inline with the table.\n */\nexport interface SqliteCreateTableMetadata extends MigrationOperationMetadata {\n inlineForeignKeys?: ForeignKeyInfo[];\n}\n\nexport interface ColumnInfo {\n name: string;\n type:\n | \"string\"\n | \"integer\"\n | \"bigint\"\n | \"decimal\"\n | \"bool\"\n | \"date\"\n | \"timestamp\"\n | \"json\"\n | \"binary\"\n | `varchar(${number})`;\n isNullable: boolean;\n role: \"external-id\" | \"internal-id\" | \"version\" | \"reference\" | \"regular\";\n default?: { value: unknown } | { dbSpecial: \"now\" } | { runtime: \"cuid\" | \"now\" };\n}\n\nexport type MigrationOperation<\n TMeta extends MigrationOperationMetadata = MigrationOperationMetadata,\n> =\n | (TableOperation & { metadata?: TMeta })\n | ({\n // warning: not supported by SQLite\n type: \"add-foreign-key\";\n table: string;\n value: ForeignKeyInfo;\n } & { metadata?: TMeta })\n | ({\n // warning: not supported by SQLite\n type: \"drop-foreign-key\";\n table: string;\n name: string;\n } & { metadata?: TMeta })\n | ({\n type: \"drop-index\";\n table: string;\n name: string;\n } & { metadata?: TMeta })\n | ({\n type: \"add-index\";\n table: string;\n columns: string[];\n name: string;\n unique: boolean;\n } & { metadata?: TMeta })\n | (CustomOperation & { metadata?: TMeta });\n\nexport type CustomOperation = {\n type: \"custom\";\n} & Record<string, unknown>;\n\nexport type TableOperation =\n | {\n type: \"create-table\";\n name: string;\n columns: ColumnInfo[];\n }\n | {\n type: \"drop-table\";\n name: string;\n }\n | {\n type: \"alter-table\";\n name: string;\n value: ColumnOperation[];\n }\n | {\n type: \"rename-table\";\n from: string;\n to: string;\n };\n\nexport type ColumnOperation =\n | {\n type: \"rename-column\";\n from: string;\n to: string;\n }\n | {\n type: \"drop-column\";\n name: string;\n }\n | {\n /**\n * Note: unique constraints are not created, please use dedicated operations like `add-index` instead\n */\n type: \"create-column\";\n value: ColumnInfo;\n }\n | {\n /**\n * warning: Not supported by SQLite\n */\n type: \"update-column\";\n name: string;\n /**\n * For databases like MySQL, it requires the full definition for any modify column statement.\n * Hence, you need to specify the full information of your column here.\n *\n * Then, opt-in for in-detail modification for other databases that supports changing data type/nullable/default separately, such as PostgreSQL.\n *\n * Note: unique constraints are not updated, please use dedicated operations like `add-index` instead\n */\n value: ColumnInfo;\n\n updateNullable: boolean;\n updateDefault: boolean;\n updateDataType: boolean;\n };\n\nexport function isUpdated(op: Extract<ColumnOperation, { type: \"update-column\" }>): boolean {\n return op.updateDataType || op.updateDefault || op.updateNullable;\n}\n"],"mappings":";AAsIA,SAAgB,UAAU,IAAkE;AAC1F,QAAO,GAAG,kBAAkB,GAAG,iBAAiB,GAAG"}
1
+ {"version":3,"file":"shared.js","names":[],"sources":["../../src/migration-engine/shared.ts"],"sourcesContent":["export interface ForeignKeyInfo {\n name: string;\n columns: string[];\n referencedTable: string;\n referencedColumns: string[];\n}\n\n/**\n * Provider-specific metadata that can be attached to operations during preprocessing.\n * This allows providers to add additional context without polluting the core operation types.\n */\nexport interface MigrationOperationMetadata {\n [key: string]: unknown;\n}\n\n/**\n * SQLite-specific metadata for create-table operations.\n * Includes foreign keys that should be created inline with the table.\n */\nexport interface SqliteCreateTableMetadata extends MigrationOperationMetadata {\n inlineForeignKeys?: ForeignKeyInfo[];\n}\n\nexport interface ColumnInfo {\n name: string;\n type:\n | \"string\"\n | \"integer\"\n | \"bigint\"\n | \"decimal\"\n | \"bool\"\n | \"date\"\n | \"timestamp\"\n | \"json\"\n | \"binary\"\n | `varchar(${number})`;\n isNullable: boolean;\n role: \"external-id\" | \"internal-id\" | \"version\" | \"reference\" | \"regular\";\n default?: { value: unknown } | { dbSpecial: \"now\" } | { runtime: \"cuid\" | \"now\" };\n}\n\nexport type MigrationOperation<\n TMeta extends MigrationOperationMetadata = MigrationOperationMetadata,\n> =\n | (TableOperation & { metadata?: TMeta })\n | ({\n // warning: not supported by SQLite\n type: \"add-foreign-key\";\n table: string;\n value: ForeignKeyInfo;\n } & { metadata?: TMeta })\n | ({\n // warning: not supported by SQLite\n type: \"drop-foreign-key\";\n table: string;\n name: string;\n referencedTable: string;\n } & { metadata?: TMeta })\n | ({\n type: \"drop-index\";\n table: string;\n name: string;\n } & { metadata?: TMeta })\n | ({\n type: \"add-index\";\n table: string;\n columns: string[];\n name: string;\n unique: boolean;\n } & { metadata?: TMeta })\n | (CustomOperation & { metadata?: TMeta });\n\nexport type CustomOperation = {\n type: \"custom\";\n} & Record<string, unknown>;\n\nexport type TableOperation =\n | {\n type: \"create-table\";\n name: string;\n columns: ColumnInfo[];\n }\n | {\n type: \"drop-table\";\n name: string;\n }\n | {\n type: \"alter-table\";\n name: string;\n value: ColumnOperation[];\n }\n | {\n type: \"rename-table\";\n from: string;\n to: string;\n };\n\nexport type ColumnOperation =\n | {\n type: \"rename-column\";\n from: string;\n to: string;\n }\n | {\n type: \"drop-column\";\n name: string;\n }\n | {\n /**\n * Note: unique constraints are not created, please use dedicated operations like `add-index` instead\n */\n type: \"create-column\";\n value: ColumnInfo;\n }\n | {\n /**\n * warning: Not supported by SQLite\n */\n type: \"update-column\";\n name: string;\n /**\n * For databases like MySQL, it requires the full definition for any modify column statement.\n * Hence, you need to specify the full information of your column here.\n *\n * Then, opt-in for in-detail modification for other databases that supports changing data type/nullable/default separately, such as PostgreSQL.\n *\n * Note: unique constraints are not updated, please use dedicated operations like `add-index` instead\n */\n value: ColumnInfo;\n\n updateNullable: boolean;\n updateDefault: boolean;\n updateDataType: boolean;\n };\n\nexport function isUpdated(op: Extract<ColumnOperation, { type: \"update-column\" }>): boolean {\n return op.updateDataType || op.updateDefault || op.updateNullable;\n}\n"],"mappings":";AAuIA,SAAgB,UAAU,IAAkE;AAC1F,QAAO,GAAG,kBAAkB,GAAG,iBAAiB,GAAG"}
package/dist/mod.d.ts CHANGED
@@ -1,20 +1,27 @@
1
+ import { DbNow, dbNow } from "./query/db-now.js";
1
2
  import { AnySchema } from "./schema/create.js";
2
3
  import { Cursor, CursorData, CursorResult, decodeCursor } from "./query/cursor.js";
3
4
  import { ExponentialBackoffRetryPolicy, LinearBackoffRetryPolicy, NoRetryPolicy, RetryPolicy } from "./query/unit-of-work/retry-policy.js";
4
- import { ExecuteUnitOfWorkCallbacks, ExecuteUnitOfWorkOptions, ExecuteUnitOfWorkResult, executeUnitOfWork } from "./query/unit-of-work/execute-unit-of-work.js";
5
- import { DatabaseFragmentContext, DatabaseFragmentDefinitionBuilder, DatabaseHandlerContext, FragnoPublicConfigWithDatabase, ImplicitDatabaseDependencies } from "./db-fragment-definition-builder.js";
5
+ import { BuilderTransformContextWithMutate, BuilderTransformContextWithoutMutate, ConcurrencyConflictError, ExtractServiceFinalResults, ExtractServiceRetrieveResults, HandlerBuilderMutateContext, HandlerTxBuilder, ServiceBuilderMutateContext, ServiceTxBuilder, TxResult, createHandlerTxBuilder, createServiceTxBuilder } from "./query/unit-of-work/execute-unit-of-work.js";
6
+ import { DatabaseFragmentContext, DatabaseFragmentDefinitionBuilder, DatabaseHandlerContext, DatabaseServiceContext, FragnoPublicConfigWithDatabase, ImplicitDatabaseDependencies } from "./db-fragment-definition-builder.js";
7
+ import { InMemoryAdapterOptions } from "./adapters/in-memory/options.js";
8
+ import { InMemoryAdapter } from "./adapters/in-memory/in-memory-adapter.js";
9
+ import "./adapters/in-memory/index.js";
10
+ import { withDatabase } from "./with-database.js";
11
+ import { OutboxConfig, OutboxEntry, OutboxMutation, OutboxPayload, OutboxRefMap } from "./outbox/outbox.js";
12
+ import { DurableHooksProcessor, createDurableHooksProcessor } from "./hooks/durable-hooks-processor.js";
13
+ import { internalSchema } from "./fragments/internal-fragment.schema.js";
6
14
  import { InternalFragmentInstance, internalFragmentDef } from "./fragments/internal-fragment.js";
7
- import { HookContext, HookFn, HookPayload, HooksMap, TriggerHookOptions } from "./hooks/hooks.js";
15
+ import { DurableHooksProcessingOptions, HookContext, HookFn, HookPayload, HooksMap, StuckHookProcessingEvent, StuckHookProcessingInfo, StuckHookProcessingTimeoutMinutes, TriggerHookOptions } from "./hooks/hooks.js";
8
16
  import { IUnitOfWork, IUnitOfWorkRestricted, TypedUnitOfWork, UOWCompiler, UOWDecoder, UOWExecutor, UnitOfWork, createUnitOfWork } from "./query/unit-of-work/unit-of-work.js";
9
17
  import { DatabaseAdapter } from "./adapters/adapters.js";
10
- import { withDatabase } from "./with-database.js";
11
18
  import { AnyFragnoInstantiatedFragment, BoundServices, FragnoInstantiatedFragment } from "@fragno-dev/core";
12
19
 
13
20
  //#region src/mod.d.ts
14
21
  declare const fragnoDatabaseFakeSymbol: "$fragno-database";
15
22
  declare const fragnoDatabaseLibraryVersion: "0.1";
16
23
  interface CreateFragnoDatabaseDefinitionOptions<T extends AnySchema> {
17
- namespace: string;
24
+ namespace: string | null;
18
25
  schema: T;
19
26
  }
20
27
  declare function isFragnoDatabase(value: unknown): value is FragnoDatabase<AnySchema>;
@@ -25,16 +32,16 @@ declare function isFragnoDatabase(value: unknown): value is FragnoDatabase<AnySc
25
32
  declare class FragnoDatabase<const T extends AnySchema, TUOWConfig = void> {
26
33
  #private;
27
34
  constructor(options: {
28
- namespace: string;
35
+ namespace: string | null;
29
36
  schema: T;
30
37
  adapter: DatabaseAdapter<TUOWConfig>;
31
38
  });
32
39
  get [fragnoDatabaseFakeSymbol](): typeof fragnoDatabaseFakeSymbol;
33
- get namespace(): string;
40
+ get namespace(): string | null;
34
41
  get schema(): T;
35
42
  get adapter(): DatabaseAdapter<TUOWConfig>;
36
43
  }
37
- type AnyFragnoInstantiatedDatabaseFragment = FragnoInstantiatedFragment<any, ImplicitDatabaseDependencies<AnySchema>, any, any, any, any, FragnoPublicConfigWithDatabase, {
44
+ type AnyFragnoInstantiatedDatabaseFragment<TSchema extends AnySchema = AnySchema> = FragnoInstantiatedFragment<any, ImplicitDatabaseDependencies<TSchema>, any, any, any, any, FragnoPublicConfigWithDatabase, {
38
45
  _fragno_internal: InternalFragmentInstance;
39
46
  } & Record<string, AnyFragnoInstantiatedFragment>>;
40
47
  /**
@@ -59,7 +66,7 @@ type AnyFragnoInstantiatedDatabaseFragment = FragnoInstantiatedFragment<any, Imp
59
66
  * await migrate(fragment);
60
67
  * ```
61
68
  */
62
- declare function migrate(fragment: AnyFragnoInstantiatedDatabaseFragment): Promise<void>;
69
+ declare function migrate<TSchema extends AnySchema>(fragment: AnyFragnoInstantiatedDatabaseFragment<TSchema>): Promise<void>;
63
70
  //#endregion
64
- export { AnyFragnoInstantiatedDatabaseFragment, type BoundServices, CreateFragnoDatabaseDefinitionOptions, Cursor, type CursorData, type CursorResult, type DatabaseAdapter, type DatabaseFragmentContext, DatabaseFragmentDefinitionBuilder, type DatabaseHandlerContext as DatabaseRequestContext, type ExecuteUnitOfWorkCallbacks, type ExecuteUnitOfWorkOptions, type ExecuteUnitOfWorkResult, ExponentialBackoffRetryPolicy, FragnoDatabase, type FragnoPublicConfigWithDatabase, type HookContext, type HookFn, type HookPayload, type HooksMap, type IUnitOfWork, type IUnitOfWorkRestricted, type ImplicitDatabaseDependencies, type InternalFragmentInstance, LinearBackoffRetryPolicy, NoRetryPolicy, type RetryPolicy, type TriggerHookOptions, TypedUnitOfWork, type UOWCompiler, type UOWDecoder, type UOWExecutor, UnitOfWork, createUnitOfWork, decodeCursor, executeUnitOfWork, fragnoDatabaseFakeSymbol, fragnoDatabaseLibraryVersion, internalFragmentDef, isFragnoDatabase, migrate, withDatabase };
71
+ export { AnyFragnoInstantiatedDatabaseFragment, type BoundServices, type BuilderTransformContextWithMutate, type BuilderTransformContextWithoutMutate, ConcurrencyConflictError, CreateFragnoDatabaseDefinitionOptions, Cursor, type CursorData, type CursorResult, type DatabaseAdapter, type DatabaseFragmentContext, DatabaseFragmentDefinitionBuilder, type DatabaseHandlerContext as DatabaseRequestContext, type DatabaseServiceContext, type DbNow, type DurableHooksProcessingOptions, type DurableHooksProcessor, ExponentialBackoffRetryPolicy, type ExtractServiceFinalResults, type ExtractServiceRetrieveResults, FragnoDatabase, type FragnoPublicConfigWithDatabase, type HandlerBuilderMutateContext, HandlerTxBuilder, type HookContext, type HookFn, type HookPayload, type HooksMap, type IUnitOfWork, type IUnitOfWorkRestricted, type ImplicitDatabaseDependencies, InMemoryAdapter, type InMemoryAdapterOptions, type InternalFragmentInstance, LinearBackoffRetryPolicy, NoRetryPolicy, type OutboxConfig, type OutboxEntry, type OutboxMutation, type OutboxPayload, type OutboxRefMap, type RetryPolicy, type ServiceBuilderMutateContext, ServiceTxBuilder, type StuckHookProcessingEvent, type StuckHookProcessingInfo, type StuckHookProcessingTimeoutMinutes, type TriggerHookOptions, type TxResult, TypedUnitOfWork, type UOWCompiler, type UOWDecoder, type UOWExecutor, UnitOfWork, createDurableHooksProcessor, createHandlerTxBuilder, createServiceTxBuilder, createUnitOfWork, dbNow, decodeCursor, fragnoDatabaseFakeSymbol, fragnoDatabaseLibraryVersion, internalFragmentDef, internalSchema, isFragnoDatabase, migrate, withDatabase };
65
72
  //# sourceMappingURL=mod.d.ts.map
package/dist/mod.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.ts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;cAiBa;cACA;UAEI,gDAAgD;;EAHpD,MAAA,EAKH,CALG;AACb;AAEiB,iBAKD,gBAAA,CALC,KAAqC,EAAA,OAAA,CAAA,EAAW,KAAA,IAKN,cAHhD,CAG+D,SAH/D,CAAA;AAGX;AAmBA;;;AAKgF,cALnE,cAKmE,CAAA,gBALpC,SAKoC,EAAA,aAAA,IAAA,CAAA,CAAA;EAAhB,CAAA,OAAA;EAMrB,WAAA,CAAA,OAAA,EAAA;IAApC,SAAA,EAAA,MAAA;IAQK,MAAA,EAdwC,CAcxC;IAIqB,OAAA,EAlB+B,eAkB/B,CAlB+C,UAkB/C,CAAA;EAAhB,CAAA;EAAe,KAZzB,wBAAA,GAYyB,EAAA,OAZW,wBAYX;EAiDpB,IAAA,SAAA,CAAA,CAAA,EAAA,MAAA;EAGmB,IAAA,MAAA,CAAA,CAAA,EAxDnB,CAwDmB;EAA7B,IAAA,OAAA,CAAA,CAAA,EApDe,eAoDf,CApD+B,UAoD/B,CAAA;;KAHU,qCAAA,GAAwC,gCAGlD,6BAA6B,gCAS7B;oBAEoB;IAA6B,eAAe;;;;;;;;;;;;;;;;;;;;;;;iBAyB5C,OAAA,WAAkB,wCAAwC"}
1
+ {"version":3,"file":"mod.d.ts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;;cAuBa;cACA;UAEI,gDAAgD;;UAEvD;;AALG,iBAQG,gBAAA,CARmD,KAAA,EAAA,OAAA,CAAA,EAAA,KAAA,IAQR,cARQ,CAQO,SARP,CAAA;AACnE;AAEA;AAKA;AAmBA;AAA4C,cAA/B,cAA+B,CAAA,gBAAA,SAAA,EAAA,aAAA,IAAA,CAAA,CAAA;EAOhC,CAAA,OAAA;EACiB,WAAA,CAAA,OAAA,EAAA;IAAhB,SAAA,EAAA,MAAA,GAAA,IAAA;IAO8B,MAAA,EAR/B,CAQ+B;IAApC,OAAA,EAPM,eAON,CAPsB,UAOtB,CAAA;EAQK,CAAA;EAIqB,KAZ1B,wBAAA,GAY0B,EAAA,OAZU,wBAYV;EAAhB,IAAA,SAAA,CAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAAe,IAAA,MAAA,CAAA,CAAA,EAJpB,CAIoB;EAiFpB,IAAA,OAAA,CAAA,CAAA,EAjFK,eAiFL,CAjFqB,UAiFgB,CAAA;;AAyCrC,KAzCA,qCAyCA,CAAA,gBAzCsD,SAyCtD,GAzCkE,SAyClE,CAAA,GAxCV,0BAwCU,CAAA,GAAA,EArCR,4BAqCQ,CArCqB,OAqCrB,CAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EA5BR,8BA4BQ,EAAA;EACT,gBAAA,EA3BqB,wBA2BrB;CAAO,GA3B2C,MA2B3C,CAAA,MAAA,EA3B0D,6BA2B1D,CAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;iBAFY,wBAAwB,qBAClC,sCAAsC,WAC/C"}
package/dist/mod.js CHANGED
@@ -1,10 +1,16 @@
1
+ import { ExponentialBackoffRetryPolicy, LinearBackoffRetryPolicy, NoRetryPolicy } from "./query/unit-of-work/retry-policy.js";
2
+ import { ConcurrencyConflictError, HandlerTxBuilder, ServiceTxBuilder, createHandlerTxBuilder, createServiceTxBuilder } from "./query/unit-of-work/execute-unit-of-work.js";
3
+ import { internalSchema } from "./fragments/internal-fragment.schema.js";
1
4
  import { Cursor, decodeCursor } from "./query/cursor.js";
5
+ import { dbNow } from "./query/db-now.js";
2
6
  import { TypedUnitOfWork, UnitOfWork, createUnitOfWork } from "./query/unit-of-work/unit-of-work.js";
3
- import { ExponentialBackoffRetryPolicy, LinearBackoffRetryPolicy, NoRetryPolicy } from "./query/unit-of-work/retry-policy.js";
4
- import { executeUnitOfWork } from "./query/unit-of-work/execute-unit-of-work.js";
7
+ import { resolveDatabaseAdapter } from "./util/default-database-adapter.js";
5
8
  import { DatabaseFragmentDefinitionBuilder } from "./db-fragment-definition-builder.js";
6
9
  import { getSchemaVersionFromDatabase, internalFragmentDef } from "./fragments/internal-fragment.js";
10
+ import { InMemoryAdapter } from "./adapters/in-memory/in-memory-adapter.js";
11
+ import "./adapters/in-memory/index.js";
7
12
  import { withDatabase } from "./with-database.js";
13
+ import { createDurableHooksProcessor } from "./hooks/durable-hooks-processor.js";
8
14
 
9
15
  //#region src/mod.ts
10
16
  const fragnoDatabaseFakeSymbol = "$fragno-database";
@@ -64,18 +70,18 @@ var FragnoDatabase = class {
64
70
  */
65
71
  async function migrate(fragment) {
66
72
  const { options, deps, linkedFragments } = fragment.$internal;
67
- const adapter = options.databaseAdapter;
73
+ const adapter = resolveDatabaseAdapter(options, deps.schema);
68
74
  if (!adapter.prepareMigrations) throw new Error("Database adapter does not support prepareMigrations. Please use an adapter that implements this method.");
69
75
  const schema = deps.schema;
70
- const namespace = deps.namespace;
76
+ const namespace = deps.namespace ?? schema.name;
71
77
  const internalFragment = linkedFragments._fragno_internal;
72
78
  if (!internalFragment) throw new Error("Internal fragment not found. Please ensure the internal fragment is linked.");
73
79
  if (!await adapter.isConnectionHealthy()) throw new Error("Database connection is not healthy. Please check your database connection and try again.");
74
80
  const internalDeps = internalFragment.$internal.deps;
75
- const internalSchema = internalDeps.schema;
76
- const internalNamespace = internalDeps.namespace;
81
+ const internalSchema$1 = internalDeps.schema;
82
+ const internalNamespace = internalDeps.namespace ?? "";
77
83
  const internalCurrentVersion = await getSchemaVersionFromDatabase(internalFragment, internalNamespace);
78
- if (internalCurrentVersion < internalSchema.version) await adapter.prepareMigrations(internalSchema, internalNamespace).execute(internalCurrentVersion, internalSchema.version);
84
+ if (internalCurrentVersion < internalSchema$1.version) await adapter.prepareMigrations(internalSchema$1, internalNamespace).execute(internalCurrentVersion, internalSchema$1.version);
79
85
  const currentVersion = await getSchemaVersionFromDatabase(internalFragment, namespace);
80
86
  const targetVersion = schema.version;
81
87
  if (currentVersion === targetVersion) return;
@@ -84,5 +90,5 @@ async function migrate(fragment) {
84
90
  }
85
91
 
86
92
  //#endregion
87
- export { Cursor, DatabaseFragmentDefinitionBuilder, ExponentialBackoffRetryPolicy, FragnoDatabase, LinearBackoffRetryPolicy, NoRetryPolicy, TypedUnitOfWork, UnitOfWork, createUnitOfWork, decodeCursor, executeUnitOfWork, fragnoDatabaseFakeSymbol, fragnoDatabaseLibraryVersion, internalFragmentDef, isFragnoDatabase, migrate, withDatabase };
93
+ export { ConcurrencyConflictError, Cursor, DatabaseFragmentDefinitionBuilder, ExponentialBackoffRetryPolicy, FragnoDatabase, HandlerTxBuilder, InMemoryAdapter, LinearBackoffRetryPolicy, NoRetryPolicy, ServiceTxBuilder, TypedUnitOfWork, UnitOfWork, createDurableHooksProcessor, createHandlerTxBuilder, createServiceTxBuilder, createUnitOfWork, dbNow, decodeCursor, fragnoDatabaseFakeSymbol, fragnoDatabaseLibraryVersion, internalFragmentDef, internalSchema, isFragnoDatabase, migrate, withDatabase };
88
94
  //# sourceMappingURL=mod.js.map
package/dist/mod.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mod.js","names":["#namespace","#schema","#adapter"],"sources":["../src/mod.ts"],"sourcesContent":["import type { DatabaseAdapter } from \"./adapters/adapters\";\nimport type { AnySchema } from \"./schema/create\";\nimport type { CursorResult } from \"./query/cursor\";\nimport { Cursor } from \"./query/cursor\";\nimport type { FragnoInstantiatedFragment, AnyFragnoInstantiatedFragment } from \"@fragno-dev/core\";\nimport type {\n FragnoPublicConfigWithDatabase,\n ImplicitDatabaseDependencies,\n} from \"./db-fragment-definition-builder\";\nimport {\n getSchemaVersionFromDatabase,\n type InternalFragmentInstance,\n} from \"./fragments/internal-fragment\";\n\nexport type { DatabaseAdapter, CursorResult };\nexport { Cursor };\n\nexport const fragnoDatabaseFakeSymbol = \"$fragno-database\" as const;\nexport const fragnoDatabaseLibraryVersion = \"0.1\" as const;\n\nexport interface CreateFragnoDatabaseDefinitionOptions<T extends AnySchema> {\n namespace: string;\n schema: T;\n}\n\nexport function isFragnoDatabase(value: unknown): value is FragnoDatabase<AnySchema> {\n if (value instanceof FragnoDatabase) {\n return true;\n }\n\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n\n return (\n fragnoDatabaseFakeSymbol in value &&\n value[fragnoDatabaseFakeSymbol] === fragnoDatabaseFakeSymbol\n );\n}\n\n/**\n * A Fragno database instance with a bound adapter.\n * Created from a FragnoDatabaseDefinition by calling .create(adapter).\n */\nexport class FragnoDatabase<const T extends AnySchema, TUOWConfig = void> {\n #namespace: string;\n #schema: T;\n #adapter: DatabaseAdapter<TUOWConfig>;\n\n constructor(options: { namespace: string; schema: T; adapter: DatabaseAdapter<TUOWConfig> }) {\n this.#namespace = options.namespace;\n this.#schema = options.schema;\n this.#adapter = options.adapter;\n }\n\n get [fragnoDatabaseFakeSymbol](): typeof fragnoDatabaseFakeSymbol {\n return fragnoDatabaseFakeSymbol;\n }\n\n get namespace() {\n return this.#namespace;\n }\n\n get schema() {\n return this.#schema;\n }\n\n get adapter(): DatabaseAdapter<TUOWConfig> {\n return this.#adapter;\n }\n}\n\nexport {\n DatabaseFragmentDefinitionBuilder,\n type FragnoPublicConfigWithDatabase,\n type DatabaseFragmentContext,\n type DatabaseHandlerContext as DatabaseRequestContext,\n type ImplicitDatabaseDependencies,\n} from \"./db-fragment-definition-builder\";\n\nexport { withDatabase } from \"./with-database\";\n\nexport { decodeCursor, type CursorData } from \"./query/cursor\";\n\nexport {\n createUnitOfWork,\n UnitOfWork,\n TypedUnitOfWork,\n type IUnitOfWork,\n type IUnitOfWorkRestricted,\n type UOWCompiler,\n type UOWExecutor,\n type UOWDecoder,\n} from \"./query/unit-of-work/unit-of-work\";\n\nexport {\n type RetryPolicy,\n NoRetryPolicy,\n ExponentialBackoffRetryPolicy,\n LinearBackoffRetryPolicy,\n} from \"./query/unit-of-work/retry-policy\";\n\nexport {\n executeUnitOfWork,\n type ExecuteUnitOfWorkResult,\n type ExecuteUnitOfWorkCallbacks,\n type ExecuteUnitOfWorkOptions,\n} from \"./query/unit-of-work/execute-unit-of-work\";\n\nexport type { BoundServices } from \"@fragno-dev/core\";\n\nexport { internalFragmentDef } from \"./fragments/internal-fragment\";\nexport type { InternalFragmentInstance } from \"./fragments/internal-fragment\";\n\nexport type { HookContext, HooksMap, HookFn, HookPayload, TriggerHookOptions } from \"./hooks/hooks\";\n\nexport type AnyFragnoInstantiatedDatabaseFragment = FragnoInstantiatedFragment<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n ImplicitDatabaseDependencies<AnySchema>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n FragnoPublicConfigWithDatabase,\n // Ensure the fragment has the internal fragment linked\n { _fragno_internal: InternalFragmentInstance } & Record<string, AnyFragnoInstantiatedFragment>\n>;\n\n/**\n * Helper function to run migrations for a database fragment.\n * Extracts the database adapter, schema, and namespace from the fragment and runs migrations.\n * This function:\n * 1. Ensures the internal settings fragment is migrated first\n * 2. Retrieves the current database version from the internal fragment\n * 3. Runs migration from current version to target version\n *\n * @param fragment - The instantiated fragment to run migrations for\n * @throws Error if the fragment doesn't have database support or the adapter doesn't support migrations\n *\n * @example\n * ```typescript\n * const fragment = instantiate(myFragmentDef)\n * .withConfig({})\n * .withRoutes([])\n * .withOptions({ databaseAdapter: myAdapter })\n * .build();\n *\n * await migrate(fragment);\n * ```\n */\nexport async function migrate(fragment: AnyFragnoInstantiatedDatabaseFragment): Promise<void> {\n const { options, deps, linkedFragments } = fragment.$internal;\n const adapter = options.databaseAdapter;\n\n // Check if adapter supports prepareMigrations\n if (!adapter.prepareMigrations) {\n throw new Error(\n \"Database adapter does not support prepareMigrations. Please use an adapter that implements this method.\",\n );\n }\n\n const schema = deps.schema;\n const namespace = deps.namespace;\n\n // Step 1: Ensure the internal fragment (settings table) is migrated first\n const internalFragment = linkedFragments._fragno_internal;\n\n if (!internalFragment) {\n throw new Error(\"Internal fragment not found. Please ensure the internal fragment is linked.\");\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 internalDeps = internalFragment.$internal.deps;\n const internalSchema = internalDeps.schema;\n const internalNamespace = internalDeps.namespace;\n\n const internalCurrentVersion = await getSchemaVersionFromDatabase(\n internalFragment,\n internalNamespace,\n );\n\n // Migrate internal fragment if needed\n if (internalCurrentVersion < internalSchema.version) {\n const internalMigrations = adapter.prepareMigrations(internalSchema, internalNamespace);\n await internalMigrations.execute(internalCurrentVersion, internalSchema.version);\n }\n\n // Step 2: Get current database version for this fragment's namespace\n const currentVersion = await getSchemaVersionFromDatabase(internalFragment, namespace);\n\n // Step 3: Run the migration from current version to target version\n const targetVersion = schema.version;\n\n if (currentVersion === targetVersion) {\n return;\n }\n\n if (currentVersion > targetVersion) {\n throw new Error(\n `Cannot migrate backwards: current version (${currentVersion}) > target version (${targetVersion})`,\n );\n }\n\n const migrations = adapter.prepareMigrations(schema, namespace);\n await migrations.execute(currentVersion, targetVersion);\n}\n"],"mappings":";;;;;;;;;AAiBA,MAAa,2BAA2B;AACxC,MAAa,+BAA+B;AAO5C,SAAgB,iBAAiB,OAAoD;AACnF,KAAI,iBAAiB,eACnB,QAAO;AAGT,KAAI,OAAO,UAAU,YAAY,UAAU,KACzC,QAAO;AAGT,QACE,4BAA4B,SAC5B,MAAM,8BAA8B;;;;;;AAQxC,IAAa,iBAAb,MAA0E;CACxE;CACA;CACA;CAEA,YAAY,SAAiF;AAC3F,QAAKA,YAAa,QAAQ;AAC1B,QAAKC,SAAU,QAAQ;AACvB,QAAKC,UAAW,QAAQ;;CAG1B,KAAK,4BAA6D;AAChE,SAAO;;CAGT,IAAI,YAAY;AACd,SAAO,MAAKF;;CAGd,IAAI,SAAS;AACX,SAAO,MAAKC;;CAGd,IAAI,UAAuC;AACzC,SAAO,MAAKC;;;;;;;;;;;;;;;;;;;;;;;;;AAuFhB,eAAsB,QAAQ,UAAgE;CAC5F,MAAM,EAAE,SAAS,MAAM,oBAAoB,SAAS;CACpD,MAAM,UAAU,QAAQ;AAGxB,KAAI,CAAC,QAAQ,kBACX,OAAM,IAAI,MACR,0GACD;CAGH,MAAM,SAAS,KAAK;CACpB,MAAM,YAAY,KAAK;CAGvB,MAAM,mBAAmB,gBAAgB;AAEzC,KAAI,CAAC,iBACH,OAAM,IAAI,MAAM,8EAA8E;AAGhG,KAAI,CAAE,MAAM,QAAQ,qBAAqB,CACvC,OAAM,IAAI,MACR,2FACD;CAGH,MAAM,eAAe,iBAAiB,UAAU;CAChD,MAAM,iBAAiB,aAAa;CACpC,MAAM,oBAAoB,aAAa;CAEvC,MAAM,yBAAyB,MAAM,6BACnC,kBACA,kBACD;AAGD,KAAI,yBAAyB,eAAe,QAE1C,OAD2B,QAAQ,kBAAkB,gBAAgB,kBAAkB,CAC9D,QAAQ,wBAAwB,eAAe,QAAQ;CAIlF,MAAM,iBAAiB,MAAM,6BAA6B,kBAAkB,UAAU;CAGtF,MAAM,gBAAgB,OAAO;AAE7B,KAAI,mBAAmB,cACrB;AAGF,KAAI,iBAAiB,cACnB,OAAM,IAAI,MACR,8CAA8C,eAAe,sBAAsB,cAAc,GAClG;AAIH,OADmB,QAAQ,kBAAkB,QAAQ,UAAU,CAC9C,QAAQ,gBAAgB,cAAc"}
1
+ {"version":3,"file":"mod.js","names":["#namespace","#schema","#adapter","internalSchema"],"sources":["../src/mod.ts"],"sourcesContent":["import type { DatabaseAdapter } from \"./adapters/adapters\";\nimport type { AnySchema } from \"./schema/create\";\nimport type { CursorResult } from \"./query/cursor\";\nimport { Cursor } from \"./query/cursor\";\nimport { dbNow, type DbNow } from \"./query/db-now\";\nimport type { FragnoInstantiatedFragment, AnyFragnoInstantiatedFragment } from \"@fragno-dev/core\";\nimport type {\n FragnoPublicConfigWithDatabase,\n ImplicitDatabaseDependencies,\n} from \"./db-fragment-definition-builder\";\nimport {\n getSchemaVersionFromDatabase,\n type InternalFragmentInstance,\n} from \"./fragments/internal-fragment\";\nimport { resolveDatabaseAdapter } from \"./util/default-database-adapter\";\n\nexport type { DatabaseAdapter, CursorResult };\nexport { Cursor };\nexport { dbNow };\nexport type { DbNow };\nexport { InMemoryAdapter, type InMemoryAdapterOptions } from \"./adapters/in-memory\";\nexport { internalSchema } from \"./fragments/internal-fragment\";\n\nexport const fragnoDatabaseFakeSymbol = \"$fragno-database\" as const;\nexport const fragnoDatabaseLibraryVersion = \"0.1\" as const;\n\nexport interface CreateFragnoDatabaseDefinitionOptions<T extends AnySchema> {\n namespace: string | null;\n schema: T;\n}\n\nexport function isFragnoDatabase(value: unknown): value is FragnoDatabase<AnySchema> {\n if (value instanceof FragnoDatabase) {\n return true;\n }\n\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n\n return (\n fragnoDatabaseFakeSymbol in value &&\n value[fragnoDatabaseFakeSymbol] === fragnoDatabaseFakeSymbol\n );\n}\n\n/**\n * A Fragno database instance with a bound adapter.\n * Created from a FragnoDatabaseDefinition by calling .create(adapter).\n */\nexport class FragnoDatabase<const T extends AnySchema, TUOWConfig = void> {\n #namespace: string | null;\n #schema: T;\n #adapter: DatabaseAdapter<TUOWConfig>;\n\n constructor(options: {\n namespace: string | null;\n schema: T;\n adapter: DatabaseAdapter<TUOWConfig>;\n }) {\n this.#namespace = options.namespace;\n this.#schema = options.schema;\n this.#adapter = options.adapter;\n }\n\n get [fragnoDatabaseFakeSymbol](): typeof fragnoDatabaseFakeSymbol {\n return fragnoDatabaseFakeSymbol;\n }\n\n get namespace() {\n return this.#namespace;\n }\n\n get schema() {\n return this.#schema;\n }\n\n get adapter(): DatabaseAdapter<TUOWConfig> {\n return this.#adapter;\n }\n}\n\nexport {\n DatabaseFragmentDefinitionBuilder,\n type FragnoPublicConfigWithDatabase,\n type DatabaseFragmentContext,\n type DatabaseServiceContext,\n type DatabaseHandlerContext as DatabaseRequestContext,\n type ImplicitDatabaseDependencies,\n} from \"./db-fragment-definition-builder\";\n\nexport { withDatabase } from \"./with-database\";\n\nexport { decodeCursor, type CursorData } from \"./query/cursor\";\n\nexport {\n createUnitOfWork,\n UnitOfWork,\n TypedUnitOfWork,\n type IUnitOfWork,\n type IUnitOfWorkRestricted,\n type UOWCompiler,\n type UOWExecutor,\n type UOWDecoder,\n} from \"./query/unit-of-work/unit-of-work\";\n\nexport {\n type RetryPolicy,\n NoRetryPolicy,\n ExponentialBackoffRetryPolicy,\n LinearBackoffRetryPolicy,\n} from \"./query/unit-of-work/retry-policy\";\n\nexport {\n ConcurrencyConflictError,\n // Builder pattern exports\n ServiceTxBuilder,\n HandlerTxBuilder,\n createServiceTxBuilder,\n createHandlerTxBuilder,\n type TxResult,\n // Builder context types\n type ServiceBuilderMutateContext,\n type HandlerBuilderMutateContext,\n type BuilderTransformContextWithMutate,\n type BuilderTransformContextWithoutMutate,\n type ExtractServiceRetrieveResults,\n type ExtractServiceFinalResults,\n} from \"./query/unit-of-work/execute-unit-of-work\";\n\nexport type { BoundServices } from \"@fragno-dev/core\";\n\nexport { internalFragmentDef } from \"./fragments/internal-fragment\";\nexport type { InternalFragmentInstance } from \"./fragments/internal-fragment\";\nexport type {\n OutboxConfig,\n OutboxEntry,\n OutboxPayload,\n OutboxMutation,\n OutboxRefMap,\n} from \"./outbox/outbox\";\n\nexport type {\n HookContext,\n HooksMap,\n HookFn,\n HookPayload,\n TriggerHookOptions,\n DurableHooksProcessingOptions,\n StuckHookProcessingInfo,\n StuckHookProcessingEvent,\n StuckHookProcessingTimeoutMinutes,\n} from \"./hooks/hooks\";\nexport {\n createDurableHooksProcessor,\n type DurableHooksProcessor,\n} from \"./hooks/durable-hooks-processor\";\n\nexport type AnyFragnoInstantiatedDatabaseFragment<TSchema extends AnySchema = AnySchema> =\n FragnoInstantiatedFragment<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n ImplicitDatabaseDependencies<TSchema>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n FragnoPublicConfigWithDatabase,\n // Ensure the fragment has the internal fragment linked\n { _fragno_internal: InternalFragmentInstance } & Record<string, AnyFragnoInstantiatedFragment>\n >;\n\n/**\n * Helper function to run migrations for a database fragment.\n * Extracts the database adapter, schema, and namespace from the fragment and runs migrations.\n * This function:\n * 1. Ensures the internal settings fragment is migrated first\n * 2. Retrieves the current database version from the internal fragment\n * 3. Runs migration from current version to target version\n *\n * @param fragment - The instantiated fragment to run migrations for\n * @throws Error if the fragment doesn't have database support or the adapter doesn't support migrations\n *\n * @example\n * ```typescript\n * const fragment = instantiate(myFragmentDef)\n * .withConfig({})\n * .withRoutes([])\n * .withOptions({ databaseAdapter: myAdapter })\n * .build();\n *\n * await migrate(fragment);\n * ```\n */\nexport async function migrate<TSchema extends AnySchema>(\n fragment: AnyFragnoInstantiatedDatabaseFragment<TSchema>,\n): Promise<void> {\n const { options, deps, linkedFragments } = fragment.$internal;\n const adapter = resolveDatabaseAdapter(options, deps.schema);\n\n // Check if adapter supports prepareMigrations\n if (!adapter.prepareMigrations) {\n throw new Error(\n \"Database adapter does not support prepareMigrations. Please use an adapter that implements this method.\",\n );\n }\n\n const schema = deps.schema;\n const namespace = deps.namespace ?? schema.name;\n\n // Step 1: Ensure the internal fragment (settings table) is migrated first\n const internalFragment = linkedFragments._fragno_internal;\n\n if (!internalFragment) {\n throw new Error(\"Internal fragment not found. Please ensure the internal fragment is linked.\");\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 internalDeps = internalFragment.$internal.deps;\n const internalSchema = internalDeps.schema;\n // Internal fragment uses databaseNamespace: null (no table suffix).\n // Version tracking uses empty string so the key is \".schema_version\",\n // which matches both the legacy format and how the internal fragment was designed.\n const internalNamespace = internalDeps.namespace ?? \"\";\n\n const internalCurrentVersion = await getSchemaVersionFromDatabase(\n internalFragment,\n internalNamespace,\n );\n\n // Migrate internal fragment if needed\n if (internalCurrentVersion < internalSchema.version) {\n const internalMigrations = adapter.prepareMigrations(internalSchema, internalNamespace);\n await internalMigrations.execute(internalCurrentVersion, internalSchema.version);\n }\n\n // Step 2: Get current database version for this fragment's namespace\n const currentVersion = await getSchemaVersionFromDatabase(internalFragment, namespace);\n\n // Step 3: Run the migration from current version to target version\n const targetVersion = schema.version;\n\n if (currentVersion === targetVersion) {\n return;\n }\n\n if (currentVersion > targetVersion) {\n throw new Error(\n `Cannot migrate backwards: current version (${currentVersion}) > target version (${targetVersion})`,\n );\n }\n\n const migrations = adapter.prepareMigrations(schema, namespace);\n await migrations.execute(currentVersion, targetVersion);\n}\n"],"mappings":";;;;;;;;;;;;;;;AAuBA,MAAa,2BAA2B;AACxC,MAAa,+BAA+B;AAO5C,SAAgB,iBAAiB,OAAoD;AACnF,KAAI,iBAAiB,eACnB,QAAO;AAGT,KAAI,OAAO,UAAU,YAAY,UAAU,KACzC,QAAO;AAGT,QACE,4BAA4B,SAC5B,MAAM,8BAA8B;;;;;;AAQxC,IAAa,iBAAb,MAA0E;CACxE;CACA;CACA;CAEA,YAAY,SAIT;AACD,QAAKA,YAAa,QAAQ;AAC1B,QAAKC,SAAU,QAAQ;AACvB,QAAKC,UAAW,QAAQ;;CAG1B,KAAK,4BAA6D;AAChE,SAAO;;CAGT,IAAI,YAAY;AACd,SAAO,MAAKF;;CAGd,IAAI,SAAS;AACX,SAAO,MAAKC;;CAGd,IAAI,UAAuC;AACzC,SAAO,MAAKC;;;;;;;;;;;;;;;;;;;;;;;;;AAwHhB,eAAsB,QACpB,UACe;CACf,MAAM,EAAE,SAAS,MAAM,oBAAoB,SAAS;CACpD,MAAM,UAAU,uBAAuB,SAAS,KAAK,OAAO;AAG5D,KAAI,CAAC,QAAQ,kBACX,OAAM,IAAI,MACR,0GACD;CAGH,MAAM,SAAS,KAAK;CACpB,MAAM,YAAY,KAAK,aAAa,OAAO;CAG3C,MAAM,mBAAmB,gBAAgB;AAEzC,KAAI,CAAC,iBACH,OAAM,IAAI,MAAM,8EAA8E;AAGhG,KAAI,CAAE,MAAM,QAAQ,qBAAqB,CACvC,OAAM,IAAI,MACR,2FACD;CAGH,MAAM,eAAe,iBAAiB,UAAU;CAChD,MAAMC,mBAAiB,aAAa;CAIpC,MAAM,oBAAoB,aAAa,aAAa;CAEpD,MAAM,yBAAyB,MAAM,6BACnC,kBACA,kBACD;AAGD,KAAI,yBAAyBA,iBAAe,QAE1C,OAD2B,QAAQ,kBAAkBA,kBAAgB,kBAAkB,CAC9D,QAAQ,wBAAwBA,iBAAe,QAAQ;CAIlF,MAAM,iBAAiB,MAAM,6BAA6B,kBAAkB,UAAU;CAGtF,MAAM,gBAAgB,OAAO;AAE7B,KAAI,mBAAmB,cACrB;AAGF,KAAI,iBAAiB,cACnB,OAAM,IAAI,MACR,8CAA8C,eAAe,sBAAsB,cAAc,GAClG;AAIH,OADmB,QAAQ,kBAAkB,QAAQ,UAAU,CAC9C,QAAQ,gBAAgB,cAAc"}