@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,811 +0,0 @@
1
- import { Kysely, PostgresDialect } from "kysely";
2
- import { describe, it, beforeAll, assert, expect } from "vitest";
3
- import { column, idColumn, referenceColumn, schema } from "../../schema/create";
4
- import type { Kysely as KyselyType, PostgresDialectConfig } from "kysely";
5
- import { UnitOfWork, type UOWDecoder } from "../../query/unit-of-work";
6
- import { createKyselyUOWCompiler } from "./kysely-uow-compiler";
7
- import type { ConnectionPool } from "../../shared/connection-pool";
8
- import { createKyselyConnectionPool } from "./kysely-connection-pool";
9
-
10
- describe("kysely-uow-joins", () => {
11
- const userSchema = schema((s) => {
12
- return (
13
- s
14
- .addTable("users", (t) => {
15
- return t
16
- .addColumn("id", idColumn())
17
- .addColumn("name", column("string"))
18
- .addColumn("email", column("string"))
19
- .addColumn("invitedBy", referenceColumn())
20
- .createIndex("idx_name", ["name"])
21
- .createIndex("idx_id", ["id"]);
22
- })
23
- .addTable("posts", (t) => {
24
- return t
25
- .addColumn("id", idColumn())
26
- .addColumn("title", column("string"))
27
- .addColumn("content", column("string"))
28
- .addColumn("userId", referenceColumn())
29
- .addColumn("publishedAt", column("timestamp"))
30
- .createIndex("idx_title", ["title"])
31
- .createIndex("idx_id", ["id"]);
32
- })
33
- .addTable("tags", (t) => {
34
- return t
35
- .addColumn("id", idColumn())
36
- .addColumn("name", column("string"))
37
- .createIndex("idx_id", ["id"]);
38
- })
39
- .addTable("post_tags", (t) => {
40
- return t
41
- .addColumn("id", idColumn())
42
- .addColumn("postId", referenceColumn())
43
- .addColumn("tagId", referenceColumn())
44
- .createIndex("idx_post", ["postId"])
45
- .createIndex("idx_tag", ["tagId"]);
46
- })
47
- .addTable("comments", (t) => {
48
- return t
49
- .addColumn("id", idColumn())
50
- .addColumn("content", column("string"))
51
- .addColumn("postId", referenceColumn())
52
- .addColumn("authorId", referenceColumn())
53
- .createIndex("idx_post", ["postId"])
54
- .createIndex("idx_author", ["authorId"]);
55
- })
56
- // Basic one-to-many relationships
57
- .addReference("author", {
58
- type: "one",
59
- from: { table: "posts", column: "userId" },
60
- to: { table: "users", column: "id" },
61
- })
62
- .addReference("inviter", {
63
- type: "one",
64
- from: { table: "users", column: "invitedBy" },
65
- to: { table: "users", column: "id" },
66
- })
67
- .addReference("post", {
68
- type: "one",
69
- from: { table: "comments", column: "postId" },
70
- to: { table: "posts", column: "id" },
71
- })
72
- .addReference("author", {
73
- type: "one",
74
- from: { table: "comments", column: "authorId" },
75
- to: { table: "users", column: "id" },
76
- })
77
- // Many-to-many relationships
78
- .addReference("post", {
79
- type: "one",
80
- from: { table: "post_tags", column: "postId" },
81
- to: { table: "posts", column: "id" },
82
- })
83
- .addReference("tag", {
84
- type: "one",
85
- from: { table: "post_tags", column: "tagId" },
86
- to: { table: "tags", column: "id" },
87
- })
88
- );
89
- });
90
-
91
- let kysely: KyselyType<any>; // eslint-disable-line @typescript-eslint/no-explicit-any
92
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
93
- let pool: ConnectionPool<Kysely<any>>;
94
-
95
- beforeAll(async () => {
96
- kysely = new Kysely({
97
- dialect: new PostgresDialect({} as PostgresDialectConfig),
98
- });
99
-
100
- // Wrap in connection pool
101
- pool = createKyselyConnectionPool(kysely);
102
- });
103
-
104
- // Helper to create UnitOfWork for testing
105
- function createTestUOW(name?: string) {
106
- const mockCompiler = createKyselyUOWCompiler(pool, "postgresql");
107
- const mockExecutor = {
108
- executeRetrievalPhase: async () => [],
109
- executeMutationPhase: async () => ({ success: true, createdInternalIds: [] }),
110
- };
111
- const mockDecoder: UOWDecoder = (rawResults, operations) => {
112
- if (rawResults.length !== operations.length) {
113
- throw new Error("rawResults and ops must have the same length");
114
- }
115
- return rawResults;
116
- };
117
- return new UnitOfWork(userSchema, mockCompiler, mockExecutor, mockDecoder, name);
118
- }
119
-
120
- describe("postgresql", () => {
121
- it("should compile select with join condition comparing columns", () => {
122
- const uow = createTestUOW();
123
- uow.find("posts", (b) =>
124
- b
125
- .whereIndex("primary")
126
- .select(["id", "userId"])
127
- .join((jb) => jb.author()),
128
- );
129
-
130
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
131
- const compiled = uow.compile(compiler);
132
-
133
- expect(compiled.retrievalBatch).toHaveLength(1);
134
- const query = compiled.retrievalBatch[0];
135
- assert(query);
136
- expect(query.sql).toMatchInlineSnapshot(
137
- `"select "author"."id" as "author:id", "author"."name" as "author:name", "author"."email" as "author:email", "author"."invitedBy" as "author:invitedBy", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "posts"."id" as "id", "posts"."userId" as "userId", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version" from "posts" left join "users" as "author" on "posts"."userId" = "author"."_internalId""`,
138
- );
139
- });
140
-
141
- it("should compile join with specific column selection", () => {
142
- const uow = createTestUOW();
143
- uow.find("posts", (b) =>
144
- b
145
- .whereIndex("primary")
146
- .select(["id", "title"])
147
- .join((jb) => jb.author((ab) => ab.select(["name", "email"]))),
148
- );
149
-
150
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
151
- const compiled = uow.compile(compiler);
152
-
153
- expect(compiled.retrievalBatch).toHaveLength(1);
154
- const query = compiled.retrievalBatch[0];
155
- assert(query);
156
- expect(query.sql).toMatchInlineSnapshot(
157
- `"select "author"."name" as "author:name", "author"."email" as "author:email", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "posts"."id" as "id", "posts"."title" as "title", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version" from "posts" left join "users" as "author" on "posts"."userId" = "author"."_internalId""`,
158
- );
159
- });
160
-
161
- it("should compile join with WHERE conditions on joined table", () => {
162
- const uow = createTestUOW();
163
- uow.find("posts", (b) =>
164
- b
165
- .whereIndex("primary")
166
- .select(["id", "title"])
167
- .join((jb) =>
168
- jb.author((ab) =>
169
- ab.select(["name"]).whereIndex("idx_name", (eb) => eb("name", "contains", "john")),
170
- ),
171
- ),
172
- );
173
-
174
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
175
- const compiled = uow.compile(compiler);
176
-
177
- expect(compiled.retrievalBatch).toHaveLength(1);
178
- const query = compiled.retrievalBatch[0];
179
- assert(query);
180
- expect(query.sql).toMatchInlineSnapshot(
181
- `"select "author"."name" as "author:name", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "posts"."id" as "id", "posts"."title" as "title", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version" from "posts" left join "users" as "author" on ("posts"."userId" = "author"."_internalId" and "users"."name" like $1)"`,
182
- );
183
- });
184
-
185
- it("should compile self-referencing join", () => {
186
- const uow = createTestUOW();
187
- uow.find("users", (b) =>
188
- b
189
- .whereIndex("primary")
190
- .select(["id", "name"])
191
- .join((jb) => jb.inviter((ib) => ib.select(["name"]))),
192
- );
193
-
194
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
195
- const compiled = uow.compile(compiler);
196
-
197
- expect(compiled.retrievalBatch).toHaveLength(1);
198
- const query = compiled.retrievalBatch[0];
199
- assert(query);
200
- expect(query.sql).toMatchInlineSnapshot(
201
- `"select "inviter"."name" as "inviter:name", "inviter"."_internalId" as "inviter:_internalId", "inviter"."_version" as "inviter:_version", "users"."id" as "id", "users"."name" as "name", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" left join "users" as "inviter" on "users"."invitedBy" = "inviter"."_internalId""`,
202
- );
203
- });
204
-
205
- it("should compile multiple joins in single query", () => {
206
- const uow = createTestUOW();
207
- uow.find("comments", (b) =>
208
- b
209
- .whereIndex("primary")
210
- .select(["id", "content"])
211
- .join((jb) => jb.post((pb) => pb.select(["title"])).author((ab) => ab.select(["name"]))),
212
- );
213
-
214
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
215
- const compiled = uow.compile(compiler);
216
-
217
- expect(compiled.retrievalBatch).toHaveLength(1);
218
- const query = compiled.retrievalBatch[0];
219
- assert(query);
220
- expect(query.sql).toMatchInlineSnapshot(
221
- `"select "post"."title" as "post:title", "post"."_internalId" as "post:_internalId", "post"."_version" as "post:_version", "author"."name" as "author:name", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "comments"."id" as "id", "comments"."content" as "content", "comments"."_internalId" as "_internalId", "comments"."_version" as "_version" from "comments" left join "posts" as "post" on "comments"."postId" = "post"."_internalId" left join "users" as "author" on "comments"."authorId" = "author"."_internalId""`,
222
- );
223
- });
224
-
225
- it("should compile many-to-many join through junction table", () => {
226
- const uow = createTestUOW();
227
- uow.find("post_tags", (b) =>
228
- b
229
- .whereIndex("primary")
230
- .select(["id"])
231
- .join((jb) => jb.post((pb) => pb.select(["title"])).tag((tb) => tb.select(["name"]))),
232
- );
233
-
234
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
235
- const compiled = uow.compile(compiler);
236
-
237
- expect(compiled.retrievalBatch).toHaveLength(1);
238
- const query = compiled.retrievalBatch[0];
239
- assert(query);
240
- expect(query.sql).toMatchInlineSnapshot(
241
- `"select "post"."title" as "post:title", "post"."_internalId" as "post:_internalId", "post"."_version" as "post:_version", "tag"."name" as "tag:name", "tag"."_internalId" as "tag:_internalId", "tag"."_version" as "tag:_version", "post_tags"."id" as "id", "post_tags"."_internalId" as "_internalId", "post_tags"."_version" as "_version" from "post_tags" left join "posts" as "post" on "post_tags"."postId" = "post"."_internalId" left join "tags" as "tag" on "post_tags"."tagId" = "tag"."_internalId""`,
242
- );
243
- });
244
-
245
- it("should compile complex join with multiple WHERE conditions", () => {
246
- const uow = createTestUOW();
247
- uow.find("posts", (b) =>
248
- b
249
- .whereIndex("primary")
250
- .select(["id", "title"])
251
- .join((jb) =>
252
- jb.author((ab) =>
253
- ab.select(["name"]).whereIndex("idx_name", (eb) =>
254
- eb.and(
255
- eb("name", "contains", "john"),
256
- // @ts-expect-error - email is not indexed
257
- eb("email", "ends with", "@example.com"),
258
- ),
259
- ),
260
- ),
261
- ),
262
- );
263
-
264
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
265
- const compiled = uow.compile(compiler);
266
-
267
- expect(compiled.retrievalBatch).toHaveLength(1);
268
- const query = compiled.retrievalBatch[0];
269
- assert(query);
270
- expect(query.sql).toMatchInlineSnapshot(
271
- `"select "author"."name" as "author:name", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "posts"."id" as "id", "posts"."title" as "title", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version" from "posts" left join "users" as "author" on ("posts"."userId" = "author"."_internalId" and ("users"."name" like $1 and "users"."email" like $2))"`,
272
- );
273
- });
274
-
275
- it("should compile join with ordering on joined table - LIMITATION: orderBy applied but may have limited effect", () => {
276
- const uow = createTestUOW();
277
- uow.find("posts", (b) =>
278
- b
279
- .whereIndex("primary")
280
- .select(["id", "title"])
281
- .join((jb) => jb.author((ab) => ab.select(["name"]).orderByIndex("idx_name", "asc"))),
282
- );
283
-
284
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
285
- const compiled = uow.compile(compiler);
286
-
287
- expect(compiled.retrievalBatch).toHaveLength(1);
288
- const query = compiled.retrievalBatch[0];
289
- assert(query);
290
- // LIMITATION: orderBy on join options is applied but has limited effect in SQL JOINs
291
- expect(query.sql).toMatchInlineSnapshot(
292
- `"select "author"."name" as "author:name", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "posts"."id" as "id", "posts"."title" as "title", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version" from "posts" left join "users" as "author" on "posts"."userId" = "author"."_internalId""`,
293
- );
294
- });
295
-
296
- it("should compile join with pageSize on joined table - LIMITATION: pageSize applied but may have limited effect", () => {
297
- const uow = createTestUOW();
298
- uow.find("posts", (b) =>
299
- b
300
- .whereIndex("primary")
301
- .select(["id", "title"])
302
- .join((jb) => jb.author((ab) => ab.select(["name"]).pageSize(1))),
303
- );
304
-
305
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
306
- const compiled = uow.compile(compiler);
307
-
308
- expect(compiled.retrievalBatch).toHaveLength(1);
309
- const query = compiled.retrievalBatch[0];
310
- assert(query);
311
- // LIMITATION: pageSize on join options is applied but has limited effect in SQL JOINs
312
- expect(query.sql).toMatchInlineSnapshot(
313
- `"select "author"."name" as "author:name", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "posts"."id" as "id", "posts"."title" as "title", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version" from "posts" left join "users" as "author" on "posts"."userId" = "author"."_internalId""`,
314
- );
315
- });
316
-
317
- // Tests for nested joins - SUPPORTED in UOW API
318
- it("should support nested joins (join on joined table) - IMPLEMENTED in UOW API", () => {
319
- const uow = createTestUOW();
320
- uow.find("posts", (b) =>
321
- b
322
- .whereIndex("primary")
323
- .select(["id", "title"])
324
- .join((jb) =>
325
- jb.author((ab) =>
326
- ab
327
- .select(["name"])
328
- .join((authorJoin) => authorJoin["inviter"]((ib) => ib.select(["name"]))),
329
- ),
330
- ),
331
- );
332
-
333
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
334
- const compiled = uow.compile(compiler);
335
-
336
- expect(compiled.retrievalBatch).toHaveLength(1);
337
- const query = compiled.retrievalBatch[0];
338
- assert(query);
339
- // EXPECTED SQL: Should include both the author join AND the inviter join
340
- expect(query.sql).toMatchInlineSnapshot(
341
- `"select "author"."name" as "author:name", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "author_inviter"."name" as "author:inviter:name", "author_inviter"."_internalId" as "author:inviter:_internalId", "author_inviter"."_version" as "author:inviter:_version", "posts"."id" as "id", "posts"."title" as "title", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version" from "posts" left join "users" as "author" on "posts"."userId" = "author"."_internalId" left join "users" as "author_inviter" on "author"."invitedBy" = "author_inviter"."_internalId""`,
342
- );
343
- });
344
- });
345
-
346
- describe("id column selection in joins", () => {
347
- it("should properly transform id columns in joined tables to FragnoId objects", () => {
348
- const uow = createTestUOW();
349
- uow.find("posts", (b) =>
350
- b
351
- .whereIndex("primary")
352
- .select(["id", "title"])
353
- .join((jb) => jb.author((ab) => ab.select(["id", "name"]))),
354
- );
355
-
356
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
357
- const compiled = uow.compile(compiler);
358
-
359
- expect(compiled.retrievalBatch).toHaveLength(1);
360
- const query = compiled.retrievalBatch[0];
361
- assert(query);
362
- expect(query.sql).toContain('"author"."id"');
363
- expect(query.sql).toContain('"author"."_internalId" as "author:_internalId"');
364
- expect(query.sql).toContain('"author"."_version" as "author:_version"');
365
- expect(query.sql).toMatchInlineSnapshot(
366
- `"select "author"."id" as "author:id", "author"."name" as "author:name", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "posts"."id" as "id", "posts"."title" as "title", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version" from "posts" left join "users" as "author" on "posts"."userId" = "author"."_internalId""`,
367
- );
368
- });
369
-
370
- it("should select id columns from main table and joined table", () => {
371
- const uow = createTestUOW();
372
- uow.find("posts", (b) =>
373
- b
374
- .whereIndex("primary")
375
- .select(["id", "title"])
376
- .join((jb) => jb.author((ab) => ab.select(["id", "name"]))),
377
- );
378
-
379
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
380
- const compiled = uow.compile(compiler);
381
-
382
- expect(compiled.retrievalBatch).toHaveLength(1);
383
- const query = compiled.retrievalBatch[0];
384
- assert(query);
385
- // Both main table id and joined table id should be in the query
386
- expect(query.sql).toContain('"posts"."id"');
387
- expect(query.sql).toContain('"author"."id"');
388
- // When id is selected from joined table, its _internalId is also included
389
- expect(query.sql).toContain('"author"."_internalId" as "author:_internalId"');
390
- expect(query.sql).toMatchInlineSnapshot(
391
- `"select "author"."id" as "author:id", "author"."name" as "author:name", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "posts"."id" as "id", "posts"."title" as "title", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version" from "posts" left join "users" as "author" on "posts"."userId" = "author"."_internalId""`,
392
- );
393
- });
394
-
395
- it("should handle id-only selection in join", () => {
396
- const uow = createTestUOW();
397
- uow.find("posts", (b) =>
398
- b
399
- .whereIndex("primary")
400
- .select(["id"])
401
- .join((jb) => jb.author((ab) => ab.select(["id"]))),
402
- );
403
-
404
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
405
- const compiled = uow.compile(compiler);
406
-
407
- expect(compiled.retrievalBatch).toHaveLength(1);
408
- const query = compiled.retrievalBatch[0];
409
- assert(query);
410
- // When only id is selected, _internalId is still included for joined table
411
- expect(query.sql).toContain('"author"."_internalId" as "author:_internalId"');
412
- expect(query.sql).toMatchInlineSnapshot(
413
- `"select "author"."id" as "author:id", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "posts"."id" as "id", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version" from "posts" left join "users" as "author" on "posts"."userId" = "author"."_internalId""`,
414
- );
415
- });
416
-
417
- it("should include _internalId for both main and joined table when id is selected", () => {
418
- const uow = createTestUOW();
419
- uow.find("posts", (b) =>
420
- b
421
- .whereIndex("primary")
422
- .select(["id", "title"])
423
- .join((jb) => jb.author((ab) => ab.select(["id", "name"]))),
424
- );
425
-
426
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
427
- const compiled = uow.compile(compiler);
428
-
429
- expect(compiled.retrievalBatch).toHaveLength(1);
430
- const query = compiled.retrievalBatch[0];
431
- assert(query);
432
- // Both tables should have their _internalId included when id is selected
433
- expect(query.sql).toContain('"posts"."_internalId"');
434
- expect(query.sql).toContain('"author"."_internalId" as "author:_internalId"');
435
- expect(query.sql).toMatchInlineSnapshot(
436
- `"select "author"."id" as "author:id", "author"."name" as "author:name", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "posts"."id" as "id", "posts"."title" as "title", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version" from "posts" left join "users" as "author" on "posts"."userId" = "author"."_internalId""`,
437
- );
438
- });
439
-
440
- it("should not include _internalId when id is not selected", () => {
441
- const uow = createTestUOW();
442
- uow.find("posts", (b) =>
443
- b
444
- .whereIndex("primary")
445
- .select(["title"])
446
- .join((jb) => jb.author((ab) => ab.select(["name"]))),
447
- );
448
-
449
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
450
- const compiled = uow.compile(compiler);
451
-
452
- expect(compiled.retrievalBatch).toHaveLength(1);
453
- const query = compiled.retrievalBatch[0];
454
- assert(query);
455
- // Hidden columns (_internalId, _version) are always included for internal use
456
- expect(query.sql).toContain('"posts"."_internalId" as "_internalId"');
457
- expect(query.sql).toContain('"author"."_internalId" as "author:_internalId"');
458
- expect(query.sql).toContain('"posts"."_version" as "_version"');
459
- expect(query.sql).toContain('"author"."_version" as "author:_version"');
460
- expect(query.sql).toMatchInlineSnapshot(
461
- `"select "author"."name" as "author:name", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "posts"."title" as "title", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version" from "posts" left join "users" as "author" on "posts"."userId" = "author"."_internalId""`,
462
- );
463
- });
464
-
465
- it("should handle select true with joins - includes all columns including id", () => {
466
- const uow = createTestUOW();
467
- uow.find("posts", (b) => b.whereIndex("primary").join((jb) => jb.author()));
468
-
469
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
470
- const compiled = uow.compile(compiler);
471
-
472
- expect(compiled.retrievalBatch).toHaveLength(1);
473
- const query = compiled.retrievalBatch[0];
474
- assert(query);
475
- expect(query.sql).toContain('"posts"."id"');
476
- expect(query.sql).toContain('"author"."id"');
477
- expect(query.sql).toContain('"posts"."_internalId"');
478
- expect(query.sql).toContain('"author"."_internalId"');
479
- expect(query.sql).toMatchInlineSnapshot(
480
- `"select "author"."id" as "author:id", "author"."name" as "author:name", "author"."email" as "author:email", "author"."invitedBy" as "author:invitedBy", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "posts"."id" as "id", "posts"."title" as "title", "posts"."content" as "content", "posts"."userId" as "userId", "posts"."publishedAt" as "publishedAt", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version" from "posts" left join "users" as "author" on "posts"."userId" = "author"."_internalId""`,
481
- );
482
- });
483
-
484
- it("should handle id column in where clause on joined table", () => {
485
- const uow = createTestUOW();
486
- uow.find("posts", (b) =>
487
- b
488
- .whereIndex("primary")
489
- .select(["id", "title"])
490
- .join((jb) =>
491
- jb.author((ab) =>
492
- ab.select(["id", "name"]).whereIndex("idx_id", (eb) => eb("id", "=", "user-123")),
493
- ),
494
- ),
495
- );
496
-
497
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
498
- const compiled = uow.compile(compiler);
499
-
500
- expect(compiled.retrievalBatch).toHaveLength(1);
501
- const query = compiled.retrievalBatch[0];
502
- assert(query);
503
- expect(query.sql).toContain('"author"."_internalId" as "author:_internalId"');
504
- expect(query.sql).toMatchInlineSnapshot(
505
- `"select "author"."id" as "author:id", "author"."name" as "author:name", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "posts"."id" as "id", "posts"."title" as "title", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version" from "posts" left join "users" as "author" on ("posts"."userId" = "author"."_internalId" and "users"."id" = $1)"`,
506
- );
507
- });
508
-
509
- it("should handle multiple joins with different id selections", () => {
510
- const uow = createTestUOW();
511
- uow.find("comments", (b) =>
512
- b
513
- .whereIndex("primary")
514
- .select(["id", "content"])
515
- .join((jb) =>
516
- jb.post((pb) => pb.select(["id", "title"])).author((ab) => ab.select(["name"])),
517
- ),
518
- );
519
-
520
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
521
- const compiled = uow.compile(compiler);
522
-
523
- expect(compiled.retrievalBatch).toHaveLength(1);
524
- const query = compiled.retrievalBatch[0];
525
- assert(query);
526
- expect(query.sql).toContain('"comments"."id"');
527
- expect(query.sql).toContain('"post"."id"');
528
- expect(query.sql).not.toContain('"author"."id"');
529
- // Hidden columns are always included regardless of ID selection
530
- expect(query.sql).toContain('"post"."_internalId" as "post:_internalId"');
531
- expect(query.sql).toContain('"author"."_internalId" as "author:_internalId"');
532
- expect(query.sql).toContain('"post"."_version" as "post:_version"');
533
- expect(query.sql).toContain('"author"."_version" as "author:_version"');
534
- expect(query.sql).toMatchInlineSnapshot(
535
- `"select "post"."id" as "post:id", "post"."title" as "post:title", "post"."_internalId" as "post:_internalId", "post"."_version" as "post:_version", "author"."name" as "author:name", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "comments"."id" as "id", "comments"."content" as "content", "comments"."_internalId" as "_internalId", "comments"."_version" as "_version" from "comments" left join "posts" as "post" on "comments"."postId" = "post"."_internalId" left join "users" as "author" on "comments"."authorId" = "author"."_internalId""`,
536
- );
537
- });
538
- });
539
-
540
- describe("custom-named id columns in joins", () => {
541
- // Schema with custom id column names
542
- const customIdSchema = schema((s) => {
543
- return s
544
- .addTable("products", (t) => {
545
- return t
546
- .addColumn("productId", idColumn())
547
- .addColumn("name", column("string"))
548
- .addColumn("price", column("integer"))
549
- .createIndex("idx_product_id", ["productId"]);
550
- })
551
- .addTable("categories", (t) => {
552
- return t
553
- .addColumn("categoryId", idColumn())
554
- .addColumn("categoryName", column("string"))
555
- .createIndex("idx_category_id", ["categoryId"]);
556
- })
557
- .addTable("product_categories", (t) => {
558
- return t
559
- .addColumn("id", idColumn())
560
- .addColumn("prodRef", referenceColumn())
561
- .addColumn("catRef", referenceColumn())
562
- .createIndex("idx_prod", ["prodRef"])
563
- .createIndex("idx_cat", ["catRef"]);
564
- })
565
- .addReference("product", {
566
- type: "one",
567
- from: { table: "product_categories", column: "prodRef" },
568
- to: { table: "products", column: "productId" },
569
- })
570
- .addReference("category", {
571
- type: "one",
572
- from: { table: "product_categories", column: "catRef" },
573
- to: { table: "categories", column: "categoryId" },
574
- });
575
- });
576
-
577
- function createCustomIdTestUOW() {
578
- const mockCompiler = createKyselyUOWCompiler(pool, "postgresql");
579
- const mockExecutor = {
580
- executeRetrievalPhase: async () => [],
581
- executeMutationPhase: async () => ({ success: true, createdInternalIds: [] }),
582
- };
583
- const mockDecoder: UOWDecoder = (rawResults, operations) => {
584
- if (rawResults.length !== operations.length) {
585
- throw new Error("rawResults and ops must have the same length");
586
- }
587
- return rawResults;
588
- };
589
- return new UnitOfWork(customIdSchema, mockCompiler, mockExecutor, mockDecoder);
590
- }
591
-
592
- it("should compile join with custom id column names", () => {
593
- const uow = createCustomIdTestUOW();
594
- uow.find("product_categories", (b) =>
595
- b
596
- .whereIndex("primary")
597
- .select(["id"])
598
- .join((jb) =>
599
- jb
600
- .product((pb) => pb.select(["productId", "name"]))
601
- .category((cb) => cb.select(["categoryId", "categoryName"])),
602
- ),
603
- );
604
-
605
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
606
- const compiled = uow.compile(compiler);
607
-
608
- expect(compiled.retrievalBatch).toHaveLength(1);
609
- const query = compiled.retrievalBatch[0];
610
- assert(query);
611
- expect(query.sql).toContain('"product"."productId"');
612
- expect(query.sql).toContain('"category"."categoryId"');
613
- // Custom id columns also get their _internalId included
614
- expect(query.sql).toContain('"product"."_internalId" as "product:_internalId"');
615
- expect(query.sql).toContain('"category"."_internalId" as "category:_internalId"');
616
- // Join conditions ALWAYS use _internalId (not custom column names) for performance
617
- expect(query.sql).toContain('"product_categories"."prodRef" = "product"."_internalId"');
618
- expect(query.sql).toContain('"product_categories"."catRef" = "category"."_internalId"');
619
- expect(query.sql).toMatchInlineSnapshot(
620
- `"select "product"."productId" as "product:productId", "product"."name" as "product:name", "product"."_internalId" as "product:_internalId", "product"."_version" as "product:_version", "category"."categoryId" as "category:categoryId", "category"."categoryName" as "category:categoryName", "category"."_internalId" as "category:_internalId", "category"."_version" as "category:_version", "product_categories"."id" as "id", "product_categories"."_internalId" as "_internalId", "product_categories"."_version" as "_version" from "product_categories" left join "products" as "product" on "product_categories"."prodRef" = "product"."_internalId" left join "categories" as "category" on "product_categories"."catRef" = "category"."_internalId""`,
621
- );
622
- });
623
-
624
- it("should handle custom id in join where clause", () => {
625
- const uow = createCustomIdTestUOW();
626
- uow.find("product_categories", (b) =>
627
- b
628
- .whereIndex("primary")
629
- .select(["id"])
630
- .join((jb) =>
631
- jb.product((pb) =>
632
- pb
633
- .select(["productId", "name"])
634
- .whereIndex("idx_product_id", (eb) => eb("productId", "=", "prod-456")),
635
- ),
636
- ),
637
- );
638
-
639
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
640
- const compiled = uow.compile(compiler);
641
-
642
- expect(compiled.retrievalBatch).toHaveLength(1);
643
- const query = compiled.retrievalBatch[0];
644
- assert(query);
645
- expect(query.sql).toContain('"products"."productId" = $1');
646
- expect(query.sql).toContain('"product"."_internalId" as "product:_internalId"');
647
- // Join condition ALWAYS uses _internalId for performance
648
- expect(query.sql).toContain('"product_categories"."prodRef" = "product"."_internalId"');
649
- expect(query.sql).toMatchInlineSnapshot(
650
- `"select "product"."productId" as "product:productId", "product"."name" as "product:name", "product"."_internalId" as "product:_internalId", "product"."_version" as "product:_version", "product_categories"."id" as "id", "product_categories"."_internalId" as "_internalId", "product_categories"."_version" as "_version" from "product_categories" left join "products" as "product" on ("product_categories"."prodRef" = "product"."_internalId" and "products"."productId" = $1)"`,
651
- );
652
- });
653
-
654
- it("should handle select true with custom id columns", () => {
655
- const uow = createCustomIdTestUOW();
656
- uow.find("product_categories", (b) => b.whereIndex("primary").join((jb) => jb.product()));
657
-
658
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
659
- const compiled = uow.compile(compiler);
660
-
661
- expect(compiled.retrievalBatch).toHaveLength(1);
662
- const query = compiled.retrievalBatch[0];
663
- assert(query);
664
- expect(query.sql).toContain('"product"."productId"');
665
- expect(query.sql).toContain('"product_categories"."id"');
666
- // With select true, _internalId IS now included when table has an id column
667
- expect(query.sql).toContain('"product"."_internalId" as "product:_internalId"');
668
- // Join condition ALWAYS uses _internalId for performance
669
- expect(query.sql).toContain('"product_categories"."prodRef" = "product"."_internalId"');
670
- expect(query.sql).toMatchInlineSnapshot(
671
- `"select "product"."productId" as "product:productId", "product"."name" as "product:name", "product"."price" as "product:price", "product"."_internalId" as "product:_internalId", "product"."_version" as "product:_version", "product_categories"."id" as "id", "product_categories"."prodRef" as "prodRef", "product_categories"."catRef" as "catRef", "product_categories"."_internalId" as "_internalId", "product_categories"."_version" as "_version" from "product_categories" left join "products" as "product" on "product_categories"."prodRef" = "product"."_internalId""`,
672
- );
673
- });
674
-
675
- it("should join tables with different custom id names", () => {
676
- const uow = createCustomIdTestUOW();
677
- uow.find("product_categories", (b) =>
678
- b
679
- .whereIndex("primary")
680
- .select(["id"])
681
- .join((jb) =>
682
- jb
683
- .product((pb) => pb.select(["productId"]))
684
- .category((cb) => cb.select(["categoryId"])),
685
- ),
686
- );
687
-
688
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
689
- const compiled = uow.compile(compiler);
690
-
691
- expect(compiled.retrievalBatch).toHaveLength(1);
692
- const query = compiled.retrievalBatch[0];
693
- assert(query);
694
- expect(query.sql).toContain('"product"."productId"');
695
- expect(query.sql).toContain('"category"."categoryId"');
696
- expect(query.sql).not.toContain('"product"."id"'); // Should not have 'id', only 'productId'
697
- expect(query.sql).not.toContain('"category"."id"'); // Should not have 'id', only 'categoryId'
698
- // _internalId included for both since custom id columns are selected
699
- expect(query.sql).toContain('"product"."_internalId" as "product:_internalId"');
700
- expect(query.sql).toContain('"category"."_internalId" as "category:_internalId"');
701
- // Join conditions ALWAYS use _internalId for performance
702
- expect(query.sql).toContain('"product_categories"."prodRef" = "product"."_internalId"');
703
- expect(query.sql).toContain('"product_categories"."catRef" = "category"."_internalId"');
704
- expect(query.sql).toMatchInlineSnapshot(
705
- `"select "product"."productId" as "product:productId", "product"."_internalId" as "product:_internalId", "product"."_version" as "product:_version", "category"."categoryId" as "category:categoryId", "category"."_internalId" as "category:_internalId", "category"."_version" as "category:_version", "product_categories"."id" as "id", "product_categories"."_internalId" as "_internalId", "product_categories"."_version" as "_version" from "product_categories" left join "products" as "product" on "product_categories"."prodRef" = "product"."_internalId" left join "categories" as "category" on "product_categories"."catRef" = "category"."_internalId""`,
706
- );
707
- });
708
- });
709
-
710
- describe("special columns in joins - _internalId aliasing", () => {
711
- it("should properly alias _internalId for joined tables", () => {
712
- const uow = createTestUOW();
713
- uow.find("posts", (b) =>
714
- b
715
- .whereIndex("primary")
716
- .select(["id"])
717
- .join((jb) => jb.author((ab) => ab.select(["id"]))),
718
- );
719
-
720
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
721
- const compiled = uow.compile(compiler);
722
-
723
- expect(compiled.retrievalBatch).toHaveLength(1);
724
- const query = compiled.retrievalBatch[0];
725
- assert(query);
726
- // Main table _internalId should be aliased as "_internalId"
727
- expect(query.sql).toContain('"posts"."_internalId" as "_internalId"');
728
- // Joined table _internalId should be aliased as "relation:_internalId" when id is selected
729
- expect(query.sql).toContain('"author"."_internalId" as "author:_internalId"');
730
- expect(query.sql).toMatchInlineSnapshot(
731
- `"select "author"."id" as "author:id", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "posts"."id" as "id", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version" from "posts" left join "users" as "author" on "posts"."userId" = "author"."_internalId""`,
732
- );
733
- });
734
-
735
- it("should handle _internalId in join conditions", () => {
736
- const uow = createTestUOW();
737
- uow.find("posts", (b) =>
738
- b
739
- .whereIndex("primary")
740
- .select(["id", "title"])
741
- .join((jb) => jb.author((ab) => ab.select(["id", "name"]))),
742
- );
743
-
744
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
745
- const compiled = uow.compile(compiler);
746
-
747
- expect(compiled.retrievalBatch).toHaveLength(1);
748
- const query = compiled.retrievalBatch[0];
749
- assert(query);
750
- // Join condition should use _internalId
751
- expect(query.sql).toContain('"posts"."userId" = "author"."_internalId"');
752
- // Joined table _internalId is included when id is selected
753
- expect(query.sql).toContain('"author"."_internalId" as "author:_internalId"');
754
- expect(query.sql).toMatchInlineSnapshot(
755
- `"select "author"."id" as "author:id", "author"."name" as "author:name", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "posts"."id" as "id", "posts"."title" as "title", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version" from "posts" left join "users" as "author" on "posts"."userId" = "author"."_internalId""`,
756
- );
757
- });
758
-
759
- it("should handle multiple joins with _internalId tracking", () => {
760
- const uow = createTestUOW();
761
- uow.find("comments", (b) =>
762
- b
763
- .whereIndex("primary")
764
- .select(["id"])
765
- .join((jb) => jb.post((pb) => pb.select(["id"])).author((ab) => ab.select(["id"]))),
766
- );
767
-
768
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
769
- const compiled = uow.compile(compiler);
770
-
771
- expect(compiled.retrievalBatch).toHaveLength(1);
772
- const query = compiled.retrievalBatch[0];
773
- assert(query);
774
- // All _internalId should be properly aliased
775
- expect(query.sql).toContain('"comments"."_internalId" as "_internalId"');
776
- // Joined tables with id selected also get _internalId
777
- expect(query.sql).toContain('"post"."_internalId" as "post:_internalId"');
778
- expect(query.sql).toContain('"author"."_internalId" as "author:_internalId"');
779
- // Join should use _internalId for connection
780
- expect(query.sql).toContain('"comments"."postId" = "post"."_internalId"');
781
- expect(query.sql).toContain('"comments"."authorId" = "author"."_internalId"');
782
- expect(query.sql).toMatchInlineSnapshot(
783
- `"select "post"."id" as "post:id", "post"."_internalId" as "post:_internalId", "post"."_version" as "post:_version", "author"."id" as "author:id", "author"."_internalId" as "author:_internalId", "author"."_version" as "author:_version", "comments"."id" as "id", "comments"."_internalId" as "_internalId", "comments"."_version" as "_version" from "comments" left join "posts" as "post" on "comments"."postId" = "post"."_internalId" left join "users" as "author" on "comments"."authorId" = "author"."_internalId""`,
784
- );
785
- });
786
-
787
- it("should handle self-referencing join with _internalId", () => {
788
- const uow = createTestUOW();
789
- uow.find("users", (b) =>
790
- b
791
- .whereIndex("primary")
792
- .select(["id", "name"])
793
- .join((jb) => jb.inviter((ib) => ib.select(["id", "name"]))),
794
- );
795
-
796
- const compiler = createKyselyUOWCompiler(pool, "postgresql");
797
- const compiled = uow.compile(compiler);
798
-
799
- expect(compiled.retrievalBatch).toHaveLength(1);
800
- const query = compiled.retrievalBatch[0];
801
- assert(query);
802
- expect(query.sql).toContain('"users"."invitedBy" = "inviter"."_internalId"');
803
- expect(query.sql).toContain('"users"."_internalId" as "_internalId"');
804
- // Self-join with id selected also includes _internalId for joined instance
805
- expect(query.sql).toContain('"inviter"."_internalId" as "inviter:_internalId"');
806
- expect(query.sql).toMatchInlineSnapshot(
807
- `"select "inviter"."id" as "inviter:id", "inviter"."name" as "inviter:name", "inviter"."_internalId" as "inviter:_internalId", "inviter"."_version" as "inviter:_version", "users"."id" as "id", "users"."name" as "name", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" left join "users" as "inviter" on "users"."invitedBy" = "inviter"."_internalId""`,
808
- );
809
- });
810
- });
811
- });