@fragno-dev/db 0.1.14 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (445) hide show
  1. package/.turbo/turbo-build.log +242 -139
  2. package/CHANGELOG.md +47 -0
  3. package/README.md +123 -8
  4. package/dist/adapters/adapters.d.ts +19 -5
  5. package/dist/adapters/adapters.d.ts.map +1 -1
  6. package/dist/adapters/adapters.js.map +1 -1
  7. package/dist/adapters/drizzle/drizzle-adapter.d.ts +6 -19
  8. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
  9. package/dist/adapters/drizzle/drizzle-adapter.js +7 -47
  10. package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
  11. package/dist/adapters/drizzle/generate.d.ts +7 -1
  12. package/dist/adapters/drizzle/generate.d.ts.map +1 -1
  13. package/dist/adapters/drizzle/generate.js +46 -45
  14. package/dist/adapters/drizzle/generate.js.map +1 -1
  15. package/dist/adapters/generic-sql/driver-config.d.ts +74 -0
  16. package/dist/adapters/generic-sql/driver-config.d.ts.map +1 -0
  17. package/dist/adapters/generic-sql/driver-config.js +94 -0
  18. package/dist/adapters/generic-sql/driver-config.js.map +1 -0
  19. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts +43 -0
  20. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -0
  21. package/dist/adapters/generic-sql/generic-sql-adapter.js +87 -0
  22. package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -0
  23. package/dist/adapters/generic-sql/generic-sql-uow-executor.js +67 -0
  24. package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -0
  25. package/dist/adapters/generic-sql/migration/cold-kysely.js +33 -0
  26. package/dist/adapters/generic-sql/migration/cold-kysely.js.map +1 -0
  27. package/dist/adapters/generic-sql/migration/dialect/mysql.js +60 -0
  28. package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -0
  29. package/dist/adapters/generic-sql/migration/dialect/postgres.js +59 -0
  30. package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -0
  31. package/dist/adapters/generic-sql/migration/dialect/sqlite.js +96 -0
  32. package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -0
  33. package/dist/adapters/generic-sql/migration/executor.d.ts +15 -0
  34. package/dist/adapters/generic-sql/migration/executor.d.ts.map +1 -0
  35. package/dist/adapters/generic-sql/migration/executor.js +18 -0
  36. package/dist/adapters/generic-sql/migration/executor.js.map +1 -0
  37. package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts +66 -0
  38. package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -0
  39. package/dist/adapters/generic-sql/migration/prepared-migrations.js +68 -0
  40. package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -0
  41. package/dist/adapters/generic-sql/migration/sql-generator.js +212 -0
  42. package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -0
  43. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +32 -0
  44. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -0
  45. package/dist/adapters/generic-sql/query/cursor-utils.js +37 -0
  46. package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -0
  47. package/dist/adapters/generic-sql/query/dialect/mysql.js +33 -0
  48. package/dist/adapters/generic-sql/query/dialect/mysql.js.map +1 -0
  49. package/dist/adapters/generic-sql/query/dialect/postgres.js +32 -0
  50. package/dist/adapters/generic-sql/query/dialect/postgres.js.map +1 -0
  51. package/dist/adapters/generic-sql/query/dialect/sqlite.js +32 -0
  52. package/dist/adapters/generic-sql/query/dialect/sqlite.js.map +1 -0
  53. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +152 -0
  54. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -0
  55. package/dist/adapters/generic-sql/query/select-builder.js +69 -0
  56. package/dist/adapters/generic-sql/query/select-builder.js.map +1 -0
  57. package/dist/adapters/generic-sql/query/sql-query-compiler.js +145 -0
  58. package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -0
  59. package/dist/adapters/generic-sql/query/where-builder.js +129 -0
  60. package/dist/adapters/generic-sql/query/where-builder.js.map +1 -0
  61. package/dist/adapters/generic-sql/result-interpreter.js +74 -0
  62. package/dist/adapters/generic-sql/result-interpreter.js.map +1 -0
  63. package/dist/adapters/generic-sql/uow-decoder.js +105 -0
  64. package/dist/adapters/generic-sql/uow-decoder.js.map +1 -0
  65. package/dist/adapters/generic-sql/uow-encoder.js +93 -0
  66. package/dist/adapters/generic-sql/uow-encoder.js.map +1 -0
  67. package/dist/adapters/kysely/kysely-adapter.d.ts +5 -16
  68. package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
  69. package/dist/adapters/kysely/kysely-adapter.js +6 -159
  70. package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
  71. package/dist/adapters/{drizzle/drizzle-query.js → shared/from-unit-of-work-compiler.js} +48 -62
  72. package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -0
  73. package/dist/adapters/{kysely/kysely-shared.d.ts → shared/table-name-mapper.d.ts} +3 -2
  74. package/dist/adapters/shared/table-name-mapper.d.ts.map +1 -0
  75. package/dist/adapters/shared/table-name-mapper.js +43 -0
  76. package/dist/adapters/shared/table-name-mapper.js.map +1 -0
  77. package/dist/adapters/shared/uow-operation-compiler.js +105 -0
  78. package/dist/adapters/shared/uow-operation-compiler.js.map +1 -0
  79. package/dist/db-fragment-definition-builder.d.ts +186 -0
  80. package/dist/db-fragment-definition-builder.d.ts.map +1 -0
  81. package/dist/db-fragment-definition-builder.js +207 -0
  82. package/dist/db-fragment-definition-builder.js.map +1 -0
  83. package/dist/fragments/internal-fragment.d.ts +53 -0
  84. package/dist/fragments/internal-fragment.d.ts.map +1 -0
  85. package/dist/fragments/internal-fragment.js +111 -0
  86. package/dist/fragments/internal-fragment.js.map +1 -0
  87. package/dist/hooks/hooks.d.ts +51 -0
  88. package/dist/hooks/hooks.d.ts.map +1 -0
  89. package/dist/hooks/hooks.js +88 -0
  90. package/dist/hooks/hooks.js.map +1 -0
  91. package/dist/migration-engine/generation-engine.d.ts +0 -2
  92. package/dist/migration-engine/generation-engine.d.ts.map +1 -1
  93. package/dist/migration-engine/generation-engine.js +38 -56
  94. package/dist/migration-engine/generation-engine.js.map +1 -1
  95. package/dist/mod.d.ts +35 -23
  96. package/dist/mod.d.ts.map +1 -1
  97. package/dist/mod.js +48 -45
  98. package/dist/mod.js.map +1 -1
  99. package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js +165 -0
  100. package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js.map +1 -0
  101. package/dist/packages/fragno/dist/api/bind-services.js +20 -0
  102. package/dist/packages/fragno/dist/api/bind-services.js.map +1 -0
  103. package/dist/packages/fragno/dist/api/error.js +48 -0
  104. package/dist/packages/fragno/dist/api/error.js.map +1 -0
  105. package/dist/packages/fragno/dist/api/fragment-definition-builder.js +320 -0
  106. package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +1 -0
  107. package/dist/packages/fragno/dist/api/fragment-instantiator.js +525 -0
  108. package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -0
  109. package/dist/packages/fragno/dist/api/fragno-response.js +73 -0
  110. package/dist/packages/fragno/dist/api/fragno-response.js.map +1 -0
  111. package/dist/packages/fragno/dist/api/internal/response-stream.js +81 -0
  112. package/dist/packages/fragno/dist/api/internal/response-stream.js.map +1 -0
  113. package/dist/packages/fragno/dist/api/internal/route.js +10 -0
  114. package/dist/packages/fragno/dist/api/internal/route.js.map +1 -0
  115. package/dist/packages/fragno/dist/api/mutable-request-state.js +97 -0
  116. package/dist/packages/fragno/dist/api/mutable-request-state.js.map +1 -0
  117. package/dist/packages/fragno/dist/api/request-context-storage.js +43 -0
  118. package/dist/packages/fragno/dist/api/request-context-storage.js.map +1 -0
  119. package/dist/packages/fragno/dist/api/request-input-context.js +118 -0
  120. package/dist/packages/fragno/dist/api/request-input-context.js.map +1 -0
  121. package/dist/packages/fragno/dist/api/request-middleware.js +83 -0
  122. package/dist/packages/fragno/dist/api/request-middleware.js.map +1 -0
  123. package/dist/packages/fragno/dist/api/request-output-context.js +119 -0
  124. package/dist/packages/fragno/dist/api/request-output-context.js.map +1 -0
  125. package/dist/packages/fragno/dist/api/route.js +17 -0
  126. package/dist/packages/fragno/dist/api/route.js.map +1 -0
  127. package/dist/packages/fragno/dist/internal/symbols.js +10 -0
  128. package/dist/packages/fragno/dist/internal/symbols.js.map +1 -0
  129. package/dist/query/column-defaults.js +27 -0
  130. package/dist/query/column-defaults.js.map +1 -0
  131. package/dist/query/cursor.d.ts +14 -6
  132. package/dist/query/cursor.d.ts.map +1 -1
  133. package/dist/query/cursor.js +16 -7
  134. package/dist/query/cursor.js.map +1 -1
  135. package/dist/query/orm/orm.d.ts +1 -1
  136. package/dist/query/orm/orm.js.map +1 -1
  137. package/dist/query/serialize/create-sql-serializer.js +30 -0
  138. package/dist/query/serialize/create-sql-serializer.js.map +1 -0
  139. package/dist/query/serialize/dialect/mysql-serializer.js +87 -0
  140. package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -0
  141. package/dist/query/serialize/dialect/postgres-serializer.js +80 -0
  142. package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -0
  143. package/dist/query/serialize/dialect/sqlite-serializer.js +93 -0
  144. package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -0
  145. package/dist/query/serialize/sql-serializer.js +67 -0
  146. package/dist/query/serialize/sql-serializer.js.map +1 -0
  147. package/dist/query/{query.d.ts → simple-query-interface.d.ts} +6 -6
  148. package/dist/query/simple-query-interface.d.ts.map +1 -0
  149. package/dist/query/unit-of-work/execute-unit-of-work.d.ts +133 -0
  150. package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -0
  151. package/dist/query/unit-of-work/execute-unit-of-work.js +197 -0
  152. package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -0
  153. package/dist/query/unit-of-work/retry-policy.d.ts +88 -0
  154. package/dist/query/unit-of-work/retry-policy.d.ts.map +1 -0
  155. package/dist/query/unit-of-work/retry-policy.js +61 -0
  156. package/dist/query/unit-of-work/retry-policy.js.map +1 -0
  157. package/dist/query/{unit-of-work.d.ts → unit-of-work/unit-of-work.d.ts} +145 -58
  158. package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -0
  159. package/dist/query/{unit-of-work.js → unit-of-work/unit-of-work.js} +435 -198
  160. package/dist/query/unit-of-work/unit-of-work.js.map +1 -0
  161. package/dist/query/value-decoding.js +71 -0
  162. package/dist/query/value-decoding.js.map +1 -0
  163. package/dist/query/value-encoding.js +124 -0
  164. package/dist/query/value-encoding.js.map +1 -0
  165. package/dist/schema/create.d.ts +3 -0
  166. package/dist/schema/create.d.ts.map +1 -1
  167. package/dist/schema/create.js +4 -0
  168. package/dist/schema/create.js.map +1 -1
  169. package/dist/schema/type-conversion/create-sql-type-mapper.js +29 -0
  170. package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -0
  171. package/dist/schema/type-conversion/dialect/mysql.js +57 -0
  172. package/dist/schema/type-conversion/dialect/mysql.js.map +1 -0
  173. package/dist/schema/type-conversion/dialect/postgres.js +56 -0
  174. package/dist/schema/type-conversion/dialect/postgres.js.map +1 -0
  175. package/dist/schema/type-conversion/dialect/sqlite.js +52 -0
  176. package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -0
  177. package/dist/schema/type-conversion/type-mapping.js +63 -0
  178. package/dist/schema/type-conversion/type-mapping.js.map +1 -0
  179. package/dist/sql-driver/connection/connection-provider.d.ts +13 -0
  180. package/dist/sql-driver/connection/connection-provider.d.ts.map +1 -0
  181. package/dist/sql-driver/connection/connection-provider.js +19 -0
  182. package/dist/sql-driver/connection/connection-provider.js.map +1 -0
  183. package/dist/sql-driver/connection/single-connection-provider.js +23 -0
  184. package/dist/sql-driver/connection/single-connection-provider.js.map +1 -0
  185. package/dist/sql-driver/dialect-adapter/dialect-adapter.d.ts +7 -0
  186. package/dist/sql-driver/dialect-adapter/dialect-adapter.d.ts.map +1 -0
  187. package/dist/sql-driver/dialects/dialects.d.ts +2 -0
  188. package/dist/sql-driver/dialects/dialects.js +3 -0
  189. package/dist/sql-driver/dialects/durable-object-dialect.d.ts +72 -0
  190. package/dist/sql-driver/dialects/durable-object-dialect.d.ts.map +1 -0
  191. package/dist/sql-driver/dialects/durable-object-dialect.js +130 -0
  192. package/dist/sql-driver/dialects/durable-object-dialect.js.map +1 -0
  193. package/dist/sql-driver/driver/runtime-driver.d.ts +23 -0
  194. package/dist/sql-driver/driver/runtime-driver.d.ts.map +1 -0
  195. package/dist/sql-driver/driver/runtime-driver.js +56 -0
  196. package/dist/sql-driver/driver/runtime-driver.js.map +1 -0
  197. package/dist/sql-driver/query-executor/default-query-executor.js +26 -0
  198. package/dist/sql-driver/query-executor/default-query-executor.js.map +1 -0
  199. package/dist/sql-driver/query-executor/plugin.d.ts +17 -0
  200. package/dist/sql-driver/query-executor/plugin.d.ts.map +1 -0
  201. package/dist/sql-driver/query-executor/query-executor-base.js +25 -0
  202. package/dist/sql-driver/query-executor/query-executor-base.js.map +1 -0
  203. package/dist/sql-driver/query-executor/query-executor.d.ts +36 -0
  204. package/dist/sql-driver/query-executor/query-executor.d.ts.map +1 -0
  205. package/dist/sql-driver/sql-driver-adapter.d.ts +29 -0
  206. package/dist/sql-driver/sql-driver-adapter.d.ts.map +1 -0
  207. package/dist/sql-driver/sql-driver-adapter.js +68 -0
  208. package/dist/sql-driver/sql-driver-adapter.js.map +1 -0
  209. package/dist/sql-driver/sql-driver.d.ts +38 -0
  210. package/dist/sql-driver/sql-driver.d.ts.map +1 -0
  211. package/dist/sql-driver/sql-driver.js +1 -0
  212. package/dist/sql-driver/sql.js +50 -0
  213. package/dist/sql-driver/sql.js.map +1 -0
  214. package/dist/with-database.d.ts +32 -0
  215. package/dist/with-database.d.ts.map +1 -0
  216. package/dist/with-database.js +34 -0
  217. package/dist/with-database.js.map +1 -0
  218. package/package.json +43 -9
  219. package/src/adapters/adapters.ts +23 -4
  220. package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +140 -185
  221. package/src/adapters/drizzle/{drizzle-adapter-sqlite.test.ts → drizzle-adapter-sqlite3.test.ts} +187 -55
  222. package/src/adapters/drizzle/drizzle-adapter.ts +14 -93
  223. package/src/adapters/drizzle/generate.test.ts +102 -269
  224. package/src/adapters/drizzle/generate.ts +89 -63
  225. package/src/adapters/drizzle/migrate-drizzle.test.ts +19 -0
  226. package/src/adapters/drizzle/shared.ts +0 -34
  227. package/src/adapters/drizzle/test-utils.ts +36 -5
  228. package/src/adapters/generic-sql/README.md +14 -0
  229. package/src/adapters/generic-sql/driver-config.ts +144 -0
  230. package/src/adapters/generic-sql/generic-sql-adapter.test.ts +50 -0
  231. package/src/adapters/generic-sql/generic-sql-adapter.ts +146 -0
  232. package/src/adapters/generic-sql/generic-sql-uow-executor.ts +130 -0
  233. package/src/adapters/generic-sql/migration/cold-kysely.ts +55 -0
  234. package/src/adapters/{kysely/migration/execute-mysql.test.ts → generic-sql/migration/dialect/mysql.test.ts} +342 -484
  235. package/src/adapters/generic-sql/migration/dialect/mysql.ts +104 -0
  236. package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +1008 -0
  237. package/src/adapters/generic-sql/migration/dialect/postgres.ts +113 -0
  238. package/src/adapters/{kysely/migration/execute-sqlite.test.ts → generic-sql/migration/dialect/sqlite.test.ts} +307 -510
  239. package/src/adapters/generic-sql/migration/dialect/sqlite.ts +189 -0
  240. package/src/adapters/generic-sql/migration/executor.ts +33 -0
  241. package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +661 -0
  242. package/src/adapters/generic-sql/migration/prepared-migrations.ts +214 -0
  243. package/src/adapters/generic-sql/migration/sql-generator.ts +413 -0
  244. package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +36 -0
  245. package/src/adapters/generic-sql/query/cursor-utils.ts +56 -0
  246. package/src/adapters/generic-sql/query/dialect/mysql.ts +34 -0
  247. package/src/adapters/generic-sql/query/dialect/postgres.ts +32 -0
  248. package/src/adapters/generic-sql/query/dialect/sqlite.ts +32 -0
  249. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +1568 -0
  250. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +314 -0
  251. package/src/adapters/generic-sql/query/select-builder.test.ts +256 -0
  252. package/src/adapters/generic-sql/query/select-builder.ts +137 -0
  253. package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +195 -0
  254. package/src/adapters/generic-sql/query/sql-query-compiler.ts +367 -0
  255. package/src/adapters/generic-sql/query/where-builder.test.ts +744 -0
  256. package/src/adapters/generic-sql/query/where-builder.ts +211 -0
  257. package/src/adapters/generic-sql/result-interpreter.ts +102 -0
  258. package/src/adapters/generic-sql/test/generic-drizzle-adapter-sqlite3.test.ts +899 -0
  259. package/src/adapters/generic-sql/uow-decoder.test.ts +399 -0
  260. package/src/adapters/generic-sql/uow-decoder.ts +152 -0
  261. package/src/adapters/generic-sql/uow-encoder.test.ts +183 -0
  262. package/src/adapters/generic-sql/uow-encoder.ts +131 -0
  263. package/src/adapters/kysely/kysely-adapter-pglite.test.ts +90 -96
  264. package/src/adapters/kysely/kysely-adapter-sqlocal.test.ts +215 -0
  265. package/src/adapters/kysely/kysely-adapter.ts +10 -242
  266. package/src/adapters/{drizzle/drizzle-query.ts → shared/from-unit-of-work-compiler.ts} +111 -106
  267. package/src/adapters/shared/table-name-mapper.ts +50 -0
  268. package/src/adapters/shared/uow-operation-compiler.ts +211 -0
  269. package/src/db-fragment-definition-builder.test.ts +887 -0
  270. package/src/db-fragment-definition-builder.ts +737 -0
  271. package/src/db-fragment-instantiator.test.ts +543 -0
  272. package/src/db-fragment-integration.test.ts +406 -0
  273. package/src/fragments/internal-fragment.test.ts +549 -0
  274. package/src/fragments/internal-fragment.ts +249 -0
  275. package/src/hooks/hooks.test.ts +575 -0
  276. package/src/hooks/hooks.ts +179 -0
  277. package/src/migration-engine/generation-engine.test.ts +60 -27
  278. package/src/migration-engine/generation-engine.ts +99 -92
  279. package/src/mod.ts +139 -78
  280. package/src/query/column-defaults.ts +49 -0
  281. package/src/query/cursor.test.ts +147 -3
  282. package/src/query/cursor.ts +25 -8
  283. package/src/query/orm/orm.ts +1 -1
  284. package/src/query/query-type.test.ts +9 -9
  285. package/src/query/serialize/create-sql-serializer.ts +34 -0
  286. package/src/query/serialize/dialect/mysql-serializer.ts +142 -0
  287. package/src/query/serialize/dialect/postgres-serializer.ts +129 -0
  288. package/src/query/serialize/dialect/sqlite-serializer.test.ts +251 -0
  289. package/src/query/serialize/dialect/sqlite-serializer.ts +156 -0
  290. package/src/query/serialize/sql-serializer.ts +143 -0
  291. package/src/query/{query.ts → simple-query-interface.ts} +4 -4
  292. package/src/query/unit-of-work/execute-unit-of-work.test.ts +1310 -0
  293. package/src/query/unit-of-work/execute-unit-of-work.ts +504 -0
  294. package/src/query/unit-of-work/retry-policy.test.ts +217 -0
  295. package/src/query/unit-of-work/retry-policy.ts +141 -0
  296. package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +831 -0
  297. package/src/query/{unit-of-work-types.test.ts → unit-of-work/unit-of-work-types.test.ts} +7 -5
  298. package/src/query/unit-of-work/unit-of-work.test.ts +1716 -0
  299. package/src/query/{unit-of-work.ts → unit-of-work/unit-of-work.ts} +716 -420
  300. package/src/query/{result-transform.test.ts → value-decoding.test.ts} +45 -298
  301. package/src/query/value-decoding.ts +113 -0
  302. package/src/query/value-encoding.test.ts +390 -0
  303. package/src/query/value-encoding.ts +168 -0
  304. package/src/schema/create.test.ts +5 -1
  305. package/src/schema/create.ts +5 -0
  306. package/src/schema/serialize.test.ts +165 -407
  307. package/src/schema/type-conversion/create-sql-type-mapper.ts +28 -0
  308. package/src/schema/type-conversion/dialect/mysql.ts +64 -0
  309. package/src/schema/type-conversion/dialect/postgres.ts +62 -0
  310. package/src/schema/type-conversion/dialect/sqlite.ts +63 -0
  311. package/src/schema/type-conversion/type-mapping.test.ts +137 -0
  312. package/src/schema/type-conversion/type-mapping.ts +153 -0
  313. package/src/shared/connection-pool.ts +5 -5
  314. package/src/sql-driver/better-sqlite3.test.ts +126 -0
  315. package/src/sql-driver/connection/connection-provider.ts +27 -0
  316. package/src/sql-driver/connection/single-connection-provider.ts +42 -0
  317. package/src/sql-driver/dialect-adapter/dialect-adapter.ts +9 -0
  318. package/src/sql-driver/dialect-adapter/sqlite-dialect-adapter.ts +7 -0
  319. package/src/sql-driver/dialects/dialects.ts +1 -0
  320. package/src/sql-driver/dialects/durable-object-dialect.ts +260 -0
  321. package/src/sql-driver/driver/runtime-driver.ts +91 -0
  322. package/src/sql-driver/query-executor/default-query-executor.ts +38 -0
  323. package/src/sql-driver/query-executor/plugin.ts +22 -0
  324. package/src/sql-driver/query-executor/query-executor-base.ts +53 -0
  325. package/src/sql-driver/query-executor/query-executor.ts +44 -0
  326. package/src/sql-driver/sql-driver-adapter.ts +96 -0
  327. package/src/sql-driver/sql-driver.ts +53 -0
  328. package/src/sql-driver/sql.ts +57 -0
  329. package/src/sql-driver/sqlocal.test.ts +117 -0
  330. package/src/with-database.ts +152 -0
  331. package/tsdown.config.ts +8 -2
  332. package/dist/adapters/drizzle/drizzle-connection-pool.js +0 -40
  333. package/dist/adapters/drizzle/drizzle-connection-pool.js.map +0 -1
  334. package/dist/adapters/drizzle/drizzle-query.d.ts +0 -23
  335. package/dist/adapters/drizzle/drizzle-query.d.ts.map +0 -1
  336. package/dist/adapters/drizzle/drizzle-query.js.map +0 -1
  337. package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +0 -10
  338. package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +0 -1
  339. package/dist/adapters/drizzle/drizzle-uow-compiler.js +0 -315
  340. package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +0 -1
  341. package/dist/adapters/drizzle/drizzle-uow-decoder.js +0 -116
  342. package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +0 -1
  343. package/dist/adapters/drizzle/drizzle-uow-executor.js +0 -149
  344. package/dist/adapters/drizzle/drizzle-uow-executor.js.map +0 -1
  345. package/dist/adapters/drizzle/join-column-utils.js +0 -28
  346. package/dist/adapters/drizzle/join-column-utils.js.map +0 -1
  347. package/dist/adapters/drizzle/shared.d.ts +0 -14
  348. package/dist/adapters/drizzle/shared.d.ts.map +0 -1
  349. package/dist/adapters/drizzle/shared.js +0 -35
  350. package/dist/adapters/drizzle/shared.js.map +0 -1
  351. package/dist/adapters/kysely/kysely-connection-pool.js +0 -41
  352. package/dist/adapters/kysely/kysely-connection-pool.js.map +0 -1
  353. package/dist/adapters/kysely/kysely-query-builder.js +0 -321
  354. package/dist/adapters/kysely/kysely-query-builder.js.map +0 -1
  355. package/dist/adapters/kysely/kysely-query-compiler.js +0 -66
  356. package/dist/adapters/kysely/kysely-query-compiler.js.map +0 -1
  357. package/dist/adapters/kysely/kysely-query.d.ts +0 -22
  358. package/dist/adapters/kysely/kysely-query.d.ts.map +0 -1
  359. package/dist/adapters/kysely/kysely-query.js +0 -223
  360. package/dist/adapters/kysely/kysely-query.js.map +0 -1
  361. package/dist/adapters/kysely/kysely-shared.d.ts.map +0 -1
  362. package/dist/adapters/kysely/kysely-shared.js +0 -18
  363. package/dist/adapters/kysely/kysely-shared.js.map +0 -1
  364. package/dist/adapters/kysely/kysely-uow-compiler.js +0 -170
  365. package/dist/adapters/kysely/kysely-uow-compiler.js.map +0 -1
  366. package/dist/adapters/kysely/kysely-uow-executor.js +0 -89
  367. package/dist/adapters/kysely/kysely-uow-executor.js.map +0 -1
  368. package/dist/adapters/kysely/migration/execute-base.js +0 -128
  369. package/dist/adapters/kysely/migration/execute-base.js.map +0 -1
  370. package/dist/adapters/kysely/migration/execute-factory.js +0 -34
  371. package/dist/adapters/kysely/migration/execute-factory.js.map +0 -1
  372. package/dist/adapters/kysely/migration/execute-mssql.js +0 -112
  373. package/dist/adapters/kysely/migration/execute-mssql.js.map +0 -1
  374. package/dist/adapters/kysely/migration/execute-mysql.js +0 -93
  375. package/dist/adapters/kysely/migration/execute-mysql.js.map +0 -1
  376. package/dist/adapters/kysely/migration/execute-postgres.js +0 -104
  377. package/dist/adapters/kysely/migration/execute-postgres.js.map +0 -1
  378. package/dist/adapters/kysely/migration/execute-sqlite.js +0 -123
  379. package/dist/adapters/kysely/migration/execute-sqlite.js.map +0 -1
  380. package/dist/adapters/kysely/migration/execute.js +0 -34
  381. package/dist/adapters/kysely/migration/execute.js.map +0 -1
  382. package/dist/bind-services.d.ts +0 -7
  383. package/dist/bind-services.d.ts.map +0 -1
  384. package/dist/bind-services.js +0 -14
  385. package/dist/bind-services.js.map +0 -1
  386. package/dist/fragment.d.ts +0 -173
  387. package/dist/fragment.d.ts.map +0 -1
  388. package/dist/fragment.js +0 -191
  389. package/dist/fragment.js.map +0 -1
  390. package/dist/migration-engine/create.d.ts +0 -37
  391. package/dist/migration-engine/create.d.ts.map +0 -1
  392. package/dist/migration-engine/create.js +0 -58
  393. package/dist/migration-engine/create.js.map +0 -1
  394. package/dist/migration-engine/shared.d.ts +0 -112
  395. package/dist/migration-engine/shared.d.ts.map +0 -1
  396. package/dist/query/query.d.ts.map +0 -1
  397. package/dist/query/result-transform.js +0 -168
  398. package/dist/query/result-transform.js.map +0 -1
  399. package/dist/query/unit-of-work.d.ts.map +0 -1
  400. package/dist/query/unit-of-work.js.map +0 -1
  401. package/dist/schema/serialize.js +0 -106
  402. package/dist/schema/serialize.js.map +0 -1
  403. package/dist/shared/settings-schema.js +0 -36
  404. package/dist/shared/settings-schema.js.map +0 -1
  405. package/src/adapters/drizzle/drizzle-adapter.test.ts +0 -170
  406. package/src/adapters/drizzle/drizzle-connection-pool.ts +0 -66
  407. package/src/adapters/drizzle/drizzle-query.test.ts +0 -499
  408. package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +0 -1383
  409. package/src/adapters/drizzle/drizzle-uow-compiler.ts +0 -636
  410. package/src/adapters/drizzle/drizzle-uow-decoder.ts +0 -218
  411. package/src/adapters/drizzle/drizzle-uow-executor.ts +0 -276
  412. package/src/adapters/drizzle/join-column-utils.test.ts +0 -79
  413. package/src/adapters/drizzle/join-column-utils.ts +0 -39
  414. package/src/adapters/kysely/kysely-connection-pool.ts +0 -70
  415. package/src/adapters/kysely/kysely-query-builder.test.ts +0 -1344
  416. package/src/adapters/kysely/kysely-query-builder.ts +0 -666
  417. package/src/adapters/kysely/kysely-query-compiler.ts +0 -132
  418. package/src/adapters/kysely/kysely-query.test.ts +0 -498
  419. package/src/adapters/kysely/kysely-query.ts +0 -390
  420. package/src/adapters/kysely/kysely-shared.ts +0 -23
  421. package/src/adapters/kysely/kysely-uow-compiler.test.ts +0 -998
  422. package/src/adapters/kysely/kysely-uow-compiler.ts +0 -318
  423. package/src/adapters/kysely/kysely-uow-executor.ts +0 -145
  424. package/src/adapters/kysely/kysely-uow-joins.test.ts +0 -811
  425. package/src/adapters/kysely/migration/execute-base.ts +0 -256
  426. package/src/adapters/kysely/migration/execute-factory.ts +0 -53
  427. package/src/adapters/kysely/migration/execute-mssql.ts +0 -250
  428. package/src/adapters/kysely/migration/execute-mysql.ts +0 -211
  429. package/src/adapters/kysely/migration/execute-postgres.test.ts +0 -2657
  430. package/src/adapters/kysely/migration/execute-postgres.ts +0 -234
  431. package/src/adapters/kysely/migration/execute-sqlite.ts +0 -247
  432. package/src/adapters/kysely/migration/execute.ts +0 -50
  433. package/src/adapters/kysely/migration/kysely-migrator.test.ts +0 -261
  434. package/src/bind-services.test.ts +0 -214
  435. package/src/bind-services.ts +0 -37
  436. package/src/db-fragment.test.ts +0 -800
  437. package/src/fragment.ts +0 -727
  438. package/src/query/result-transform.ts +0 -271
  439. package/src/query/unit-of-work-multi-schema.test.ts +0 -64
  440. package/src/query/unit-of-work.test.ts +0 -943
  441. package/src/schema/serialize.ts +0 -396
  442. package/src/shared/settings-schema.ts +0 -61
  443. package/src/uow-context-integration.test.ts +0 -102
  444. package/src/uow-context.test.ts +0 -182
  445. /package/dist/query/{query.js → simple-query-interface.js} +0 -0
