@fragno-dev/db 0.2.1 → 0.3.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 (362) hide show
  1. package/.turbo/turbo-build.log +206 -140
  2. package/CHANGELOG.md +67 -0
  3. package/README.md +30 -9
  4. package/dist/adapters/adapters.d.ts +23 -21
  5. package/dist/adapters/adapters.d.ts.map +1 -1
  6. package/dist/adapters/adapters.js.map +1 -1
  7. package/dist/adapters/generic-sql/driver-config.d.ts +16 -1
  8. package/dist/adapters/generic-sql/driver-config.d.ts.map +1 -1
  9. package/dist/adapters/generic-sql/driver-config.js +23 -1
  10. package/dist/adapters/generic-sql/driver-config.js.map +1 -1
  11. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts +27 -9
  12. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -1
  13. package/dist/adapters/generic-sql/generic-sql-adapter.js +55 -16
  14. package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -1
  15. package/dist/adapters/generic-sql/generic-sql-uow-executor.js +129 -3
  16. package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -1
  17. package/dist/adapters/generic-sql/migration/dialect/mysql.js +24 -5
  18. package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -1
  19. package/dist/adapters/generic-sql/migration/dialect/postgres.js +6 -5
  20. package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -1
  21. package/dist/adapters/generic-sql/migration/dialect/sqlite.js +21 -10
  22. package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -1
  23. package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -1
  24. package/dist/adapters/generic-sql/migration/prepared-migrations.js +8 -8
  25. package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -1
  26. package/dist/adapters/generic-sql/migration/sql-generator.js +74 -51
  27. package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -1
  28. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +6 -5
  29. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -1
  30. package/dist/adapters/generic-sql/query/cursor-utils.js +42 -4
  31. package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -1
  32. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +25 -17
  33. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -1
  34. package/dist/adapters/generic-sql/query/select-builder.js +5 -3
  35. package/dist/adapters/generic-sql/query/select-builder.js.map +1 -1
  36. package/dist/adapters/generic-sql/query/sql-query-compiler.js +15 -12
  37. package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -1
  38. package/dist/adapters/generic-sql/query/where-builder.js +38 -28
  39. package/dist/adapters/generic-sql/query/where-builder.js.map +1 -1
  40. package/dist/adapters/generic-sql/sqlite-storage.d.ts +13 -0
  41. package/dist/adapters/generic-sql/sqlite-storage.d.ts.map +1 -0
  42. package/dist/adapters/generic-sql/sqlite-storage.js +15 -0
  43. package/dist/adapters/generic-sql/sqlite-storage.js.map +1 -0
  44. package/dist/adapters/generic-sql/uow-decoder.js +7 -3
  45. package/dist/adapters/generic-sql/uow-decoder.js.map +1 -1
  46. package/dist/adapters/generic-sql/uow-encoder.js +28 -8
  47. package/dist/adapters/generic-sql/uow-encoder.js.map +1 -1
  48. package/dist/adapters/in-memory/condition-evaluator.js +131 -0
  49. package/dist/adapters/in-memory/condition-evaluator.js.map +1 -0
  50. package/dist/adapters/in-memory/errors.d.ts +13 -0
  51. package/dist/adapters/in-memory/errors.d.ts.map +1 -0
  52. package/dist/adapters/in-memory/errors.js +23 -0
  53. package/dist/adapters/in-memory/errors.js.map +1 -0
  54. package/dist/adapters/in-memory/in-memory-adapter.d.ts +27 -0
  55. package/dist/adapters/in-memory/in-memory-adapter.d.ts.map +1 -0
  56. package/dist/adapters/in-memory/in-memory-adapter.js +176 -0
  57. package/dist/adapters/in-memory/in-memory-adapter.js.map +1 -0
  58. package/dist/adapters/in-memory/in-memory-uow.js +648 -0
  59. package/dist/adapters/in-memory/in-memory-uow.js.map +1 -0
  60. package/dist/adapters/in-memory/index.d.ts +4 -0
  61. package/dist/adapters/in-memory/index.js +4 -0
  62. package/dist/adapters/in-memory/options.d.ts +28 -0
  63. package/dist/adapters/in-memory/options.d.ts.map +1 -0
  64. package/dist/adapters/in-memory/options.js +61 -0
  65. package/dist/adapters/in-memory/options.js.map +1 -0
  66. package/dist/adapters/in-memory/reference-resolution.js +26 -0
  67. package/dist/adapters/in-memory/reference-resolution.js.map +1 -0
  68. package/dist/adapters/in-memory/sorted-array-index.js +129 -0
  69. package/dist/adapters/in-memory/sorted-array-index.js.map +1 -0
  70. package/dist/adapters/in-memory/store.js +71 -0
  71. package/dist/adapters/in-memory/store.js.map +1 -0
  72. package/dist/adapters/in-memory/value-comparison.js +28 -0
  73. package/dist/adapters/in-memory/value-comparison.js.map +1 -0
  74. package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -1
  75. package/dist/adapters/shared/uow-operation-compiler.js +11 -11
  76. package/dist/adapters/shared/uow-operation-compiler.js.map +1 -1
  77. package/dist/adapters/sql/index.d.ts +5 -0
  78. package/dist/adapters/sql/index.js +4 -0
  79. package/dist/db-fragment-definition-builder.d.ts +45 -96
  80. package/dist/db-fragment-definition-builder.d.ts.map +1 -1
  81. package/dist/db-fragment-definition-builder.js +121 -99
  82. package/dist/db-fragment-definition-builder.js.map +1 -1
  83. package/dist/dispatchers/cloudflare-do/index.d.ts +26 -0
  84. package/dist/dispatchers/cloudflare-do/index.d.ts.map +1 -0
  85. package/dist/dispatchers/cloudflare-do/index.js +63 -0
  86. package/dist/dispatchers/cloudflare-do/index.js.map +1 -0
  87. package/dist/dispatchers/node/index.d.ts +17 -0
  88. package/dist/dispatchers/node/index.d.ts.map +1 -0
  89. package/dist/dispatchers/node/index.js +59 -0
  90. package/dist/dispatchers/node/index.js.map +1 -0
  91. package/dist/fragments/internal-fragment.d.ts +172 -9
  92. package/dist/fragments/internal-fragment.d.ts.map +1 -1
  93. package/dist/fragments/internal-fragment.js +193 -74
  94. package/dist/fragments/internal-fragment.js.map +1 -1
  95. package/dist/fragments/internal-fragment.routes.js +29 -0
  96. package/dist/fragments/internal-fragment.routes.js.map +1 -0
  97. package/dist/fragments/internal-fragment.schema.d.ts +9 -0
  98. package/dist/fragments/internal-fragment.schema.d.ts.map +1 -0
  99. package/dist/fragments/internal-fragment.schema.js +22 -0
  100. package/dist/fragments/internal-fragment.schema.js.map +1 -0
  101. package/dist/hooks/durable-hooks-processor.d.ts +14 -0
  102. package/dist/hooks/durable-hooks-processor.d.ts.map +1 -0
  103. package/dist/hooks/durable-hooks-processor.js +32 -0
  104. package/dist/hooks/durable-hooks-processor.js.map +1 -0
  105. package/dist/hooks/hooks.d.ts +47 -4
  106. package/dist/hooks/hooks.d.ts.map +1 -1
  107. package/dist/hooks/hooks.js +106 -39
  108. package/dist/hooks/hooks.js.map +1 -1
  109. package/dist/migration-engine/auto-from-schema.js +14 -11
  110. package/dist/migration-engine/auto-from-schema.js.map +1 -1
  111. package/dist/migration-engine/generation-engine.d.ts +16 -10
  112. package/dist/migration-engine/generation-engine.d.ts.map +1 -1
  113. package/dist/migration-engine/generation-engine.js +72 -33
  114. package/dist/migration-engine/generation-engine.js.map +1 -1
  115. package/dist/migration-engine/shared.js.map +1 -1
  116. package/dist/mod.d.ts +17 -10
  117. package/dist/mod.d.ts.map +1 -1
  118. package/dist/mod.js +14 -8
  119. package/dist/mod.js.map +1 -1
  120. package/dist/naming/sql-naming.d.ts +19 -0
  121. package/dist/naming/sql-naming.d.ts.map +1 -0
  122. package/dist/naming/sql-naming.js +116 -0
  123. package/dist/naming/sql-naming.js.map +1 -0
  124. package/dist/node_modules/.pnpm/{rou3@0.7.10 → rou3@0.7.12}/node_modules/rou3/dist/index.js +8 -5
  125. package/dist/node_modules/.pnpm/rou3@0.7.12/node_modules/rou3/dist/index.js.map +1 -0
  126. package/dist/outbox/outbox-builder.js +156 -0
  127. package/dist/outbox/outbox-builder.js.map +1 -0
  128. package/dist/outbox/outbox.d.ts +52 -0
  129. package/dist/outbox/outbox.d.ts.map +1 -0
  130. package/dist/outbox/outbox.js +37 -0
  131. package/dist/outbox/outbox.js.map +1 -0
  132. package/dist/packages/fragno/dist/api/fragment-definition-builder.js +3 -2
  133. package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +1 -1
  134. package/dist/packages/fragno/dist/api/fragment-instantiator.js +164 -20
  135. package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -1
  136. package/dist/packages/fragno/dist/api/request-input-context.js +67 -0
  137. package/dist/packages/fragno/dist/api/request-input-context.js.map +1 -1
  138. package/dist/packages/fragno/dist/api/route.js +14 -1
  139. package/dist/packages/fragno/dist/api/route.js.map +1 -1
  140. package/dist/packages/fragno/dist/internal/trace-context.js +12 -0
  141. package/dist/packages/fragno/dist/internal/trace-context.js.map +1 -0
  142. package/dist/query/column-defaults.js +20 -4
  143. package/dist/query/column-defaults.js.map +1 -1
  144. package/dist/query/cursor.d.ts +3 -1
  145. package/dist/query/cursor.d.ts.map +1 -1
  146. package/dist/query/cursor.js +45 -14
  147. package/dist/query/cursor.js.map +1 -1
  148. package/dist/query/db-now.d.ts +8 -0
  149. package/dist/query/db-now.d.ts.map +1 -0
  150. package/dist/query/db-now.js +7 -0
  151. package/dist/query/db-now.js.map +1 -0
  152. package/dist/query/serialize/create-sql-serializer.js +3 -2
  153. package/dist/query/serialize/create-sql-serializer.js.map +1 -1
  154. package/dist/query/serialize/dialect/mysql-serializer.js +12 -6
  155. package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -1
  156. package/dist/query/serialize/dialect/postgres-serializer.js +25 -7
  157. package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -1
  158. package/dist/query/serialize/dialect/sqlite-serializer.js +55 -11
  159. package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -1
  160. package/dist/query/serialize/sql-serializer.js +2 -2
  161. package/dist/query/serialize/sql-serializer.js.map +1 -1
  162. package/dist/query/simple-query-interface.d.ts +6 -1
  163. package/dist/query/simple-query-interface.d.ts.map +1 -1
  164. package/dist/query/unit-of-work/execute-unit-of-work.d.ts +351 -100
  165. package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -1
  166. package/dist/query/unit-of-work/execute-unit-of-work.js +440 -267
  167. package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -1
  168. package/dist/query/unit-of-work/unit-of-work.d.ts +67 -22
  169. package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
  170. package/dist/query/unit-of-work/unit-of-work.js +110 -13
  171. package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
  172. package/dist/query/value-decoding.js +8 -5
  173. package/dist/query/value-decoding.js.map +1 -1
  174. package/dist/query/value-encoding.js +29 -9
  175. package/dist/query/value-encoding.js.map +1 -1
  176. package/dist/schema/create.d.ts +40 -14
  177. package/dist/schema/create.d.ts.map +1 -1
  178. package/dist/schema/create.js +82 -42
  179. package/dist/schema/create.js.map +1 -1
  180. package/dist/schema/generate-id.d.ts +20 -0
  181. package/dist/schema/generate-id.d.ts.map +1 -0
  182. package/dist/schema/generate-id.js +28 -0
  183. package/dist/schema/generate-id.js.map +1 -0
  184. package/dist/schema/type-conversion/create-sql-type-mapper.js +3 -2
  185. package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -1
  186. package/dist/schema/type-conversion/dialect/sqlite.js +9 -0
  187. package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -1
  188. package/dist/schema/validator.d.ts +10 -0
  189. package/dist/schema/validator.d.ts.map +1 -0
  190. package/dist/schema/validator.js +123 -0
  191. package/dist/schema/validator.js.map +1 -0
  192. package/dist/schema-output/drizzle.d.ts +30 -0
  193. package/dist/schema-output/drizzle.d.ts.map +1 -0
  194. package/dist/{adapters/drizzle/generate.js → schema-output/drizzle.js} +82 -56
  195. package/dist/schema-output/drizzle.js.map +1 -0
  196. package/dist/schema-output/prisma.d.ts +17 -0
  197. package/dist/schema-output/prisma.d.ts.map +1 -0
  198. package/dist/schema-output/prisma.js +296 -0
  199. package/dist/schema-output/prisma.js.map +1 -0
  200. package/dist/util/default-database-adapter.js +61 -0
  201. package/dist/util/default-database-adapter.js.map +1 -0
  202. package/dist/with-database.d.ts +1 -1
  203. package/dist/with-database.d.ts.map +1 -1
  204. package/dist/with-database.js +12 -3
  205. package/dist/with-database.js.map +1 -1
  206. package/package.json +43 -28
  207. package/src/adapters/adapters.ts +30 -24
  208. package/src/adapters/drizzle/migrate-drizzle.test.ts +54 -33
  209. package/src/adapters/drizzle/migration-parity-drizzle-kit.test.ts +599 -0
  210. package/src/adapters/drizzle/test-utils.ts +12 -8
  211. package/src/adapters/generic-sql/driver-config.ts +38 -0
  212. package/src/adapters/generic-sql/generic-sql-adapter.test.ts +5 -5
  213. package/src/adapters/generic-sql/generic-sql-adapter.ts +110 -24
  214. package/src/adapters/generic-sql/generic-sql-uow-executor.test.ts +54 -0
  215. package/src/adapters/generic-sql/generic-sql-uow-executor.ts +231 -3
  216. package/src/adapters/generic-sql/migration/adapter-migration-parity.test.ts +118 -0
  217. package/src/adapters/generic-sql/migration/dialect/mysql.test.ts +26 -8
  218. package/src/adapters/generic-sql/migration/dialect/mysql.ts +46 -8
  219. package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +25 -7
  220. package/src/adapters/generic-sql/migration/dialect/postgres.ts +8 -4
  221. package/src/adapters/generic-sql/migration/dialect/sqlite.test.ts +47 -8
  222. package/src/adapters/generic-sql/migration/dialect/sqlite.ts +27 -12
  223. package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +128 -39
  224. package/src/adapters/generic-sql/migration/prepared-migrations.ts +15 -8
  225. package/src/adapters/generic-sql/migration/sql-generator.ts +142 -65
  226. package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +9 -6
  227. package/src/adapters/generic-sql/query/cursor-utils.test.ts +271 -0
  228. package/src/adapters/generic-sql/query/cursor-utils.ts +41 -6
  229. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +27 -27
  230. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +38 -24
  231. package/src/adapters/generic-sql/query/select-builder.test.ts +15 -11
  232. package/src/adapters/generic-sql/query/select-builder.ts +6 -2
  233. package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +52 -2
  234. package/src/adapters/generic-sql/query/sql-query-compiler.ts +50 -15
  235. package/src/adapters/generic-sql/query/where-builder.test.ts +91 -17
  236. package/src/adapters/generic-sql/query/where-builder.ts +90 -38
  237. package/src/adapters/{kysely/kysely-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-migrations.test.ts} +6 -6
  238. package/src/adapters/generic-sql/sql-adapter-pglite-pagination.test.ts +806 -0
  239. package/src/adapters/{drizzle/drizzle-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-queries.test.ts} +11 -11
  240. package/src/adapters/generic-sql/{test/generic-drizzle-adapter-sqlite3.test.ts → sql-adapter-sqlite3-driver.test.ts} +49 -35
  241. package/src/adapters/{drizzle/drizzle-adapter-sqlite3.test.ts → generic-sql/sql-adapter-sqlite3-uow.test.ts} +48 -32
  242. package/src/adapters/{kysely/kysely-adapter-sqlocal.test.ts → generic-sql/sql-adapter-sqlocal.test.ts} +6 -6
  243. package/src/adapters/generic-sql/sqlite-storage.ts +20 -0
  244. package/src/adapters/generic-sql/uow-decoder.test.ts +1 -1
  245. package/src/adapters/generic-sql/uow-decoder.ts +21 -3
  246. package/src/adapters/generic-sql/uow-encoder.test.ts +33 -2
  247. package/src/adapters/generic-sql/uow-encoder.ts +50 -11
  248. package/src/adapters/in-memory/condition-evaluator.test.ts +193 -0
  249. package/src/adapters/in-memory/condition-evaluator.ts +275 -0
  250. package/src/adapters/in-memory/errors.ts +20 -0
  251. package/src/adapters/in-memory/in-memory-adapter.ts +277 -0
  252. package/src/adapters/in-memory/in-memory-uow.mutations.test.ts +296 -0
  253. package/src/adapters/in-memory/in-memory-uow.retrieval.test.ts +100 -0
  254. package/src/adapters/in-memory/in-memory-uow.ts +1348 -0
  255. package/src/adapters/in-memory/index.ts +3 -0
  256. package/src/adapters/in-memory/options.test.ts +41 -0
  257. package/src/adapters/in-memory/options.ts +87 -0
  258. package/src/adapters/in-memory/reference-resolution.test.ts +50 -0
  259. package/src/adapters/in-memory/reference-resolution.ts +67 -0
  260. package/src/adapters/in-memory/sorted-array-index.test.ts +123 -0
  261. package/src/adapters/in-memory/sorted-array-index.ts +228 -0
  262. package/src/adapters/in-memory/store.test.ts +68 -0
  263. package/src/adapters/in-memory/store.ts +145 -0
  264. package/src/adapters/in-memory/value-comparison.ts +53 -0
  265. package/src/adapters/in-memory/value-normalization.test.ts +57 -0
  266. package/src/adapters/prisma/prisma-adapter-sqlite3.test.ts +1163 -0
  267. package/src/adapters/shared/from-unit-of-work-compiler.ts +3 -1
  268. package/src/adapters/shared/uow-operation-compiler.ts +26 -16
  269. package/src/adapters/sql/index.ts +12 -0
  270. package/src/db-fragment-definition-builder.test.ts +88 -54
  271. package/src/db-fragment-definition-builder.ts +201 -322
  272. package/src/db-fragment-instantiator.test.ts +169 -101
  273. package/src/db-fragment-integration.test.ts +301 -149
  274. package/src/dispatchers/cloudflare-do/index.test.ts +73 -0
  275. package/src/dispatchers/cloudflare-do/index.ts +104 -0
  276. package/src/dispatchers/node/index.test.ts +91 -0
  277. package/src/dispatchers/node/index.ts +87 -0
  278. package/src/fragments/internal-fragment.routes.ts +42 -0
  279. package/src/fragments/internal-fragment.schema.ts +51 -0
  280. package/src/fragments/internal-fragment.test.ts +730 -274
  281. package/src/fragments/internal-fragment.ts +447 -154
  282. package/src/hooks/durable-hooks-processor.test.ts +117 -0
  283. package/src/hooks/durable-hooks-processor.ts +67 -0
  284. package/src/hooks/hooks.test.ts +411 -259
  285. package/src/hooks/hooks.ts +265 -66
  286. package/src/migration-engine/auto-from-schema.test.ts +14 -14
  287. package/src/migration-engine/auto-from-schema.ts +5 -2
  288. package/src/migration-engine/create.test.ts +2 -2
  289. package/src/migration-engine/generation-engine.test.ts +229 -104
  290. package/src/migration-engine/generation-engine.ts +94 -64
  291. package/src/migration-engine/shared.ts +1 -0
  292. package/src/mod.ts +78 -30
  293. package/src/naming/sql-naming.ts +180 -0
  294. package/src/outbox/outbox-builder.ts +241 -0
  295. package/src/outbox/outbox.test.ts +253 -0
  296. package/src/outbox/outbox.ts +137 -0
  297. package/src/query/column-defaults.ts +41 -3
  298. package/src/query/condition-builder.test.ts +3 -3
  299. package/src/query/cursor.test.ts +116 -18
  300. package/src/query/cursor.ts +75 -26
  301. package/src/query/db-now.ts +6 -0
  302. package/src/query/query-type.test.ts +2 -2
  303. package/src/query/serialize/create-sql-serializer.ts +7 -2
  304. package/src/query/serialize/dialect/mysql-serializer.ts +12 -4
  305. package/src/query/serialize/dialect/postgres-serializer.ts +34 -4
  306. package/src/query/serialize/dialect/sqlite-serializer.test.ts +51 -1
  307. package/src/query/serialize/dialect/sqlite-serializer.ts +92 -9
  308. package/src/query/serialize/sql-serializer.ts +4 -4
  309. package/src/query/simple-query-interface.ts +5 -0
  310. package/src/query/unit-of-work/execute-unit-of-work.test.ts +1512 -1458
  311. package/src/query/unit-of-work/execute-unit-of-work.ts +1708 -596
  312. package/src/query/unit-of-work/tx-builder.test.ts +1041 -0
  313. package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +32 -32
  314. package/src/query/unit-of-work/unit-of-work-types.test.ts +1 -1
  315. package/src/query/unit-of-work/unit-of-work.test.ts +231 -36
  316. package/src/query/unit-of-work/unit-of-work.ts +229 -31
  317. package/src/query/value-decoding.test.ts +13 -2
  318. package/src/query/value-decoding.ts +17 -4
  319. package/src/query/value-encoding.test.ts +85 -2
  320. package/src/query/value-encoding.ts +56 -6
  321. package/src/schema/create.test.ts +129 -42
  322. package/src/schema/create.ts +187 -47
  323. package/src/schema/generate-id.test.ts +57 -0
  324. package/src/schema/generate-id.ts +38 -0
  325. package/src/schema/serialize.test.ts +14 -2
  326. package/src/schema/type-conversion/create-sql-type-mapper.ts +7 -2
  327. package/src/schema/type-conversion/dialect/sqlite.ts +18 -0
  328. package/src/schema/type-conversion/type-mapping.test.ts +25 -1
  329. package/src/schema/validator.test.ts +197 -0
  330. package/src/schema/validator.ts +231 -0
  331. package/src/{adapters/drizzle/generate.test.ts → schema-output/drizzle.test.ts} +179 -129
  332. package/src/{adapters/drizzle/generate.ts → schema-output/drizzle.ts} +143 -93
  333. package/src/schema-output/prisma.test.ts +536 -0
  334. package/src/schema-output/prisma.ts +573 -0
  335. package/src/util/default-database-adapter.ts +106 -0
  336. package/src/with-database.ts +22 -3
  337. package/tsdown.config.ts +6 -4
  338. package/dist/adapters/drizzle/drizzle-adapter.d.ts +0 -20
  339. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +0 -1
  340. package/dist/adapters/drizzle/drizzle-adapter.js +0 -27
  341. package/dist/adapters/drizzle/drizzle-adapter.js.map +0 -1
  342. package/dist/adapters/drizzle/generate.d.ts +0 -30
  343. package/dist/adapters/drizzle/generate.d.ts.map +0 -1
  344. package/dist/adapters/drizzle/generate.js.map +0 -1
  345. package/dist/adapters/kysely/kysely-adapter.d.ts +0 -19
  346. package/dist/adapters/kysely/kysely-adapter.d.ts.map +0 -1
  347. package/dist/adapters/kysely/kysely-adapter.js +0 -17
  348. package/dist/adapters/kysely/kysely-adapter.js.map +0 -1
  349. package/dist/adapters/shared/table-name-mapper.d.ts +0 -12
  350. package/dist/adapters/shared/table-name-mapper.d.ts.map +0 -1
  351. package/dist/adapters/shared/table-name-mapper.js +0 -43
  352. package/dist/adapters/shared/table-name-mapper.js.map +0 -1
  353. package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js.map +0 -1
  354. package/dist/schema-generator/schema-generator.d.ts +0 -15
  355. package/dist/schema-generator/schema-generator.d.ts.map +0 -1
  356. package/src/adapters/drizzle/drizzle-adapter.ts +0 -39
  357. package/src/adapters/kysely/kysely-adapter.ts +0 -27
  358. package/src/adapters/shared/table-name-mapper.ts +0 -50
  359. package/src/schema-generator/schema-generator.ts +0 -12
  360. package/src/shared/config.ts +0 -10
  361. package/src/shared/connection-pool.ts +0 -24
  362. package/src/shared/prisma.ts +0 -45
