@fragno-dev/db 0.1.14 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (445) hide show
  1. package/.turbo/turbo-build.log +242 -139
  2. package/CHANGELOG.md +47 -0
  3. package/README.md +123 -8
  4. package/dist/adapters/adapters.d.ts +19 -5
  5. package/dist/adapters/adapters.d.ts.map +1 -1
  6. package/dist/adapters/adapters.js.map +1 -1
  7. package/dist/adapters/drizzle/drizzle-adapter.d.ts +6 -19
  8. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
  9. package/dist/adapters/drizzle/drizzle-adapter.js +7 -47
  10. package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
  11. package/dist/adapters/drizzle/generate.d.ts +7 -1
  12. package/dist/adapters/drizzle/generate.d.ts.map +1 -1
  13. package/dist/adapters/drizzle/generate.js +46 -45
  14. package/dist/adapters/drizzle/generate.js.map +1 -1
  15. package/dist/adapters/generic-sql/driver-config.d.ts +74 -0
  16. package/dist/adapters/generic-sql/driver-config.d.ts.map +1 -0
  17. package/dist/adapters/generic-sql/driver-config.js +94 -0
  18. package/dist/adapters/generic-sql/driver-config.js.map +1 -0
  19. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts +43 -0
  20. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -0
  21. package/dist/adapters/generic-sql/generic-sql-adapter.js +87 -0
  22. package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -0
  23. package/dist/adapters/generic-sql/generic-sql-uow-executor.js +67 -0
  24. package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -0
  25. package/dist/adapters/generic-sql/migration/cold-kysely.js +33 -0
  26. package/dist/adapters/generic-sql/migration/cold-kysely.js.map +1 -0
  27. package/dist/adapters/generic-sql/migration/dialect/mysql.js +60 -0
  28. package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -0
  29. package/dist/adapters/generic-sql/migration/dialect/postgres.js +59 -0
  30. package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -0
  31. package/dist/adapters/generic-sql/migration/dialect/sqlite.js +96 -0
  32. package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -0
  33. package/dist/adapters/generic-sql/migration/executor.d.ts +15 -0
  34. package/dist/adapters/generic-sql/migration/executor.d.ts.map +1 -0
  35. package/dist/adapters/generic-sql/migration/executor.js +18 -0
  36. package/dist/adapters/generic-sql/migration/executor.js.map +1 -0
  37. package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts +66 -0
  38. package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -0
  39. package/dist/adapters/generic-sql/migration/prepared-migrations.js +68 -0
  40. package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -0
  41. package/dist/adapters/generic-sql/migration/sql-generator.js +212 -0
  42. package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -0
  43. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +32 -0
  44. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -0
  45. package/dist/adapters/generic-sql/query/cursor-utils.js +37 -0
  46. package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -0
  47. package/dist/adapters/generic-sql/query/dialect/mysql.js +33 -0
  48. package/dist/adapters/generic-sql/query/dialect/mysql.js.map +1 -0
  49. package/dist/adapters/generic-sql/query/dialect/postgres.js +32 -0
  50. package/dist/adapters/generic-sql/query/dialect/postgres.js.map +1 -0
  51. package/dist/adapters/generic-sql/query/dialect/sqlite.js +32 -0
  52. package/dist/adapters/generic-sql/query/dialect/sqlite.js.map +1 -0
  53. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +152 -0
  54. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -0
  55. package/dist/adapters/generic-sql/query/select-builder.js +69 -0
  56. package/dist/adapters/generic-sql/query/select-builder.js.map +1 -0
  57. package/dist/adapters/generic-sql/query/sql-query-compiler.js +145 -0
  58. package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -0
  59. package/dist/adapters/generic-sql/query/where-builder.js +129 -0
  60. package/dist/adapters/generic-sql/query/where-builder.js.map +1 -0
  61. package/dist/adapters/generic-sql/result-interpreter.js +74 -0
  62. package/dist/adapters/generic-sql/result-interpreter.js.map +1 -0
  63. package/dist/adapters/generic-sql/uow-decoder.js +105 -0
  64. package/dist/adapters/generic-sql/uow-decoder.js.map +1 -0
  65. package/dist/adapters/generic-sql/uow-encoder.js +93 -0
  66. package/dist/adapters/generic-sql/uow-encoder.js.map +1 -0
  67. package/dist/adapters/kysely/kysely-adapter.d.ts +5 -16
  68. package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
  69. package/dist/adapters/kysely/kysely-adapter.js +6 -159
  70. package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
  71. package/dist/adapters/{drizzle/drizzle-query.js → shared/from-unit-of-work-compiler.js} +48 -62
  72. package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -0
  73. package/dist/adapters/{kysely/kysely-shared.d.ts → shared/table-name-mapper.d.ts} +3 -2
  74. package/dist/adapters/shared/table-name-mapper.d.ts.map +1 -0
  75. package/dist/adapters/shared/table-name-mapper.js +43 -0
  76. package/dist/adapters/shared/table-name-mapper.js.map +1 -0
  77. package/dist/adapters/shared/uow-operation-compiler.js +105 -0
  78. package/dist/adapters/shared/uow-operation-compiler.js.map +1 -0
  79. package/dist/db-fragment-definition-builder.d.ts +186 -0
  80. package/dist/db-fragment-definition-builder.d.ts.map +1 -0
  81. package/dist/db-fragment-definition-builder.js +207 -0
  82. package/dist/db-fragment-definition-builder.js.map +1 -0
  83. package/dist/fragments/internal-fragment.d.ts +53 -0
  84. package/dist/fragments/internal-fragment.d.ts.map +1 -0
  85. package/dist/fragments/internal-fragment.js +111 -0
  86. package/dist/fragments/internal-fragment.js.map +1 -0
  87. package/dist/hooks/hooks.d.ts +51 -0
  88. package/dist/hooks/hooks.d.ts.map +1 -0
  89. package/dist/hooks/hooks.js +88 -0
  90. package/dist/hooks/hooks.js.map +1 -0
  91. package/dist/migration-engine/generation-engine.d.ts +0 -2
  92. package/dist/migration-engine/generation-engine.d.ts.map +1 -1
  93. package/dist/migration-engine/generation-engine.js +38 -56
  94. package/dist/migration-engine/generation-engine.js.map +1 -1
  95. package/dist/mod.d.ts +35 -23
  96. package/dist/mod.d.ts.map +1 -1
  97. package/dist/mod.js +48 -45
  98. package/dist/mod.js.map +1 -1
  99. package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js +165 -0
  100. package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js.map +1 -0
  101. package/dist/packages/fragno/dist/api/bind-services.js +20 -0
  102. package/dist/packages/fragno/dist/api/bind-services.js.map +1 -0
  103. package/dist/packages/fragno/dist/api/error.js +48 -0
  104. package/dist/packages/fragno/dist/api/error.js.map +1 -0
  105. package/dist/packages/fragno/dist/api/fragment-definition-builder.js +320 -0
  106. package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +1 -0
  107. package/dist/packages/fragno/dist/api/fragment-instantiator.js +525 -0
  108. package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -0
  109. package/dist/packages/fragno/dist/api/fragno-response.js +73 -0
  110. package/dist/packages/fragno/dist/api/fragno-response.js.map +1 -0
  111. package/dist/packages/fragno/dist/api/internal/response-stream.js +81 -0
  112. package/dist/packages/fragno/dist/api/internal/response-stream.js.map +1 -0
  113. package/dist/packages/fragno/dist/api/internal/route.js +10 -0
  114. package/dist/packages/fragno/dist/api/internal/route.js.map +1 -0
  115. package/dist/packages/fragno/dist/api/mutable-request-state.js +97 -0
  116. package/dist/packages/fragno/dist/api/mutable-request-state.js.map +1 -0
  117. package/dist/packages/fragno/dist/api/request-context-storage.js +43 -0
  118. package/dist/packages/fragno/dist/api/request-context-storage.js.map +1 -0
  119. package/dist/packages/fragno/dist/api/request-input-context.js +118 -0
  120. package/dist/packages/fragno/dist/api/request-input-context.js.map +1 -0
  121. package/dist/packages/fragno/dist/api/request-middleware.js +83 -0
  122. package/dist/packages/fragno/dist/api/request-middleware.js.map +1 -0
  123. package/dist/packages/fragno/dist/api/request-output-context.js +119 -0
  124. package/dist/packages/fragno/dist/api/request-output-context.js.map +1 -0
  125. package/dist/packages/fragno/dist/api/route.js +17 -0
  126. package/dist/packages/fragno/dist/api/route.js.map +1 -0
  127. package/dist/packages/fragno/dist/internal/symbols.js +10 -0
  128. package/dist/packages/fragno/dist/internal/symbols.js.map +1 -0
  129. package/dist/query/column-defaults.js +27 -0
  130. package/dist/query/column-defaults.js.map +1 -0
  131. package/dist/query/cursor.d.ts +14 -6
  132. package/dist/query/cursor.d.ts.map +1 -1
  133. package/dist/query/cursor.js +16 -7
  134. package/dist/query/cursor.js.map +1 -1
  135. package/dist/query/orm/orm.d.ts +1 -1
  136. package/dist/query/orm/orm.js.map +1 -1
  137. package/dist/query/serialize/create-sql-serializer.js +30 -0
  138. package/dist/query/serialize/create-sql-serializer.js.map +1 -0
  139. package/dist/query/serialize/dialect/mysql-serializer.js +87 -0
  140. package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -0
  141. package/dist/query/serialize/dialect/postgres-serializer.js +80 -0
  142. package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -0
  143. package/dist/query/serialize/dialect/sqlite-serializer.js +93 -0
  144. package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -0
  145. package/dist/query/serialize/sql-serializer.js +67 -0
  146. package/dist/query/serialize/sql-serializer.js.map +1 -0
  147. package/dist/query/{query.d.ts → simple-query-interface.d.ts} +6 -6
  148. package/dist/query/simple-query-interface.d.ts.map +1 -0
  149. package/dist/query/unit-of-work/execute-unit-of-work.d.ts +133 -0
  150. package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -0
  151. package/dist/query/unit-of-work/execute-unit-of-work.js +197 -0
  152. package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -0
  153. package/dist/query/unit-of-work/retry-policy.d.ts +88 -0
  154. package/dist/query/unit-of-work/retry-policy.d.ts.map +1 -0
  155. package/dist/query/unit-of-work/retry-policy.js +61 -0
  156. package/dist/query/unit-of-work/retry-policy.js.map +1 -0
  157. package/dist/query/{unit-of-work.d.ts → unit-of-work/unit-of-work.d.ts} +145 -58
  158. package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -0
  159. package/dist/query/{unit-of-work.js → unit-of-work/unit-of-work.js} +435 -198
  160. package/dist/query/unit-of-work/unit-of-work.js.map +1 -0
  161. package/dist/query/value-decoding.js +71 -0
  162. package/dist/query/value-decoding.js.map +1 -0
  163. package/dist/query/value-encoding.js +124 -0
  164. package/dist/query/value-encoding.js.map +1 -0
  165. package/dist/schema/create.d.ts +3 -0
  166. package/dist/schema/create.d.ts.map +1 -1
  167. package/dist/schema/create.js +4 -0
  168. package/dist/schema/create.js.map +1 -1
  169. package/dist/schema/type-conversion/create-sql-type-mapper.js +29 -0
  170. package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -0
  171. package/dist/schema/type-conversion/dialect/mysql.js +57 -0
  172. package/dist/schema/type-conversion/dialect/mysql.js.map +1 -0
  173. package/dist/schema/type-conversion/dialect/postgres.js +56 -0
  174. package/dist/schema/type-conversion/dialect/postgres.js.map +1 -0
  175. package/dist/schema/type-conversion/dialect/sqlite.js +52 -0
  176. package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -0
  177. package/dist/schema/type-conversion/type-mapping.js +63 -0
  178. package/dist/schema/type-conversion/type-mapping.js.map +1 -0
  179. package/dist/sql-driver/connection/connection-provider.d.ts +13 -0
  180. package/dist/sql-driver/connection/connection-provider.d.ts.map +1 -0
  181. package/dist/sql-driver/connection/connection-provider.js +19 -0
  182. package/dist/sql-driver/connection/connection-provider.js.map +1 -0
  183. package/dist/sql-driver/connection/single-connection-provider.js +23 -0
  184. package/dist/sql-driver/connection/single-connection-provider.js.map +1 -0
  185. package/dist/sql-driver/dialect-adapter/dialect-adapter.d.ts +7 -0
  186. package/dist/sql-driver/dialect-adapter/dialect-adapter.d.ts.map +1 -0
  187. package/dist/sql-driver/dialects/dialects.d.ts +2 -0
  188. package/dist/sql-driver/dialects/dialects.js +3 -0
  189. package/dist/sql-driver/dialects/durable-object-dialect.d.ts +72 -0
  190. package/dist/sql-driver/dialects/durable-object-dialect.d.ts.map +1 -0
  191. package/dist/sql-driver/dialects/durable-object-dialect.js +130 -0
  192. package/dist/sql-driver/dialects/durable-object-dialect.js.map +1 -0
  193. package/dist/sql-driver/driver/runtime-driver.d.ts +23 -0
  194. package/dist/sql-driver/driver/runtime-driver.d.ts.map +1 -0
  195. package/dist/sql-driver/driver/runtime-driver.js +56 -0
  196. package/dist/sql-driver/driver/runtime-driver.js.map +1 -0
  197. package/dist/sql-driver/query-executor/default-query-executor.js +26 -0
  198. package/dist/sql-driver/query-executor/default-query-executor.js.map +1 -0
  199. package/dist/sql-driver/query-executor/plugin.d.ts +17 -0
  200. package/dist/sql-driver/query-executor/plugin.d.ts.map +1 -0
  201. package/dist/sql-driver/query-executor/query-executor-base.js +25 -0
  202. package/dist/sql-driver/query-executor/query-executor-base.js.map +1 -0
  203. package/dist/sql-driver/query-executor/query-executor.d.ts +36 -0
  204. package/dist/sql-driver/query-executor/query-executor.d.ts.map +1 -0
  205. package/dist/sql-driver/sql-driver-adapter.d.ts +29 -0
  206. package/dist/sql-driver/sql-driver-adapter.d.ts.map +1 -0
  207. package/dist/sql-driver/sql-driver-adapter.js +68 -0
  208. package/dist/sql-driver/sql-driver-adapter.js.map +1 -0
  209. package/dist/sql-driver/sql-driver.d.ts +38 -0
  210. package/dist/sql-driver/sql-driver.d.ts.map +1 -0
  211. package/dist/sql-driver/sql-driver.js +1 -0
  212. package/dist/sql-driver/sql.js +50 -0
  213. package/dist/sql-driver/sql.js.map +1 -0
  214. package/dist/with-database.d.ts +32 -0
  215. package/dist/with-database.d.ts.map +1 -0
  216. package/dist/with-database.js +34 -0
  217. package/dist/with-database.js.map +1 -0
  218. package/package.json +43 -9
  219. package/src/adapters/adapters.ts +23 -4
  220. package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +140 -185
  221. package/src/adapters/drizzle/{drizzle-adapter-sqlite.test.ts → drizzle-adapter-sqlite3.test.ts} +187 -55
  222. package/src/adapters/drizzle/drizzle-adapter.ts +14 -93
  223. package/src/adapters/drizzle/generate.test.ts +102 -269
  224. package/src/adapters/drizzle/generate.ts +89 -63
  225. package/src/adapters/drizzle/migrate-drizzle.test.ts +19 -0
  226. package/src/adapters/drizzle/shared.ts +0 -34
  227. package/src/adapters/drizzle/test-utils.ts +36 -5
  228. package/src/adapters/generic-sql/README.md +14 -0
  229. package/src/adapters/generic-sql/driver-config.ts +144 -0
  230. package/src/adapters/generic-sql/generic-sql-adapter.test.ts +50 -0
  231. package/src/adapters/generic-sql/generic-sql-adapter.ts +146 -0
  232. package/src/adapters/generic-sql/generic-sql-uow-executor.ts +130 -0
  233. package/src/adapters/generic-sql/migration/cold-kysely.ts +55 -0
  234. package/src/adapters/{kysely/migration/execute-mysql.test.ts → generic-sql/migration/dialect/mysql.test.ts} +342 -484
  235. package/src/adapters/generic-sql/migration/dialect/mysql.ts +104 -0
  236. package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +1008 -0
  237. package/src/adapters/generic-sql/migration/dialect/postgres.ts +113 -0
  238. package/src/adapters/{kysely/migration/execute-sqlite.test.ts → generic-sql/migration/dialect/sqlite.test.ts} +307 -510
  239. package/src/adapters/generic-sql/migration/dialect/sqlite.ts +189 -0
  240. package/src/adapters/generic-sql/migration/executor.ts +33 -0
  241. package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +661 -0
  242. package/src/adapters/generic-sql/migration/prepared-migrations.ts +214 -0
  243. package/src/adapters/generic-sql/migration/sql-generator.ts +413 -0
  244. package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +36 -0
  245. package/src/adapters/generic-sql/query/cursor-utils.ts +56 -0
  246. package/src/adapters/generic-sql/query/dialect/mysql.ts +34 -0
  247. package/src/adapters/generic-sql/query/dialect/postgres.ts +32 -0
  248. package/src/adapters/generic-sql/query/dialect/sqlite.ts +32 -0
  249. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +1568 -0
  250. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +314 -0
  251. package/src/adapters/generic-sql/query/select-builder.test.ts +256 -0
  252. package/src/adapters/generic-sql/query/select-builder.ts +137 -0
  253. package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +195 -0
  254. package/src/adapters/generic-sql/query/sql-query-compiler.ts +367 -0
  255. package/src/adapters/generic-sql/query/where-builder.test.ts +744 -0
  256. package/src/adapters/generic-sql/query/where-builder.ts +211 -0
  257. package/src/adapters/generic-sql/result-interpreter.ts +102 -0
  258. package/src/adapters/generic-sql/test/generic-drizzle-adapter-sqlite3.test.ts +899 -0
  259. package/src/adapters/generic-sql/uow-decoder.test.ts +399 -0
  260. package/src/adapters/generic-sql/uow-decoder.ts +152 -0
  261. package/src/adapters/generic-sql/uow-encoder.test.ts +183 -0
  262. package/src/adapters/generic-sql/uow-encoder.ts +131 -0
  263. package/src/adapters/kysely/kysely-adapter-pglite.test.ts +90 -96
  264. package/src/adapters/kysely/kysely-adapter-sqlocal.test.ts +215 -0
  265. package/src/adapters/kysely/kysely-adapter.ts +10 -242
  266. package/src/adapters/{drizzle/drizzle-query.ts → shared/from-unit-of-work-compiler.ts} +111 -106
  267. package/src/adapters/shared/table-name-mapper.ts +50 -0
  268. package/src/adapters/shared/uow-operation-compiler.ts +211 -0
  269. package/src/db-fragment-definition-builder.test.ts +887 -0
  270. package/src/db-fragment-definition-builder.ts +737 -0
  271. package/src/db-fragment-instantiator.test.ts +543 -0
  272. package/src/db-fragment-integration.test.ts +406 -0
  273. package/src/fragments/internal-fragment.test.ts +549 -0
  274. package/src/fragments/internal-fragment.ts +249 -0
  275. package/src/hooks/hooks.test.ts +575 -0
  276. package/src/hooks/hooks.ts +179 -0
  277. package/src/migration-engine/generation-engine.test.ts +60 -27
  278. package/src/migration-engine/generation-engine.ts +99 -92
  279. package/src/mod.ts +139 -78
  280. package/src/query/column-defaults.ts +49 -0
  281. package/src/query/cursor.test.ts +147 -3
  282. package/src/query/cursor.ts +25 -8
  283. package/src/query/orm/orm.ts +1 -1
  284. package/src/query/query-type.test.ts +9 -9
  285. package/src/query/serialize/create-sql-serializer.ts +34 -0
  286. package/src/query/serialize/dialect/mysql-serializer.ts +142 -0
  287. package/src/query/serialize/dialect/postgres-serializer.ts +129 -0
  288. package/src/query/serialize/dialect/sqlite-serializer.test.ts +251 -0
  289. package/src/query/serialize/dialect/sqlite-serializer.ts +156 -0
  290. package/src/query/serialize/sql-serializer.ts +143 -0
  291. package/src/query/{query.ts → simple-query-interface.ts} +4 -4
  292. package/src/query/unit-of-work/execute-unit-of-work.test.ts +1310 -0
  293. package/src/query/unit-of-work/execute-unit-of-work.ts +504 -0
  294. package/src/query/unit-of-work/retry-policy.test.ts +217 -0
  295. package/src/query/unit-of-work/retry-policy.ts +141 -0
  296. package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +831 -0
  297. package/src/query/{unit-of-work-types.test.ts → unit-of-work/unit-of-work-types.test.ts} +7 -5
  298. package/src/query/unit-of-work/unit-of-work.test.ts +1716 -0
  299. package/src/query/{unit-of-work.ts → unit-of-work/unit-of-work.ts} +716 -420
  300. package/src/query/{result-transform.test.ts → value-decoding.test.ts} +45 -298
  301. package/src/query/value-decoding.ts +113 -0
  302. package/src/query/value-encoding.test.ts +390 -0
  303. package/src/query/value-encoding.ts +168 -0
  304. package/src/schema/create.test.ts +5 -1
  305. package/src/schema/create.ts +5 -0
  306. package/src/schema/serialize.test.ts +165 -407
  307. package/src/schema/type-conversion/create-sql-type-mapper.ts +28 -0
  308. package/src/schema/type-conversion/dialect/mysql.ts +64 -0
  309. package/src/schema/type-conversion/dialect/postgres.ts +62 -0
  310. package/src/schema/type-conversion/dialect/sqlite.ts +63 -0
  311. package/src/schema/type-conversion/type-mapping.test.ts +137 -0
  312. package/src/schema/type-conversion/type-mapping.ts +153 -0
  313. package/src/shared/connection-pool.ts +5 -5
  314. package/src/sql-driver/better-sqlite3.test.ts +126 -0
  315. package/src/sql-driver/connection/connection-provider.ts +27 -0
  316. package/src/sql-driver/connection/single-connection-provider.ts +42 -0
  317. package/src/sql-driver/dialect-adapter/dialect-adapter.ts +9 -0
  318. package/src/sql-driver/dialect-adapter/sqlite-dialect-adapter.ts +7 -0
  319. package/src/sql-driver/dialects/dialects.ts +1 -0
  320. package/src/sql-driver/dialects/durable-object-dialect.ts +260 -0
  321. package/src/sql-driver/driver/runtime-driver.ts +91 -0
  322. package/src/sql-driver/query-executor/default-query-executor.ts +38 -0
  323. package/src/sql-driver/query-executor/plugin.ts +22 -0
  324. package/src/sql-driver/query-executor/query-executor-base.ts +53 -0
  325. package/src/sql-driver/query-executor/query-executor.ts +44 -0
  326. package/src/sql-driver/sql-driver-adapter.ts +96 -0
  327. package/src/sql-driver/sql-driver.ts +53 -0
  328. package/src/sql-driver/sql.ts +57 -0
  329. package/src/sql-driver/sqlocal.test.ts +117 -0
  330. package/src/with-database.ts +152 -0
  331. package/tsdown.config.ts +8 -2
  332. package/dist/adapters/drizzle/drizzle-connection-pool.js +0 -40
  333. package/dist/adapters/drizzle/drizzle-connection-pool.js.map +0 -1
  334. package/dist/adapters/drizzle/drizzle-query.d.ts +0 -23
  335. package/dist/adapters/drizzle/drizzle-query.d.ts.map +0 -1
  336. package/dist/adapters/drizzle/drizzle-query.js.map +0 -1
  337. package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +0 -10
  338. package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +0 -1
  339. package/dist/adapters/drizzle/drizzle-uow-compiler.js +0 -315
  340. package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +0 -1
  341. package/dist/adapters/drizzle/drizzle-uow-decoder.js +0 -116
  342. package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +0 -1
  343. package/dist/adapters/drizzle/drizzle-uow-executor.js +0 -149
  344. package/dist/adapters/drizzle/drizzle-uow-executor.js.map +0 -1
  345. package/dist/adapters/drizzle/join-column-utils.js +0 -28
  346. package/dist/adapters/drizzle/join-column-utils.js.map +0 -1
  347. package/dist/adapters/drizzle/shared.d.ts +0 -14
  348. package/dist/adapters/drizzle/shared.d.ts.map +0 -1
  349. package/dist/adapters/drizzle/shared.js +0 -35
  350. package/dist/adapters/drizzle/shared.js.map +0 -1
  351. package/dist/adapters/kysely/kysely-connection-pool.js +0 -41
  352. package/dist/adapters/kysely/kysely-connection-pool.js.map +0 -1
  353. package/dist/adapters/kysely/kysely-query-builder.js +0 -321
  354. package/dist/adapters/kysely/kysely-query-builder.js.map +0 -1
  355. package/dist/adapters/kysely/kysely-query-compiler.js +0 -66
  356. package/dist/adapters/kysely/kysely-query-compiler.js.map +0 -1
  357. package/dist/adapters/kysely/kysely-query.d.ts +0 -22
  358. package/dist/adapters/kysely/kysely-query.d.ts.map +0 -1
  359. package/dist/adapters/kysely/kysely-query.js +0 -223
  360. package/dist/adapters/kysely/kysely-query.js.map +0 -1
  361. package/dist/adapters/kysely/kysely-shared.d.ts.map +0 -1
  362. package/dist/adapters/kysely/kysely-shared.js +0 -18
  363. package/dist/adapters/kysely/kysely-shared.js.map +0 -1
  364. package/dist/adapters/kysely/kysely-uow-compiler.js +0 -170
  365. package/dist/adapters/kysely/kysely-uow-compiler.js.map +0 -1
  366. package/dist/adapters/kysely/kysely-uow-executor.js +0 -89
  367. package/dist/adapters/kysely/kysely-uow-executor.js.map +0 -1
  368. package/dist/adapters/kysely/migration/execute-base.js +0 -128
  369. package/dist/adapters/kysely/migration/execute-base.js.map +0 -1
  370. package/dist/adapters/kysely/migration/execute-factory.js +0 -34
  371. package/dist/adapters/kysely/migration/execute-factory.js.map +0 -1
  372. package/dist/adapters/kysely/migration/execute-mssql.js +0 -112
  373. package/dist/adapters/kysely/migration/execute-mssql.js.map +0 -1
  374. package/dist/adapters/kysely/migration/execute-mysql.js +0 -93
  375. package/dist/adapters/kysely/migration/execute-mysql.js.map +0 -1
  376. package/dist/adapters/kysely/migration/execute-postgres.js +0 -104
  377. package/dist/adapters/kysely/migration/execute-postgres.js.map +0 -1
  378. package/dist/adapters/kysely/migration/execute-sqlite.js +0 -123
  379. package/dist/adapters/kysely/migration/execute-sqlite.js.map +0 -1
  380. package/dist/adapters/kysely/migration/execute.js +0 -34
  381. package/dist/adapters/kysely/migration/execute.js.map +0 -1
  382. package/dist/bind-services.d.ts +0 -7
  383. package/dist/bind-services.d.ts.map +0 -1
  384. package/dist/bind-services.js +0 -14
  385. package/dist/bind-services.js.map +0 -1
  386. package/dist/fragment.d.ts +0 -173
  387. package/dist/fragment.d.ts.map +0 -1
  388. package/dist/fragment.js +0 -191
  389. package/dist/fragment.js.map +0 -1
  390. package/dist/migration-engine/create.d.ts +0 -37
  391. package/dist/migration-engine/create.d.ts.map +0 -1
  392. package/dist/migration-engine/create.js +0 -58
  393. package/dist/migration-engine/create.js.map +0 -1
  394. package/dist/migration-engine/shared.d.ts +0 -112
  395. package/dist/migration-engine/shared.d.ts.map +0 -1
  396. package/dist/query/query.d.ts.map +0 -1
  397. package/dist/query/result-transform.js +0 -168
  398. package/dist/query/result-transform.js.map +0 -1
  399. package/dist/query/unit-of-work.d.ts.map +0 -1
  400. package/dist/query/unit-of-work.js.map +0 -1
  401. package/dist/schema/serialize.js +0 -106
  402. package/dist/schema/serialize.js.map +0 -1
  403. package/dist/shared/settings-schema.js +0 -36
  404. package/dist/shared/settings-schema.js.map +0 -1
  405. package/src/adapters/drizzle/drizzle-adapter.test.ts +0 -170
  406. package/src/adapters/drizzle/drizzle-connection-pool.ts +0 -66
  407. package/src/adapters/drizzle/drizzle-query.test.ts +0 -499
  408. package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +0 -1383
  409. package/src/adapters/drizzle/drizzle-uow-compiler.ts +0 -636
  410. package/src/adapters/drizzle/drizzle-uow-decoder.ts +0 -218
  411. package/src/adapters/drizzle/drizzle-uow-executor.ts +0 -276
  412. package/src/adapters/drizzle/join-column-utils.test.ts +0 -79
  413. package/src/adapters/drizzle/join-column-utils.ts +0 -39
  414. package/src/adapters/kysely/kysely-connection-pool.ts +0 -70
  415. package/src/adapters/kysely/kysely-query-builder.test.ts +0 -1344
  416. package/src/adapters/kysely/kysely-query-builder.ts +0 -666
  417. package/src/adapters/kysely/kysely-query-compiler.ts +0 -132
  418. package/src/adapters/kysely/kysely-query.test.ts +0 -498
  419. package/src/adapters/kysely/kysely-query.ts +0 -390
  420. package/src/adapters/kysely/kysely-shared.ts +0 -23
  421. package/src/adapters/kysely/kysely-uow-compiler.test.ts +0 -998
  422. package/src/adapters/kysely/kysely-uow-compiler.ts +0 -318
  423. package/src/adapters/kysely/kysely-uow-executor.ts +0 -145
  424. package/src/adapters/kysely/kysely-uow-joins.test.ts +0 -811
  425. package/src/adapters/kysely/migration/execute-base.ts +0 -256
  426. package/src/adapters/kysely/migration/execute-factory.ts +0 -53
  427. package/src/adapters/kysely/migration/execute-mssql.ts +0 -250
  428. package/src/adapters/kysely/migration/execute-mysql.ts +0 -211
  429. package/src/adapters/kysely/migration/execute-postgres.test.ts +0 -2657
  430. package/src/adapters/kysely/migration/execute-postgres.ts +0 -234
  431. package/src/adapters/kysely/migration/execute-sqlite.ts +0 -247
  432. package/src/adapters/kysely/migration/execute.ts +0 -50
  433. package/src/adapters/kysely/migration/kysely-migrator.test.ts +0 -261
  434. package/src/bind-services.test.ts +0 -214
  435. package/src/bind-services.ts +0 -37
  436. package/src/db-fragment.test.ts +0 -800
  437. package/src/fragment.ts +0 -727
  438. package/src/query/result-transform.ts +0 -271
  439. package/src/query/unit-of-work-multi-schema.test.ts +0 -64
  440. package/src/query/unit-of-work.test.ts +0 -943
  441. package/src/schema/serialize.ts +0 -396
  442. package/src/shared/settings-schema.ts +0 -61
  443. package/src/uow-context-integration.test.ts +0 -102
  444. package/src/uow-context.test.ts +0 -182
  445. /package/dist/query/{query.js → simple-query-interface.js} +0 -0
