@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,183 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { UnitOfWorkEncoder } from "./uow-encoder";
3
+ import { schema, column, idColumn, referenceColumn } from "../../schema/create";
4
+ import {
5
+ BetterSQLite3DriverConfig,
6
+ MySQL2DriverConfig,
7
+ NodePostgresDriverConfig,
8
+ } from "./driver-config";
9
+
10
+ describe("UnitOfWorkEncoder", () => {
11
+ const testSchema = schema((s) => {
12
+ return s
13
+ .addTable("users", (t) => {
14
+ return t
15
+ .addColumn("id", idColumn())
16
+ .addColumn("name", column("string"))
17
+ .addColumn("age", column("integer").nullable())
18
+ .addColumn("isActive", column("bool"))
19
+ .addColumn("createdAt", column("timestamp"));
20
+ })
21
+ .addTable("posts", (t) => {
22
+ return t
23
+ .addColumn("id", idColumn())
24
+ .addColumn("userId", referenceColumn())
25
+ .addColumn("title", column("string"));
26
+ });
27
+ });
28
+
29
+ const usersTable = testSchema.tables.users;
30
+ const postsTable = testSchema.tables.posts;
31
+
32
+ describe("SQLite encoding", () => {
33
+ const sqliteConfig = new BetterSQLite3DriverConfig();
34
+
35
+ // Mock Kysely instance (only needed for reference subquery processing)
36
+ const db = {} as any; // eslint-disable-line @typescript-eslint/no-explicit-any
37
+ const encoder = new UnitOfWorkEncoder(sqliteConfig, db);
38
+
39
+ it("should serialize Date to number for sqlite", () => {
40
+ const date = new Date("2024-01-15T10:30:00Z");
41
+ const result = encoder.encodeForDatabase({
42
+ values: { createdAt: date },
43
+ table: usersTable,
44
+ generateDefaults: false,
45
+ });
46
+
47
+ expect(result).toEqual({ createdAt: date.getTime() });
48
+ });
49
+
50
+ it("should serialize boolean to number for sqlite", () => {
51
+ const result = encoder.encodeForDatabase({
52
+ values: { isActive: true },
53
+ table: usersTable,
54
+ generateDefaults: false,
55
+ });
56
+
57
+ expect(result).toEqual({ isActive: 1 });
58
+ });
59
+
60
+ it("should serialize bigint to Number for reference columns in sqlite", () => {
61
+ const result = encoder.encodeForDatabase({
62
+ values: { userId: BigInt(456) },
63
+ table: postsTable,
64
+ generateDefaults: false,
65
+ });
66
+
67
+ // Reference columns should be converted to Number for SQLite
68
+ expect(result).toEqual({ userId: 456 });
69
+ });
70
+
71
+ it("should handle multiple fields", () => {
72
+ const date = new Date("2024-01-15T10:30:00Z");
73
+ const result = encoder.encodeForDatabase({
74
+ values: {
75
+ name: "Alice",
76
+ age: 30,
77
+ isActive: false,
78
+ createdAt: date,
79
+ },
80
+ table: usersTable,
81
+ generateDefaults: false,
82
+ });
83
+
84
+ expect(result).toEqual({
85
+ name: "Alice",
86
+ age: 30,
87
+ isActive: 0,
88
+ createdAt: date.getTime(),
89
+ });
90
+ });
91
+
92
+ it("should handle null values", () => {
93
+ const result = encoder.encodeForDatabase({
94
+ values: { age: null },
95
+ table: usersTable,
96
+ generateDefaults: false,
97
+ });
98
+
99
+ expect(result).toEqual({ age: null });
100
+ });
101
+
102
+ it("should generate defaults when requested", () => {
103
+ const result = encoder.encodeForDatabase({
104
+ values: { title: "Test" },
105
+ table: postsTable,
106
+ generateDefaults: true,
107
+ });
108
+
109
+ // Should have generated an ID
110
+ expect(result["id"]).toBeDefined();
111
+ expect(typeof result["id"]).toBe("string");
112
+ expect(result["title"]).toBe("Test");
113
+ });
114
+ });
115
+
116
+ describe("PostgreSQL encoding", () => {
117
+ const postgresConfig = new NodePostgresDriverConfig();
118
+
119
+ // Mock Kysely instance
120
+ const db = {} as any; // eslint-disable-line @typescript-eslint/no-explicit-any
121
+ const encoder = new UnitOfWorkEncoder(postgresConfig, db);
122
+
123
+ it("should keep Date as Date for postgresql", () => {
124
+ const date = new Date("2024-01-15T10:30:00Z");
125
+ const result = encoder.encodeForDatabase({
126
+ values: { createdAt: date },
127
+ table: usersTable,
128
+ generateDefaults: false,
129
+ });
130
+
131
+ expect(result).toEqual({ createdAt: date });
132
+ });
133
+
134
+ it("should keep boolean as boolean for postgresql", () => {
135
+ const result = encoder.encodeForDatabase({
136
+ values: { isActive: true },
137
+ table: usersTable,
138
+ generateDefaults: false,
139
+ });
140
+
141
+ expect(result).toEqual({ isActive: true });
142
+ });
143
+
144
+ it("should keep bigint as bigint for reference columns in postgresql", () => {
145
+ const result = encoder.encodeForDatabase({
146
+ values: { userId: BigInt(456) },
147
+ table: postsTable,
148
+ generateDefaults: false,
149
+ });
150
+
151
+ expect(result).toEqual({ userId: BigInt(456) });
152
+ });
153
+ });
154
+
155
+ describe("MySQL encoding", () => {
156
+ const mysqlConfig = new MySQL2DriverConfig();
157
+
158
+ // Mock Kysely instance
159
+ const db = {} as any; // eslint-disable-line @typescript-eslint/no-explicit-any
160
+ const encoder = new UnitOfWorkEncoder(mysqlConfig, db);
161
+
162
+ it("should keep Date as Date for mysql", () => {
163
+ const date = new Date("2024-01-15T10:30:00Z");
164
+ const result = encoder.encodeForDatabase({
165
+ values: { createdAt: date },
166
+ table: usersTable,
167
+ generateDefaults: false,
168
+ });
169
+
170
+ expect(result).toEqual({ createdAt: date });
171
+ });
172
+
173
+ it("should keep boolean as boolean for mysql", () => {
174
+ const result = encoder.encodeForDatabase({
175
+ values: { isActive: true },
176
+ table: usersTable,
177
+ generateDefaults: false,
178
+ });
179
+
180
+ expect(result).toEqual({ isActive: true });
181
+ });
182
+ });
183
+ });
@@ -0,0 +1,131 @@
1
+ import type { AnyTable, AnyColumn } from "../../schema/create";
2
+ import type { DriverConfig } from "./driver-config";
3
+ import {
4
+ createSQLSerializer,
5
+ type SQLSerializer,
6
+ } from "../../query/serialize/create-sql-serializer";
7
+ import { encodeValues } from "../../query/value-encoding";
8
+ import { processReferenceSubqueries } from "./query/where-builder";
9
+ import type { TableNameMapper } from "../shared/table-name-mapper";
10
+ import type { Kysely } from "kysely";
11
+
12
+ /**
13
+ * Encoder class for Unit of Work mutation operations.
14
+ *
15
+ * Handles the complete transformation from application values to database-ready values
16
+ * in three clear steps:
17
+ * 1. Resolution - Resolve FragnoId/FragnoReference objects and generate defaults
18
+ * 2. Reference Processing - Create subqueries for external ID lookups
19
+ * 3. Serialization - Apply database-specific type conversions
20
+ *
21
+ * This class mirrors the UnitOfWorkDecoder pattern for symmetry.
22
+ */
23
+ export class UnitOfWorkEncoder {
24
+ readonly #serializer: SQLSerializer;
25
+ readonly #db: Kysely<any>; // eslint-disable-line @typescript-eslint/no-explicit-any
26
+ readonly #mapper?: TableNameMapper;
27
+
28
+ constructor(
29
+ driverConfig: DriverConfig,
30
+ db: Kysely<any>, // eslint-disable-line @typescript-eslint/no-explicit-any
31
+ mapper?: TableNameMapper,
32
+ ) {
33
+ this.#serializer = createSQLSerializer(driverConfig);
34
+ this.#db = db;
35
+ this.#mapper = mapper;
36
+ }
37
+
38
+ /**
39
+ * Encode application values to database-ready format.
40
+ *
41
+ * This is the main entry point that handles all encoding steps:
42
+ * 1. **Resolution**: Transform ORM names to DB columns, resolve FragnoId/FragnoReference,
43
+ * generate defaults (CUIDs for IDs, etc.)
44
+ * 2. **Reference Processing**: Convert external ID strings to subqueries for internal ID lookup
45
+ * 3. **Serialization**: Apply database-specific conversions (Date → number for SQLite, etc.)
46
+ *
47
+ * @param options - Encoding options
48
+ * @param options.values - Application values to encode
49
+ * @param options.table - Table schema definition
50
+ * @param options.generateDefaults - Whether to generate default values for undefined columns
51
+ * @returns Database-ready values
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * const encoded = encoder.encodeForDatabase({
56
+ * values: { userId: FragnoId(...), createdAt: new Date(), isActive: true },
57
+ * table: usersTable,
58
+ * generateDefaults: true
59
+ * });
60
+ * // For SQLite: { user_id: 456, created_at: 1705316400000, is_active: 1 }
61
+ * ```
62
+ */
63
+ encodeForDatabase(options: {
64
+ values: Record<string, unknown>;
65
+ table: AnyTable;
66
+ generateDefaults: boolean;
67
+ }): Record<string, unknown> {
68
+ // Step 1: Resolution - Resolve FragnoId/FragnoReference and generate defaults
69
+ const resolved = encodeValues(options.values, options.table, options.generateDefaults);
70
+
71
+ // Step 2: Reference Processing - Convert external IDs to subqueries
72
+ const processed = processReferenceSubqueries(resolved, this.#db, this.#mapper);
73
+
74
+ // Step 3: Serialization - Apply database-specific type conversions
75
+ const serialized = this.serializeValues(processed, options.table);
76
+
77
+ return serialized;
78
+ }
79
+
80
+ /**
81
+ * Serialize resolved values to database format.
82
+ *
83
+ * Applies database-specific type conversions:
84
+ * - SQLite: Date → number, boolean → 0/1, bigint → Buffer (or Number for reference columns)
85
+ * - PostgreSQL: Mostly pass-through (database handles types natively)
86
+ * - MySQL: Mostly pass-through
87
+ *
88
+ * @param values - Resolved values (after resolution and reference processing)
89
+ * @param table - The table schema definition
90
+ * @returns Serialized values ready for database driver
91
+ */
92
+ private serializeValues(
93
+ values: Record<string, unknown>,
94
+ table: AnyTable,
95
+ ): Record<string, unknown> {
96
+ const result: Record<string, unknown> = {};
97
+
98
+ for (const [dbColumnName, value] of Object.entries(values)) {
99
+ // Find the column definition by database column name
100
+ const col = this.findColumnByDbName(table, dbColumnName);
101
+
102
+ if (!col) {
103
+ // Not a regular column (might be a special value like sql.raw())
104
+ // Pass through as-is
105
+ result[dbColumnName] = value;
106
+ continue;
107
+ }
108
+
109
+ // Serialize the value using the column definition and database type
110
+ result[dbColumnName] = this.#serializer.serialize(value, col);
111
+ }
112
+
113
+ return result;
114
+ }
115
+
116
+ /**
117
+ * Find a column definition by its database column name.
118
+ *
119
+ * @param table - The table to search
120
+ * @param dbColumnName - The database column name (e.g., "user_id")
121
+ * @returns The column definition or undefined if not found
122
+ */
123
+ private findColumnByDbName(table: AnyTable, dbColumnName: string): AnyColumn | undefined {
124
+ for (const col of Object.values(table.columns)) {
125
+ if (col.name === dbColumnName) {
126
+ return col;
127
+ }
128
+ }
129
+ return undefined;
130
+ }
131
+ }
@@ -1,6 +1,5 @@
1
- import { Kysely } from "kysely";
2
1
  import { KyselyPGlite } from "kysely-pglite";
3
- import { assert, beforeAll, describe, expect, expectTypeOf, it } from "vitest";
2
+ import { beforeAll, describe, expect, expectTypeOf, it } from "vitest";
4
3
  import { KyselyAdapter } from "./kysely-adapter";
5
4
  import {
6
5
  column,
@@ -11,6 +10,8 @@ import {
11
10
  type FragnoReference,
12
11
  } from "../../schema/create";
13
12
  import { Cursor } from "../../query/cursor";
13
+ import { PGLiteDriverConfig } from "../generic-sql/driver-config";
14
+ import { internalSchema } from "../../fragments/internal-fragment";
14
15
 
15
16
  describe("KyselyAdapter PGLite", () => {
16
17
  const testSchema = schema((s) => {
@@ -95,19 +96,14 @@ describe("KyselyAdapter PGLite", () => {
95
96
  });
96
97
  });
97
98
 
98
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
99
- let kysely: Kysely<any>;
100
99
  let adapter: KyselyAdapter;
101
100
 
102
101
  beforeAll(async () => {
103
102
  const { dialect } = await KyselyPGlite.create();
104
- kysely = new Kysely({
105
- dialect,
106
- });
107
103
 
108
104
  adapter = new KyselyAdapter({
109
- db: kysely,
110
- provider: "postgresql",
105
+ dialect,
106
+ driverConfig: new PGLiteDriverConfig(),
111
107
  });
112
108
  }, 12000);
113
109
 
@@ -115,72 +111,26 @@ describe("KyselyAdapter PGLite", () => {
115
111
  const schemaVersion = await adapter.getSchemaVersion("test");
116
112
  expect(schemaVersion).toBeUndefined();
117
113
 
118
- const migrator = adapter.createMigrationEngine(testSchema, "test");
119
- const preparedMigration = await migrator.prepareMigration({
120
- updateSettings: false,
121
- });
122
- assert(preparedMigration.getSQL);
123
-
124
- expect(preparedMigration.getSQL()).toMatchInlineSnapshot(`
125
- "create table "users_test" ("id" varchar(30) not null unique, "name" text not null, "age" integer, "_internalId" bigserial not null primary key, "_version" integer default 0 not null);
126
-
127
- create index "name_idx" on "users_test" ("name");
128
-
129
- create index "age_idx" on "users_test" ("age");
130
-
131
- create table "emails_test" ("id" varchar(30) not null unique, "user_id" bigint not null, "email" text not null, "is_primary" boolean default false not null, "_internalId" bigserial not null primary key, "_version" integer default 0 not null);
132
-
133
- create unique index "unique_email" on "emails_test" ("email");
134
-
135
- create index "user_emails" on "emails_test" ("user_id");
136
-
137
- create table "posts_test" ("id" varchar(30) not null unique, "user_id" bigint not null, "title" text not null, "content" text not null, "_internalId" bigserial not null primary key, "_version" integer default 0 not null);
138
-
139
- create index "posts_user_idx" on "posts_test" ("user_id");
140
-
141
- create table "tags_test" ("id" varchar(30) not null unique, "name" text not null, "_internalId" bigserial not null primary key, "_version" integer default 0 not null);
142
-
143
- create index "tag_name" on "tags_test" ("name");
144
-
145
- create table "post_tags_test" ("id" varchar(30) not null unique, "post_id" bigint not null, "tag_id" bigint not null, "_internalId" bigserial not null primary key, "_version" integer default 0 not null);
146
-
147
- create index "pt_post" on "post_tags_test" ("post_id");
148
-
149
- create index "pt_tag" on "post_tags_test" ("tag_id");
150
-
151
- create table "comments_test" ("id" varchar(30) not null unique, "post_id" bigint not null, "user_id" bigint not null, "text" text not null, "_internalId" bigserial not null primary key, "_version" integer default 0 not null);
152
-
153
- create index "comments_post_idx" on "comments_test" ("post_id");
154
-
155
- create index "comments_user_idx" on "comments_test" ("user_id");
156
-
157
- alter table "emails_test" add constraint "emails_users_user_fk" foreign key ("user_id") references "users_test" ("_internalId") on delete restrict on update restrict;
158
-
159
- alter table "posts_test" add constraint "posts_users_author_fk" foreign key ("user_id") references "users_test" ("_internalId") on delete restrict on update restrict;
160
-
161
- alter table "post_tags_test" add constraint "post_tags_posts_post_fk" foreign key ("post_id") references "posts_test" ("_internalId") on delete restrict on update restrict;
162
-
163
- alter table "post_tags_test" add constraint "post_tags_tags_tag_fk" foreign key ("tag_id") references "tags_test" ("_internalId") on delete restrict on update restrict;
164
-
165
- alter table "comments_test" add constraint "comments_posts_post_fk" foreign key ("post_id") references "posts_test" ("_internalId") on delete restrict on update restrict;
166
-
167
- alter table "comments_test" add constraint "comments_users_commenter_fk" foreign key ("user_id") references "users_test" ("_internalId") on delete restrict on update restrict;"
168
- `);
114
+ {
115
+ const migrations = adapter.prepareMigrations(internalSchema, "");
116
+ await migrations.executeWithDriver(adapter.driver, 0);
117
+ }
169
118
 
170
- await preparedMigration.execute();
119
+ {
120
+ const migrations = adapter.prepareMigrations(testSchema, "test");
121
+ await migrations.executeWithDriver(adapter.driver, 0);
122
+ }
171
123
 
172
124
  const queryEngine = adapter.createQueryEngine(testSchema, "test");
173
125
 
174
- // Create a user
175
126
  const userId = await queryEngine.create("users", {
176
127
  name: "John Doe",
177
128
  age: 30,
178
129
  });
179
130
 
180
- // create() now returns just the ID
181
131
  expect(userId).toMatchObject({
182
132
  externalId: expect.stringMatching(/^[a-z0-9]{20,}$/),
183
- internalId: expect.any(Number),
133
+ internalId: expect.any(BigInt),
184
134
  });
185
135
 
186
136
  expect(userId.version).toBe(0);
@@ -191,7 +141,7 @@ describe("KyselyAdapter PGLite", () => {
191
141
  expect(getUser).toMatchObject({
192
142
  id: expect.objectContaining({
193
143
  externalId: expect.stringMatching(/^[a-z0-9]{20,}$/),
194
- internalId: expect.any(Number),
144
+ internalId: expect.any(BigInt),
195
145
  }),
196
146
  name: "John Doe",
197
147
  });
@@ -212,12 +162,12 @@ describe("KyselyAdapter PGLite", () => {
212
162
 
213
163
  expect(email1Id).toMatchObject({
214
164
  externalId: expect.stringMatching(/^[a-z0-9]{20,}$/),
215
- internalId: expect.any(Number),
165
+ internalId: expect.any(BigInt),
216
166
  });
217
167
 
218
168
  expect(email2Id).toMatchObject({
219
169
  externalId: expect.stringMatching(/^[a-z0-9]{20,}$/),
220
- internalId: expect.any(Number),
170
+ internalId: expect.any(BigInt),
221
171
  });
222
172
 
223
173
  // Update user name
@@ -244,17 +194,17 @@ describe("KyselyAdapter PGLite", () => {
244
194
  expect(emailsWithUsers[0]).toEqual({
245
195
  id: expect.objectContaining({
246
196
  externalId: expect.stringMatching(/^[a-z0-9]{20,}$/),
247
- internalId: expect.any(Number),
197
+ internalId: expect.any(BigInt),
248
198
  }),
249
199
  user_id: expect.objectContaining({
250
- internalId: expect.any(Number),
200
+ internalId: expect.any(BigInt),
251
201
  }),
252
202
  email: expect.stringMatching(/\.com$/),
253
203
  is_primary: expect.any(Boolean),
254
204
  user: {
255
205
  id: expect.objectContaining({
256
206
  externalId: expect.stringMatching(/^[a-z0-9]{20,}$/),
257
- internalId: expect.any(Number),
207
+ internalId: expect.any(BigInt),
258
208
  }),
259
209
  name: "Jane Doe",
260
210
  age: 30,
@@ -498,10 +448,10 @@ describe("KyselyAdapter PGLite", () => {
498
448
  externalId: expect.any(String),
499
449
  }),
500
450
  post_id: expect.objectContaining({
501
- internalId: expect.any(Number),
451
+ internalId: expect.any(BigInt),
502
452
  }),
503
453
  tag_id: expect.objectContaining({
504
- internalId: expect.any(Number),
454
+ internalId: expect.any(BigInt),
505
455
  }),
506
456
  post: {
507
457
  title: expect.any(String),
@@ -640,7 +590,7 @@ describe("KyselyAdapter PGLite", () => {
640
590
  expect(comment).toMatchObject({
641
591
  id: expect.objectContaining({
642
592
  externalId: expect.stringMatching(/^[a-z0-9]{20,}$/),
643
- internalId: expect.any(Number),
593
+ internalId: expect.any(BigInt),
644
594
  }),
645
595
  text: "Great post!",
646
596
  // Post join (first level)
@@ -687,15 +637,15 @@ describe("KyselyAdapter PGLite", () => {
687
637
  expect(createdIds1).toMatchObject([
688
638
  expect.objectContaining({
689
639
  externalId: expect.stringMatching(/^[a-z0-9]{20,}$/),
690
- internalId: expect.any(Number),
640
+ internalId: expect.any(BigInt),
691
641
  }),
692
642
  expect.objectContaining({
693
643
  externalId: expect.stringMatching(/^[a-z0-9]{20,}$/),
694
- internalId: expect.any(Number),
644
+ internalId: expect.any(BigInt),
695
645
  }),
696
646
  expect.objectContaining({
697
647
  externalId: expect.stringMatching(/^[a-z0-9]{20,}$/),
698
- internalId: expect.any(Number),
648
+ internalId: expect.any(BigInt),
699
649
  }),
700
650
  ]);
701
651
 
@@ -878,10 +828,11 @@ describe("KyselyAdapter PGLite", () => {
878
828
  it("should support cursor-based pagination with findWithCursor()", async () => {
879
829
  const queryEngine = adapter.createQueryEngine(testSchema, "test");
880
830
 
881
- // Create multiple users for pagination testing with unique prefix
831
+ // Create exactly 15 users for precise pagination testing with unique prefix
882
832
  const prefix = "CursorPagTest";
833
+
883
834
  const userIds: FragnoId[] = [];
884
- for (let i = 1; i <= 25; i++) {
835
+ for (let i = 1; i <= 15; i++) {
885
836
  const userId = await queryEngine.create("users", {
886
837
  name: `${prefix} ${i.toString().padStart(2, "0")}`,
887
838
  age: 20 + i,
@@ -889,29 +840,35 @@ describe("KyselyAdapter PGLite", () => {
889
840
  userIds.push(userId);
890
841
  }
891
842
 
892
- // Fetch first page with cursor (filter by prefix to avoid other test data)
843
+ // Fetch first page with cursor (pageSize=10, total=15 items)
893
844
  const firstPage = await queryEngine.findWithCursor("users", (b) =>
894
- b.whereIndex("name_idx").orderByIndex("name_idx", "asc").pageSize(10),
845
+ b
846
+ .whereIndex("name_idx", (eb) => eb("name", "starts with", prefix))
847
+ .orderByIndex("name_idx", "asc")
848
+ .pageSize(10),
895
849
  );
896
850
 
897
- // Check structure
851
+ // Check structure and hasNextPage
898
852
  expect(firstPage).toHaveProperty("items");
899
853
  expect(firstPage).toHaveProperty("cursor");
854
+ expect(firstPage).toHaveProperty("hasNextPage");
900
855
  expect(Array.isArray(firstPage.items)).toBe(true);
901
- expect(firstPage.items.length).toBeGreaterThan(0);
902
-
903
- assert(firstPage.cursor instanceof Cursor);
856
+ expect(firstPage.items).toHaveLength(10);
857
+ expect(firstPage.hasNextPage).toBe(true);
858
+ expect(firstPage.cursor).toBeInstanceOf(Cursor);
904
859
 
905
- // Fetch second page using cursor
860
+ // Fetch second page using cursor (last page with 5 remaining items)
906
861
  const secondPage = await queryEngine.findWithCursor("users", (b) =>
907
862
  b
908
- .whereIndex("name_idx")
863
+ .whereIndex("name_idx", (eb) => eb("name", "starts with", prefix))
909
864
  .after(firstPage.cursor!)
910
865
  .orderByIndex("name_idx", "asc")
911
866
  .pageSize(10),
912
867
  );
913
868
 
914
- expect(secondPage.items.length).toBeGreaterThan(0);
869
+ expect(secondPage.items).toHaveLength(5);
870
+ expect(secondPage.hasNextPage).toBe(false);
871
+ expect(secondPage.cursor).toBeUndefined();
915
872
 
916
873
  // Verify no overlap - all names in second page should be different from first page
917
874
  const firstPageNames = new Set(firstPage.items.map((u) => u.name));
@@ -926,12 +883,16 @@ describe("KyselyAdapter PGLite", () => {
926
883
  const secondPageFirst = secondPage.items[0].name;
927
884
  expect(firstPageLast < secondPageFirst).toBe(true);
928
885
 
929
- // Verify our test data is present
930
- const testUsers = await queryEngine.find("users", (b) =>
931
- b.whereIndex("name_idx").pageSize(100),
886
+ // Test empty results
887
+ const emptyPage = await queryEngine.findWithCursor("users", (b) =>
888
+ b
889
+ .whereIndex("name_idx", (eb) => eb("name", "starts with", "NonExistentPrefix"))
890
+ .orderByIndex("name_idx", "asc")
891
+ .pageSize(10),
932
892
  );
933
- const testUserNames = testUsers.filter((u) => u.name.startsWith(prefix)).map((u) => u.name);
934
- expect(testUserNames).toHaveLength(25);
893
+ expect(emptyPage.items).toHaveLength(0);
894
+ expect(emptyPage.hasNextPage).toBe(false);
895
+ expect(emptyPage.cursor).toBeUndefined();
935
896
  });
936
897
 
937
898
  it("should support findWithCursor() in Unit of Work", async () => {
@@ -960,14 +921,47 @@ describe("KyselyAdapter PGLite", () => {
960
921
 
961
922
  const [result] = await uow.executeRetrieve();
962
923
 
963
- // Verify result structure
924
+ // Verify result structure including hasNextPage
964
925
  expect(result).toHaveProperty("items");
965
926
  expect(result).toHaveProperty("cursor");
927
+ expect(result).toHaveProperty("hasNextPage");
966
928
  expect(Array.isArray(result.items)).toBe(true);
967
929
  expect(result.items.length).toBeGreaterThan(0);
930
+ expect(typeof result.hasNextPage).toBe("boolean");
931
+ expect(result.cursor).toBeInstanceOf(Cursor);
932
+ });
968
933
 
969
- if (result.items.length === 3) {
970
- expect(result.cursor).toBeInstanceOf(Cursor);
971
- }
934
+ it("should fail check() when version changes", async () => {
935
+ const queryEngine = adapter.createQueryEngine(testSchema, "test");
936
+
937
+ // Create a user
938
+ const userId = await queryEngine.create("users", {
939
+ name: "Version Conflict User",
940
+ age: 40,
941
+ });
942
+
943
+ // Update the user to increment their version
944
+ await queryEngine.updateMany("users", (b) =>
945
+ b.whereIndex("primary", (eb) => eb("id", "=", userId)).set({ age: 41 }),
946
+ );
947
+
948
+ // Try to check with the old version (should fail)
949
+ const uow = queryEngine.createUnitOfWork("check-stale-version");
950
+ uow.check("users", userId); // This has version 0, but the user now has version 1
951
+ uow.create("posts", {
952
+ user_id: userId,
953
+ title: "Should Not Be Created",
954
+ content: "Content",
955
+ });
956
+
957
+ const { success } = await uow.executeMutations();
958
+ expect(success).toBe(false);
959
+
960
+ // Verify the post was NOT created
961
+ const posts = await queryEngine.find("posts", (b) =>
962
+ b.whereIndex("posts_user_idx", (eb) => eb("user_id", "=", userId)),
963
+ );
964
+ const conflictPosts = posts.filter((p) => p.title === "Should Not Be Created");
965
+ expect(conflictPosts).toHaveLength(0);
972
966
  });
973
967
  });