@fragno-dev/db 0.1.15 → 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 (407) hide show
  1. package/.turbo/turbo-build.log +242 -179
  2. package/CHANGELOG.md +23 -0
  3. package/README.md +123 -8
  4. package/dist/adapters/adapters.d.ts +5 -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 -21
  8. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
  9. package/dist/adapters/drizzle/drizzle-adapter.js +7 -54
  10. package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
  11. package/dist/adapters/drizzle/generate.d.ts +3 -0
  12. package/dist/adapters/drizzle/generate.d.ts.map +1 -1
  13. package/dist/adapters/drizzle/generate.js +36 -28
  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 -18
  68. package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
  69. package/dist/adapters/kysely/kysely-adapter.js +6 -165
  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} +47 -61
  72. package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -0
  73. package/dist/adapters/{drizzle/shared.d.ts → shared/table-name-mapper.d.ts} +2 -4
  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 +53 -19
  80. package/dist/db-fragment-definition-builder.d.ts.map +1 -1
  81. package/dist/db-fragment-definition-builder.js +89 -19
  82. package/dist/db-fragment-definition-builder.js.map +1 -1
  83. package/dist/fragments/internal-fragment.d.ts +39 -5
  84. package/dist/fragments/internal-fragment.d.ts.map +1 -1
  85. package/dist/fragments/internal-fragment.js +82 -10
  86. package/dist/fragments/internal-fragment.js.map +1 -1
  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 +23 -61
  94. package/dist/migration-engine/generation-engine.js.map +1 -1
  95. package/dist/mod.d.ts +34 -10
  96. package/dist/mod.d.ts.map +1 -1
  97. package/dist/mod.js +47 -16
  98. package/dist/mod.js.map +1 -1
  99. package/dist/node_modules/.pnpm/{rou3@0.7.8 → rou3@0.7.10}/node_modules/rou3/dist/index.js +1 -1
  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/fragment-instantiator.js +69 -31
  102. package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -1
  103. package/dist/query/column-defaults.js +27 -0
  104. package/dist/query/column-defaults.js.map +1 -0
  105. package/dist/query/cursor.d.ts +4 -4
  106. package/dist/query/cursor.d.ts.map +1 -1
  107. package/dist/query/cursor.js +8 -6
  108. package/dist/query/cursor.js.map +1 -1
  109. package/dist/query/orm/orm.d.ts +1 -1
  110. package/dist/query/orm/orm.js.map +1 -1
  111. package/dist/query/serialize/create-sql-serializer.js +30 -0
  112. package/dist/query/serialize/create-sql-serializer.js.map +1 -0
  113. package/dist/query/serialize/dialect/mysql-serializer.js +87 -0
  114. package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -0
  115. package/dist/query/serialize/dialect/postgres-serializer.js +80 -0
  116. package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -0
  117. package/dist/query/serialize/dialect/sqlite-serializer.js +93 -0
  118. package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -0
  119. package/dist/query/serialize/sql-serializer.js +67 -0
  120. package/dist/query/serialize/sql-serializer.js.map +1 -0
  121. package/dist/query/{query.d.ts → simple-query-interface.d.ts} +5 -5
  122. package/dist/query/simple-query-interface.d.ts.map +1 -0
  123. package/dist/query/{execute-unit-of-work.d.ts → unit-of-work/execute-unit-of-work.d.ts} +13 -3
  124. package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -0
  125. package/dist/query/{execute-unit-of-work.js → unit-of-work/execute-unit-of-work.js} +17 -4
  126. package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -0
  127. package/dist/query/{retry-policy.d.ts → unit-of-work/retry-policy.d.ts} +1 -1
  128. package/dist/query/unit-of-work/retry-policy.d.ts.map +1 -0
  129. package/dist/query/{retry-policy.js → unit-of-work/retry-policy.js} +1 -1
  130. package/dist/query/unit-of-work/retry-policy.js.map +1 -0
  131. package/dist/query/{unit-of-work.d.ts → unit-of-work/unit-of-work.d.ts} +51 -18
  132. package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -0
  133. package/dist/query/{unit-of-work.js → unit-of-work/unit-of-work.js} +58 -11
  134. package/dist/query/unit-of-work/unit-of-work.js.map +1 -0
  135. package/dist/query/value-decoding.js +71 -0
  136. package/dist/query/value-decoding.js.map +1 -0
  137. package/dist/query/value-encoding.js +124 -0
  138. package/dist/query/value-encoding.js.map +1 -0
  139. package/dist/schema/create.d.ts +3 -0
  140. package/dist/schema/create.d.ts.map +1 -1
  141. package/dist/schema/create.js +4 -0
  142. package/dist/schema/create.js.map +1 -1
  143. package/dist/schema/type-conversion/create-sql-type-mapper.js +29 -0
  144. package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -0
  145. package/dist/schema/type-conversion/dialect/mysql.js +57 -0
  146. package/dist/schema/type-conversion/dialect/mysql.js.map +1 -0
  147. package/dist/schema/type-conversion/dialect/postgres.js +56 -0
  148. package/dist/schema/type-conversion/dialect/postgres.js.map +1 -0
  149. package/dist/schema/type-conversion/dialect/sqlite.js +52 -0
  150. package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -0
  151. package/dist/schema/type-conversion/type-mapping.js +63 -0
  152. package/dist/schema/type-conversion/type-mapping.js.map +1 -0
  153. package/dist/sql-driver/connection/connection-provider.d.ts +13 -0
  154. package/dist/sql-driver/connection/connection-provider.d.ts.map +1 -0
  155. package/dist/sql-driver/connection/connection-provider.js +19 -0
  156. package/dist/sql-driver/connection/connection-provider.js.map +1 -0
  157. package/dist/sql-driver/connection/single-connection-provider.js +23 -0
  158. package/dist/sql-driver/connection/single-connection-provider.js.map +1 -0
  159. package/dist/sql-driver/dialect-adapter/dialect-adapter.d.ts +7 -0
  160. package/dist/sql-driver/dialect-adapter/dialect-adapter.d.ts.map +1 -0
  161. package/dist/sql-driver/dialects/dialects.d.ts +2 -0
  162. package/dist/sql-driver/dialects/dialects.js +3 -0
  163. package/dist/sql-driver/dialects/durable-object-dialect.d.ts +72 -0
  164. package/dist/sql-driver/dialects/durable-object-dialect.d.ts.map +1 -0
  165. package/dist/sql-driver/dialects/durable-object-dialect.js +130 -0
  166. package/dist/sql-driver/dialects/durable-object-dialect.js.map +1 -0
  167. package/dist/sql-driver/driver/runtime-driver.d.ts +23 -0
  168. package/dist/sql-driver/driver/runtime-driver.d.ts.map +1 -0
  169. package/dist/sql-driver/driver/runtime-driver.js +56 -0
  170. package/dist/sql-driver/driver/runtime-driver.js.map +1 -0
  171. package/dist/sql-driver/query-executor/default-query-executor.js +26 -0
  172. package/dist/sql-driver/query-executor/default-query-executor.js.map +1 -0
  173. package/dist/sql-driver/query-executor/plugin.d.ts +17 -0
  174. package/dist/sql-driver/query-executor/plugin.d.ts.map +1 -0
  175. package/dist/sql-driver/query-executor/query-executor-base.js +25 -0
  176. package/dist/sql-driver/query-executor/query-executor-base.js.map +1 -0
  177. package/dist/sql-driver/query-executor/query-executor.d.ts +36 -0
  178. package/dist/sql-driver/query-executor/query-executor.d.ts.map +1 -0
  179. package/dist/sql-driver/sql-driver-adapter.d.ts +29 -0
  180. package/dist/sql-driver/sql-driver-adapter.d.ts.map +1 -0
  181. package/dist/sql-driver/sql-driver-adapter.js +68 -0
  182. package/dist/sql-driver/sql-driver-adapter.js.map +1 -0
  183. package/dist/sql-driver/sql-driver.d.ts +38 -0
  184. package/dist/sql-driver/sql-driver.d.ts.map +1 -0
  185. package/dist/sql-driver/sql-driver.js +1 -0
  186. package/dist/sql-driver/sql.js +50 -0
  187. package/dist/sql-driver/sql.js.map +1 -0
  188. package/dist/with-database.d.ts +6 -2
  189. package/dist/with-database.d.ts.map +1 -1
  190. package/dist/with-database.js +1 -1
  191. package/dist/with-database.js.map +1 -1
  192. package/package.json +37 -10
  193. package/src/adapters/adapters.ts +8 -5
  194. package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +60 -169
  195. package/src/adapters/drizzle/{drizzle-adapter-sqlite.test.ts → drizzle-adapter-sqlite3.test.ts} +31 -55
  196. package/src/adapters/drizzle/drizzle-adapter.ts +15 -107
  197. package/src/adapters/drizzle/generate.test.ts +2 -2
  198. package/src/adapters/drizzle/generate.ts +78 -34
  199. package/src/adapters/drizzle/migrate-drizzle.test.ts +19 -0
  200. package/src/adapters/drizzle/shared.ts +0 -34
  201. package/src/adapters/drizzle/test-utils.ts +3 -3
  202. package/src/adapters/generic-sql/README.md +14 -0
  203. package/src/adapters/generic-sql/driver-config.ts +144 -0
  204. package/src/adapters/generic-sql/generic-sql-adapter.test.ts +50 -0
  205. package/src/adapters/generic-sql/generic-sql-adapter.ts +146 -0
  206. package/src/adapters/generic-sql/generic-sql-uow-executor.ts +130 -0
  207. package/src/adapters/generic-sql/migration/cold-kysely.ts +55 -0
  208. package/src/adapters/{kysely/migration/execute-mysql.test.ts → generic-sql/migration/dialect/mysql.test.ts} +342 -484
  209. package/src/adapters/generic-sql/migration/dialect/mysql.ts +104 -0
  210. package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +1008 -0
  211. package/src/adapters/generic-sql/migration/dialect/postgres.ts +113 -0
  212. package/src/adapters/{kysely/migration/execute-sqlite.test.ts → generic-sql/migration/dialect/sqlite.test.ts} +307 -510
  213. package/src/adapters/generic-sql/migration/dialect/sqlite.ts +189 -0
  214. package/src/adapters/generic-sql/migration/executor.ts +33 -0
  215. package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +661 -0
  216. package/src/adapters/generic-sql/migration/prepared-migrations.ts +214 -0
  217. package/src/adapters/generic-sql/migration/sql-generator.ts +413 -0
  218. package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +36 -0
  219. package/src/adapters/generic-sql/query/cursor-utils.ts +56 -0
  220. package/src/adapters/generic-sql/query/dialect/mysql.ts +34 -0
  221. package/src/adapters/generic-sql/query/dialect/postgres.ts +32 -0
  222. package/src/adapters/generic-sql/query/dialect/sqlite.ts +32 -0
  223. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +1568 -0
  224. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +314 -0
  225. package/src/adapters/generic-sql/query/select-builder.test.ts +256 -0
  226. package/src/adapters/generic-sql/query/select-builder.ts +137 -0
  227. package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +195 -0
  228. package/src/adapters/generic-sql/query/sql-query-compiler.ts +367 -0
  229. package/src/adapters/generic-sql/query/where-builder.test.ts +744 -0
  230. package/src/adapters/generic-sql/query/where-builder.ts +211 -0
  231. package/src/adapters/generic-sql/result-interpreter.ts +102 -0
  232. package/src/adapters/generic-sql/test/generic-drizzle-adapter-sqlite3.test.ts +899 -0
  233. package/src/adapters/generic-sql/uow-decoder.test.ts +399 -0
  234. package/src/adapters/generic-sql/uow-decoder.ts +152 -0
  235. package/src/adapters/generic-sql/uow-encoder.test.ts +183 -0
  236. package/src/adapters/generic-sql/uow-encoder.ts +131 -0
  237. package/src/adapters/kysely/kysely-adapter-pglite.test.ts +26 -76
  238. package/src/adapters/kysely/{kysely-adapter-sqlite.test.ts → kysely-adapter-sqlocal.test.ts} +76 -17
  239. package/src/adapters/kysely/kysely-adapter.ts +10 -250
  240. package/src/adapters/{drizzle/drizzle-query.ts → shared/from-unit-of-work-compiler.ts} +110 -104
  241. package/src/adapters/shared/table-name-mapper.ts +50 -0
  242. package/src/adapters/shared/uow-operation-compiler.ts +211 -0
  243. package/src/db-fragment-definition-builder.test.ts +2 -2
  244. package/src/db-fragment-definition-builder.ts +281 -50
  245. package/src/db-fragment-instantiator.test.ts +78 -2
  246. package/src/db-fragment-integration.test.ts +14 -16
  247. package/src/fragments/internal-fragment.test.ts +434 -45
  248. package/src/fragments/internal-fragment.ts +184 -20
  249. package/src/hooks/hooks.test.ts +575 -0
  250. package/src/hooks/hooks.ts +179 -0
  251. package/src/migration-engine/generation-engine.test.ts +44 -54
  252. package/src/migration-engine/generation-engine.ts +48 -94
  253. package/src/mod.ts +117 -29
  254. package/src/query/column-defaults.ts +49 -0
  255. package/src/query/cursor.test.ts +31 -6
  256. package/src/query/cursor.ts +11 -7
  257. package/src/query/orm/orm.ts +1 -1
  258. package/src/query/query-type.test.ts +9 -9
  259. package/src/query/serialize/create-sql-serializer.ts +34 -0
  260. package/src/query/serialize/dialect/mysql-serializer.ts +142 -0
  261. package/src/query/serialize/dialect/postgres-serializer.ts +129 -0
  262. package/src/query/serialize/dialect/sqlite-serializer.test.ts +251 -0
  263. package/src/query/serialize/dialect/sqlite-serializer.ts +156 -0
  264. package/src/query/serialize/sql-serializer.ts +143 -0
  265. package/src/query/{query.ts → simple-query-interface.ts} +2 -2
  266. package/src/query/{execute-unit-of-work.test.ts → unit-of-work/execute-unit-of-work.test.ts} +16 -16
  267. package/src/query/{execute-unit-of-work.ts → unit-of-work/execute-unit-of-work.ts} +49 -8
  268. package/src/query/{unit-of-work-coordinator.test.ts → unit-of-work/unit-of-work-coordinator.test.ts} +41 -43
  269. package/src/query/{unit-of-work-types.test.ts → unit-of-work/unit-of-work-types.test.ts} +5 -3
  270. package/src/query/{unit-of-work.test.ts → unit-of-work/unit-of-work.test.ts} +100 -9
  271. package/src/query/{unit-of-work.ts → unit-of-work/unit-of-work.ts} +135 -32
  272. package/src/query/{result-transform.test.ts → value-decoding.test.ts} +45 -427
  273. package/src/query/value-decoding.ts +113 -0
  274. package/src/query/value-encoding.test.ts +390 -0
  275. package/src/query/value-encoding.ts +168 -0
  276. package/src/schema/create.test.ts +5 -1
  277. package/src/schema/create.ts +5 -0
  278. package/src/schema/serialize.test.ts +165 -407
  279. package/src/schema/type-conversion/create-sql-type-mapper.ts +28 -0
  280. package/src/schema/type-conversion/dialect/mysql.ts +64 -0
  281. package/src/schema/type-conversion/dialect/postgres.ts +62 -0
  282. package/src/schema/type-conversion/dialect/sqlite.ts +63 -0
  283. package/src/schema/type-conversion/type-mapping.test.ts +137 -0
  284. package/src/schema/type-conversion/type-mapping.ts +153 -0
  285. package/src/shared/connection-pool.ts +5 -5
  286. package/src/sql-driver/better-sqlite3.test.ts +126 -0
  287. package/src/sql-driver/connection/connection-provider.ts +27 -0
  288. package/src/sql-driver/connection/single-connection-provider.ts +42 -0
  289. package/src/sql-driver/dialect-adapter/dialect-adapter.ts +9 -0
  290. package/src/sql-driver/dialect-adapter/sqlite-dialect-adapter.ts +7 -0
  291. package/src/sql-driver/dialects/dialects.ts +1 -0
  292. package/src/sql-driver/dialects/durable-object-dialect.ts +260 -0
  293. package/src/sql-driver/driver/runtime-driver.ts +91 -0
  294. package/src/sql-driver/query-executor/default-query-executor.ts +38 -0
  295. package/src/sql-driver/query-executor/plugin.ts +22 -0
  296. package/src/sql-driver/query-executor/query-executor-base.ts +53 -0
  297. package/src/sql-driver/query-executor/query-executor.ts +44 -0
  298. package/src/sql-driver/sql-driver-adapter.ts +96 -0
  299. package/src/sql-driver/sql-driver.ts +53 -0
  300. package/src/sql-driver/sql.ts +57 -0
  301. package/src/sql-driver/sqlocal.test.ts +117 -0
  302. package/src/with-database.ts +35 -23
  303. package/tsdown.config.ts +7 -2
  304. package/dist/adapters/drizzle/drizzle-connection-pool.js +0 -40
  305. package/dist/adapters/drizzle/drizzle-connection-pool.js.map +0 -1
  306. package/dist/adapters/drizzle/drizzle-query.d.ts +0 -23
  307. package/dist/adapters/drizzle/drizzle-query.d.ts.map +0 -1
  308. package/dist/adapters/drizzle/drizzle-query.js.map +0 -1
  309. package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +0 -10
  310. package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +0 -1
  311. package/dist/adapters/drizzle/drizzle-uow-compiler.js +0 -334
  312. package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +0 -1
  313. package/dist/adapters/drizzle/drizzle-uow-decoder.js +0 -123
  314. package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +0 -1
  315. package/dist/adapters/drizzle/drizzle-uow-executor.js +0 -160
  316. package/dist/adapters/drizzle/drizzle-uow-executor.js.map +0 -1
  317. package/dist/adapters/drizzle/join-column-utils.js +0 -28
  318. package/dist/adapters/drizzle/join-column-utils.js.map +0 -1
  319. package/dist/adapters/drizzle/shared.d.ts.map +0 -1
  320. package/dist/adapters/drizzle/shared.js +0 -35
  321. package/dist/adapters/drizzle/shared.js.map +0 -1
  322. package/dist/adapters/kysely/kysely-connection-pool.js +0 -41
  323. package/dist/adapters/kysely/kysely-connection-pool.js.map +0 -1
  324. package/dist/adapters/kysely/kysely-query-builder.js +0 -321
  325. package/dist/adapters/kysely/kysely-query-builder.js.map +0 -1
  326. package/dist/adapters/kysely/kysely-query-compiler.js +0 -67
  327. package/dist/adapters/kysely/kysely-query-compiler.js.map +0 -1
  328. package/dist/adapters/kysely/kysely-query.d.ts +0 -23
  329. package/dist/adapters/kysely/kysely-query.d.ts.map +0 -1
  330. package/dist/adapters/kysely/kysely-query.js +0 -230
  331. package/dist/adapters/kysely/kysely-query.js.map +0 -1
  332. package/dist/adapters/kysely/kysely-shared.d.ts +0 -14
  333. package/dist/adapters/kysely/kysely-shared.d.ts.map +0 -1
  334. package/dist/adapters/kysely/kysely-shared.js +0 -33
  335. package/dist/adapters/kysely/kysely-shared.js.map +0 -1
  336. package/dist/adapters/kysely/kysely-uow-compiler.js +0 -193
  337. package/dist/adapters/kysely/kysely-uow-compiler.js.map +0 -1
  338. package/dist/adapters/kysely/kysely-uow-executor.js +0 -93
  339. package/dist/adapters/kysely/kysely-uow-executor.js.map +0 -1
  340. package/dist/adapters/kysely/migration/execute-base.js +0 -128
  341. package/dist/adapters/kysely/migration/execute-base.js.map +0 -1
  342. package/dist/adapters/kysely/migration/execute-factory.js +0 -34
  343. package/dist/adapters/kysely/migration/execute-factory.js.map +0 -1
  344. package/dist/adapters/kysely/migration/execute-mssql.js +0 -112
  345. package/dist/adapters/kysely/migration/execute-mssql.js.map +0 -1
  346. package/dist/adapters/kysely/migration/execute-mysql.js +0 -93
  347. package/dist/adapters/kysely/migration/execute-mysql.js.map +0 -1
  348. package/dist/adapters/kysely/migration/execute-postgres.js +0 -104
  349. package/dist/adapters/kysely/migration/execute-postgres.js.map +0 -1
  350. package/dist/adapters/kysely/migration/execute-sqlite.js +0 -123
  351. package/dist/adapters/kysely/migration/execute-sqlite.js.map +0 -1
  352. package/dist/adapters/kysely/migration/execute.js +0 -34
  353. package/dist/adapters/kysely/migration/execute.js.map +0 -1
  354. package/dist/migration-engine/create.d.ts +0 -37
  355. package/dist/migration-engine/create.d.ts.map +0 -1
  356. package/dist/migration-engine/create.js +0 -58
  357. package/dist/migration-engine/create.js.map +0 -1
  358. package/dist/migration-engine/shared.d.ts +0 -112
  359. package/dist/migration-engine/shared.d.ts.map +0 -1
  360. package/dist/node_modules/.pnpm/rou3@0.7.8/node_modules/rou3/dist/index.js.map +0 -1
  361. package/dist/query/execute-unit-of-work.d.ts.map +0 -1
  362. package/dist/query/execute-unit-of-work.js.map +0 -1
  363. package/dist/query/query.d.ts.map +0 -1
  364. package/dist/query/result-transform.js +0 -170
  365. package/dist/query/result-transform.js.map +0 -1
  366. package/dist/query/retry-policy.d.ts.map +0 -1
  367. package/dist/query/retry-policy.js.map +0 -1
  368. package/dist/query/unit-of-work.d.ts.map +0 -1
  369. package/dist/query/unit-of-work.js.map +0 -1
  370. package/dist/schema/serialize.js +0 -111
  371. package/dist/schema/serialize.js.map +0 -1
  372. package/src/adapters/drizzle/drizzle-adapter.test.ts +0 -122
  373. package/src/adapters/drizzle/drizzle-connection-pool.ts +0 -66
  374. package/src/adapters/drizzle/drizzle-query.test.ts +0 -499
  375. package/src/adapters/drizzle/drizzle-uow-compiler-mysql.test.ts +0 -1442
  376. package/src/adapters/drizzle/drizzle-uow-compiler-sqlite.test.ts +0 -1414
  377. package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +0 -1400
  378. package/src/adapters/drizzle/drizzle-uow-compiler.ts +0 -677
  379. package/src/adapters/drizzle/drizzle-uow-decoder.ts +0 -228
  380. package/src/adapters/drizzle/drizzle-uow-executor.ts +0 -309
  381. package/src/adapters/drizzle/join-column-utils.test.ts +0 -79
  382. package/src/adapters/drizzle/join-column-utils.ts +0 -39
  383. package/src/adapters/kysely/kysely-connection-pool.ts +0 -70
  384. package/src/adapters/kysely/kysely-query-builder.test.ts +0 -1344
  385. package/src/adapters/kysely/kysely-query-builder.ts +0 -666
  386. package/src/adapters/kysely/kysely-query-compiler.ts +0 -127
  387. package/src/adapters/kysely/kysely-query.test.ts +0 -498
  388. package/src/adapters/kysely/kysely-query.ts +0 -399
  389. package/src/adapters/kysely/kysely-shared.ts +0 -57
  390. package/src/adapters/kysely/kysely-uow-compiler.test.ts +0 -986
  391. package/src/adapters/kysely/kysely-uow-compiler.ts +0 -350
  392. package/src/adapters/kysely/kysely-uow-executor.ts +0 -164
  393. package/src/adapters/kysely/kysely-uow-joins.test.ts +0 -794
  394. package/src/adapters/kysely/migration/execute-base.ts +0 -256
  395. package/src/adapters/kysely/migration/execute-factory.ts +0 -53
  396. package/src/adapters/kysely/migration/execute-mssql.ts +0 -250
  397. package/src/adapters/kysely/migration/execute-mysql.ts +0 -211
  398. package/src/adapters/kysely/migration/execute-postgres.test.ts +0 -2657
  399. package/src/adapters/kysely/migration/execute-postgres.ts +0 -234
  400. package/src/adapters/kysely/migration/execute-sqlite.ts +0 -247
  401. package/src/adapters/kysely/migration/execute.ts +0 -50
  402. package/src/adapters/kysely/migration/kysely-migrator.test.ts +0 -261
  403. package/src/query/result-transform.ts +0 -274
  404. package/src/schema/serialize.ts +0 -407
  405. /package/dist/query/{query.js → simple-query-interface.js} +0 -0
  406. /package/src/query/{retry-policy.test.ts → unit-of-work/retry-policy.test.ts} +0 -0
  407. /package/src/query/{retry-policy.ts → unit-of-work/retry-policy.ts} +0 -0