@@ -0,0 +1,661 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { column, idColumn, referenceColumn, schema } from "../../../schema/create";
3
+ import { createColdKysely } from "./cold-kysely";
4
+ import { SQLiteSQLGenerator } from "./dialect/sqlite";
5
+ import { PostgresSQLGenerator } from "./dialect/postgres";
6
+ import { MySQLSQLGenerator } from "./dialect/mysql";
7
+ import { createPreparedMigrations } from "./prepared-migrations";
8
+ import { createTableNameMapper } from "../../shared/table-name-mapper";
9
+
10
+ const testSchema = schema((s) => {
11
+ return s
12
+ .addTable("users", (t) => {
13
+ return t.addColumn("id", idColumn()).addColumn("name", column("string"));
14
+ })
15
+ .alterTable("users", (t) => {
16
+ return t
17
+ .addColumn("age", column("integer").nullable())
18
+ .createIndex("name_idx", ["name"])
19
+ .createIndex("age_idx", ["age"]);
20
+ })
21
+ .addTable("posts", (t) => {
22
+ return t
23
+ .addColumn("id", idColumn())
24
+ .addColumn("title", column("string"))
25
+ .addColumn("authorId", referenceColumn());
26
+ })
27
+ .addReference("author", {
28
+ type: "one",
29
+ from: { table: "posts", column: "authorId" },
30
+ to: { table: "users", column: "id" },
31
+ });
32
+ });
33
+
34
+ describe("PreparedMigrations - PostgreSQL", () => {
35
+ const coldKysely = createColdKysely("postgresql");
36
+ const generator = new PostgresSQLGenerator(coldKysely, "postgresql");
37
+
38
+ test("compile migration 0 -> 1 (create users table)", () => {
39
+ const statements = generator.compile(
40
+ [
41
+ {
42
+ type: "create-table",
43
+ name: "users",
44
+ columns: [
45
+ { name: "id", type: "string", isNullable: false, role: "external-id" },
46
+ { name: "name", type: "string", isNullable: false, role: "regular" },
47
+ { name: "_internalId", type: "bigint", isNullable: false, role: "internal-id" },
48
+ {
49
+ name: "_version",
50
+ type: "integer",
51
+ isNullable: false,
52
+ role: "version",
53
+ default: { value: 0 },
54
+ },
55
+ ],
56
+ },
57
+ ],
58
+ { toPhysical: (n) => `${n}_test`, toLogical: (n) => n.replace("_test", "") },
59
+ );
60
+
61
+ expect(statements.length).toBe(1);
62
+ expect(statements[0].sql).toMatchInlineSnapshot(
63
+ `"create table "users_test" ("id" text not null unique, "name" text not null, "_internalId" bigserial not null primary key, "_version" integer default 0 not null)"`,
64
+ );
65
+ });
66
+
67
+ test("compile alter table with add column", () => {
68
+ const statements = generator.compile(
69
+ [
70
+ {
71
+ type: "alter-table",
72
+ name: "users",
73
+ value: [
74
+ {
75
+ type: "create-column",
76
+ value: { name: "age", type: "integer", isNullable: true, role: "regular" },
77
+ },
78
+ ],
79
+ },
80
+ ],
81
+ { toPhysical: (n) => `${n}_test`, toLogical: (n) => n.replace("_test", "") },
82
+ );
83
+
84
+ expect(statements.length).toBe(1);
85
+ expect(statements[0].sql).toMatchInlineSnapshot(
86
+ `"alter table "users_test" add column "age" integer"`,
87
+ );
88
+ });
89
+
90
+ test("compile add index", () => {
91
+ const statements = generator.compile(
92
+ [
93
+ {
94
+ type: "add-index",
95
+ table: "users",
96
+ name: "name_idx",
97
+ columns: ["name"],
98
+ unique: false,
99
+ },
100
+ ],
101
+ { toPhysical: (n) => `${n}_test`, toLogical: (n) => n.replace("_test", "") },
102
+ );
103
+
104
+ expect(statements.length).toBe(1);
105
+ expect(statements[0].sql).toMatchInlineSnapshot(
106
+ `"create index "name_idx_users_test" on "users_test" ("name")"`,
107
+ );
108
+ });
109
+
110
+ test("generate version update SQL for new migration", () => {
111
+ const sql = generator.generateVersionUpdateSQL("test_namespace", 0, 1);
112
+
113
+ expect(sql.sql).toMatchInlineSnapshot(
114
+ `"insert into "fragno_db_settings" ("id", "key", "value") values ('jprP_43K5uMwxAFiepbbrQ', 'test_namespace.schema_version', '1')"`,
115
+ );
116
+ });
117
+
118
+ test("generate version update SQL for existing migration", () => {
119
+ const sql = generator.generateVersionUpdateSQL("test_namespace", 1, 2);
120
+
121
+ expect(sql.sql).toMatchInlineSnapshot(
122
+ `"update "fragno_db_settings" set "value" = '2' where "key" = 'test_namespace.schema_version'"`,
123
+ );
124
+ });
125
+ });
126
+
127
+ describe("PreparedMigrations - SQLite FK Merging", () => {
128
+ const coldKysely = createColdKysely("sqlite");
129
+ const generator = new SQLiteSQLGenerator(coldKysely, "sqlite");
130
+
131
+ test("preprocess merges FK into create-table", () => {
132
+ const operations = generator.preprocess([
133
+ {
134
+ type: "create-table",
135
+ name: "users",
136
+ columns: [{ name: "id", type: "string", isNullable: false, role: "external-id" }],
137
+ },
138
+ {
139
+ type: "create-table",
140
+ name: "posts",
141
+ columns: [
142
+ { name: "id", type: "string", isNullable: false, role: "external-id" },
143
+ { name: "authorId", type: "bigint", isNullable: false, role: "reference" },
144
+ ],
145
+ },
146
+ {
147
+ type: "add-foreign-key",
148
+ table: "posts",
149
+ value: {
150
+ name: "posts_users_author_fk",
151
+ columns: ["authorId"],
152
+ referencedTable: "users",
153
+ referencedColumns: ["_internalId"],
154
+ },
155
+ },
156
+ ]);
157
+
158
+ // FK should be merged into posts create-table, plus pragma statement
159
+ expect(operations.length).toBe(3);
160
+ expect(operations[0]).toEqual({ type: "custom", sql: "PRAGMA defer_foreign_keys = ON" });
161
+ const postsOp = operations.find((op) => op.type === "create-table" && op.name === "posts");
162
+ expect(postsOp).toBeDefined();
163
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
164
+ expect((postsOp as any).metadata?.inlineForeignKeys).toHaveLength(1);
165
+ });
166
+
167
+ test("compile creates table with inline FK constraint", () => {
168
+ const statements = generator.compile(
169
+ [
170
+ {
171
+ type: "create-table",
172
+ name: "users",
173
+ columns: [{ name: "id", type: "string", isNullable: false, role: "external-id" }],
174
+ },
175
+ {
176
+ type: "create-table",
177
+ name: "posts",
178
+ columns: [
179
+ { name: "id", type: "string", isNullable: false, role: "external-id" },
180
+ { name: "authorId", type: "bigint", isNullable: false, role: "reference" },
181
+ ],
182
+ },
183
+ {
184
+ type: "add-foreign-key",
185
+ table: "posts",
186
+ value: {
187
+ name: "posts_users_author_fk",
188
+ columns: ["authorId"],
189
+ referencedTable: "users",
190
+ referencedColumns: ["_internalId"],
191
+ },
192
+ },
193
+ ],
194
+ { toPhysical: (n) => `${n}_test`, toLogical: (n) => n.replace("_test", "") },
195
+ );
196
+
197
+ expect(statements.length).toBe(3);
198
+ expect(statements[0].sql).toMatchInlineSnapshot(`"PRAGMA defer_foreign_keys = ON"`);
199
+ expect(statements[1].sql).toMatchInlineSnapshot(
200
+ `"create table "users_test" ("id" text not null unique)"`,
201
+ );
202
+ expect(statements[2].sql).toMatchInlineSnapshot(
203
+ `"create table "posts_test" ("id" text not null unique, "authorId" integer not null, constraint "posts_users_author_fk" foreign key ("authorId") references "users_test" ("_internalId") on delete restrict on update restrict)"`,
204
+ );
205
+ });
206
+
207
+ test("throws error for add-foreign-key on existing table", () => {
208
+ expect(() =>
209
+ generator.compile(
210
+ [
211
+ {
212
+ type: "add-foreign-key",
213
+ table: "posts",
214
+ value: {
215
+ name: "posts_users_fk",
216
+ columns: ["authorId"],
217
+ referencedTable: "users",
218
+ referencedColumns: ["_internalId"],
219
+ },
220
+ },
221
+ ],
222
+ undefined,
223
+ ),
224
+ ).toThrow("SQLite doesn't support modifying foreign keys");
225
+ });
226
+
227
+ test("uses autoIncrement for internal-id columns", () => {
228
+ const statements = generator.compile(
229
+ [
230
+ {
231
+ type: "create-table",
232
+ name: "users",
233
+ columns: [
234
+ { name: "_internalId", type: "integer", isNullable: false, role: "internal-id" },
235
+ ],
236
+ },
237
+ ],
238
+ undefined,
239
+ );
240
+
241
+ expect(statements[0].sql).toMatchInlineSnapshot(`"PRAGMA defer_foreign_keys = ON"`);
242
+ expect(statements[1].sql).toMatchInlineSnapshot(
243
+ `"create table "users" ("_internalId" integer not null primary key autoincrement)"`,
244
+ );
245
+ });
246
+ });
247
+
248
+ describe("PreparedMigrations - MySQL", () => {
249
+ const coldKysely = createColdKysely("mysql");
250
+ const generator = new MySQLSQLGenerator(coldKysely, "mysql");
251
+
252
+ test("preprocess wraps with FK checks disabled", () => {
253
+ const operations = generator.preprocess([
254
+ {
255
+ type: "create-table",
256
+ name: "users",
257
+ columns: [{ name: "id", type: "string", isNullable: false, role: "external-id" }],
258
+ },
259
+ ]);
260
+
261
+ expect(operations.length).toBe(3);
262
+ expect(operations[0].type).toBe("custom");
263
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
264
+ expect((operations[0] as any).sql).toBe("SET FOREIGN_KEY_CHECKS = 0");
265
+ expect(operations[1].type).toBe("create-table");
266
+ expect(operations[2].type).toBe("custom");
267
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
268
+ expect((operations[2] as any).sql).toBe("SET FOREIGN_KEY_CHECKS = 1");
269
+ });
270
+
271
+ test("uses autoIncrement for internal-id columns", () => {
272
+ const statements = generator.compile(
273
+ [
274
+ {
275
+ type: "create-table",
276
+ name: "users",
277
+ columns: [
278
+ { name: "_internalId", type: "bigint", isNullable: false, role: "internal-id" },
279
+ ],
280
+ },
281
+ ],
282
+ undefined,
283
+ );
284
+
285
+ // MySQL wraps with FK checks, so we have 3 statements
286
+ expect(statements.length).toBe(3);
287
+ expect(statements[0].sql).toMatchInlineSnapshot(`"SET FOREIGN_KEY_CHECKS = 0"`);
288
+ expect(statements[1].sql).toMatchInlineSnapshot(
289
+ `"create table \`users\` (\`_internalId\` bigint not null primary key auto_increment)"`,
290
+ );
291
+ expect(statements[2].sql).toMatchInlineSnapshot(`"SET FOREIGN_KEY_CHECKS = 1"`);
292
+ });
293
+
294
+ test("returns undefined for TEXT column defaults", () => {
295
+ const defaultValue = generator.getDefaultValue({
296
+ name: "description",
297
+ type: "string",
298
+ isNullable: true,
299
+ role: "regular",
300
+ default: { value: "default text" },
301
+ });
302
+
303
+ expect(defaultValue).toBeUndefined();
304
+ });
305
+ });
306
+
307
+ describe("PreparedMigrations - Integration", () => {
308
+ test("createPreparedMigrations - execute with version tracking", async () => {
309
+ const executedStatements: string[] = [];
310
+ let transactionStarted = false;
311
+
312
+ // Create a mock driver that captures SQL statements
313
+ const mockDriver = {
314
+ async executeQuery(query: { sql: string }) {
315
+ executedStatements.push(query.sql);
316
+ return { rows: [] };
317
+ },
318
+ async transaction(
319
+ callback: (tx: {
320
+ executeQuery: (q: { sql: string }) => Promise<{ rows: [] }>;
321
+ }) => Promise<void>,
322
+ ) {
323
+ transactionStarted = true;
324
+ await callback({
325
+ async executeQuery(query: { sql: string }) {
326
+ executedStatements.push(query.sql);
327
+ return { rows: [] };
328
+ },
329
+ });
330
+ },
331
+ async destroy() {},
332
+ };
333
+
334
+ const prepared = createPreparedMigrations({
335
+ schema: testSchema,
336
+ namespace: "test",
337
+ database: "postgresql",
338
+ mapper: createTableNameMapper("test"),
339
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
340
+ driver: mockDriver as any,
341
+ });
342
+
343
+ await prepared.execute(0, 1);
344
+
345
+ expect(transactionStarted).toBe(true);
346
+ expect(executedStatements.length).toBe(2);
347
+ expect(executedStatements[0]).toMatchInlineSnapshot(
348
+ `"create table "users_test" ("id" varchar(30) not null unique, "name" text not null, "_internalId" bigserial not null primary key, "_version" integer default 0 not null)"`,
349
+ );
350
+ expect(executedStatements[1]).toMatchInlineSnapshot(
351
+ `"insert into "fragno_db_settings" ("id", "key", "value") values ('BflimUWc1NbCMMDD9SM3gQ', 'test.schema_version', '1')"`,
352
+ );
353
+ });
354
+
355
+ test("execute with updateVersionInMigration=false skips version update", async () => {
356
+ const executedStatements: string[] = [];
357
+
358
+ const mockDriver = {
359
+ async executeQuery(query: { sql: string }) {
360
+ executedStatements.push(query.sql);
361
+ return { rows: [] };
362
+ },
363
+ async transaction(
364
+ callback: (tx: {
365
+ executeQuery: (q: { sql: string }) => Promise<{ rows: [] }>;
366
+ }) => Promise<void>,
367
+ ) {
368
+ await callback({
369
+ async executeQuery(query: { sql: string }) {
370
+ executedStatements.push(query.sql);
371
+ return { rows: [] };
372
+ },
373
+ });
374
+ },
375
+ async destroy() {},
376
+ };
377
+
378
+ const prepared = createPreparedMigrations({
379
+ schema: testSchema,
380
+ namespace: "test",
381
+ database: "postgresql",
382
+ mapper: createTableNameMapper("test"),
383
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
384
+ driver: mockDriver as any,
385
+ });
386
+
387
+ await prepared.execute(0, 1, { updateVersionInMigration: false });
388
+
389
+ // Should only have the create table statement, no version update
390
+ expect(executedStatements.length).toBe(1);
391
+ expect(executedStatements[0]).toContain('create table "users_test"');
392
+ });
393
+
394
+ test("throws error for backward migration", async () => {
395
+ const mockDriver = {
396
+ async executeQuery() {
397
+ return { rows: [] };
398
+ },
399
+ async transaction() {},
400
+ async destroy() {},
401
+ };
402
+
403
+ const prepared = createPreparedMigrations({
404
+ schema: testSchema,
405
+ namespace: "test",
406
+ database: "postgresql",
407
+ mapper: createTableNameMapper("test"),
408
+ });
409
+
410
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
411
+ await expect(() => prepared.executeWithDriver(mockDriver as any, 2, 1)).rejects.toThrow(
412
+ "Cannot migrate backwards",
413
+ );
414
+ });
415
+
416
+ test("throws error for version beyond schema", async () => {
417
+ const mockDriver = {
418
+ async executeQuery() {
419
+ return { rows: [] };
420
+ },
421
+ async transaction() {},
422
+ async destroy() {},
423
+ };
424
+
425
+ const prepared = createPreparedMigrations({
426
+ schema: testSchema,
427
+ namespace: "test",
428
+ database: "postgresql",
429
+ mapper: createTableNameMapper("test"),
430
+ });
431
+
432
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
433
+ await expect(() => prepared.executeWithDriver(mockDriver as any, 0, 100)).rejects.toThrow(
434
+ "exceeds schema version",
435
+ );
436
+ });
437
+
438
+ test("returns early for same version (no statements executed)", async () => {
439
+ const executedStatements: string[] = [];
440
+
441
+ const mockDriver = {
442
+ async executeQuery(query: { sql: string }) {
443
+ executedStatements.push(query.sql);
444
+ return { rows: [] };
445
+ },
446
+ async transaction(
447
+ callback: (tx: {
448
+ executeQuery: (q: { sql: string }) => Promise<{ rows: [] }>;
449
+ }) => Promise<void>,
450
+ ) {
451
+ await callback({
452
+ async executeQuery(query: { sql: string }) {
453
+ executedStatements.push(query.sql);
454
+ return { rows: [] };
455
+ },
456
+ });
457
+ },
458
+ async destroy() {},
459
+ };
460
+
461
+ const prepared = createPreparedMigrations({
462
+ schema: testSchema,
463
+ namespace: "test",
464
+ database: "postgresql",
465
+ mapper: createTableNameMapper("test"),
466
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
467
+ driver: mockDriver as any,
468
+ });
469
+
470
+ await prepared.execute(2, 2);
471
+
472
+ // No statements should be executed
473
+ expect(executedStatements.length).toBe(0);
474
+ });
475
+
476
+ test("throws error when execute is called without driver", async () => {
477
+ const prepared = createPreparedMigrations({
478
+ schema: testSchema,
479
+ namespace: "test",
480
+ database: "postgresql",
481
+ mapper: createTableNameMapper("test"),
482
+ // No driver provided
483
+ });
484
+
485
+ await expect(() => prepared.execute(0, 1)).rejects.toThrow(
486
+ "Driver not provided. Cannot execute migration. Use `executeWithDriver` instead.",
487
+ );
488
+ });
489
+ });
490
+
491
+ describe("PreparedMigrations - Multi-step Migration Scenarios", () => {
492
+ test("PostgreSQL: migration 0 -> 2 (create users table and add age + indexes)", () => {
493
+ const prepared = createPreparedMigrations({
494
+ schema: testSchema,
495
+ namespace: "test",
496
+ database: "postgresql",
497
+ mapper: createTableNameMapper("test"),
498
+ });
499
+
500
+ const sql = prepared.getSQL(0, 2, { updateVersionInMigration: true });
501
+ expect(sql).toMatchInlineSnapshot(`
502
+ "create table "users_test" ("id" varchar(30) not null unique, "name" text not null, "_internalId" bigserial not null primary key, "_version" integer default 0 not null);
503
+
504
+ alter table "users_test" add column "age" integer;
505
+
506
+ create index "name_idx_users_test" on "users_test" ("name");
507
+
508
+ create index "age_idx_users_test" on "users_test" ("age");
509
+
510
+ insert into "fragno_db_settings" ("id", "key", "value") values ('BflimUWc1NbCMMDD9SM3gQ', 'test.schema_version', '2');"
511
+ `);
512
+ });
513
+
514
+ test("PostgreSQL: migration 0 -> 4 (full schema with posts and FK)", () => {
515
+ const prepared = createPreparedMigrations({
516
+ schema: testSchema,
517
+ namespace: "test",
518
+ database: "postgresql",
519
+ mapper: createTableNameMapper("test"),
520
+ });
521
+
522
+ const sql = prepared.getSQL(0, 4, { updateVersionInMigration: true });
523
+ expect(sql).toMatchInlineSnapshot(`
524
+ "create table "users_test" ("id" varchar(30) not null unique, "name" text not null, "_internalId" bigserial not null primary key, "_version" integer default 0 not null);
525
+
526
+ alter table "users_test" add column "age" integer;
527
+
528
+ create index "name_idx_users_test" on "users_test" ("name");
529
+
530
+ create index "age_idx_users_test" on "users_test" ("age");
531
+
532
+ create table "posts_test" ("id" varchar(30) not null unique, "title" text not null, "authorId" bigint not null, "_internalId" bigserial not null primary key, "_version" integer default 0 not null);
533
+
534
+ alter table "posts_test" add constraint "posts_users_author_fk" foreign key ("authorId") references "users_test" ("_internalId") on delete restrict on update restrict;
535
+
536
+ insert into "fragno_db_settings" ("id", "key", "value") values ('BflimUWc1NbCMMDD9SM3gQ', 'test.schema_version', '4');"
537
+ `);
538
+ });
539
+
540
+ test("PostgreSQL: migration 1 -> 2 (add age column and indexes only)", () => {
541
+ const prepared = createPreparedMigrations({
542
+ schema: testSchema,
543
+ namespace: "test",
544
+ database: "postgresql",
545
+ mapper: createTableNameMapper("test"),
546
+ });
547
+
548
+ const sql = prepared.getSQL(1, 2, { updateVersionInMigration: true });
549
+ expect(sql).toMatchInlineSnapshot(`
550
+ "alter table "users_test" add column "age" integer;
551
+
552
+ create index "name_idx_users_test" on "users_test" ("name");
553
+
554
+ create index "age_idx_users_test" on "users_test" ("age");
555
+
556
+ update "fragno_db_settings" set "value" = '2' where "key" = 'test.schema_version';"
557
+ `);
558
+ });
559
+
560
+ test("PostgreSQL: migration 2 -> 3 (add posts table)", () => {
561
+ const prepared = createPreparedMigrations({
562
+ schema: testSchema,
563
+ namespace: "test",
564
+ database: "postgresql",
565
+ mapper: createTableNameMapper("test"),
566
+ });
567
+
568
+ const sql = prepared.getSQL(2, 3, { updateVersionInMigration: true });
569
+ expect(sql).toMatchInlineSnapshot(`
570
+ "create table "posts_test" ("id" varchar(30) not null unique, "title" text not null, "authorId" bigint not null, "_internalId" bigserial not null primary key, "_version" integer default 0 not null);
571
+
572
+ update "fragno_db_settings" set "value" = '3' where "key" = 'test.schema_version';"
573
+ `);
574
+ });
575
+
576
+ test("SQLite: migration 0 -> 4 with FK merging", () => {
577
+ const prepared = createPreparedMigrations({
578
+ schema: testSchema,
579
+ namespace: "test",
580
+ database: "sqlite",
581
+ mapper: createTableNameMapper("test"),
582
+ });
583
+
584
+ const sql = prepared.getSQL(0, 4, { updateVersionInMigration: true });
585
+ expect(sql).toMatchInlineSnapshot(`
586
+ "PRAGMA defer_foreign_keys = ON;
587
+
588
+ create table "users_test" ("id" text not null unique, "name" text not null, "_internalId" integer not null primary key autoincrement, "_version" integer default 0 not null);
589
+
590
+ alter table "users_test" add column "age" integer;
591
+
592
+ create index "name_idx_users_test" on "users_test" ("name");
593
+
594
+ create index "age_idx_users_test" on "users_test" ("age");
595
+
596
+ create table "posts_test" ("id" text not null unique, "title" text not null, "authorId" integer not null, "_internalId" integer not null primary key autoincrement, "_version" integer default 0 not null, constraint "posts_users_author_fk" foreign key ("authorId") references "users_test" ("_internalId") on delete restrict on update restrict);
597
+
598
+ insert into "fragno_db_settings" ("id", "key", "value") values ('BflimUWc1NbCMMDD9SM3gQ', 'test.schema_version', '4');"
599
+ `);
600
+ });
601
+
602
+ test("MySQL: migration 0 -> 4 with FK checks disabled", () => {
603
+ const prepared = createPreparedMigrations({
604
+ schema: testSchema,
605
+ namespace: "test",
606
+ database: "mysql",
607
+ mapper: createTableNameMapper("test"),
608
+ });
609
+
610
+ const sql = prepared.getSQL(0, 4, { updateVersionInMigration: true });
611
+ expect(sql).toMatchInlineSnapshot(`
612
+ "SET FOREIGN_KEY_CHECKS = 0;
613
+
614
+ create table \`users_test\` (\`id\` varchar(30) not null unique, \`name\` text not null, \`_internalId\` bigint not null primary key auto_increment, \`_version\` integer default 0 not null);
615
+
616
+ alter table \`users_test\` add column \`age\` integer;
617
+
618
+ create index \`name_idx_users_test\` on \`users_test\` (\`name\`);
619
+
620
+ create index \`age_idx_users_test\` on \`users_test\` (\`age\`);
621
+
622
+ create table \`posts_test\` (\`id\` varchar(30) not null unique, \`title\` text not null, \`authorId\` bigint not null, \`_internalId\` bigint not null primary key auto_increment, \`_version\` integer default 0 not null);
623
+
624
+ alter table \`posts_test\` add constraint \`posts_users_author_fk\` foreign key (\`authorId\`) references \`users_test\` (\`_internalId\`) on delete restrict on update restrict;
625
+
626
+ SET FOREIGN_KEY_CHECKS = 1;
627
+
628
+ insert into \`fragno_db_settings\` (\`id\`, \`key\`, \`value\`) values ('BflimUWc1NbCMMDD9SM3gQ', 'test.schema_version', '4');"
629
+ `);
630
+ });
631
+
632
+ test("compile returns CompiledMigration with statements array", () => {
633
+ const prepared = createPreparedMigrations({
634
+ schema: testSchema,
635
+ namespace: "test",
636
+ database: "postgresql",
637
+ mapper: createTableNameMapper("test"),
638
+ });
639
+
640
+ const compiled = prepared.compile(0, 2, { updateVersionInMigration: true });
641
+ expect(compiled.statements).toBeDefined();
642
+ expect(compiled.statements.length).toBeGreaterThan(0);
643
+ // Should have: create table, add column, 2 indexes, version insert
644
+ expect(compiled.statements.length).toBe(5);
645
+ });
646
+
647
+ test("getSQL with updateVersionInMigration=false excludes version statement", () => {
648
+ const prepared = createPreparedMigrations({
649
+ schema: testSchema,
650
+ namespace: "test",
651
+ database: "postgresql",
652
+ mapper: createTableNameMapper("test"),
653
+ });
654
+
655
+ const sql = prepared.getSQL(0, 1, { updateVersionInMigration: false });
656
+ expect(sql).not.toContain("fragno_db_settings");
657
+ expect(sql).toMatchInlineSnapshot(
658
+ `"create table "users_test" ("id" varchar(30) not null unique, "name" text not null, "_internalId" bigserial not null primary key, "_version" integer default 0 not null);"`,
659
+ );
660
+ });
661
+ });