@@ -1,18 +1,18 @@
1
1
  import { PGlite } from "@electric-sql/pglite";
2
2
  import { KyselyPGlite } from "kysely-pglite";
3
- import { DrizzleAdapter } from "./drizzle-adapter";
3
+ import { SqlAdapter } from "./generic-sql-adapter";
4
4
  import { beforeAll, describe, expect, expectTypeOf, it } from "vitest";
5
5
  import { column, idColumn, referenceColumn, schema } from "../../schema/create";
6
6
  import { Cursor } from "../../query/cursor";
7
- import { PGLiteDriverConfig } from "../generic-sql/driver-config";
7
+ import { PGLiteDriverConfig } from "./driver-config";
8
8
  import type { CompiledQuery } from "../../sql-driver/sql-driver";
9
9
  import { internalSchema } from "../../fragments/internal-fragment";
10
10
 
11
- describe("DrizzleAdapter PGLite", () => {
11
+ describe("SqlAdapter PGLite", () => {
12
12
  let pgliteDatabase: PGlite;
13
- let adapter: DrizzleAdapter;
13
+ let adapter: SqlAdapter;
14
14
 
15
- const testSchema = schema((s) => {
15
+ const testSchema = schema("test", (s) => {
16
16
  return s
17
17
  .addTable("users", (t) => {
18
18
  return t
@@ -73,7 +73,7 @@ describe("DrizzleAdapter PGLite", () => {
73
73
  });
74
74
  });
75
75
 
76
- const schema2 = schema((s) => {
76
+ const schema2 = schema("schema2", (s) => {
77
77
  return s
78
78
  .addTable("products", (t) => {
79
79
  return t
@@ -98,7 +98,7 @@ describe("DrizzleAdapter PGLite", () => {
98
98
 
99
99
  const { dialect } = new KyselyPGlite(pgliteDatabase);
100
100
 
101
- adapter = new DrizzleAdapter({
101
+ adapter = new SqlAdapter({
102
102
  dialect,
103
103
  driverConfig: new PGLiteDriverConfig(),
104
104
  });
@@ -321,7 +321,7 @@ describe("DrizzleAdapter PGLite", () => {
321
321
 
322
322
  const [query] = queries;
323
323
  expect(query.sql).toMatchInlineSnapshot(
324
- `"select "user"."name" as "user:name", "user"."id" as "user:id", "user"."age" as "user:age", "user"."_internalId" as "user:_internalId", "user"."_version" as "user:_version", "emails_namespace"."id" as "id", "emails_namespace"."user_id" as "user_id", "emails_namespace"."email" as "email", "emails_namespace"."is_primary" as "is_primary", "emails_namespace"."_internalId" as "_internalId", "emails_namespace"."_version" as "_version" from "emails_namespace" left join "users_namespace" as "user" on "emails_namespace"."user_id" = "user"."_internalId""`,
324
+ `"select "user"."name" as "user:name", "user"."id" as "user:id", "user"."age" as "user:age", "user"."_internalId" as "user:_internalId", "user"."_version" as "user:_version", "namespace"."emails"."id" as "id", "namespace"."emails"."user_id" as "user_id", "namespace"."emails"."email" as "email", "namespace"."emails"."is_primary" as "is_primary", "namespace"."emails"."_internalId" as "_internalId", "namespace"."emails"."_version" as "_version" from "namespace"."emails" left join "namespace"."users" as "user" on "namespace"."emails"."user_id" = "user"."_internalId""`,
325
325
  );
326
326
 
327
327
  expect(email).toMatchObject({
@@ -502,7 +502,7 @@ describe("DrizzleAdapter PGLite", () => {
502
502
 
503
503
  const [query] = queries;
504
504
  expect(query.sql).toMatchInlineSnapshot(
505
- `"select "post"."id" as "post:id", "post"."title" as "post:title", "post"."content" as "post:content", "post"."_internalId" as "post:_internalId", "post"."_version" as "post:_version", "post_author"."id" as "post:author:id", "post_author"."name" as "post:author:name", "post_author"."age" as "post:author:age", "post_author"."_internalId" as "post:author:_internalId", "post_author"."_version" as "post:author:_version", "commenter"."id" as "commenter:id", "commenter"."name" as "commenter:name", "commenter"."_internalId" as "commenter:_internalId", "commenter"."_version" as "commenter:_version", "comments_namespace"."id" as "id", "comments_namespace"."post_id" as "post_id", "comments_namespace"."user_id" as "user_id", "comments_namespace"."text" as "text", "comments_namespace"."_internalId" as "_internalId", "comments_namespace"."_version" as "_version" from "comments_namespace" left join "posts_namespace" as "post" on "comments_namespace"."post_id" = "post"."_internalId" left join "users_namespace" as "post_author" on "post"."user_id" = "post_author"."_internalId" left join "users_namespace" as "commenter" on "comments_namespace"."user_id" = "commenter"."_internalId""`,
505
+ `"select "post"."id" as "post:id", "post"."title" as "post:title", "post"."content" as "post:content", "post"."_internalId" as "post:_internalId", "post"."_version" as "post:_version", "post_author"."id" as "post:author:id", "post_author"."name" as "post:author:name", "post_author"."age" as "post:author:age", "post_author"."_internalId" as "post:author:_internalId", "post_author"."_version" as "post:author:_version", "commenter"."id" as "commenter:id", "commenter"."name" as "commenter:name", "commenter"."_internalId" as "commenter:_internalId", "commenter"."_version" as "commenter:_version", "namespace"."comments"."id" as "id", "namespace"."comments"."post_id" as "post_id", "namespace"."comments"."user_id" as "user_id", "namespace"."comments"."text" as "text", "namespace"."comments"."_internalId" as "_internalId", "namespace"."comments"."_version" as "_version" from "namespace"."comments" left join "namespace"."posts" as "post" on "namespace"."comments"."post_id" = "post"."_internalId" left join "namespace"."users" as "post_author" on "post"."user_id" = "post_author"."_internalId" left join "namespace"."users" as "commenter" on "namespace"."comments"."user_id" = "commenter"."_internalId""`,
506
506
  );
507
507
  });
508
508
 
@@ -614,11 +614,11 @@ describe("DrizzleAdapter PGLite", () => {
614
614
 
615
615
  const [insertUserQuery, insertPostQuery] = queries;
616
616
  expect(insertUserQuery.sql).toMatchInlineSnapshot(
617
- `"insert into "users_namespace" ("id", "name", "age") values ($1, $2, $3) returning "users_namespace"."id" as "id", "users_namespace"."name" as "name", "users_namespace"."age" as "age", "users_namespace"."_internalId" as "_internalId", "users_namespace"."_version" as "_version""`,
617
+ `"insert into "namespace"."users" ("id", "name", "age") values ($1, $2, $3) returning "namespace"."users"."id" as "id", "namespace"."users"."name" as "name", "namespace"."users"."age" as "age", "namespace"."users"."_internalId" as "_internalId", "namespace"."users"."_version" as "_version""`,
618
618
  );
619
619
  expect(insertUserQuery.parameters).toEqual([userId.externalId, "UOW Test User", 35]);
620
620
  expect(insertPostQuery.sql).toMatchInlineSnapshot(
621
- `"insert into "posts_namespace" ("id", "user_id", "title", "content") values ($1, (select "_internalId" from "users_namespace" where "id" = $2 limit $3), $4, $5) returning "posts_namespace"."id" as "id", "posts_namespace"."user_id" as "user_id", "posts_namespace"."title" as "title", "posts_namespace"."content" as "content", "posts_namespace"."created_at" as "created_at", "posts_namespace"."_internalId" as "_internalId", "posts_namespace"."_version" as "_version""`,
621
+ `"insert into "namespace"."posts" ("id", "user_id", "title", "content") values ($1, (select "_internalId" from "namespace"."users" where "id" = $2 limit $3), $4, $5) returning "namespace"."posts"."id" as "id", "namespace"."posts"."user_id" as "user_id", "namespace"."posts"."title" as "title", "namespace"."posts"."content" as "content", "namespace"."posts"."created_at" as "created_at", "namespace"."posts"."_internalId" as "_internalId", "namespace"."posts"."_version" as "_version""`,
622
622
  );
623
623
  expect(insertPostQuery.parameters).toEqual([
624
624
  postId.externalId,
@@ -1,20 +1,21 @@
1
1
  import SQLite from "better-sqlite3";
2
- import { beforeAll, describe, expect, expectTypeOf, it, assert } from "vitest";
3
- import { column, idColumn, referenceColumn, schema, type FragnoId } from "../../../schema/create";
2
+ import { beforeAll, describe, expect, expectTypeOf, it } from "vitest";
3
+ import { column, idColumn, referenceColumn, schema, type FragnoId } from "../../schema/create";
4
4
  import {
5
5
  Cursor,
6
- executeUnitOfWork,
6
+ createServiceTxBuilder,
7
+ createHandlerTxBuilder,
7
8
  ExponentialBackoffRetryPolicy,
8
9
  type DatabaseAdapter,
9
- } from "../../../mod";
10
+ } from "../../mod";
10
11
  import { SqliteDialect } from "kysely";
11
- import { SqlDriverAdapter } from "../../../sql-driver/sql-driver-adapter";
12
- import { BetterSQLite3DriverConfig } from "../driver-config";
13
- import { GenericSQLAdapter } from "../generic-sql-adapter";
14
- import { internalSchema } from "../../../fragments/internal-fragment";
12
+ import { SqlDriverAdapter } from "../../sql-driver/sql-driver-adapter";
13
+ import { BetterSQLite3DriverConfig } from "./driver-config";
14
+ import { SqlAdapter } from "./generic-sql-adapter";
15
+ import { internalSchema } from "../../fragments/internal-fragment";
15
16
 
16
- describe("GenericSQLAdapter with DrizzleAdapter better-sqlite3", () => {
17
- const testSchema = schema((s) => {
17
+ describe("SqlAdapter with better-sqlite3", () => {
18
+ const testSchema = schema("test", (s) => {
18
19
  return s
19
20
  .addTable("users", (t) => {
20
21
  return t
@@ -72,7 +73,7 @@ describe("GenericSQLAdapter with DrizzleAdapter better-sqlite3", () => {
72
73
  });
73
74
 
74
75
  // Second schema for multi-schema testing
75
- const schema2 = schema((s) => {
76
+ const schema2 = schema("schema2", (s) => {
76
77
  return s
77
78
  .addTable("products", (t) => {
78
79
  return t
@@ -104,7 +105,7 @@ describe("GenericSQLAdapter with DrizzleAdapter better-sqlite3", () => {
104
105
  });
105
106
  const sqlAdapter = new SqlDriverAdapter(dialect);
106
107
  const driverConfig = new BetterSQLite3DriverConfig();
107
- const genericAdapter = new GenericSQLAdapter({ dialect, driverConfig });
108
+ const genericAdapter = new SqlAdapter({ dialect, driverConfig });
108
109
 
109
110
  {
110
111
  const migrations = genericAdapter.prepareMigrations(internalSchema, "");
@@ -793,7 +794,7 @@ describe("GenericSQLAdapter with DrizzleAdapter better-sqlite3", () => {
793
794
  expect(emptyPage.cursor).toBeUndefined();
794
795
  });
795
796
 
796
- it("should support executeUnitOfWork with retry logic", async () => {
797
+ it("should support handlerTx with retry logic", async () => {
797
798
  const queryEngine = adapter.createQueryEngine(testSchema, "namespace");
798
799
 
799
800
  // Create a test user
@@ -807,31 +808,44 @@ describe("GenericSQLAdapter with DrizzleAdapter better-sqlite3", () => {
807
808
  .find("users", (b) => b.whereIndex("name_idx", (eb) => eb("name", "=", "Execute UOW User")))
808
809
  .executeRetrieve();
809
810
 
810
- // Use executeUnitOfWork to increment age with optimistic locking
811
- const result = await executeUnitOfWork(
812
- {
813
- retrieve: (uow) =>
814
- uow.find("users", (b) => b.whereIndex("primary", (eb) => eb("id", "=", user.id))),
815
- mutate: (uow, [users]) => {
816
- const foundUser = users[0];
817
- const newAge = foundUser.age! + 1;
818
- uow.update("users", foundUser.id, (b) => b.set({ age: newAge }).check());
819
- return { previousAge: foundUser.age, newAge };
820
- },
821
- onSuccess: ({ mutationResult }) => {
822
- // Verify the age was incremented correctly
823
- expect(mutationResult.newAge).toBe(mutationResult.previousAge! + 1);
824
- },
825
- },
826
- {
827
- createUnitOfWork: () => queryEngine.createUnitOfWork("execute-uow-update"),
828
- retryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 3, initialDelayMs: 1 }),
811
+ // Use handlerTx to increment age with optimistic locking
812
+ let currentUow: ReturnType<typeof queryEngine.createUnitOfWork> | null = null;
813
+
814
+ // Service that retrieves user by ID
815
+ const getUserById = (userId: typeof user.id) => {
816
+ return createServiceTxBuilder(testSchema, currentUow!)
817
+ .retrieve((uow) =>
818
+ uow.find("users", (b) => b.whereIndex("primary", (eb) => eb("id", "=", userId))),
819
+ )
820
+ .transformRetrieve(([users]) => users[0] ?? null)
821
+ .build();
822
+ };
823
+
824
+ const result = await createHandlerTxBuilder({
825
+ createUnitOfWork: () => {
826
+ currentUow = queryEngine.createUnitOfWork("execute-uow-update");
827
+ return currentUow;
829
828
  },
830
- );
829
+ retryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 3, initialDelayMs: 1 }),
830
+ })
831
+ .withServiceCalls(() => [getUserById(user.id)])
832
+ .mutate(({ forSchema, serviceIntermediateResult: [foundUser] }) => {
833
+ if (!foundUser) {
834
+ throw new Error("User not found");
835
+ }
836
+ const newAge = foundUser.age! + 1;
837
+ forSchema(testSchema).update("users", foundUser.id, (b) => b.set({ age: newAge }).check());
838
+ return { previousAge: foundUser.age, newAge };
839
+ })
840
+ .transform(({ mutateResult }) => {
841
+ // Verify the age was incremented correctly
842
+ expect(mutateResult.newAge).toBe(mutateResult.previousAge! + 1);
843
+ return mutateResult;
844
+ })
845
+ .execute();
831
846
 
832
847
  // Verify the operation succeeded
833
- assert(result.success);
834
- expect(result.mutationResult).toEqual({
848
+ expect(result).toEqual({
835
849
  previousAge: 42,
836
850
  newAge: 43,
837
851
  });
@@ -1,16 +1,19 @@
1
1
  import SQLite from "better-sqlite3";
2
2
  import { SqliteDialect } from "kysely";
3
- import { DrizzleAdapter } from "./drizzle-adapter";
4
- import { beforeAll, describe, expect, expectTypeOf, it, assert } from "vitest";
3
+ import { SqlAdapter } from "./generic-sql-adapter";
4
+ import { beforeAll, describe, expect, expectTypeOf, it } from "vitest";
5
5
  import { column, idColumn, referenceColumn, schema, type FragnoId } from "../../schema/create";
6
6
  import { Cursor } from "../../query/cursor";
7
- import { executeUnitOfWork } from "../../query/unit-of-work/execute-unit-of-work";
7
+ import {
8
+ createServiceTxBuilder,
9
+ createHandlerTxBuilder,
10
+ } from "../../query/unit-of-work/execute-unit-of-work";
8
11
  import { ExponentialBackoffRetryPolicy } from "../../query/unit-of-work/retry-policy";
9
- import { BetterSQLite3DriverConfig } from "../generic-sql/driver-config";
12
+ import { BetterSQLite3DriverConfig } from "./driver-config";
10
13
  import { internalSchema } from "../../fragments/internal-fragment";
11
14
 
12
- describe("DrizzleAdapter SQLite", () => {
13
- const testSchema = schema((s) => {
15
+ describe("SqlAdapter SQLite", () => {
16
+ const testSchema = schema("test", (s) => {
14
17
  return s
15
18
  .addTable("users", (t) => {
16
19
  return t
@@ -68,7 +71,7 @@ describe("DrizzleAdapter SQLite", () => {
68
71
  });
69
72
 
70
73
  // Second schema for multi-schema testing
71
- const schema2 = schema((s) => {
74
+ const schema2 = schema("schema2", (s) => {
72
75
  return s
73
76
  .addTable("products", (t) => {
74
77
  return t
@@ -91,7 +94,7 @@ describe("DrizzleAdapter SQLite", () => {
91
94
  });
92
95
  });
93
96
 
94
- let adapter: DrizzleAdapter;
97
+ let adapter: SqlAdapter;
95
98
  let sqliteDatabase: InstanceType<typeof SQLite>;
96
99
 
97
100
  beforeAll(async () => {
@@ -101,7 +104,7 @@ describe("DrizzleAdapter SQLite", () => {
101
104
  database: sqliteDatabase,
102
105
  });
103
106
 
104
- adapter = new DrizzleAdapter({
107
+ adapter = new SqlAdapter({
105
108
  dialect,
106
109
  driverConfig: new BetterSQLite3DriverConfig(),
107
110
  });
@@ -793,7 +796,7 @@ describe("DrizzleAdapter SQLite", () => {
793
796
  expect(emptyPage.cursor).toBeUndefined();
794
797
  });
795
798
 
796
- it("should support executeUnitOfWork with retry logic", async () => {
799
+ it("should support handlerTx with retry logic", async () => {
797
800
  const queryEngine = adapter.createQueryEngine(testSchema, "namespace");
798
801
 
799
802
  // Create a test user
@@ -807,31 +810,44 @@ describe("DrizzleAdapter SQLite", () => {
807
810
  .find("users", (b) => b.whereIndex("name_idx", (eb) => eb("name", "=", "Execute UOW User")))
808
811
  .executeRetrieve();
809
812
 
810
- // Use executeUnitOfWork to increment age with optimistic locking
811
- const result = await executeUnitOfWork(
812
- {
813
- retrieve: (uow) =>
814
- uow.find("users", (b) => b.whereIndex("primary", (eb) => eb("id", "=", user.id))),
815
- mutate: (uow, [users]) => {
816
- const foundUser = users[0];
817
- const newAge = foundUser.age! + 1;
818
- uow.update("users", foundUser.id, (b) => b.set({ age: newAge }).check());
819
- return { previousAge: foundUser.age, newAge };
820
- },
821
- onSuccess: ({ mutationResult }) => {
822
- // Verify the age was incremented correctly
823
- expect(mutationResult.newAge).toBe(mutationResult.previousAge! + 1);
824
- },
825
- },
826
- {
827
- createUnitOfWork: () => queryEngine.createUnitOfWork("execute-uow-update"),
828
- retryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 3, initialDelayMs: 1 }),
813
+ // Use handlerTx to increment age with optimistic locking
814
+ let currentUow: ReturnType<typeof queryEngine.createUnitOfWork> | null = null;
815
+
816
+ // Service that retrieves user by ID
817
+ const getUserById = (userId: typeof user.id) => {
818
+ return createServiceTxBuilder(testSchema, currentUow!)
819
+ .retrieve((uow) =>
820
+ uow.find("users", (b) => b.whereIndex("primary", (eb) => eb("id", "=", userId))),
821
+ )
822
+ .transformRetrieve(([users]) => users[0] ?? null)
823
+ .build();
824
+ };
825
+
826
+ const result = await createHandlerTxBuilder({
827
+ createUnitOfWork: () => {
828
+ currentUow = queryEngine.createUnitOfWork("execute-uow-update");
829
+ return currentUow;
829
830
  },
830
- );
831
+ retryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 3, initialDelayMs: 1 }),
832
+ })
833
+ .withServiceCalls(() => [getUserById(user.id)])
834
+ .mutate(({ forSchema, serviceIntermediateResult: [foundUser] }) => {
835
+ if (!foundUser) {
836
+ throw new Error("User not found");
837
+ }
838
+ const newAge = foundUser.age! + 1;
839
+ forSchema(testSchema).update("users", foundUser.id, (b) => b.set({ age: newAge }).check());
840
+ return { previousAge: foundUser.age, newAge };
841
+ })
842
+ .transform(({ mutateResult }) => {
843
+ // Verify the age was incremented correctly
844
+ expect(mutateResult.newAge).toBe(mutateResult.previousAge! + 1);
845
+ return mutateResult;
846
+ })
847
+ .execute();
831
848
 
832
849
  // Verify the operation succeeded
833
- assert(result.success);
834
- expect(result.mutationResult).toEqual({
850
+ expect(result).toEqual({
835
851
  previousAge: 42,
836
852
  newAge: 43,
837
853
  });
@@ -1,11 +1,11 @@
1
1
  import { SQLocalKysely } from "sqlocal/kysely";
2
2
  import { beforeAll, describe, expect, it } from "vitest";
3
- import { KyselyAdapter } from "./kysely-adapter";
3
+ import { SqlAdapter } from "./generic-sql-adapter";
4
4
  import { column, idColumn, referenceColumn, schema } from "../../schema/create";
5
- import { SQLocalDriverConfig } from "../generic-sql/driver-config";
5
+ import { SQLocalDriverConfig } from "./driver-config";
6
6
 
7
- describe("KyselyAdapter SQLite", () => {
8
- const testSchema = schema((s) => {
7
+ describe("SqlAdapter SQLite", () => {
8
+ const testSchema = schema("test", (s) => {
9
9
  return s
10
10
  .addTable("accounts", (t) => {
11
11
  return t
@@ -33,11 +33,11 @@ describe("KyselyAdapter SQLite", () => {
33
33
  });
34
34
  });
35
35
 
36
- let adapter: KyselyAdapter;
36
+ let adapter: SqlAdapter;
37
37
 
38
38
  beforeAll(async () => {
39
39
  const { dialect } = new SQLocalKysely(":memory:");
40
- adapter = new KyselyAdapter({
40
+ adapter = new SqlAdapter({
41
41
  dialect,
42
42
  driverConfig: new SQLocalDriverConfig(),
43
43
  });
@@ -0,0 +1,20 @@
1
+ export type SQLiteDateStorage = "epoch-ms" | "iso-text";
2
+ export type SQLiteBigintStorage = "blob" | "integer";
3
+
4
+ export interface SQLiteStorageMode {
5
+ timestampStorage: SQLiteDateStorage;
6
+ dateStorage: SQLiteDateStorage;
7
+ bigintStorage: SQLiteBigintStorage;
8
+ }
9
+
10
+ export const sqliteStorageDefault: SQLiteStorageMode = {
11
+ timestampStorage: "epoch-ms",
12
+ dateStorage: "epoch-ms",
13
+ bigintStorage: "blob",
14
+ };
15
+
16
+ export const sqliteStoragePrisma: SQLiteStorageMode = {
17
+ timestampStorage: "iso-text",
18
+ dateStorage: "iso-text",
19
+ bigintStorage: "integer",
20
+ };
@@ -8,7 +8,7 @@ import type { AnySchema } from "../../schema/create";
8
8
  describe("UnitOfWorkDecoder", () => {
9
9
  const driverConfig = new SQLocalDriverConfig();
10
10
 
11
- const testSchema = schema((s) => {
11
+ const testSchema = schema("test", (s) => {
12
12
  return s
13
13
  .addTable("users", (t) => {
14
14
  return t
@@ -4,6 +4,8 @@ import type { AnySchema, AnyTable } from "../../schema/create";
4
4
  import { decodeResult } from "../../query/value-decoding";
5
5
  import { createCursorFromRecord, type Cursor, type CursorResult } from "../../query/cursor";
6
6
  import type { DriverConfig } from "./driver-config";
7
+ import type { SQLiteStorageMode } from "./sqlite-storage";
8
+ import type { NamingResolver } from "../../naming/sql-naming";
7
9
 
8
10
  /**
9
11
  * Decoder class for Unit of Work retrieval results.
@@ -13,9 +15,17 @@ import type { DriverConfig } from "./driver-config";
13
15
  */
14
16
  export class UnitOfWorkDecoder implements UOWDecoder<unknown> {
15
17
  readonly #driverConfig: DriverConfig;
16
-
17
- constructor(driverConfig: DriverConfig) {
18
+ readonly #sqliteStorageMode?: SQLiteStorageMode;
19
+ readonly #resolver?: NamingResolver;
20
+
21
+ constructor(
22
+ driverConfig: DriverConfig,
23
+ sqliteStorageMode?: SQLiteStorageMode,
24
+ resolver?: NamingResolver,
25
+ ) {
18
26
  this.#driverConfig = driverConfig;
27
+ this.#sqliteStorageMode = sqliteStorageMode;
28
+ this.#resolver = resolver;
19
29
  }
20
30
 
21
31
  /**
@@ -60,7 +70,15 @@ export class UnitOfWorkDecoder implements UOWDecoder<unknown> {
60
70
  return this.decodeCountResult(rows);
61
71
  }
62
72
 
63
- const decodedRows = rows.map((row) => decodeResult(row, operation.table, this.#driverConfig));
73
+ const decodedRows = rows.map((row) =>
74
+ decodeResult(
75
+ row,
76
+ operation.table,
77
+ this.#driverConfig,
78
+ this.#sqliteStorageMode,
79
+ this.#resolver,
80
+ ),
81
+ );
64
82
 
65
83
  if (operation.withCursor) {
66
84
  return this.decodeCursorResult(decodedRows, operation.table, operation);
@@ -1,6 +1,8 @@
1
1
  import { describe, it, expect } from "vitest";
2
+ import { Kysely, PostgresDialect } from "kysely";
2
3
  import { UnitOfWorkEncoder } from "./uow-encoder";
3
4
  import { schema, column, idColumn, referenceColumn } from "../../schema/create";
5
+ import { dbNow } from "../../query/db-now";
4
6
  import {
5
7
  BetterSQLite3DriverConfig,
6
8
  MySQL2DriverConfig,
@@ -8,7 +10,7 @@ import {
8
10
  } from "./driver-config";
9
11
 
10
12
  describe("UnitOfWorkEncoder", () => {
11
- const testSchema = schema((s) => {
13
+ const testSchema = schema("test", (s) => {
12
14
  return s
13
15
  .addTable("users", (t) => {
14
16
  return t
@@ -16,7 +18,8 @@ describe("UnitOfWorkEncoder", () => {
16
18
  .addColumn("name", column("string"))
17
19
  .addColumn("age", column("integer").nullable())
18
20
  .addColumn("isActive", column("bool"))
19
- .addColumn("createdAt", column("timestamp"));
21
+ .addColumn("createdAt", column("timestamp"))
22
+ .addColumn("birthDate", column("date").nullable());
20
23
  })
21
24
  .addTable("posts", (t) => {
22
25
  return t
@@ -111,6 +114,34 @@ describe("UnitOfWorkEncoder", () => {
111
114
  expect(typeof result["id"]).toBe("string");
112
115
  expect(result["title"]).toBe("Test");
113
116
  });
117
+
118
+ it("should use sqlite dateStorage for dbNow date columns", () => {
119
+ type TestDB = { users: { id: string; birthDate: unknown } };
120
+ const dialectConfig = {} as unknown as ConstructorParameters<typeof PostgresDialect>[0];
121
+ const sqliteDb = new Kysely<TestDB>({
122
+ dialect: new PostgresDialect(dialectConfig),
123
+ });
124
+ const encoderWithStorage = new UnitOfWorkEncoder(sqliteConfig, sqliteDb, {
125
+ timestampStorage: "epoch-ms",
126
+ dateStorage: "iso-text",
127
+ bigintStorage: "blob",
128
+ });
129
+
130
+ const result = encoderWithStorage.encodeForDatabase({
131
+ values: { birthDate: dbNow() },
132
+ table: usersTable,
133
+ generateDefaults: false,
134
+ });
135
+
136
+ const query = sqliteDb
137
+ .updateTable("users")
138
+ .set({ birthDate: result["birthDate"] as unknown })
139
+ .where("id", "=", "test");
140
+
141
+ const sqlText = query.compile().sql;
142
+ expect(sqlText).toContain("CURRENT_TIMESTAMP");
143
+ expect(sqlText).not.toContain("julianday");
144
+ });
114
145
  });
115
146
 
116
147
  describe("PostgreSQL encoding", () => {
@@ -6,8 +6,10 @@ import {
6
6
  } from "../../query/serialize/create-sql-serializer";
7
7
  import { encodeValues } from "../../query/value-encoding";
8
8
  import { processReferenceSubqueries } from "./query/where-builder";
9
- import type { TableNameMapper } from "../shared/table-name-mapper";
10
- import type { Kysely } from "kysely";
9
+ import type { NamingResolver } from "../../naming/sql-naming";
10
+ import { sql, type Kysely } from "kysely";
11
+ import { isDbNow } from "../../query/db-now";
12
+ import { sqliteStorageDefault, type SQLiteStorageMode } from "./sqlite-storage";
11
13
 
12
14
  /**
13
15
  * Encoder class for Unit of Work mutation operations.
@@ -21,18 +23,23 @@ import type { Kysely } from "kysely";
21
23
  * This class mirrors the UnitOfWorkDecoder pattern for symmetry.
22
24
  */
23
25
  export class UnitOfWorkEncoder {
26
+ readonly #driverConfig: DriverConfig;
24
27
  readonly #serializer: SQLSerializer;
25
28
  readonly #db: Kysely<any>; // eslint-disable-line @typescript-eslint/no-explicit-any
26
- readonly #mapper?: TableNameMapper;
29
+ readonly #sqliteStorageMode?: SQLiteStorageMode;
30
+ readonly #resolver?: NamingResolver;
27
31
 
28
32
  constructor(
29
33
  driverConfig: DriverConfig,
30
34
  db: Kysely<any>, // eslint-disable-line @typescript-eslint/no-explicit-any
31
- mapper?: TableNameMapper,
35
+ sqliteStorageMode?: SQLiteStorageMode,
36
+ resolver?: NamingResolver,
32
37
  ) {
33
- this.#serializer = createSQLSerializer(driverConfig);
38
+ this.#driverConfig = driverConfig;
39
+ this.#serializer = createSQLSerializer(driverConfig, sqliteStorageMode);
34
40
  this.#db = db;
35
- this.#mapper = mapper;
41
+ this.#sqliteStorageMode = sqliteStorageMode;
42
+ this.#resolver = resolver;
36
43
  }
37
44
 
38
45
  /**
@@ -66,10 +73,16 @@ export class UnitOfWorkEncoder {
66
73
  generateDefaults: boolean;
67
74
  }): Record<string, unknown> {
68
75
  // Step 1: Resolution - Resolve FragnoId/FragnoReference and generate defaults
69
- const resolved = encodeValues(options.values, options.table, options.generateDefaults);
76
+ const resolved = encodeValues(
77
+ options.values,
78
+ options.table,
79
+ options.generateDefaults,
80
+ {},
81
+ this.#resolver,
82
+ );
70
83
 
71
84
  // Step 2: Reference Processing - Convert external IDs to subqueries
72
- const processed = processReferenceSubqueries(resolved, this.#db, this.#mapper);
85
+ const processed = processReferenceSubqueries(resolved, this.#db, this.#resolver);
73
86
 
74
87
  // Step 3: Serialization - Apply database-specific type conversions
75
88
  const serialized = this.serializeValues(processed, options.table);
@@ -94,10 +107,11 @@ export class UnitOfWorkEncoder {
94
107
  table: AnyTable,
95
108
  ): Record<string, unknown> {
96
109
  const result: Record<string, unknown> = {};
110
+ const columnMap = this.#resolver ? this.#resolver.getColumnNameMap(table) : undefined;
97
111
 
98
112
  for (const [dbColumnName, value] of Object.entries(values)) {
99
113
  // Find the column definition by database column name
100
- const col = this.findColumnByDbName(table, dbColumnName);
114
+ const col = this.findColumnByDbName(table, dbColumnName, columnMap);
101
115
 
102
116
  if (!col) {
103
117
  // Not a regular column (might be a special value like sql.raw())
@@ -106,6 +120,22 @@ export class UnitOfWorkEncoder {
106
120
  continue;
107
121
  }
108
122
 
123
+ if (isDbNow(value)) {
124
+ if (this.#driverConfig.databaseType === "sqlite") {
125
+ const storageMode = this.#sqliteStorageMode ?? sqliteStorageDefault;
126
+ const storage =
127
+ col.type === "date" ? storageMode.dateStorage : storageMode.timestampStorage;
128
+ if ((col.type === "timestamp" || col.type === "date") && storage === "epoch-ms") {
129
+ result[dbColumnName] = sql`(cast((julianday('now') - 2440587.5)*86400000 as integer))`;
130
+ } else {
131
+ result[dbColumnName] = sql`CURRENT_TIMESTAMP`;
132
+ }
133
+ } else {
134
+ result[dbColumnName] = sql`CURRENT_TIMESTAMP`;
135
+ }
136
+ continue;
137
+ }
138
+
109
139
  // Serialize the value using the column definition and database type
110
140
  result[dbColumnName] = this.#serializer.serialize(value, col);
111
141
  }
@@ -120,9 +150,18 @@ export class UnitOfWorkEncoder {
120
150
  * @param dbColumnName - The database column name (e.g., "user_id")
121
151
  * @returns The column definition or undefined if not found
122
152
  */
123
- private findColumnByDbName(table: AnyTable, dbColumnName: string): AnyColumn | undefined {
153
+ private findColumnByDbName(
154
+ table: AnyTable,
155
+ dbColumnName: string,
156
+ columnMap?: Record<string, string>,
157
+ ): AnyColumn | undefined {
158
+ const logicalName = columnMap?.[dbColumnName] ?? dbColumnName;
159
+ const direct = table.columns[logicalName];
160
+ if (direct) {
161
+ return direct;
162
+ }
124
163
  for (const col of Object.values(table.columns)) {
125
- if (col.name === dbColumnName) {
164
+ if (col.name === logicalName) {
126
165
  return col;
127
166
  }
128
167
  }