@@ -0,0 +1,113 @@
1
+ import type { AnyTable } from "../schema/create";
2
+ import { createSQLSerializer } from "./serialize/create-sql-serializer";
3
+ import { FragnoId, FragnoReference } from "../schema/create";
4
+ import type { DriverConfig } from "../adapters/generic-sql/driver-config";
5
+
6
+ /**
7
+ * Decodes a database result record to application format.
8
+ *
9
+ * This function transforms database column names back to application property names
10
+ * and deserializes values according to the database provider's format (e.g., converting
11
+ * SQLite integers back to JavaScript Date objects).
12
+ *
13
+ * Supports relation data encoded with the pattern `relationName:columnName`.
14
+ *
15
+ * @param result - The raw database result record
16
+ * @param table - The table schema definition containing column and relation information
17
+ * @param driverConfig - The driver configuration containing database type information
18
+ * @returns A record in application format with deserialized values
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const decoded = decodeResult(
23
+ * { user_id: 123, created_at: 1234567890, 'posts:title': 'Hello' },
24
+ * userTable,
25
+ * driverConfig
26
+ * );
27
+ * // Returns: { userId: 123, createdAt: Date, posts: { title: 'Hello' } }
28
+ * ```
29
+ */
30
+ export function decodeResult(
31
+ result: Record<string, unknown>,
32
+ table: AnyTable,
33
+ driverConfig: DriverConfig,
34
+ ): Record<string, unknown> {
35
+ const serializer = createSQLSerializer(driverConfig);
36
+ const output: Record<string, unknown> = {};
37
+ // First pass: collect all column values
38
+ const columnValues: Record<string, unknown> = {};
39
+
40
+ // Collect all relation data (including nested) keyed by relation name
41
+ const relationData: Record<string, Record<string, unknown>> = {};
42
+
43
+ for (const k in result) {
44
+ const colonIndex = k.indexOf(":");
45
+ const value = result[k];
46
+
47
+ // Direct column (no colon)
48
+ if (colonIndex === -1) {
49
+ const col = table.columns[k];
50
+ if (!col) {
51
+ continue;
52
+ }
53
+
54
+ // Store all column values (including hidden ones for FragnoId creation)
55
+ columnValues[k] = serializer.deserialize(value, col);
56
+ continue;
57
+ }
58
+
59
+ // Relation column (has colon)
60
+ const relationName = k.slice(0, colonIndex);
61
+ const remainder = k.slice(colonIndex + 1);
62
+
63
+ const relation = table.relations[relationName];
64
+ if (relation === undefined) {
65
+ continue;
66
+ }
67
+
68
+ // Collect relation data with the remaining key path
69
+ relationData[relationName] ??= {};
70
+ relationData[relationName][remainder] = value;
71
+ }
72
+
73
+ // Process each relation's data recursively
74
+ for (const relationName in relationData) {
75
+ const relation = table.relations[relationName];
76
+ if (!relation) {
77
+ continue;
78
+ }
79
+
80
+ // Recursively decode the relation data
81
+ output[relationName] = decodeResult(relationData[relationName], relation.table, driverConfig);
82
+ }
83
+
84
+ // Second pass: create output with FragnoId objects where appropriate
85
+ for (const k in columnValues) {
86
+ const col = table.columns[k];
87
+ if (!col) {
88
+ continue;
89
+ }
90
+
91
+ // Filter out hidden columns (like _internalId, _version) from results
92
+ if (col.isHidden) {
93
+ continue;
94
+ }
95
+
96
+ // For external ID columns, create FragnoId if we have both external and internal IDs
97
+ if (col.role === "external-id" && columnValues["_internalId"] !== undefined) {
98
+ output[k] = new FragnoId({
99
+ externalId: columnValues[k] as string,
100
+ internalId: columnValues["_internalId"] as bigint,
101
+ // _version is always selected as a hidden column, so it should always be present
102
+ version: columnValues["_version"] as number,
103
+ });
104
+ } else if (col.role === "reference") {
105
+ // For reference columns, create FragnoReference with internal ID
106
+ output[k] = FragnoReference.fromInternal(columnValues[k] as bigint);
107
+ } else {
108
+ output[k] = columnValues[k];
109
+ }
110
+ }
111
+
112
+ return output;
113
+ }
@@ -0,0 +1,390 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ column,
4
+ FragnoId,
5
+ FragnoReference,
6
+ idColumn,
7
+ schema,
8
+ referenceColumn,
9
+ } from "../schema/create";
10
+ import { resolveFragnoIdValue, encodeValues, ReferenceSubquery } from "./value-encoding";
11
+
12
+ describe("encodeValues", () => {
13
+ const testSchema = schema((s) => {
14
+ return s
15
+ .addTable("users", (t) => {
16
+ return t
17
+ .addColumn("id", idColumn())
18
+ .addColumn("name", column("string"))
19
+ .addColumn("email", column("string"))
20
+ .addColumn("age", column("integer").nullable())
21
+ .addColumn("isActive", column("bool"))
22
+ .addColumn("createdAt", column("timestamp"));
23
+ })
24
+ .addTable("posts", (t) => {
25
+ return t
26
+ .addColumn("id", idColumn())
27
+ .addColumn("title", column("string"))
28
+ .addColumn("userId", referenceColumn())
29
+ .addColumn("viewCount", column("integer").defaultTo(0))
30
+ .addColumn("publishedAt", column("timestamp").nullable());
31
+ })
32
+ .addReference("author", {
33
+ type: "one",
34
+ from: { table: "posts", column: "userId" },
35
+ to: { table: "users", column: "id" },
36
+ });
37
+ });
38
+
39
+ const usersTable = testSchema.tables.users;
40
+ const postsTable = testSchema.tables.posts;
41
+
42
+ describe("basic encoding", () => {
43
+ it("should resolve string values", () => {
44
+ const result = encodeValues(
45
+ { id: "user1", name: "John", email: "john@example.com" },
46
+ usersTable,
47
+ false,
48
+ );
49
+
50
+ expect(result).toEqual({
51
+ id: "user1",
52
+ name: "John",
53
+ email: "john@example.com",
54
+ });
55
+ });
56
+
57
+ it("should resolve integer values", () => {
58
+ const result = encodeValues({ age: 25 }, usersTable, false);
59
+
60
+ expect(result).toEqual({ age: 25 });
61
+ });
62
+
63
+ it("should resolve boolean values (not serialized)", () => {
64
+ const result = encodeValues({ isActive: true }, usersTable, false);
65
+
66
+ // Boolean stays as boolean (not converted to 0/1)
67
+ expect(result).toEqual({ isActive: true });
68
+ });
69
+ });
70
+
71
+ describe("date encoding", () => {
72
+ it("should keep Date as Date (not serialized)", () => {
73
+ const date = new Date("2024-01-15T10:30:00Z");
74
+ const result = encodeValues({ createdAt: date }, usersTable, false);
75
+
76
+ // Date stays as Date (serialization happens later in encoder)
77
+ expect(result).toEqual({ createdAt: date });
78
+ });
79
+ });
80
+
81
+ describe("nullable columns", () => {
82
+ it("should handle null values", () => {
83
+ const result = encodeValues({ age: null }, usersTable, false);
84
+
85
+ expect(result).toEqual({ age: null });
86
+ });
87
+
88
+ it("should omit undefined values", () => {
89
+ const result = encodeValues({ age: undefined }, usersTable, false);
90
+
91
+ expect(result).toEqual({});
92
+ });
93
+
94
+ it("should handle nullable timestamp", () => {
95
+ const result = encodeValues({ publishedAt: null }, postsTable, false);
96
+
97
+ expect(result).toEqual({ publishedAt: null });
98
+ });
99
+ });
100
+
101
+ describe("default value generation", () => {
102
+ it("should generate runtime defaults when generateDefault is true", () => {
103
+ const result = encodeValues({ title: "Test Post", userId: "user1" }, postsTable, true);
104
+
105
+ expect(result["title"]).toBe("Test Post");
106
+ expect(result["userId"]).toBeInstanceOf(ReferenceSubquery);
107
+ // viewCount has static default (defaultTo), so it's omitted to let DB handle it
108
+ expect(result["viewCount"]).toBeUndefined();
109
+ expect(result["id"]).toBeDefined();
110
+ expect(typeof result["id"]).toBe("string");
111
+ });
112
+
113
+ it("should not generate default values when generateDefault is false", () => {
114
+ const result = encodeValues({ title: "Test Post", userId: "user1" }, postsTable, false);
115
+
116
+ expect(result).toEqual({
117
+ title: "Test Post",
118
+ userId: expect.any(ReferenceSubquery),
119
+ });
120
+ });
121
+
122
+ it("should not override explicitly provided values", () => {
123
+ const result = encodeValues(
124
+ { title: "Test Post", userId: "user1", viewCount: 100 },
125
+ postsTable,
126
+ true,
127
+ );
128
+
129
+ expect(result["viewCount"]).toBe(100);
130
+ });
131
+ });
132
+
133
+ describe("complete record encoding", () => {
134
+ it("should resolve all fields correctly (without serialization)", () => {
135
+ const date = new Date("2024-01-15T10:30:00Z");
136
+ const result = encodeValues(
137
+ {
138
+ id: "user1",
139
+ name: "Alice",
140
+ email: "alice@example.com",
141
+ age: 30,
142
+ isActive: false,
143
+ createdAt: date,
144
+ },
145
+ usersTable,
146
+ false,
147
+ );
148
+
149
+ // Values are resolved but NOT serialized (Date stays as Date, boolean stays as boolean)
150
+ expect(result).toEqual({
151
+ id: "user1",
152
+ name: "Alice",
153
+ email: "alice@example.com",
154
+ age: 30,
155
+ isActive: false, // Not serialized to 0
156
+ createdAt: date, // Not serialized to timestamp
157
+ });
158
+ });
159
+ });
160
+
161
+ describe("FragnoId encoding", () => {
162
+ it("should resolve FragnoId with external ID only", () => {
163
+ const fragnoId = FragnoId.fromExternal("user123", 1);
164
+ const result = encodeValues({ id: fragnoId, name: "John" }, usersTable, false);
165
+
166
+ expect(result).toEqual({
167
+ id: "user123",
168
+ name: "John",
169
+ });
170
+ });
171
+
172
+ it("should resolve FragnoId with both IDs", () => {
173
+ const fragnoId = new FragnoId({
174
+ externalId: "user123",
175
+ internalId: BigInt(456),
176
+ version: 1,
177
+ });
178
+ const result = encodeValues({ id: fragnoId, name: "John" }, usersTable, false);
179
+
180
+ expect(result).toEqual({
181
+ id: "user123",
182
+ name: "John",
183
+ });
184
+ });
185
+
186
+ it("should resolve FragnoId in reference columns", () => {
187
+ const fragnoId = new FragnoId({
188
+ externalId: "user123",
189
+ internalId: BigInt(456),
190
+ version: 1,
191
+ });
192
+ const result = encodeValues({ title: "Test Post", userId: fragnoId }, postsTable, false);
193
+
194
+ // Reference columns should use the internal ID (bigint, not serialized)
195
+ expect(result).toEqual({
196
+ title: "Test Post",
197
+ userId: BigInt(456),
198
+ });
199
+ });
200
+
201
+ it("should convert FragnoId without internalId to ReferenceSubquery for reference columns", () => {
202
+ const fragnoId = new FragnoId({
203
+ externalId: "user123",
204
+ version: 1,
205
+ });
206
+ const result = encodeValues({ title: "Test Post", userId: fragnoId }, postsTable, false);
207
+
208
+ // FragnoId without internalId should be converted to ReferenceSubquery for database lookup
209
+ expect(result["title"]).toBe("Test Post");
210
+ expect(result["userId"]).toBeInstanceOf(ReferenceSubquery);
211
+ expect((result["userId"] as ReferenceSubquery).externalIdValue).toBe("user123");
212
+ });
213
+
214
+ it("should handle FragnoId across different providers", () => {
215
+ const fragnoId = new FragnoId({
216
+ externalId: "user123",
217
+ internalId: BigInt(456),
218
+ version: 1,
219
+ });
220
+ const testData = { id: fragnoId, name: "John" };
221
+
222
+ // Test that provider-agnostic resolution works
223
+ const result = encodeValues(testData, usersTable, false);
224
+
225
+ expect(result).toEqual({ id: "user123", name: "John" });
226
+ });
227
+
228
+ it("should handle ReferenceSubquery correctly", () => {
229
+ const fragnoId = FragnoId.fromExternal("user123", 1);
230
+ const result = encodeValues({ id: fragnoId, name: "John" }, usersTable, false);
231
+
232
+ // FragnoId handling should still work
233
+ expect(result).toEqual({
234
+ id: "user123",
235
+ name: "John",
236
+ });
237
+
238
+ // Test ReferenceSubquery
239
+ const refResult = encodeValues(
240
+ { title: "Test Post", userId: "user_external_id" },
241
+ postsTable,
242
+ false,
243
+ );
244
+
245
+ expect(refResult["title"]).toBe("Test Post");
246
+ expect(refResult["userId"]).toBeInstanceOf(ReferenceSubquery);
247
+ });
248
+ });
249
+ });
250
+
251
+ describe("resolveFragnoIdValue", () => {
252
+ describe("FragnoReference handling", () => {
253
+ it("should extract internal ID from FragnoReference", () => {
254
+ const ref = FragnoReference.fromInternal(BigInt(123));
255
+ const col = column("bigint");
256
+ col.role = "reference";
257
+
258
+ const result = resolveFragnoIdValue(ref, col);
259
+
260
+ expect(result).toBe(BigInt(123));
261
+ });
262
+ });
263
+
264
+ describe("FragnoId handling for external-id columns", () => {
265
+ it("should extract external ID from FragnoId", () => {
266
+ const externalIdCol = column("string");
267
+ externalIdCol.role = "external-id";
268
+ const fragnoId = new FragnoId({
269
+ externalId: "user123",
270
+ internalId: BigInt(456),
271
+ version: 1,
272
+ });
273
+
274
+ const result = resolveFragnoIdValue(fragnoId, externalIdCol);
275
+
276
+ expect(result).toBe("user123");
277
+ });
278
+
279
+ it("should work with FragnoId created from fromExternal", () => {
280
+ const externalIdCol = column("string");
281
+ externalIdCol.role = "external-id";
282
+ const fragnoId = FragnoId.fromExternal("user789", 2);
283
+
284
+ const result = resolveFragnoIdValue(fragnoId, externalIdCol);
285
+
286
+ expect(result).toBe("user789");
287
+ });
288
+ });
289
+
290
+ describe("FragnoId handling for internal-id columns", () => {
291
+ it("should extract internal ID from FragnoId", () => {
292
+ const internalIdCol = column("bigint");
293
+ internalIdCol.role = "internal-id";
294
+ const fragnoId = new FragnoId({
295
+ externalId: "user123",
296
+ internalId: BigInt(456),
297
+ version: 1,
298
+ });
299
+
300
+ const result = resolveFragnoIdValue(fragnoId, internalIdCol);
301
+
302
+ expect(result).toBe(BigInt(456));
303
+ });
304
+
305
+ it("should throw error when FragnoId lacks internal ID", () => {
306
+ const internalIdCol = column("bigint");
307
+ internalIdCol.role = "internal-id";
308
+ const fragnoId = FragnoId.fromExternal("user123", 1);
309
+
310
+ expect(() => resolveFragnoIdValue(fragnoId, internalIdCol)).toThrow(
311
+ "FragnoId must have internalId for internal-id column",
312
+ );
313
+ });
314
+ });
315
+
316
+ describe("FragnoId handling for reference columns", () => {
317
+ it("should prefer internal ID when available", () => {
318
+ const referenceCol = column("bigint");
319
+ referenceCol.role = "reference";
320
+ const fragnoId = new FragnoId({
321
+ externalId: "user123",
322
+ internalId: BigInt(456),
323
+ version: 1,
324
+ });
325
+
326
+ const result = resolveFragnoIdValue(fragnoId, referenceCol);
327
+
328
+ expect(result).toBe(BigInt(456));
329
+ });
330
+
331
+ it("should fallback to external ID when internal ID unavailable", () => {
332
+ const referenceCol = column("bigint");
333
+ referenceCol.role = "reference";
334
+ const fragnoId = FragnoId.fromExternal("user123", 1);
335
+
336
+ const result = resolveFragnoIdValue(fragnoId, referenceCol);
337
+
338
+ expect(result).toBe("user123");
339
+ });
340
+ });
341
+
342
+ describe("FragnoId handling for regular columns", () => {
343
+ it("should use external ID for regular columns", () => {
344
+ const regularCol = column("string");
345
+ regularCol.role = "regular";
346
+ const fragnoId = new FragnoId({
347
+ externalId: "user123",
348
+ internalId: BigInt(456),
349
+ version: 1,
350
+ });
351
+
352
+ const result = resolveFragnoIdValue(fragnoId, regularCol);
353
+
354
+ expect(result).toBe("user123");
355
+ });
356
+ });
357
+
358
+ describe("non-FragnoId values", () => {
359
+ it("should pass through strings", () => {
360
+ const col = column("string");
361
+ const result = resolveFragnoIdValue("hello", col);
362
+ expect(result).toBe("hello");
363
+ });
364
+
365
+ it("should pass through numbers", () => {
366
+ const col = column("integer");
367
+ const result = resolveFragnoIdValue(42, col);
368
+ expect(result).toBe(42);
369
+ });
370
+
371
+ it("should pass through dates", () => {
372
+ const col = column("timestamp");
373
+ const date = new Date();
374
+ const result = resolveFragnoIdValue(date, col);
375
+ expect(result).toBe(date);
376
+ });
377
+
378
+ it("should pass through null", () => {
379
+ const col = column("string").nullable();
380
+ const result = resolveFragnoIdValue(null, col);
381
+ expect(result).toBe(null);
382
+ });
383
+
384
+ it("should pass through bigint", () => {
385
+ const col = column("bigint");
386
+ const result = resolveFragnoIdValue(BigInt(999), col);
387
+ expect(result).toBe(BigInt(999));
388
+ });
389
+ });
390
+ });
@@ -0,0 +1,168 @@
1
+ import type { AnyTable, AnyColumn } from "../schema/create";
2
+ import { FragnoId, FragnoReference } from "../schema/create";
3
+ import { generateRuntimeDefault } from "./column-defaults";
4
+
5
+ /**
6
+ * Marker class for reference column values that need subquery resolution.
7
+ * When a reference column receives a string (external ID), this marker tells
8
+ * the query builder to generate a subquery to look up the internal ID.
9
+ * @internal
10
+ */
11
+ export class ReferenceSubquery {
12
+ #referencedTable: AnyTable;
13
+ #externalIdValue: string;
14
+
15
+ constructor(referencedTable: AnyTable, externalIdValue: string) {
16
+ this.#referencedTable = referencedTable;
17
+ this.#externalIdValue = externalIdValue;
18
+ }
19
+
20
+ get referencedTable() {
21
+ return this.#referencedTable;
22
+ }
23
+
24
+ get externalIdValue() {
25
+ return this.#externalIdValue;
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Resolves FragnoId or FragnoReference objects to their appropriate primitive values.
31
+ *
32
+ * This function handles the Fragno ID system's conversion to database values:
33
+ * - FragnoReference objects are resolved to their internal IDs
34
+ * - FragnoId objects are resolved based on the column role:
35
+ * - external-id: uses the external ID
36
+ * - internal-id: uses the internal ID (must be present)
37
+ * - reference: uses databaseId (internal ID if available, else external ID)
38
+ * - other: uses the external ID by default
39
+ *
40
+ * @param value - The value to resolve (may be FragnoId, FragnoReference, or any other value)
41
+ * @param col - The column schema definition
42
+ * @returns The resolved primitive value, or the original value if not a FragnoId/FragnoReference
43
+ * @throws Error if internal ID is required but not available
44
+ * @internal
45
+ */
46
+ export function resolveFragnoIdValue(value: unknown, col: AnyColumn): unknown {
47
+ // Handle FragnoReference objects (for reference columns)
48
+ if (value instanceof FragnoReference) {
49
+ return value.internalId;
50
+ }
51
+
52
+ // Handle FragnoId objects
53
+ if (value instanceof FragnoId) {
54
+ // For external ID columns, use the external ID
55
+ if (col.role === "external-id") {
56
+ return value.externalId;
57
+ }
58
+ // For internal ID columns, use the internal ID (must be present)
59
+ if (col.role === "internal-id") {
60
+ if (value.internalId === undefined) {
61
+ throw new Error(`FragnoId must have internalId for internal-id column ${col.name}`);
62
+ }
63
+ return value.internalId;
64
+ }
65
+ // For reference columns, prefer internal ID if available, else external ID
66
+ if (col.role === "reference") {
67
+ return value.databaseId;
68
+ }
69
+ // Default to external ID for other columns
70
+ return value.externalId;
71
+ }
72
+
73
+ return value;
74
+ }
75
+
76
+ /**
77
+ * Encodes a record of values from the application format to resolved format.
78
+ *
79
+ * This function:
80
+ * - Transforms object keys from ORM names to database column names
81
+ * - Resolves FragnoId/FragnoReference objects to primitive values
82
+ * - Generates default values for undefined columns
83
+ * - Creates ReferenceSubquery markers for external ID lookups
84
+ *
85
+ * Note: This function does NOT serialize values (Date → number, bigint → Buffer, etc.).
86
+ * Use UnitOfWorkEncoder.encode() to apply driver-specific serialization after this step.
87
+ *
88
+ * @param values - The record of values to encode in application format
89
+ * @param table - The table schema definition containing column information
90
+ * @param generateDefault - Whether to generate default values for undefined columns
91
+ * @returns A record with database column names and resolved (but not serialized) values
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * const encoded = encodeValues(
96
+ * { userId: 123, createdAt: new Date() },
97
+ * userTable,
98
+ * true
99
+ * );
100
+ * // Returns: { user_id: 123, created_at: Date } (not yet serialized)
101
+ * ```
102
+ */
103
+ export function encodeValues(
104
+ values: Record<string, unknown>,
105
+ table: AnyTable,
106
+ generateDefault: boolean,
107
+ ): Record<string, unknown> {
108
+ const result: Record<string, unknown> = {};
109
+
110
+ for (const k in table.columns) {
111
+ const col = table.columns[k];
112
+
113
+ // Skip internal ID - never provided by user, auto-generated by database
114
+ if (col.role === "internal-id") {
115
+ continue;
116
+ }
117
+ let value = values[k];
118
+
119
+ if (generateDefault && value === undefined) {
120
+ // Only generate runtime defaults (defaultTo$), not static defaults (defaultTo).
121
+ // Static defaults should be handled by the database via DEFAULT constraints.
122
+ value = generateRuntimeDefault(col);
123
+ }
124
+
125
+ if (value !== undefined) {
126
+ // Handle reference columns: strings or FragnoIds without internal IDs need subqueries
127
+ if (col.role === "reference") {
128
+ let needsSubquery = false;
129
+ let externalIdForSubquery: string | undefined;
130
+
131
+ if (typeof value === "string") {
132
+ // String external ID - needs subquery
133
+ needsSubquery = true;
134
+ externalIdForSubquery = value;
135
+ } else if (value instanceof FragnoId && value.internalId === undefined) {
136
+ // FragnoId without internal ID - needs subquery
137
+ needsSubquery = true;
138
+ externalIdForSubquery = value.externalId;
139
+ } else if (value instanceof FragnoId && value.internalId !== undefined) {
140
+ // FragnoId with internal ID - use it directly (will be serialized later)
141
+ result[col.name] = value.internalId;
142
+ continue;
143
+ } else if (value instanceof FragnoReference) {
144
+ // FragnoReference - use internal ID directly (will be serialized later)
145
+ result[col.name] = value.internalId;
146
+ continue;
147
+ }
148
+
149
+ if (needsSubquery) {
150
+ const relation = Object.values(table.relations).find((rel) =>
151
+ rel.on.some(([localCol]) => localCol === k),
152
+ );
153
+ if (relation) {
154
+ result[col.name] = new ReferenceSubquery(relation.table, externalIdForSubquery!);
155
+ continue;
156
+ }
157
+ throw new Error(`Reference column ${k} not found in table ${table.name}`);
158
+ }
159
+ }
160
+
161
+ // Resolve FragnoId/FragnoReference to primitive values (serialization happens later)
162
+ const resolvedValue = resolveFragnoIdValue(value, col);
163
+ result[col.name] = resolvedValue;
164
+ }
165
+ }
166
+
167
+ return result;
168
+ }
@@ -8,7 +8,11 @@ import {
8
8
  schema,
9
9
  SchemaBuilder,
10
10
  } from "./create";
11
- import type { RawColumnValues, TableToColumnValues, TableToInsertValues } from "../query/query";
11
+ import type {
12
+ RawColumnValues,
13
+ TableToColumnValues,
14
+ TableToInsertValues,
15
+ } from "../query/simple-query-interface";
12
16
 
13
17
  describe("create", () => {
14
18
  it("should create a table with columns using callback pattern", () => {
@@ -1,4 +1,5 @@
1
1
  import { createId } from "../id";
2
+ import { inspect } from "node:util";
2
3
 
3
4
  export type AnySchema = Schema<Record<string, AnyTable>>;
4
5
 
@@ -547,6 +548,10 @@ export class FragnoId {
547
548
  valueOf(): string {
548
549
  return this.#externalId;
549
550
  }
551
+
552
+ [inspect.custom](): string {
553
+ return `FragnoId { externalId: ${this.#externalId}, internalId: ${this.#internalId?.toString()} }`;
554
+ }
550
555
  }
551
556
 
552
557
  /**