@@ -0,0 +1,1568 @@
1
+ import { describe, test, expect } from "vitest";
2
+ import { GenericSQLUOWOperationCompiler } from "./generic-sql-uow-operation-compiler";
3
+ import { BetterSQLite3DriverConfig, NodePostgresDriverConfig } from "../driver-config";
4
+ import { schema, column, idColumn, referenceColumn, FragnoId } from "../../../schema/create";
5
+ import { Cursor } from "../../../query/cursor";
6
+
7
+ // Test schema with indexes
8
+ const testSchema = schema((s) => {
9
+ return s
10
+ .addTable("users", (t) => {
11
+ return t
12
+ .addColumn("id", idColumn())
13
+ .addColumn("name", column("string"))
14
+ .addColumn("email", column("string"))
15
+ .addColumn("age", column("integer").nullable())
16
+ .addColumn("isActive", column("bool"))
17
+ .addColumn("createdAt", column("timestamp"))
18
+ .addColumn("invitedBy", referenceColumn().nullable())
19
+ .createIndex("idx_email", ["email"], { unique: true })
20
+ .createIndex("idx_name", ["name"])
21
+ .createIndex("idx_age", ["age"]);
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("viewCount", column("integer").defaultTo(0))
30
+ .addColumn("publishedAt", column("timestamp").nullable())
31
+ .createIndex("idx_title", ["title"])
32
+ .createIndex("idx_user", ["userId"]);
33
+ })
34
+ .addTable("comments", (t) => {
35
+ return t
36
+ .addColumn("id", idColumn())
37
+ .addColumn("content", column("string"))
38
+ .addColumn("postId", referenceColumn())
39
+ .addColumn("authorId", referenceColumn())
40
+ .createIndex("idx_post", ["postId"])
41
+ .createIndex("idx_author", ["authorId"]);
42
+ })
43
+ .addTable("tags", (t) => {
44
+ return t
45
+ .addColumn("id", idColumn())
46
+ .addColumn("name", column("string"))
47
+ .createIndex("idx_name", ["name"]);
48
+ })
49
+ .addTable("post_tags", (t) => {
50
+ return t
51
+ .addColumn("id", idColumn())
52
+ .addColumn("postId", referenceColumn())
53
+ .addColumn("tagId", referenceColumn())
54
+ .createIndex("idx_post", ["postId"])
55
+ .createIndex("idx_tag", ["tagId"]);
56
+ })
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
+ .addReference("post", {
78
+ type: "one",
79
+ from: { table: "post_tags", column: "postId" },
80
+ to: { table: "posts", column: "id" },
81
+ })
82
+ .addReference("tag", {
83
+ type: "one",
84
+ from: { table: "post_tags", column: "tagId" },
85
+ to: { table: "tags", column: "id" },
86
+ });
87
+ });
88
+
89
+ // Schema with custom-named id columns
90
+ const customIdSchema = schema((s) => {
91
+ return s
92
+ .addTable("products", (t) => {
93
+ return t
94
+ .addColumn("productId", idColumn())
95
+ .addColumn("name", column("string"))
96
+ .addColumn("price", column("integer"))
97
+ .createIndex("idx_product_id", ["productId"]);
98
+ })
99
+ .addTable("orders", (t) => {
100
+ return t
101
+ .addColumn("orderId", idColumn())
102
+ .addColumn("productRef", referenceColumn())
103
+ .addColumn("quantity", column("integer"));
104
+ })
105
+ .addTable("categories", (t) => {
106
+ return t
107
+ .addColumn("categoryId", idColumn())
108
+ .addColumn("categoryName", column("string"))
109
+ .createIndex("idx_category_id", ["categoryId"]);
110
+ })
111
+ .addTable("product_categories", (t) => {
112
+ return t
113
+ .addColumn("id", idColumn())
114
+ .addColumn("prodRef", referenceColumn())
115
+ .addColumn("catRef", referenceColumn())
116
+ .createIndex("idx_prod", ["prodRef"])
117
+ .createIndex("idx_cat", ["catRef"]);
118
+ })
119
+ .addReference("product", {
120
+ type: "one",
121
+ from: { table: "orders", column: "productRef" },
122
+ to: { table: "products", column: "productId" },
123
+ })
124
+ .addReference("product", {
125
+ type: "one",
126
+ from: { table: "product_categories", column: "prodRef" },
127
+ to: { table: "products", column: "productId" },
128
+ })
129
+ .addReference("category", {
130
+ type: "one",
131
+ from: { table: "product_categories", column: "catRef" },
132
+ to: { table: "categories", column: "categoryId" },
133
+ });
134
+ });
135
+
136
+ describe("GenericSQLUOWOperationCompiler", () => {
137
+ const driverConfig = new BetterSQLite3DriverConfig();
138
+
139
+ test("compileCount operation", () => {
140
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
141
+
142
+ const result = compiler.compileCount({
143
+ type: "count",
144
+ schema: testSchema,
145
+ table: testSchema.tables.users,
146
+ indexName: "primary",
147
+ options: {
148
+ useIndex: "primary",
149
+ },
150
+ });
151
+
152
+ expect(result).not.toBeNull();
153
+ expect(result!.sql).toMatchInlineSnapshot(`"select count(*) as "count" from "users""`);
154
+ });
155
+
156
+ test("compileCount with where clause", () => {
157
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
158
+
159
+ const result = compiler.compileCount({
160
+ type: "count",
161
+ schema: testSchema,
162
+ table: testSchema.tables.users,
163
+ indexName: "primary",
164
+ options: {
165
+ useIndex: "primary",
166
+ where: (eb) => eb("age", ">", 18),
167
+ },
168
+ });
169
+
170
+ expect(result).not.toBeNull();
171
+ expect(result!.sql).toMatchInlineSnapshot(
172
+ `"select count(*) as "count" from "users" where "users"."age" > ?"`,
173
+ );
174
+ });
175
+
176
+ test("compileFind operation", () => {
177
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
178
+
179
+ const result = compiler.compileFind({
180
+ type: "find",
181
+ schema: testSchema,
182
+ table: testSchema.tables.users,
183
+ indexName: "primary",
184
+ options: {
185
+ useIndex: "primary",
186
+ select: true,
187
+ pageSize: 10,
188
+ },
189
+ });
190
+
191
+ expect(result).not.toBeNull();
192
+ expect(result!.sql).toMatchInlineSnapshot(
193
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."age" as "age", "users"."isActive" as "isActive", "users"."createdAt" as "createdAt", "users"."invitedBy" as "invitedBy", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" limit ?"`,
194
+ );
195
+ });
196
+
197
+ test("compileCreate operation", () => {
198
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
199
+
200
+ const result = compiler.compileCreate({
201
+ type: "create",
202
+ schema: testSchema,
203
+ table: "users",
204
+ values: {
205
+ name: "John",
206
+ email: "john@example.com",
207
+ age: 30,
208
+ },
209
+ generatedExternalId: "user123",
210
+ });
211
+
212
+ expect(result).not.toBeNull();
213
+ expect(result!.query.sql).toMatchInlineSnapshot(
214
+ `"insert into "users" ("id", "name", "email", "age") values (?, ?, ?, ?) returning "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."age" as "age", "users"."isActive" as "isActive", "users"."createdAt" as "createdAt", "users"."invitedBy" as "invitedBy", "users"."_internalId" as "_internalId", "users"."_version" as "_version""`,
215
+ );
216
+ expect(result!.expectedAffectedRows).toBeNull();
217
+ });
218
+
219
+ test("compileUpdate operation", () => {
220
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
221
+
222
+ const result = compiler.compileUpdate({
223
+ type: "update",
224
+ schema: testSchema,
225
+ table: "users",
226
+ id: "user123",
227
+ checkVersion: false,
228
+ set: {
229
+ name: "Jane",
230
+ },
231
+ });
232
+
233
+ expect(result).not.toBeNull();
234
+ expect(result!.query.sql).toMatchInlineSnapshot(
235
+ `"update "users" set "name" = ?, "_version" = COALESCE(_version, 0) + 1 where "users"."id" = ?"`,
236
+ );
237
+ expect(result!.expectedAffectedRows).toBeNull();
238
+ });
239
+
240
+ test("compileUpdate with version check", () => {
241
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
242
+
243
+ const result = compiler.compileUpdate({
244
+ type: "update",
245
+ schema: testSchema,
246
+ table: "users",
247
+ id: new FragnoId({ externalId: "user123", internalId: 1n, version: 5 }),
248
+ checkVersion: true,
249
+ set: {
250
+ name: "Jane",
251
+ },
252
+ });
253
+
254
+ expect(result).not.toBeNull();
255
+ expect(result!.query.sql).toMatchInlineSnapshot(
256
+ `"update "users" set "name" = ?, "_version" = COALESCE(_version, 0) + 1 where ("users"."id" = ? and "users"."_version" = ?)"`,
257
+ );
258
+ expect(result!.expectedAffectedRows).toBe(1n);
259
+ });
260
+
261
+ test("compileDelete operation", () => {
262
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
263
+
264
+ const result = compiler.compileDelete({
265
+ type: "delete",
266
+ schema: testSchema,
267
+ table: "users",
268
+ id: "user123",
269
+ checkVersion: false,
270
+ });
271
+
272
+ expect(result).not.toBeNull();
273
+ expect(result!.query.sql).toMatchInlineSnapshot(`"delete from "users" where "users"."id" = ?"`);
274
+ expect(result!.expectedAffectedRows).toBeNull();
275
+ });
276
+
277
+ test("compileCheck operation", () => {
278
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
279
+
280
+ const result = compiler.compileCheck({
281
+ type: "check",
282
+ schema: testSchema,
283
+ table: "users",
284
+ id: new FragnoId({ externalId: "user123", internalId: 1n, version: 5 }),
285
+ });
286
+
287
+ expect(result).not.toBeNull();
288
+ expect(result!.query.sql).toMatchInlineSnapshot(
289
+ `"select 1 as "exists" from "users" where ("users"."id" = ? and "users"."_version" = ?) limit ?"`,
290
+ );
291
+ expect(result!.expectedReturnedRows).toBe(1);
292
+ });
293
+
294
+ describe("compileCreate - dialect differences", () => {
295
+ test("should compile insert query for PostgreSQL", () => {
296
+ const compiler = new GenericSQLUOWOperationCompiler(new NodePostgresDriverConfig());
297
+
298
+ const result = compiler.compileCreate({
299
+ type: "create",
300
+ schema: testSchema,
301
+ table: "users",
302
+ values: {
303
+ name: "John",
304
+ email: "john@example.com",
305
+ },
306
+ generatedExternalId: "user-123",
307
+ });
308
+
309
+ expect(result).not.toBeNull();
310
+ expect(result!.query.sql).toMatchInlineSnapshot(
311
+ `"insert into "users" ("id", "name", "email") values ($1, $2, $3) returning "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."age" as "age", "users"."isActive" as "isActive", "users"."createdAt" as "createdAt", "users"."invitedBy" as "invitedBy", "users"."_internalId" as "_internalId", "users"."_version" as "_version""`,
312
+ );
313
+ });
314
+
315
+ test("should compile insert query for SQLite", () => {
316
+ const compiler = new GenericSQLUOWOperationCompiler(new BetterSQLite3DriverConfig());
317
+
318
+ const result = compiler.compileCreate({
319
+ type: "create",
320
+ schema: testSchema,
321
+ table: "users",
322
+ values: {
323
+ name: "John",
324
+ email: "john@example.com",
325
+ },
326
+ generatedExternalId: "user-123",
327
+ });
328
+
329
+ expect(result).not.toBeNull();
330
+ expect(result!.query.sql).toMatchInlineSnapshot(
331
+ `"insert into "users" ("id", "name", "email") values (?, ?, ?) returning "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."age" as "age", "users"."isActive" as "isActive", "users"."createdAt" as "createdAt", "users"."invitedBy" as "invitedBy", "users"."_internalId" as "_internalId", "users"."_version" as "_version""`,
332
+ );
333
+ });
334
+ });
335
+
336
+ describe("compileCreate - reference column handling", () => {
337
+ test("should handle string reference (external ID) in create", () => {
338
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
339
+
340
+ const result = compiler.compileCreate({
341
+ type: "create",
342
+ schema: testSchema,
343
+ table: "posts",
344
+ values: {
345
+ title: "My Post",
346
+ content: "Post content",
347
+ userId: "user-external-id-123",
348
+ },
349
+ generatedExternalId: "post-123",
350
+ });
351
+
352
+ expect(result).not.toBeNull();
353
+ expect(result!.query.sql).toMatchInlineSnapshot(
354
+ `"insert into "posts" ("id", "title", "content", "userId") values (?, ?, ?, (select "_internalId" from "users" where "id" = ? limit ?)) returning "posts"."id" as "id", "posts"."title" as "title", "posts"."content" as "content", "posts"."userId" as "userId", "posts"."viewCount" as "viewCount", "posts"."publishedAt" as "publishedAt", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version""`,
355
+ );
356
+ });
357
+
358
+ test("should handle bigint reference without subquery", () => {
359
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
360
+
361
+ const result = compiler.compileCreate({
362
+ type: "create",
363
+ schema: testSchema,
364
+ table: "posts",
365
+ values: {
366
+ title: "Direct ID Post",
367
+ content: "Content",
368
+ userId: 12345n,
369
+ },
370
+ generatedExternalId: "post-456",
371
+ });
372
+
373
+ expect(result).not.toBeNull();
374
+ // Should not have nested SELECT for the userId value
375
+ expect(result!.query.sql).not.toMatch(/\(select.*from.*users/i);
376
+ expect(result!.query.sql).toMatchInlineSnapshot(
377
+ `"insert into "posts" ("id", "title", "content", "userId") values (?, ?, ?, ?) returning "posts"."id" as "id", "posts"."title" as "title", "posts"."content" as "content", "posts"."userId" as "userId", "posts"."viewCount" as "viewCount", "posts"."publishedAt" as "publishedAt", "posts"."_internalId" as "_internalId", "posts"."_version" as "_version""`,
378
+ );
379
+ });
380
+ });
381
+
382
+ describe("compileUpdate - reference column handling", () => {
383
+ test("should handle string reference in update", () => {
384
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
385
+
386
+ const result = compiler.compileUpdate({
387
+ type: "update",
388
+ schema: testSchema,
389
+ table: "posts",
390
+ id: "post-123",
391
+ checkVersion: false,
392
+ set: {
393
+ userId: "new-user-id-456",
394
+ },
395
+ });
396
+
397
+ expect(result).not.toBeNull();
398
+ expect(result!.query.sql).toMatchInlineSnapshot(
399
+ `"update "posts" set "userId" = (select "_internalId" from "users" where "id" = ? limit ?), "_version" = COALESCE(_version, 0) + 1 where "posts"."id" = ?"`,
400
+ );
401
+ });
402
+
403
+ test("should handle bigint reference in update without subquery", () => {
404
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
405
+
406
+ const result = compiler.compileUpdate({
407
+ type: "update",
408
+ schema: testSchema,
409
+ table: "posts",
410
+ id: "post-123",
411
+ checkVersion: false,
412
+ set: {
413
+ userId: 78910n,
414
+ },
415
+ });
416
+
417
+ expect(result).not.toBeNull();
418
+ // Should not have nested SELECT for the userId value
419
+ expect(result!.query.sql).not.toMatch(/\(select.*from.*users/i);
420
+ expect(result!.query.sql).toMatchInlineSnapshot(
421
+ `"update "posts" set "userId" = ?, "_version" = COALESCE(_version, 0) + 1 where "posts"."id" = ?"`,
422
+ );
423
+ });
424
+
425
+ test("should compile update with multiple fields", () => {
426
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
427
+
428
+ const result = compiler.compileUpdate({
429
+ type: "update",
430
+ schema: testSchema,
431
+ table: "users",
432
+ id: "user-123",
433
+ checkVersion: false,
434
+ set: {
435
+ name: "Updated Name",
436
+ email: "updated@example.com",
437
+ isActive: true,
438
+ },
439
+ });
440
+
441
+ expect(result).not.toBeNull();
442
+ expect(result!.query.sql).toMatchInlineSnapshot(
443
+ `"update "users" set "name" = ?, "email" = ?, "isActive" = ?, "_version" = COALESCE(_version, 0) + 1 where "users"."id" = ?"`,
444
+ );
445
+ });
446
+ });
447
+
448
+ describe("compileDelete with version check", () => {
449
+ test("should compile delete with version check", () => {
450
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
451
+
452
+ const result = compiler.compileDelete({
453
+ type: "delete",
454
+ schema: testSchema,
455
+ table: "users",
456
+ id: new FragnoId({ externalId: "user123", internalId: 1n, version: 5 }),
457
+ checkVersion: true,
458
+ });
459
+
460
+ expect(result).not.toBeNull();
461
+ expect(result!.query.sql).toMatchInlineSnapshot(
462
+ `"delete from "users" where ("users"."id" = ? and "users"."_version" = ?)"`,
463
+ );
464
+ expect(result!.expectedAffectedRows).toBe(1n);
465
+ });
466
+ });
467
+
468
+ describe("compileFind - select options", () => {
469
+ test("should compile select with specific columns", () => {
470
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
471
+
472
+ const result = compiler.compileFind({
473
+ type: "find",
474
+ schema: testSchema,
475
+ table: testSchema.tables.users,
476
+ indexName: "primary",
477
+ options: {
478
+ useIndex: "primary",
479
+ select: ["id", "name"],
480
+ pageSize: 10,
481
+ },
482
+ });
483
+
484
+ expect(result).not.toBeNull();
485
+ expect(result!.sql).toMatchInlineSnapshot(
486
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" limit ?"`,
487
+ );
488
+ });
489
+
490
+ test("should compile select with where clause", () => {
491
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
492
+
493
+ const result = compiler.compileFind({
494
+ type: "find",
495
+ schema: testSchema,
496
+ table: testSchema.tables.users,
497
+ indexName: "primary",
498
+ options: {
499
+ useIndex: "primary",
500
+ select: true,
501
+ where: (eb) => eb("age", ">", 18),
502
+ pageSize: 10,
503
+ },
504
+ });
505
+
506
+ expect(result).not.toBeNull();
507
+ expect(result!.sql).toMatchInlineSnapshot(
508
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."age" as "age", "users"."isActive" as "isActive", "users"."createdAt" as "createdAt", "users"."invitedBy" as "invitedBy", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" where "users"."age" > ? limit ?"`,
509
+ );
510
+ });
511
+
512
+ test("should compile complete query with where clause", () => {
513
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
514
+
515
+ const result = compiler.compileFind({
516
+ type: "find",
517
+ schema: testSchema,
518
+ table: testSchema.tables.users,
519
+ indexName: "primary",
520
+ options: {
521
+ useIndex: "primary",
522
+ select: ["id", "name", "email"],
523
+ where: (eb) => eb.and(eb("isActive", "=", true), eb("age", ">=", 18)),
524
+ pageSize: 10,
525
+ },
526
+ });
527
+
528
+ expect(result).not.toBeNull();
529
+ expect(result!.sql).toMatchInlineSnapshot(
530
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" where ("users"."isActive" = ? and "users"."age" >= ?) limit ?"`,
531
+ );
532
+ });
533
+ });
534
+
535
+ describe("custom-named id columns", () => {
536
+ test("should handle custom id column in create", () => {
537
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
538
+
539
+ const result = compiler.compileCreate({
540
+ type: "create",
541
+ schema: customIdSchema,
542
+ table: "products",
543
+ values: {
544
+ name: "Widget",
545
+ price: 1000,
546
+ },
547
+ generatedExternalId: "prod-123",
548
+ });
549
+
550
+ expect(result).not.toBeNull();
551
+ expect(result!.query.sql).toMatchInlineSnapshot(
552
+ `"insert into "products" ("productId", "name", "price") values (?, ?, ?) returning "products"."productId" as "productId", "products"."name" as "name", "products"."price" as "price", "products"."_internalId" as "_internalId", "products"."_version" as "_version""`,
553
+ );
554
+ });
555
+
556
+ test("should handle custom id column in find", () => {
557
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
558
+
559
+ const result = compiler.compileFind({
560
+ type: "find",
561
+ schema: customIdSchema,
562
+ table: customIdSchema.tables.products,
563
+ indexName: "primary",
564
+ options: {
565
+ useIndex: "primary",
566
+ select: ["productId", "name"],
567
+ pageSize: 10,
568
+ },
569
+ });
570
+
571
+ expect(result).not.toBeNull();
572
+ expect(result!.sql).toMatchInlineSnapshot(
573
+ `"select "products"."productId" as "productId", "products"."name" as "name", "products"."_internalId" as "_internalId", "products"."_version" as "_version" from "products" limit ?"`,
574
+ );
575
+ });
576
+
577
+ test("should handle custom id column in where clause", () => {
578
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
579
+
580
+ const result = compiler.compileFind({
581
+ type: "find",
582
+ schema: customIdSchema,
583
+ table: customIdSchema.tables.products,
584
+ indexName: "primary",
585
+ options: {
586
+ useIndex: "primary",
587
+ select: true,
588
+ where: (eb) => eb("productId", "=", "prod-123"),
589
+ pageSize: 10,
590
+ },
591
+ });
592
+
593
+ expect(result).not.toBeNull();
594
+ expect(result!.sql).toMatchInlineSnapshot(
595
+ `"select "products"."productId" as "productId", "products"."name" as "name", "products"."price" as "price", "products"."_internalId" as "_internalId", "products"."_version" as "_version" from "products" where "products"."productId" = ? limit ?"`,
596
+ );
597
+ });
598
+
599
+ test("should handle custom id column in update", () => {
600
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
601
+
602
+ const result = compiler.compileUpdate({
603
+ type: "update",
604
+ schema: customIdSchema,
605
+ table: "products",
606
+ id: "prod-456",
607
+ checkVersion: false,
608
+ set: {
609
+ price: 2000,
610
+ },
611
+ });
612
+
613
+ expect(result).not.toBeNull();
614
+ expect(result!.query.sql).toMatchInlineSnapshot(
615
+ `"update "products" set "price" = ?, "_version" = COALESCE(_version, 0) + 1 where "products"."productId" = ?"`,
616
+ );
617
+ });
618
+
619
+ test("should handle references to custom id columns", () => {
620
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
621
+
622
+ const result = compiler.compileFind({
623
+ type: "find",
624
+ schema: customIdSchema,
625
+ table: customIdSchema.tables.orders,
626
+ indexName: "primary",
627
+ options: {
628
+ useIndex: "primary",
629
+ select: ["orderId", "productRef", "quantity"],
630
+ where: (eb) => eb("orderId", "=", "order-789"),
631
+ pageSize: 10,
632
+ },
633
+ });
634
+
635
+ expect(result).not.toBeNull();
636
+ expect(result!.sql).toMatchInlineSnapshot(
637
+ `"select "orders"."orderId" as "orderId", "orders"."productRef" as "productRef", "orders"."quantity" as "quantity", "orders"."_internalId" as "_internalId", "orders"."_version" as "_version" from "orders" where "orders"."orderId" = ? limit ?"`,
638
+ );
639
+ });
640
+ });
641
+
642
+ describe("special columns - _internalId and _version", () => {
643
+ test("should always include _internalId and _version", () => {
644
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
645
+
646
+ const result = compiler.compileFind({
647
+ type: "find",
648
+ schema: testSchema,
649
+ table: testSchema.tables.users,
650
+ indexName: "primary",
651
+ options: {
652
+ useIndex: "primary",
653
+ select: ["name", "email"],
654
+ pageSize: 10,
655
+ },
656
+ });
657
+
658
+ expect(result).not.toBeNull();
659
+ expect(result!.sql).toMatchInlineSnapshot(
660
+ `"select "users"."name" as "name", "users"."email" as "email", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" limit ?"`,
661
+ );
662
+ });
663
+
664
+ test("should include _internalId when id is selected", () => {
665
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
666
+
667
+ const result = compiler.compileFind({
668
+ type: "find",
669
+ schema: testSchema,
670
+ table: testSchema.tables.users,
671
+ indexName: "primary",
672
+ options: {
673
+ useIndex: "primary",
674
+ select: ["id", "name"],
675
+ pageSize: 10,
676
+ },
677
+ });
678
+
679
+ expect(result).not.toBeNull();
680
+ expect(result!.sql).toMatchInlineSnapshot(
681
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" limit ?"`,
682
+ );
683
+ });
684
+ });
685
+
686
+ describe("id column selection", () => {
687
+ test("should select id column explicitly", () => {
688
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
689
+
690
+ const result = compiler.compileFind({
691
+ type: "find",
692
+ schema: testSchema,
693
+ table: testSchema.tables.users,
694
+ indexName: "primary",
695
+ options: {
696
+ useIndex: "primary",
697
+ select: ["id"],
698
+ pageSize: 10,
699
+ },
700
+ });
701
+
702
+ expect(result).not.toBeNull();
703
+ expect(result!.sql).toMatchInlineSnapshot(
704
+ `"select "users"."id" as "id", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" limit ?"`,
705
+ );
706
+ });
707
+
708
+ test("should handle id column in where clause", () => {
709
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
710
+
711
+ const result = compiler.compileFind({
712
+ type: "find",
713
+ schema: testSchema,
714
+ table: testSchema.tables.users,
715
+ indexName: "primary",
716
+ options: {
717
+ useIndex: "primary",
718
+ select: ["id", "name"],
719
+ where: (eb) => eb("id", "=", "test-id-123"),
720
+ pageSize: 10,
721
+ },
722
+ });
723
+
724
+ expect(result).not.toBeNull();
725
+ expect(result!.sql).toMatchInlineSnapshot(
726
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" where "users"."id" = ? limit ?"`,
727
+ );
728
+ });
729
+ });
730
+
731
+ describe("orderByIndex", () => {
732
+ test("should compile find with orderByIndex on primary index", () => {
733
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
734
+
735
+ const result = compiler.compileFind({
736
+ type: "find",
737
+ schema: testSchema,
738
+ table: testSchema.tables.users,
739
+ indexName: "_primary",
740
+ options: {
741
+ useIndex: "_primary",
742
+ select: true,
743
+ orderByIndex: { indexName: "_primary", direction: "desc" },
744
+ },
745
+ });
746
+
747
+ expect(result).not.toBeNull();
748
+ expect(result!.sql).toMatchInlineSnapshot(
749
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."age" as "age", "users"."isActive" as "isActive", "users"."createdAt" as "createdAt", "users"."invitedBy" as "invitedBy", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" order by "users"."id" desc"`,
750
+ );
751
+ });
752
+
753
+ test("should compile find with orderByIndex on named index", () => {
754
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
755
+
756
+ const result = compiler.compileFind({
757
+ type: "find",
758
+ schema: testSchema,
759
+ table: testSchema.tables.users,
760
+ indexName: "idx_name",
761
+ options: {
762
+ useIndex: "idx_name",
763
+ select: true,
764
+ orderByIndex: { indexName: "idx_name", direction: "asc" },
765
+ },
766
+ });
767
+
768
+ expect(result).not.toBeNull();
769
+ expect(result!.sql).toMatchInlineSnapshot(
770
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."age" as "age", "users"."isActive" as "isActive", "users"."createdAt" as "createdAt", "users"."invitedBy" as "invitedBy", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" order by "users"."name" asc"`,
771
+ );
772
+ });
773
+
774
+ test("should compile find with orderByIndex and where clause", () => {
775
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
776
+
777
+ const result = compiler.compileFind({
778
+ type: "find",
779
+ schema: testSchema,
780
+ table: testSchema.tables.users,
781
+ indexName: "idx_age",
782
+ options: {
783
+ useIndex: "idx_age",
784
+ select: ["id", "name", "age"],
785
+ where: (eb) => eb("age", ">", 18),
786
+ orderByIndex: { indexName: "idx_age", direction: "desc" },
787
+ pageSize: 10,
788
+ },
789
+ });
790
+
791
+ expect(result).not.toBeNull();
792
+ expect(result!.sql).toMatchInlineSnapshot(
793
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."age" as "age", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" where "users"."age" > ? order by "users"."age" desc limit ?"`,
794
+ );
795
+ });
796
+ });
797
+
798
+ describe("cursor pagination", () => {
799
+ test("should compile find with cursor pagination using after", () => {
800
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
801
+ const cursor = new Cursor({
802
+ indexName: "idx_name",
803
+ orderDirection: "asc",
804
+ pageSize: 10,
805
+ indexValues: { name: "Alice" },
806
+ });
807
+
808
+ const result = compiler.compileFind({
809
+ type: "find",
810
+ schema: testSchema,
811
+ table: testSchema.tables.users,
812
+ indexName: "idx_name",
813
+ options: {
814
+ useIndex: "idx_name",
815
+ select: true,
816
+ orderByIndex: { indexName: "idx_name", direction: "asc" },
817
+ after: cursor,
818
+ pageSize: 10,
819
+ },
820
+ });
821
+
822
+ expect(result).not.toBeNull();
823
+ expect(result!.sql).toMatchInlineSnapshot(
824
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."age" as "age", "users"."isActive" as "isActive", "users"."createdAt" as "createdAt", "users"."invitedBy" as "invitedBy", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" where "users"."name" > ? order by "users"."name" asc limit ?"`,
825
+ );
826
+ expect(result!.parameters).toEqual(["Alice", 10]);
827
+ });
828
+
829
+ test("should compile find with cursor pagination using before", () => {
830
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
831
+ const cursor = new Cursor({
832
+ indexName: "idx_name",
833
+ orderDirection: "desc",
834
+ pageSize: 10,
835
+ indexValues: { name: "Bob" },
836
+ });
837
+
838
+ const result = compiler.compileFind({
839
+ type: "find",
840
+ schema: testSchema,
841
+ table: testSchema.tables.users,
842
+ indexName: "idx_name",
843
+ options: {
844
+ useIndex: "idx_name",
845
+ select: true,
846
+ orderByIndex: { indexName: "idx_name", direction: "desc" },
847
+ before: cursor,
848
+ pageSize: 10,
849
+ },
850
+ });
851
+
852
+ expect(result).not.toBeNull();
853
+ expect(result!.sql).toMatchInlineSnapshot(
854
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."age" as "age", "users"."isActive" as "isActive", "users"."createdAt" as "createdAt", "users"."invitedBy" as "invitedBy", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" where "users"."name" > ? order by "users"."name" desc limit ?"`,
855
+ );
856
+ expect(result!.parameters).toEqual(["Bob", 10]);
857
+ });
858
+
859
+ test("should compile find with cursor pagination and additional where conditions", () => {
860
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
861
+ const cursor = new Cursor({
862
+ indexName: "idx_name",
863
+ orderDirection: "asc",
864
+ pageSize: 5,
865
+ indexValues: { name: "Alice" },
866
+ });
867
+
868
+ const result = compiler.compileFind({
869
+ type: "find",
870
+ schema: testSchema,
871
+ table: testSchema.tables.users,
872
+ indexName: "idx_name",
873
+ options: {
874
+ useIndex: "idx_name",
875
+ select: true,
876
+ where: (eb) => eb("isActive", "=", true),
877
+ orderByIndex: { indexName: "idx_name", direction: "asc" },
878
+ after: cursor,
879
+ pageSize: 5,
880
+ },
881
+ });
882
+
883
+ expect(result).not.toBeNull();
884
+ expect(result!.sql).toMatchInlineSnapshot(
885
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."age" as "age", "users"."isActive" as "isActive", "users"."createdAt" as "createdAt", "users"."invitedBy" as "invitedBy", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" where ("users"."isActive" = ? and "users"."name" > ?) order by "users"."name" asc limit ?"`,
886
+ );
887
+ expect(result!.parameters).toEqual([1, "Alice", 5]);
888
+ });
889
+ });
890
+
891
+ describe("complex where conditions", () => {
892
+ test("should compile find with AND conditions", () => {
893
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
894
+
895
+ const result = compiler.compileFind({
896
+ type: "find",
897
+ schema: testSchema,
898
+ table: testSchema.tables.users,
899
+ indexName: "primary",
900
+ options: {
901
+ useIndex: "primary",
902
+ select: true,
903
+ where: (eb) => eb.and(eb("age", ">", 18), eb("isActive", "=", true)),
904
+ pageSize: 10,
905
+ },
906
+ });
907
+
908
+ expect(result).not.toBeNull();
909
+ expect(result!.sql).toMatchInlineSnapshot(
910
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."age" as "age", "users"."isActive" as "isActive", "users"."createdAt" as "createdAt", "users"."invitedBy" as "invitedBy", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" where ("users"."age" > ? and "users"."isActive" = ?) limit ?"`,
911
+ );
912
+ });
913
+
914
+ test("should compile find with OR conditions", () => {
915
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
916
+
917
+ const result = compiler.compileFind({
918
+ type: "find",
919
+ schema: testSchema,
920
+ table: testSchema.tables.users,
921
+ indexName: "primary",
922
+ options: {
923
+ useIndex: "primary",
924
+ select: true,
925
+ where: (eb) => eb.or(eb("name", "=", "Alice"), eb("name", "=", "Bob")),
926
+ pageSize: 10,
927
+ },
928
+ });
929
+
930
+ expect(result).not.toBeNull();
931
+ expect(result!.sql).toMatchInlineSnapshot(
932
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."age" as "age", "users"."isActive" as "isActive", "users"."createdAt" as "createdAt", "users"."invitedBy" as "invitedBy", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" where ("users"."name" = ? or "users"."name" = ?) limit ?"`,
933
+ );
934
+ expect(result!.parameters).toEqual(["Alice", "Bob", 10]);
935
+ });
936
+
937
+ test("should compile find with nested AND/OR conditions", () => {
938
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
939
+
940
+ const result = compiler.compileFind({
941
+ type: "find",
942
+ schema: testSchema,
943
+ table: testSchema.tables.users,
944
+ indexName: "primary",
945
+ options: {
946
+ useIndex: "primary",
947
+ select: true,
948
+ where: (eb) =>
949
+ eb.and(
950
+ eb("isActive", "=", true),
951
+ eb.or(eb("name", "=", "Alice"), eb("name", "=", "Bob")),
952
+ ),
953
+ pageSize: 10,
954
+ },
955
+ });
956
+
957
+ expect(result).not.toBeNull();
958
+ expect(result!.sql).toMatchInlineSnapshot(
959
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."age" as "age", "users"."isActive" as "isActive", "users"."createdAt" as "createdAt", "users"."invitedBy" as "invitedBy", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" where ("users"."isActive" = ? and ("users"."name" = ? or "users"."name" = ?)) limit ?"`,
960
+ );
961
+ expect(result!.parameters).toEqual([1, "Alice", "Bob", 10]);
962
+ });
963
+ });
964
+
965
+ describe("always-false/always-true conditions", () => {
966
+ test("should return null for always-false conditions in find", () => {
967
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
968
+
969
+ const result = compiler.compileFind({
970
+ type: "find",
971
+ schema: testSchema,
972
+ table: testSchema.tables.users,
973
+ indexName: "primary",
974
+ options: {
975
+ useIndex: "primary",
976
+ select: true,
977
+ where: () => false,
978
+ pageSize: 10,
979
+ },
980
+ });
981
+
982
+ expect(result).toBeNull();
983
+ });
984
+
985
+ test("should compile query without where for always-true conditions", () => {
986
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
987
+
988
+ const result = compiler.compileFind({
989
+ type: "find",
990
+ schema: testSchema,
991
+ table: testSchema.tables.users,
992
+ indexName: "primary",
993
+ options: {
994
+ useIndex: "primary",
995
+ select: true,
996
+ where: () => true,
997
+ pageSize: 10,
998
+ },
999
+ });
1000
+
1001
+ expect(result).not.toBeNull();
1002
+ expect(result!.sql).toMatchInlineSnapshot(
1003
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."age" as "age", "users"."isActive" as "isActive", "users"."createdAt" as "createdAt", "users"."invitedBy" as "invitedBy", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" limit ?"`,
1004
+ );
1005
+ });
1006
+
1007
+ test("should return null for always-false conditions in count", () => {
1008
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1009
+
1010
+ const result = compiler.compileCount({
1011
+ type: "count",
1012
+ schema: testSchema,
1013
+ table: testSchema.tables.users,
1014
+ indexName: "primary",
1015
+ options: {
1016
+ useIndex: "primary",
1017
+ where: () => false,
1018
+ },
1019
+ });
1020
+
1021
+ expect(result).toBeNull();
1022
+ });
1023
+ });
1024
+
1025
+ describe("contains and starts with operators", () => {
1026
+ test("should compile find with contains operator", () => {
1027
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1028
+
1029
+ const result = compiler.compileFind({
1030
+ type: "find",
1031
+ schema: testSchema,
1032
+ table: testSchema.tables.users,
1033
+ indexName: "primary",
1034
+ options: {
1035
+ useIndex: "primary",
1036
+ select: true,
1037
+ where: (eb) => eb("email", "contains", "@example.com"),
1038
+ pageSize: 10,
1039
+ },
1040
+ });
1041
+
1042
+ expect(result).not.toBeNull();
1043
+ expect(result!.sql).toMatchInlineSnapshot(
1044
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."age" as "age", "users"."isActive" as "isActive", "users"."createdAt" as "createdAt", "users"."invitedBy" as "invitedBy", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" where "users"."email" like ? limit ?"`,
1045
+ );
1046
+ expect(result!.parameters).toEqual(["%@example.com%", 10]);
1047
+ });
1048
+
1049
+ test("should compile find with starts with operator", () => {
1050
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1051
+
1052
+ const result = compiler.compileFind({
1053
+ type: "find",
1054
+ schema: testSchema,
1055
+ table: testSchema.tables.users,
1056
+ indexName: "primary",
1057
+ options: {
1058
+ useIndex: "primary",
1059
+ select: true,
1060
+ where: (eb) => eb("name", "starts with", "John"),
1061
+ pageSize: 10,
1062
+ },
1063
+ });
1064
+
1065
+ expect(result).not.toBeNull();
1066
+ expect(result!.sql).toMatchInlineSnapshot(
1067
+ `"select "users"."id" as "id", "users"."name" as "name", "users"."email" as "email", "users"."age" as "age", "users"."isActive" as "isActive", "users"."createdAt" as "createdAt", "users"."invitedBy" as "invitedBy", "users"."_internalId" as "_internalId", "users"."_version" as "_version" from "users" where "users"."name" like ? limit ?"`,
1068
+ );
1069
+ expect(result!.parameters).toEqual(["John%", 10]);
1070
+ });
1071
+ });
1072
+
1073
+ describe("join operations", () => {
1074
+ test("should compile find with basic join", () => {
1075
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1076
+
1077
+ const result = compiler.compileFind({
1078
+ type: "find",
1079
+ schema: testSchema,
1080
+ table: testSchema.tables.posts,
1081
+ indexName: "primary",
1082
+ options: {
1083
+ useIndex: "primary",
1084
+ select: ["id", "title"],
1085
+ joins: [
1086
+ {
1087
+ relation: testSchema.tables.posts.relations.author,
1088
+ options: {
1089
+ select: ["name", "email"],
1090
+ },
1091
+ },
1092
+ ],
1093
+ },
1094
+ });
1095
+
1096
+ expect(result).not.toBeNull();
1097
+ expect(result!.sql).toMatchInlineSnapshot(
1098
+ `"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""`,
1099
+ );
1100
+ });
1101
+
1102
+ test("should compile join with specific column selection", () => {
1103
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1104
+
1105
+ const result = compiler.compileFind({
1106
+ type: "find",
1107
+ schema: testSchema,
1108
+ table: testSchema.tables.posts,
1109
+ indexName: "primary",
1110
+ options: {
1111
+ useIndex: "primary",
1112
+ select: ["id", "userId"],
1113
+ joins: [
1114
+ {
1115
+ relation: testSchema.tables.posts.relations.author,
1116
+ options: {
1117
+ select: true,
1118
+ },
1119
+ },
1120
+ ],
1121
+ },
1122
+ });
1123
+
1124
+ expect(result).not.toBeNull();
1125
+ expect(result!.sql).toMatchInlineSnapshot(
1126
+ `"select "author"."id" as "author:id", "author"."name" as "author:name", "author"."email" as "author:email", "author"."age" as "author:age", "author"."isActive" as "author:isActive", "author"."createdAt" as "author:createdAt", "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""`,
1127
+ );
1128
+ });
1129
+
1130
+ test("should compile find with multiple joins", () => {
1131
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1132
+
1133
+ const result = compiler.compileFind({
1134
+ type: "find",
1135
+ schema: testSchema,
1136
+ table: testSchema.tables.comments,
1137
+ indexName: "primary",
1138
+ options: {
1139
+ useIndex: "primary",
1140
+ select: ["id", "content"],
1141
+ joins: [
1142
+ {
1143
+ relation: testSchema.tables.comments.relations.post,
1144
+ options: {
1145
+ select: ["title"],
1146
+ },
1147
+ },
1148
+ {
1149
+ relation: testSchema.tables.comments.relations.author,
1150
+ options: {
1151
+ select: ["name"],
1152
+ },
1153
+ },
1154
+ ],
1155
+ },
1156
+ });
1157
+
1158
+ expect(result).not.toBeNull();
1159
+ expect(result!.sql).toMatchInlineSnapshot(
1160
+ `"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""`,
1161
+ );
1162
+ });
1163
+
1164
+ test("should compile self-referencing join", () => {
1165
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1166
+
1167
+ const result = compiler.compileFind({
1168
+ type: "find",
1169
+ schema: testSchema,
1170
+ table: testSchema.tables.users,
1171
+ indexName: "primary",
1172
+ options: {
1173
+ useIndex: "primary",
1174
+ select: ["id", "name"],
1175
+ joins: [
1176
+ {
1177
+ relation: testSchema.tables.users.relations.inviter,
1178
+ options: {
1179
+ select: ["name", "email"],
1180
+ },
1181
+ },
1182
+ ],
1183
+ },
1184
+ });
1185
+
1186
+ expect(result).not.toBeNull();
1187
+ expect(result!.sql).toMatchInlineSnapshot(
1188
+ `"select "inviter"."name" as "inviter:name", "inviter"."email" as "inviter:email", "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""`,
1189
+ );
1190
+ });
1191
+
1192
+ test("should compile join with where clause on joined table", () => {
1193
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1194
+ const usersTable = testSchema.tables.users;
1195
+
1196
+ const result = compiler.compileFind({
1197
+ type: "find",
1198
+ schema: testSchema,
1199
+ table: testSchema.tables.posts,
1200
+ indexName: "primary",
1201
+ options: {
1202
+ useIndex: "primary",
1203
+ select: ["id", "title"],
1204
+ joins: [
1205
+ {
1206
+ relation: testSchema.tables.posts.relations.author,
1207
+ options: {
1208
+ select: ["name"],
1209
+ where: {
1210
+ type: "compare",
1211
+ a: usersTable.columns.name,
1212
+ operator: "contains",
1213
+ b: "john",
1214
+ },
1215
+ },
1216
+ },
1217
+ ],
1218
+ },
1219
+ });
1220
+
1221
+ expect(result).not.toBeNull();
1222
+ expect(result!.sql).toMatchInlineSnapshot(
1223
+ `"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 ?)"`,
1224
+ );
1225
+ expect(result!.parameters).toEqual(["%john%"]);
1226
+ });
1227
+
1228
+ test("should compile join with complex AND where conditions", () => {
1229
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1230
+ const usersTable = testSchema.tables.users;
1231
+
1232
+ const result = compiler.compileFind({
1233
+ type: "find",
1234
+ schema: testSchema,
1235
+ table: testSchema.tables.posts,
1236
+ indexName: "primary",
1237
+ options: {
1238
+ useIndex: "primary",
1239
+ select: ["id", "title"],
1240
+ joins: [
1241
+ {
1242
+ relation: testSchema.tables.posts.relations.author,
1243
+ options: {
1244
+ select: ["name"],
1245
+ where: {
1246
+ type: "and",
1247
+ items: [
1248
+ {
1249
+ type: "compare",
1250
+ a: usersTable.columns.name,
1251
+ operator: "contains",
1252
+ b: "john",
1253
+ },
1254
+ {
1255
+ type: "compare",
1256
+ a: usersTable.columns.isActive,
1257
+ operator: "=",
1258
+ b: true,
1259
+ },
1260
+ ],
1261
+ },
1262
+ },
1263
+ },
1264
+ ],
1265
+ },
1266
+ });
1267
+
1268
+ expect(result).not.toBeNull();
1269
+ expect(result!.sql).toMatchInlineSnapshot(
1270
+ `"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 ? and "users"."isActive" = ?))"`,
1271
+ );
1272
+ });
1273
+
1274
+ test("should compile join with id column selection", () => {
1275
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1276
+
1277
+ const result = compiler.compileFind({
1278
+ type: "find",
1279
+ schema: testSchema,
1280
+ table: testSchema.tables.posts,
1281
+ indexName: "primary",
1282
+ options: {
1283
+ useIndex: "primary",
1284
+ select: ["id", "title"],
1285
+ joins: [
1286
+ {
1287
+ relation: testSchema.tables.posts.relations.author,
1288
+ options: {
1289
+ select: ["id", "name"],
1290
+ },
1291
+ },
1292
+ ],
1293
+ },
1294
+ });
1295
+
1296
+ expect(result).not.toBeNull();
1297
+ expect(result!.sql).toMatchInlineSnapshot(
1298
+ `"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""`,
1299
+ );
1300
+ });
1301
+
1302
+ test("should compile join with select true (all columns)", () => {
1303
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1304
+
1305
+ const result = compiler.compileFind({
1306
+ type: "find",
1307
+ schema: testSchema,
1308
+ table: testSchema.tables.posts,
1309
+ indexName: "primary",
1310
+ options: {
1311
+ useIndex: "primary",
1312
+ select: ["id"],
1313
+ joins: [
1314
+ {
1315
+ relation: testSchema.tables.posts.relations.author,
1316
+ options: {
1317
+ select: true,
1318
+ },
1319
+ },
1320
+ ],
1321
+ },
1322
+ });
1323
+
1324
+ expect(result).not.toBeNull();
1325
+ expect(result!.sql).toMatchInlineSnapshot(
1326
+ `"select "author"."id" as "author:id", "author"."name" as "author:name", "author"."email" as "author:email", "author"."age" as "author:age", "author"."isActive" as "author:isActive", "author"."createdAt" as "author:createdAt", "author"."invitedBy" as "author:invitedBy", "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""`,
1327
+ );
1328
+ });
1329
+
1330
+ test("should compile join with id in where clause on joined table", () => {
1331
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1332
+ const usersTable = testSchema.tables.users;
1333
+
1334
+ const result = compiler.compileFind({
1335
+ type: "find",
1336
+ schema: testSchema,
1337
+ table: testSchema.tables.posts,
1338
+ indexName: "primary",
1339
+ options: {
1340
+ useIndex: "primary",
1341
+ select: ["id", "title"],
1342
+ joins: [
1343
+ {
1344
+ relation: testSchema.tables.posts.relations.author,
1345
+ options: {
1346
+ select: ["id", "name"],
1347
+ where: {
1348
+ type: "compare",
1349
+ a: usersTable.columns.id,
1350
+ operator: "=",
1351
+ b: "user-123",
1352
+ },
1353
+ },
1354
+ },
1355
+ ],
1356
+ },
1357
+ });
1358
+
1359
+ expect(result).not.toBeNull();
1360
+ expect(result!.sql).toMatchInlineSnapshot(
1361
+ `"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" = ?)"`,
1362
+ );
1363
+ expect(result!.parameters).toEqual(["user-123"]);
1364
+ });
1365
+
1366
+ test("should compile multiple joins with different id selections", () => {
1367
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1368
+
1369
+ const result = compiler.compileFind({
1370
+ type: "find",
1371
+ schema: testSchema,
1372
+ table: testSchema.tables.comments,
1373
+ indexName: "primary",
1374
+ options: {
1375
+ useIndex: "primary",
1376
+ select: ["id", "content"],
1377
+ joins: [
1378
+ {
1379
+ relation: testSchema.tables.comments.relations.post,
1380
+ options: {
1381
+ select: ["id", "title"],
1382
+ },
1383
+ },
1384
+ {
1385
+ relation: testSchema.tables.comments.relations.author,
1386
+ options: {
1387
+ select: ["name"],
1388
+ },
1389
+ },
1390
+ ],
1391
+ },
1392
+ });
1393
+
1394
+ expect(result).not.toBeNull();
1395
+ expect(result!.sql).toMatchInlineSnapshot(
1396
+ `"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""`,
1397
+ );
1398
+ });
1399
+
1400
+ test("should compile many-to-many join through junction table", () => {
1401
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1402
+
1403
+ const result = compiler.compileFind({
1404
+ type: "find",
1405
+ schema: testSchema,
1406
+ table: testSchema.tables.post_tags,
1407
+ indexName: "primary",
1408
+ options: {
1409
+ useIndex: "primary",
1410
+ select: ["id"],
1411
+ joins: [
1412
+ {
1413
+ relation: testSchema.tables.post_tags.relations.post,
1414
+ options: {
1415
+ select: ["title"],
1416
+ },
1417
+ },
1418
+ {
1419
+ relation: testSchema.tables.post_tags.relations.tag,
1420
+ options: {
1421
+ select: ["name"],
1422
+ },
1423
+ },
1424
+ ],
1425
+ },
1426
+ });
1427
+
1428
+ expect(result).not.toBeNull();
1429
+ expect(result!.sql).toMatchInlineSnapshot(
1430
+ `"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""`,
1431
+ );
1432
+ });
1433
+ });
1434
+
1435
+ describe("custom-named id columns in joins", () => {
1436
+ test("should compile join with custom id column names", () => {
1437
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1438
+
1439
+ const result = compiler.compileFind({
1440
+ type: "find",
1441
+ schema: customIdSchema,
1442
+ table: customIdSchema.tables.product_categories,
1443
+ indexName: "primary",
1444
+ options: {
1445
+ useIndex: "primary",
1446
+ select: ["id"],
1447
+ joins: [
1448
+ {
1449
+ relation: customIdSchema.tables.product_categories.relations.product,
1450
+ options: {
1451
+ select: ["productId", "name"],
1452
+ },
1453
+ },
1454
+ {
1455
+ relation: customIdSchema.tables.product_categories.relations.category,
1456
+ options: {
1457
+ select: ["categoryId", "categoryName"],
1458
+ },
1459
+ },
1460
+ ],
1461
+ },
1462
+ });
1463
+
1464
+ expect(result).not.toBeNull();
1465
+ expect(result!.sql).toMatchInlineSnapshot(
1466
+ `"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""`,
1467
+ );
1468
+ });
1469
+
1470
+ test("should handle custom id in join where clause", () => {
1471
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1472
+ const productsTable = customIdSchema.tables.products;
1473
+
1474
+ const result = compiler.compileFind({
1475
+ type: "find",
1476
+ schema: customIdSchema,
1477
+ table: customIdSchema.tables.product_categories,
1478
+ indexName: "primary",
1479
+ options: {
1480
+ useIndex: "primary",
1481
+ select: ["id"],
1482
+ joins: [
1483
+ {
1484
+ relation: customIdSchema.tables.product_categories.relations.product,
1485
+ options: {
1486
+ select: ["productId", "name"],
1487
+ where: {
1488
+ type: "compare",
1489
+ a: productsTable.columns.productId,
1490
+ operator: "=",
1491
+ b: "prod-456",
1492
+ },
1493
+ },
1494
+ },
1495
+ ],
1496
+ },
1497
+ });
1498
+
1499
+ expect(result).not.toBeNull();
1500
+ expect(result!.sql).toMatchInlineSnapshot(
1501
+ `"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" = ?)"`,
1502
+ );
1503
+ expect(result!.parameters).toEqual(["prod-456"]);
1504
+ });
1505
+
1506
+ test("should handle select true with custom id columns in join", () => {
1507
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1508
+
1509
+ const result = compiler.compileFind({
1510
+ type: "find",
1511
+ schema: customIdSchema,
1512
+ table: customIdSchema.tables.product_categories,
1513
+ indexName: "primary",
1514
+ options: {
1515
+ useIndex: "primary",
1516
+ select: ["id"],
1517
+ joins: [
1518
+ {
1519
+ relation: customIdSchema.tables.product_categories.relations.product,
1520
+ options: {
1521
+ select: true,
1522
+ },
1523
+ },
1524
+ ],
1525
+ },
1526
+ });
1527
+
1528
+ expect(result).not.toBeNull();
1529
+ expect(result!.sql).toMatchInlineSnapshot(
1530
+ `"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"."_internalId" as "_internalId", "product_categories"."_version" as "_version" from "product_categories" left join "products" as "product" on "product_categories"."prodRef" = "product"."_internalId""`,
1531
+ );
1532
+ });
1533
+
1534
+ test("should join tables with different custom id names", () => {
1535
+ const compiler = new GenericSQLUOWOperationCompiler(driverConfig);
1536
+
1537
+ const result = compiler.compileFind({
1538
+ type: "find",
1539
+ schema: customIdSchema,
1540
+ table: customIdSchema.tables.product_categories,
1541
+ indexName: "primary",
1542
+ options: {
1543
+ useIndex: "primary",
1544
+ select: ["id"],
1545
+ joins: [
1546
+ {
1547
+ relation: customIdSchema.tables.product_categories.relations.product,
1548
+ options: {
1549
+ select: ["productId"],
1550
+ },
1551
+ },
1552
+ {
1553
+ relation: customIdSchema.tables.product_categories.relations.category,
1554
+ options: {
1555
+ select: ["categoryId"],
1556
+ },
1557
+ },
1558
+ ],
1559
+ },
1560
+ });
1561
+
1562
+ expect(result).not.toBeNull();
1563
+ expect(result!.sql).toMatchInlineSnapshot(
1564
+ `"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""`,
1565
+ );
1566
+ });
1567
+ });
1568
+ });