@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
@@ -1,800 +0,0 @@
1
- import { test, expect, describe, expectTypeOf } from "vitest";
2
- import { defineFragmentWithDatabase, type FragnoPublicConfigWithDatabase } from "./fragment";
3
- import {
4
- createFragment,
5
- instantiateFragment,
6
- type FragnoPublicClientConfig,
7
- defineRoute,
8
- defineRoutes,
9
- } from "@fragno-dev/core";
10
- import { createClientBuilder } from "@fragno-dev/core/client";
11
- import { schema, idColumn, column } from "./schema/create";
12
- import type { AbstractQuery } from "./query/query";
13
- import type { DatabaseAdapter } from "./mod";
14
- import type { DatabaseRequestThisContext } from "./fragment";
15
- import { z } from "zod";
16
- import {
17
- fragnoDatabaseAdapterNameFakeSymbol,
18
- fragnoDatabaseAdapterVersionFakeSymbol,
19
- } from "./adapters/adapters";
20
-
21
- type Empty = Record<never, never>;
22
-
23
- const mockDatabaseAdapter: DatabaseAdapter = {
24
- [fragnoDatabaseAdapterNameFakeSymbol]: "mock",
25
- [fragnoDatabaseAdapterVersionFakeSymbol]: 0,
26
- close: () => Promise.resolve(),
27
- createQueryEngine: () => {
28
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
- return {} as any;
30
- },
31
- getSchemaVersion: () => Promise.resolve("0"),
32
- createMigrationEngine: () => {
33
- throw new Error("Not implemented");
34
- },
35
- createSchemaGenerator: () => {
36
- throw new Error("Not implemented");
37
- },
38
- createTableNameMapper: (namespace: string) => ({
39
- toPhysical: (logicalName: string) => `${logicalName}_${namespace}`,
40
- toLogical: (physicalName: string) => physicalName.replace(`_${namespace}`, ""),
41
- }),
42
- isConnectionHealthy: () => Promise.resolve(true),
43
- };
44
-
45
- describe("DatabaseFragmentBuilder", () => {
46
- describe("Type inference", () => {
47
- test("defineFragmentWithDatabase infers schema type from withDatabase", () => {
48
- const _testSchema = schema((s) =>
49
- s.addTable("users", (t) =>
50
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
51
- ),
52
- );
53
-
54
- const _fragment = defineFragmentWithDatabase("test").withDatabase(_testSchema);
55
-
56
- // Type check that withDatabase returns a builder with the schema
57
- expectTypeOf(_fragment.definition.name).toEqualTypeOf<string>();
58
- });
59
-
60
- test("withDatabase correctly transforms schema type", () => {
61
- const _testSchema1 = schema((s) =>
62
- s.addTable("users", (t) =>
63
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
64
- ),
65
- );
66
-
67
- const _testSchema2 = schema((s) =>
68
- s.addTable("posts", (t) =>
69
- t.addColumn("id", idColumn()).addColumn("title", column("string")),
70
- ),
71
- );
72
-
73
- const fragment1 = defineFragmentWithDatabase("test").withDatabase(_testSchema1);
74
- const fragment2 = fragment1.withDatabase(_testSchema2);
75
-
76
- // Type check that we can chain withDatabase
77
- expectTypeOf(fragment1.definition.name).toEqualTypeOf<string>();
78
- expectTypeOf(fragment2.definition.name).toEqualTypeOf<string>();
79
- });
80
-
81
- test("withDependencies has access to config, fragnoConfig, and orm", () => {
82
- const _testSchema = schema((s) =>
83
- s.addTable("users", (t) =>
84
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
85
- ),
86
- );
87
-
88
- const _fragment = defineFragmentWithDatabase("test")
89
- .withDatabase(_testSchema)
90
- .withDependencies(({ fragnoConfig, orm }) => {
91
- expectTypeOf(fragnoConfig).toEqualTypeOf<{ mountRoute?: string }>();
92
- expectTypeOf(orm).toEqualTypeOf<AbstractQuery<typeof _testSchema>>();
93
-
94
- return {
95
- userService: {
96
- getUser: async (id: string) => ({ id, name: "Test" }),
97
- },
98
- };
99
- });
100
-
101
- // Type check that the fragment has the expected structure
102
- expectTypeOf(_fragment.definition.name).toEqualTypeOf<string>();
103
- });
104
-
105
- test("providesService has access to config, fragnoConfig, deps, and db", () => {
106
- const _testSchema = schema((s) =>
107
- s.addTable("users", (t) =>
108
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
109
- ),
110
- );
111
-
112
- const _fragment = defineFragmentWithDatabase("test")
113
- .withDatabase(_testSchema)
114
- .withDependencies(({ orm }) => ({
115
- userRepo: {
116
- create: (name: string) => orm.create("users", { name }),
117
- },
118
- }))
119
- .providesService(({ fragnoConfig, deps, db }) => {
120
- expectTypeOf(fragnoConfig).toEqualTypeOf<{ mountRoute?: string }>();
121
- expectTypeOf(deps).toEqualTypeOf<{
122
- userRepo: {
123
- create: (name: string) => ReturnType<AbstractQuery<typeof _testSchema>["create"]>;
124
- };
125
- }>();
126
- expectTypeOf(db).toEqualTypeOf<AbstractQuery<typeof _testSchema>>();
127
-
128
- return {
129
- cacheService: {
130
- get: (_key: string) => "cached",
131
- },
132
- };
133
- });
134
-
135
- // Type check that the fragment has the expected structure
136
- expectTypeOf(_fragment.definition.name).toEqualTypeOf<string>();
137
- });
138
- });
139
-
140
- describe("Builder pattern", () => {
141
- test("Builder methods return new instances", () => {
142
- const _testSchema1 = schema((s) =>
143
- s.addTable("users", (t) =>
144
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
145
- ),
146
- );
147
-
148
- const _testSchema2 = schema((s) =>
149
- s.addTable("posts", (t) =>
150
- t.addColumn("id", idColumn()).addColumn("title", column("string")),
151
- ),
152
- );
153
-
154
- const builder1 = defineFragmentWithDatabase("test");
155
- const builder2 = builder1.withDatabase(_testSchema1);
156
- const builder3 = builder2.withDatabase(_testSchema2);
157
- const builder4 = builder3.withDependencies(() => ({ dep1: "value1" }));
158
- const builder5 = builder4.providesService(({ defineService }) =>
159
- defineService({ service1: "value1" }),
160
- );
161
-
162
- expect(builder1).not.toBe(builder2);
163
- expect(builder2).not.toBe(builder3);
164
- expect(builder3).not.toBe(builder4);
165
- expect(builder4).not.toBe(builder5);
166
- });
167
-
168
- test("Each builder step preserves previous configuration", () => {
169
- const _testSchema = schema((s) =>
170
- s.addTable("users", (t) =>
171
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
172
- ),
173
- );
174
-
175
- const fragment = defineFragmentWithDatabase("my-db-lib")
176
- .withDatabase(_testSchema)
177
- .withDependencies(({ orm }) => ({
178
- client: "test client",
179
- orm,
180
- }))
181
- .providesService(({ deps, defineService }) =>
182
- defineService({
183
- service: `Service using ${deps.client}`,
184
- }),
185
- );
186
-
187
- expect(fragment.definition.name).toBe("my-db-lib");
188
- expect(fragment.definition.dependencies).toBeDefined();
189
- expect(fragment.definition.services).toBeDefined();
190
- });
191
- });
192
-
193
- describe("Fragment instantiation", () => {
194
- test("createFragment works with database adapter", async () => {
195
- const testSchema = schema((s) =>
196
- s.addTable("users", (t) =>
197
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
198
- ),
199
- );
200
-
201
- const fragmentDef = defineFragmentWithDatabase("test-db")
202
- .withDatabase(testSchema)
203
- .withDependencies(({ orm }) => ({
204
- userService: {
205
- createUser: (name: string) => orm.create("users", { name }),
206
- },
207
- }))
208
- .providesService(({ defineService }) =>
209
- defineService({
210
- logger: { log: (s: string) => console.log(s) },
211
- }),
212
- );
213
-
214
- const options: FragnoPublicConfigWithDatabase = {
215
- databaseAdapter: mockDatabaseAdapter,
216
- };
217
-
218
- const fragment = createFragment(fragmentDef, {}, [], options);
219
-
220
- expect(fragment.config.name).toBe("test-db");
221
- expect(fragment.deps).toHaveProperty("userService");
222
- expect(fragment.services).toHaveProperty("logger");
223
- });
224
-
225
- test("throws error when database adapter is missing from dependencies", () => {
226
- const testSchema = schema((s) =>
227
- s.addTable("users", (t) =>
228
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
229
- ),
230
- );
231
-
232
- const fragmentDef = defineFragmentWithDatabase("test-db")
233
- .withDatabase(testSchema)
234
- .withDependencies(() => ({
235
- service: "test",
236
- }));
237
-
238
- expect(() => {
239
- // @ts-expect-error - Test case
240
- createFragment(fragmentDef, {}, [], {});
241
- }).toThrow(/requires a database adapter/);
242
- });
243
-
244
- test("throws error when database adapter is missing from services", () => {
245
- const testSchema = schema((s) =>
246
- s.addTable("users", (t) =>
247
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
248
- ),
249
- );
250
-
251
- const fragmentDef = defineFragmentWithDatabase("test-db")
252
- .withDatabase(testSchema)
253
- .withDependencies(() => ({
254
- service: "test",
255
- }))
256
- .providesService(({ defineService }) =>
257
- defineService({
258
- serviceValue: "test",
259
- }),
260
- );
261
-
262
- const options: FragnoPublicConfigWithDatabase = {
263
- databaseAdapter: mockDatabaseAdapter,
264
- };
265
-
266
- // Services are called after dependencies, so this should work
267
- const fragment = createFragment(fragmentDef, {}, [], options);
268
- expect(fragment.services).toHaveProperty("serviceValue");
269
- });
270
-
271
- test("throws error when schema is not provided via withDatabase", () => {
272
- const fragmentDef = defineFragmentWithDatabase<Empty>("test-db").withDependencies(() => ({
273
- service: "test",
274
- }));
275
-
276
- const options: FragnoPublicConfigWithDatabase = {
277
- databaseAdapter: mockDatabaseAdapter,
278
- };
279
-
280
- expect(() => {
281
- createFragment(fragmentDef, {}, [], options);
282
- }).toThrow(/requires a schema/);
283
- });
284
-
285
- test("orm is accessible in both dependencies and services", async () => {
286
- const testSchema = schema((s) =>
287
- s.addTable("users", (t) =>
288
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
289
- ),
290
- );
291
-
292
- let depsOrm: AbstractQuery<typeof testSchema> | undefined;
293
- let servicesOrm: AbstractQuery<typeof testSchema> | undefined;
294
-
295
- const fragmentDef = defineFragmentWithDatabase("test-db")
296
- .withDatabase(testSchema)
297
- .withDependencies(({ orm }) => {
298
- depsOrm = orm;
299
- return { dep: "value" };
300
- })
301
- .providesService(({ db }) => {
302
- servicesOrm = db;
303
- return { service: "value" };
304
- });
305
-
306
- const options: FragnoPublicConfigWithDatabase = {
307
- databaseAdapter: mockDatabaseAdapter,
308
- };
309
-
310
- createFragment(fragmentDef, {}, [], options);
311
-
312
- expect(depsOrm).toBeDefined();
313
- expect(servicesOrm).toBeDefined();
314
- });
315
- });
316
-
317
- describe("Client builder integration", () => {
318
- test("createClientBuilder works with database fragment", () => {
319
- const testSchema = schema((s) =>
320
- s.addTable("users", (t) =>
321
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
322
- ),
323
- );
324
-
325
- const fragmentDef = defineFragmentWithDatabase("test-db")
326
- .withDatabase(testSchema)
327
- .providesService(({ db }) => {
328
- return {
329
- getUserById: (id: string) =>
330
- db.findFirst("users", (b) => b.whereIndex("primary", (eb) => eb("id", "=", id))),
331
- };
332
- });
333
-
334
- const routes = [
335
- defineRoute({
336
- method: "GET",
337
- path: "/users",
338
- outputSchema: z.array(
339
- z.object({
340
- id: z.string(),
341
- name: z.string(),
342
- }),
343
- ),
344
- handler: async (_ctx, { json }) => json([]),
345
- }),
346
- ] as const;
347
-
348
- const clientConfig: FragnoPublicClientConfig = {
349
- baseUrl: "http://localhost:3000",
350
- };
351
-
352
- const builder = createClientBuilder(fragmentDef, clientConfig, routes);
353
-
354
- expect(builder).toBeDefined();
355
- expectTypeOf(builder.createHook).toBeFunction();
356
-
357
- const useUsers = builder.createHook("/users");
358
- expect(useUsers).toHaveProperty("route");
359
- expect(useUsers.route.path).toBe("/users");
360
- });
361
- });
362
-
363
- describe("Route handler this context", () => {
364
- test("this context has database functionality for database fragments", () => {
365
- const testSchema = schema((s) =>
366
- s.addTable("users", (t) =>
367
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
368
- ),
369
- );
370
-
371
- const fragmentDef = defineFragmentWithDatabase("test-db").withDatabase(testSchema);
372
-
373
- // Use defineRoutes with the fragment builder to get proper this typing
374
- const routesFactory = defineRoutes(fragmentDef).create(({ defineRoute }) => {
375
- return [
376
- defineRoute({
377
- method: "GET",
378
- path: "/test",
379
- handler: async function (_, { json }) {
380
- // Type check that this has getUnitOfWork method
381
- expectTypeOf(this).toHaveProperty("getUnitOfWork");
382
- expectTypeOf(this.getUnitOfWork).toBeFunction();
383
- return json({ ok: true });
384
- },
385
- }),
386
- ];
387
- });
388
-
389
- const options: FragnoPublicConfigWithDatabase = {
390
- databaseAdapter: mockDatabaseAdapter,
391
- };
392
-
393
- const fragment = createFragment(fragmentDef, {}, [routesFactory], options);
394
- expect(fragment).toBeDefined();
395
- });
396
-
397
- test("database fragment routes have access to database this context", async () => {
398
- const testSchema = schema((s) =>
399
- s.addTable("users", (t) =>
400
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
401
- ),
402
- );
403
-
404
- const fragmentDef = defineFragmentWithDatabase("test-db").withDatabase(testSchema);
405
-
406
- // Use defineRoutes with fragment builder reference for proper this typing
407
- const routesFactory = defineRoutes(fragmentDef).create(({ defineRoute }) => {
408
- return [
409
- defineRoute({
410
- method: "GET",
411
- path: "/test-uow",
412
- outputSchema: z.object({ result: z.string() }),
413
- handler: async function (_, { json }) {
414
- // The type system ensures 'this' is DatabaseRequestThisContext
415
- // which has getUnitOfWork method available
416
- expectTypeOf(this).toHaveProperty("getUnitOfWork");
417
- expectTypeOf(this.getUnitOfWork).toBeFunction();
418
- return json({ result: "ok" });
419
- },
420
- }),
421
- ];
422
- });
423
-
424
- const options: FragnoPublicConfigWithDatabase = {
425
- databaseAdapter: mockDatabaseAdapter,
426
- };
427
-
428
- const fragment = createFragment(fragmentDef, {}, [routesFactory], options);
429
-
430
- // Verify the fragment was created successfully
431
- expect(fragment).toBeDefined();
432
- expect(fragment.config.name).toBe("test-db");
433
- });
434
- });
435
-
436
- describe("providesService with this context", () => {
437
- test("providesService functions have access to DatabaseRequestThisContext", () => {
438
- const testSchema = schema((s) =>
439
- s.addTable("users", (t) =>
440
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
441
- ),
442
- );
443
-
444
- // Define a service with a function that uses 'this'
445
- const userService = {
446
- getCurrentUser: function (this: DatabaseRequestThisContext, userId: string) {
447
- // Type check that this has getUnitOfWork method
448
- expectTypeOf(this).toHaveProperty("getUnitOfWork");
449
- expectTypeOf(this.getUnitOfWork).toBeFunction();
450
- return { id: userId, name: "Test User" };
451
- },
452
- };
453
-
454
- // This should compile without errors because the function has the correct this type
455
- const fragmentDef = defineFragmentWithDatabase("test-service")
456
- .withDatabase(testSchema)
457
- .providesService("userService", ({ defineService }) => defineService(userService));
458
-
459
- expect(fragmentDef).toBeDefined();
460
- expect(fragmentDef.definition.providedServices).toBeDefined();
461
- expect(typeof fragmentDef.definition.providedServices).toBe("object");
462
- });
463
-
464
- test("providesService binds services correctly", async () => {
465
- const testSchema = schema((s) =>
466
- s.addTable("users", (t) =>
467
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
468
- ),
469
- );
470
-
471
- const userService = {
472
- testMethod: function (this: DatabaseRequestThisContext) {
473
- // At runtime, this should have access to getUnitOfWork
474
- const uow = this.getUnitOfWork();
475
- return { hasUow: !!uow };
476
- },
477
- };
478
-
479
- const fragmentDef = defineFragmentWithDatabase("test-service-runtime")
480
- .withDatabase(testSchema)
481
- .providesService("userService", ({ defineService }) => defineService(userService));
482
-
483
- // Verify the definition has the provided service (now it's an object with factory functions)
484
- expect(fragmentDef.definition.providedServices).toBeDefined();
485
- expect(typeof fragmentDef.definition.providedServices).toBe("object");
486
-
487
- // Type checking is the main test here - if the service functions
488
- // don't have the correct `this` type, TypeScript will error at compile time
489
- });
490
-
491
- test("providesService with direct object (no factory)", () => {
492
- const testSchema = schema((s) =>
493
- s.addTable("users", (t) =>
494
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
495
- ),
496
- );
497
-
498
- const fragmentDef = defineFragmentWithDatabase("test-direct")
499
- .withDatabase(testSchema)
500
- .providesService("helpers", {
501
- slugify: (text: string) => text.toLowerCase().replace(/\s+/g, "-"),
502
- capitalize: (text: string) => text.charAt(0).toUpperCase() + text.slice(1),
503
- });
504
-
505
- const options: FragnoPublicConfigWithDatabase = {
506
- databaseAdapter: mockDatabaseAdapter,
507
- };
508
-
509
- const fragment = createFragment(fragmentDef, {}, [], options);
510
-
511
- expect(fragment.services.helpers).toBeDefined();
512
- expect(fragment.services.helpers.slugify("Hello World")).toBe("hello-world");
513
- expect(fragment.services.helpers.capitalize("hello")).toBe("Hello");
514
- });
515
-
516
- test("providesService with 0-arity factory", () => {
517
- const testSchema = schema((s) =>
518
- s.addTable("users", (t) =>
519
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
520
- ),
521
- );
522
-
523
- const fragmentDef = defineFragmentWithDatabase("test-zero-arity")
524
- .withDatabase(testSchema)
525
- .providesService("constants", () => ({
526
- MAX_USERS: 100,
527
- MIN_PASSWORD_LENGTH: 8,
528
- }));
529
-
530
- const options: FragnoPublicConfigWithDatabase = {
531
- databaseAdapter: mockDatabaseAdapter,
532
- };
533
-
534
- const fragment = createFragment(fragmentDef, {}, [], options);
535
-
536
- expect(fragment.services.constants).toBeDefined();
537
- expect(fragment.services.constants.MAX_USERS).toBe(100);
538
- expect(fragment.services.constants.MIN_PASSWORD_LENGTH).toBe(8);
539
- });
540
-
541
- test("chaining multiple provided services", () => {
542
- const testSchema = schema((s) =>
543
- s.addTable("users", (t) =>
544
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
545
- ),
546
- );
547
-
548
- const fragmentDef = defineFragmentWithDatabase("test-chaining")
549
- .withDatabase(testSchema)
550
- .providesService("logger", {
551
- log: (msg: string) => console.log(msg),
552
- })
553
- .providesService("validator", () => ({
554
- validate: (value: string) => value.length > 0,
555
- }))
556
- .providesService("formatter", () => ({
557
- format: (value: string) => value.trim(),
558
- }));
559
-
560
- const options: FragnoPublicConfigWithDatabase = {
561
- databaseAdapter: mockDatabaseAdapter,
562
- };
563
-
564
- const fragment = createFragment(fragmentDef, {}, [], options);
565
-
566
- expect(fragment.services.logger).toBeDefined();
567
- expect(fragment.services.validator).toBeDefined();
568
- expect(fragment.services.formatter).toBeDefined();
569
- expect(fragment.services.logger.log).toBeDefined();
570
- expect(fragment.services.validator.validate).toBeDefined();
571
- expect(fragment.services.formatter.format).toBeDefined();
572
- });
573
- });
574
-
575
- describe("usesService", () => {
576
- test("should declare required service", () => {
577
- const testSchema = schema((s) =>
578
- s.addTable("users", (t) =>
579
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
580
- ),
581
- );
582
-
583
- interface IEmailService {
584
- sendEmail(to: string, subject: string): Promise<void>;
585
- }
586
-
587
- const fragment = defineFragmentWithDatabase("test-uses-service")
588
- .withDatabase(testSchema)
589
- .usesService<"email", IEmailService>("email");
590
-
591
- expect(fragment.definition.usedServices).toBeDefined();
592
- expect(fragment.definition.usedServices?.email).toEqual({ name: "email", required: true });
593
- });
594
-
595
- test("should declare optional service", () => {
596
- const testSchema = schema((s) =>
597
- s.addTable("users", (t) =>
598
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
599
- ),
600
- );
601
-
602
- interface ILogger {
603
- log(message: string): void;
604
- }
605
-
606
- const fragment = defineFragmentWithDatabase("test-optional-service")
607
- .withDatabase(testSchema)
608
- .usesService<"logger", ILogger>("logger", { optional: true });
609
-
610
- expect(fragment.definition.usedServices).toBeDefined();
611
- expect(fragment.definition.usedServices?.logger).toEqual({ name: "logger", required: false });
612
- });
613
-
614
- test("should throw when required service not provided", () => {
615
- const testSchema = schema((s) =>
616
- s.addTable("users", (t) =>
617
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
618
- ),
619
- );
620
-
621
- interface IEmailService {
622
- sendEmail(to: string, subject: string): Promise<void>;
623
- }
624
-
625
- const fragment = defineFragmentWithDatabase("test-required")
626
- .withDatabase(testSchema)
627
- .usesService<"email", IEmailService>("email");
628
-
629
- const options: FragnoPublicConfigWithDatabase = {
630
- databaseAdapter: mockDatabaseAdapter,
631
- };
632
-
633
- expect(() => {
634
- createFragment(fragment, {}, [], options);
635
- }).toThrow("Fragment 'test-required' requires service 'email' but it was not provided");
636
- });
637
-
638
- test("should not throw when optional service not provided", () => {
639
- const testSchema = schema((s) =>
640
- s.addTable("users", (t) =>
641
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
642
- ),
643
- );
644
-
645
- interface ILogger {
646
- log(message: string): void;
647
- }
648
-
649
- const fragment = defineFragmentWithDatabase("test-optional")
650
- .withDatabase(testSchema)
651
- .usesService<"logger", ILogger>("logger", { optional: true });
652
-
653
- const options: FragnoPublicConfigWithDatabase = {
654
- databaseAdapter: mockDatabaseAdapter,
655
- };
656
-
657
- expect(() => {
658
- createFragment(fragment, {}, [], options);
659
- }).not.toThrow();
660
- });
661
-
662
- test("provided service can access used services", () => {
663
- const testSchema = schema((s) =>
664
- s.addTable("users", (t) =>
665
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
666
- ),
667
- );
668
-
669
- interface IEmailService {
670
- sendEmail(to: string, subject: string): Promise<void>;
671
- }
672
-
673
- const emailImpl: IEmailService = {
674
- sendEmail: async () => {},
675
- };
676
-
677
- const fragment = defineFragmentWithDatabase("test-deps")
678
- .withDatabase(testSchema)
679
- .usesService<"email", IEmailService>("email")
680
- .providesService(({ deps }) => ({
681
- notifyUser: async (userId: string) => {
682
- await deps.email.sendEmail(userId, "Notification");
683
- },
684
- }));
685
-
686
- const options: FragnoPublicConfigWithDatabase = {
687
- databaseAdapter: mockDatabaseAdapter,
688
- };
689
-
690
- const instance = createFragment(fragment, {}, [], options, { email: emailImpl });
691
-
692
- expect(instance.services.notifyUser).toBeDefined();
693
- expect(typeof instance.services.notifyUser).toBe("function");
694
- });
695
- });
696
-
697
- describe("FragmentInstantiationBuilder with database fragments", () => {
698
- test("works with database fragments using builder API", () => {
699
- const testSchema = schema((s) =>
700
- s.addTable("users", (t) =>
701
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
702
- ),
703
- );
704
-
705
- const fragmentDef = defineFragmentWithDatabase("test-builder")
706
- .withDatabase(testSchema)
707
- .withDependencies(({ orm }) => ({
708
- userService: {
709
- createUser: (name: string) => orm.create("users", { name }),
710
- },
711
- }))
712
- .providesService(({ defineService }) =>
713
- defineService({
714
- logger: { log: (s: string) => console.log(s) },
715
- }),
716
- );
717
-
718
- const fragment = instantiateFragment(fragmentDef)
719
- .withConfig({})
720
- .withOptions({ databaseAdapter: mockDatabaseAdapter })
721
- .build();
722
-
723
- expect(fragment.config.name).toBe("test-builder");
724
- expect(fragment.deps).toHaveProperty("userService");
725
- expect(fragment.services).toHaveProperty("logger");
726
- });
727
-
728
- test("builder works with routes and database adapter", () => {
729
- const testSchema = schema((s) =>
730
- s.addTable("users", (t) =>
731
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
732
- ),
733
- );
734
-
735
- const fragmentDef = defineFragmentWithDatabase("test-routes")
736
- .withDatabase(testSchema)
737
- .providesService(({ db }) => ({
738
- getUserById: (id: string) =>
739
- db.findFirst("users", (b) => b.whereIndex("primary", (eb) => eb("id", "=", id))),
740
- }));
741
-
742
- const route = defineRoute({
743
- method: "GET",
744
- path: "/users",
745
- outputSchema: z.array(
746
- z.object({
747
- id: z.string(),
748
- name: z.string(),
749
- }),
750
- ),
751
- handler: async (_ctx, { json }) => json([]),
752
- });
753
-
754
- const fragment = instantiateFragment(fragmentDef)
755
- .withConfig({})
756
- .withRoutes([route])
757
- .withOptions({ databaseAdapter: mockDatabaseAdapter })
758
- .build();
759
-
760
- expect(fragment.config.name).toBe("test-routes");
761
- expect(fragment.services).toHaveProperty("getUserById");
762
- expect(fragment.config.routes).toHaveLength(1);
763
- expect(fragment.config.routes[0].path).toBe("/users");
764
- });
765
-
766
- test("builder works with used services in database fragments", () => {
767
- const testSchema = schema((s) =>
768
- s.addTable("users", (t) =>
769
- t.addColumn("id", idColumn()).addColumn("name", column("string")),
770
- ),
771
- );
772
-
773
- interface IEmailService {
774
- sendEmail(to: string, subject: string): Promise<void>;
775
- }
776
-
777
- const emailImpl: IEmailService = {
778
- sendEmail: async () => {},
779
- };
780
-
781
- const fragmentDef = defineFragmentWithDatabase("test-services")
782
- .withDatabase(testSchema)
783
- .usesService<"email", IEmailService>("email")
784
- .providesService(({ deps }) => ({
785
- notifyUser: async (userId: string) => {
786
- await deps.email.sendEmail(userId, "Notification");
787
- },
788
- }));
789
-
790
- const fragment = instantiateFragment(fragmentDef)
791
- .withConfig({})
792
- .withOptions({ databaseAdapter: mockDatabaseAdapter })
793
- .withServices({ email: emailImpl })
794
- .build();
795
-
796
- expect(fragment.services.notifyUser).toBeDefined();
797
- expect(fragment.services.email).toBeDefined();
798
- });
799
- });
800
- });