@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
@@ -7,6 +7,7 @@ import type {
7
7
  Relation,
8
8
  } from "../../schema/create";
9
9
  import { FragnoId } from "../../schema/create";
10
+ import { generateId } from "../../schema/generate-id";
10
11
  import type { Condition, ConditionBuilder } from "../condition-builder";
11
12
  import type {
12
13
  SelectClause,
@@ -160,7 +161,7 @@ export type RetrievalOperation<
160
161
  | {
161
162
  type: "find";
162
163
  schema: TSchema;
163
- namespace?: string;
164
+ namespace?: string | null;
164
165
  table: TTable;
165
166
  indexName: string;
166
167
  options: FindOptions<TTable, SelectClause<TTable>>;
@@ -170,7 +171,7 @@ export type RetrievalOperation<
170
171
  | {
171
172
  type: "count";
172
173
  schema: TSchema;
173
- namespace?: string;
174
+ namespace?: string | null;
174
175
  table: TTable;
175
176
  indexName: string;
176
177
  options: Pick<FindOptions<TTable>, "where" | "useIndex">;
@@ -186,7 +187,7 @@ export type MutationOperation<
186
187
  | {
187
188
  type: "update";
188
189
  schema: TSchema;
189
- namespace?: string;
190
+ namespace?: string | null;
190
191
  table: TTable["name"];
191
192
  id: FragnoId | string;
192
193
  checkVersion: boolean;
@@ -195,7 +196,7 @@ export type MutationOperation<
195
196
  | {
196
197
  type: "create";
197
198
  schema: TSchema;
198
- namespace?: string;
199
+ namespace?: string | null;
199
200
  table: TTable["name"];
200
201
  values: TableToInsertValues<TTable>;
201
202
  generatedExternalId: string;
@@ -203,7 +204,7 @@ export type MutationOperation<
203
204
  | {
204
205
  type: "delete";
205
206
  schema: TSchema;
206
- namespace?: string;
207
+ namespace?: string | null;
207
208
  table: TTable["name"];
208
209
  id: FragnoId | string;
209
210
  checkVersion: boolean;
@@ -211,7 +212,7 @@ export type MutationOperation<
211
212
  | {
212
213
  type: "check";
213
214
  schema: TSchema;
214
- namespace?: string;
215
+ namespace?: string | null;
215
216
  table: TTable["name"];
216
217
  id: FragnoId;
217
218
  };
@@ -221,6 +222,14 @@ export type MutationOperation<
221
222
  */
222
223
  export interface CompiledMutation<TOutput> {
223
224
  query: TOutput;
225
+ /**
226
+ * Original mutation operation for execution metadata (e.g., outbox payloads).
227
+ */
228
+ operation?: MutationOperation<AnySchema>;
229
+ /**
230
+ * Idempotency key for the Unit of Work that produced this mutation.
231
+ */
232
+ uowId?: string;
224
233
  /**
225
234
  * The type of mutation operation (create, update, delete, or check).
226
235
  */
@@ -262,13 +271,9 @@ export type MutationResult =
262
271
  * Executor interface for Unit of Work operations
263
272
  */
264
273
  export interface UOWExecutor<TOutput, TRawResult = unknown> {
265
- /**
266
- * Execute the retrieval phase - all queries run in a single transaction for snapshot isolation
267
- */
268
274
  executeRetrievalPhase(retrievalBatch: TOutput[]): Promise<TRawResult[]>;
269
275
 
270
276
  /**
271
- * Execute the mutation phase - all queries run in a transaction with version checks
272
277
  * Returns success status indicating if mutations completed without conflicts,
273
278
  * and internal IDs for create operations (null if database doesn't support RETURNING)
274
279
  */
@@ -835,7 +840,7 @@ export function buildJoinIndexed<TTable extends AnyTable, TJoinOut>(
835
840
 
836
841
  builder[name] = (builderFn?: (b: JoinFindBuilder<AnyTable>) => JoinFindBuilder<AnyTable>) => {
837
842
  // Create join builder for this relation's table
838
- const joinBuilder = new JoinFindBuilder(relation.table.ormName, relation.table);
843
+ const joinBuilder = new JoinFindBuilder(relation.table.name, relation.table);
839
844
  if (builderFn) {
840
845
  builderFn(joinBuilder);
841
846
  }
@@ -903,7 +908,7 @@ export interface IUnitOfWork {
903
908
  // Getters (schema-agnostic)
904
909
  readonly state: UOWState;
905
910
  readonly name: string | undefined;
906
- readonly nonce: string;
911
+ readonly idempotencyKey: string;
907
912
  readonly retrievalPhase: Promise<unknown[]>;
908
913
  readonly mutationPhase: Promise<void>;
909
914
 
@@ -936,7 +941,7 @@ export interface IUnitOfWork {
936
941
  ): TypedUnitOfWork<TOtherSchema, [], any, TOtherHooks>;
937
942
 
938
943
  // Schema registration (for cross-fragment operations like hooks)
939
- registerSchema(schema: AnySchema, namespace: string): void;
944
+ registerSchema(schema: AnySchema, namespace: string | null): void;
940
945
 
941
946
  // Hook triggering (schema-agnostic, string-based hook names)
942
947
  triggerHook(hookName: string, payload: unknown, options?: TriggerHookOptions): void;
@@ -954,11 +959,50 @@ export interface IUnitOfWork {
954
959
  export interface IUnitOfWorkRestricted
955
960
  extends Omit<IUnitOfWork, "executeRetrieve" | "executeMutations"> {}
956
961
 
962
+ export type UOWInstrumentationPhase =
963
+ | "beforeRetrieve"
964
+ | "afterRetrieve"
965
+ | "beforeMutate"
966
+ | "afterMutate";
967
+
968
+ export type UOWInstrumentationInjection =
969
+ | { type: "conflict"; reason?: string }
970
+ | { type: "error"; error: Error };
971
+
972
+ export type UOWInstrumentationContext = {
973
+ phase: UOWInstrumentationPhase;
974
+ uowName?: string;
975
+ idempotencyKey: string;
976
+ retrievalOpsCount: number;
977
+ mutationOpsCount: number;
978
+ uow: IUnitOfWork;
979
+ };
980
+
981
+ export type UOWInstrumentation = {
982
+ beforeRetrieve?: (
983
+ ctx: UOWInstrumentationContext,
984
+ ) => void | Promise<void> | UOWInstrumentationInjection;
985
+ afterRetrieve?: (
986
+ ctx: UOWInstrumentationContext,
987
+ ) => void | Promise<void> | UOWInstrumentationInjection;
988
+ beforeMutate?: (
989
+ ctx: UOWInstrumentationContext,
990
+ ) => void | Promise<void> | UOWInstrumentationInjection;
991
+ afterMutate?: (
992
+ ctx: UOWInstrumentationContext,
993
+ ) => void | Promise<void> | UOWInstrumentationInjection;
994
+ };
995
+
996
+ export type UOWInstrumentationFinalizer = {
997
+ afterRetrieve?: (ctx: UOWInstrumentationContext) => void | Promise<void>;
998
+ afterMutate?: (ctx: UOWInstrumentationContext) => void | Promise<void>;
999
+ };
1000
+
957
1001
  export function createUnitOfWork(
958
1002
  compiler: UOWCompiler<unknown>,
959
1003
  executor: UOWExecutor<unknown, unknown>,
960
1004
  decoder: UOWDecoder<unknown>,
961
- schemaNamespaceMap?: WeakMap<AnySchema, string>,
1005
+ schemaNamespaceMap?: WeakMap<AnySchema, string | null>,
962
1006
  name?: string,
963
1007
  ): UnitOfWork {
964
1008
  return new UnitOfWork(compiler, executor, decoder, name, undefined, schemaNamespaceMap);
@@ -967,7 +1011,17 @@ export function createUnitOfWork(
967
1011
  export interface UnitOfWorkConfig {
968
1012
  dryRun?: boolean;
969
1013
  onQuery?: (query: unknown) => void;
970
- nonce?: string;
1014
+ idempotencyKey?: string;
1015
+ instrumentation?: UOWInstrumentation;
1016
+ instrumentationFinalizer?: UOWInstrumentationFinalizer;
1017
+ }
1018
+
1019
+ function isUowInstrumentationInjection(value: unknown): value is UOWInstrumentationInjection {
1020
+ if (!value || typeof value !== "object") {
1021
+ return false;
1022
+ }
1023
+ const injection = value as UOWInstrumentationInjection;
1024
+ return injection.type === "conflict" || injection.type === "error";
971
1025
  }
972
1026
 
973
1027
  /**
@@ -1199,7 +1253,7 @@ class UOWChildCoordinator<TRawInput> {
1199
1253
  export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
1200
1254
  #name?: string;
1201
1255
  #config?: UnitOfWorkConfig;
1202
- #nonce: string;
1256
+ #idempotencyKey: string;
1203
1257
 
1204
1258
  #state: UOWState = "building-retrieval";
1205
1259
 
@@ -1210,7 +1264,7 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
1210
1264
  #compiler: UOWCompiler<unknown>;
1211
1265
  #executor: UOWExecutor<unknown, TRawInput>;
1212
1266
  #decoder: UOWDecoder<TRawInput>;
1213
- #schemaNamespaceMap: WeakMap<AnySchema, string>;
1267
+ #schemaNamespaceMap: WeakMap<AnySchema, string | null>;
1214
1268
 
1215
1269
  #retrievalResults?: unknown[];
1216
1270
  #createdInternalIds: (bigint | null)[] = [];
@@ -1235,7 +1289,7 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
1235
1289
  decoder: UOWDecoder<TRawInput>,
1236
1290
  name?: string,
1237
1291
  config?: UnitOfWorkConfig,
1238
- schemaNamespaceMap?: WeakMap<AnySchema, string>,
1292
+ schemaNamespaceMap?: WeakMap<AnySchema, string | null>,
1239
1293
  ) {
1240
1294
  this.#compiler = compiler;
1241
1295
  this.#executor = executor;
@@ -1243,7 +1297,62 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
1243
1297
  this.#schemaNamespaceMap = schemaNamespaceMap ?? new WeakMap();
1244
1298
  this.#name = name;
1245
1299
  this.#config = config;
1246
- this.#nonce = config?.nonce ?? crypto.randomUUID();
1300
+ this.#idempotencyKey = config?.idempotencyKey ?? crypto.randomUUID();
1301
+ }
1302
+
1303
+ #createInstrumentationContext(phase: UOWInstrumentationPhase): UOWInstrumentationContext {
1304
+ return {
1305
+ phase,
1306
+ uowName: this.#name,
1307
+ idempotencyKey: this.#idempotencyKey,
1308
+ retrievalOpsCount: this.#retrievalOps.length,
1309
+ mutationOpsCount: this.#mutationOps.length,
1310
+ uow: this,
1311
+ };
1312
+ }
1313
+
1314
+ async #runInstrumentation(
1315
+ phase: UOWInstrumentationPhase,
1316
+ ): Promise<UOWInstrumentationInjection | null> {
1317
+ const hook = this.#config?.instrumentation?.[phase];
1318
+ if (!hook) {
1319
+ return null;
1320
+ }
1321
+
1322
+ const result = await hook(this.#createInstrumentationContext(phase));
1323
+ if (isUowInstrumentationInjection(result)) {
1324
+ return result;
1325
+ }
1326
+
1327
+ return null;
1328
+ }
1329
+
1330
+ async #runInstrumentationFinalizer(phase: "afterRetrieve" | "afterMutate"): Promise<void> {
1331
+ const hook = this.#config?.instrumentationFinalizer?.[phase];
1332
+ if (!hook) {
1333
+ return;
1334
+ }
1335
+
1336
+ await hook(this.#createInstrumentationContext(phase));
1337
+ }
1338
+
1339
+ #handleRetrieveInjection(injection: UOWInstrumentationInjection): never {
1340
+ if (injection.type === "error") {
1341
+ throw injection.error;
1342
+ }
1343
+
1344
+ throw new Error(injection.reason ?? "Injected conflict");
1345
+ }
1346
+
1347
+ #handleMutationInjection(injection: UOWInstrumentationInjection): { success: false } | never {
1348
+ if (injection.type === "error") {
1349
+ throw injection.error;
1350
+ }
1351
+
1352
+ this.#state = "executed";
1353
+ this.#createdInternalIds.length = 0;
1354
+ this.#mutationPhaseDeferred.resolve();
1355
+ return { success: false };
1247
1356
  }
1248
1357
 
1249
1358
  /**
@@ -1251,7 +1360,7 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
1251
1360
  * This is used for internal fragments like hooks that need to create
1252
1361
  * records in a different schema during the same transaction.
1253
1362
  */
1254
- registerSchema(schema: AnySchema, namespace: string): void {
1363
+ registerSchema(schema: AnySchema, namespace: string | null): void {
1255
1364
  this.#schemaNamespaceMap.set(schema, namespace);
1256
1365
  }
1257
1366
 
@@ -1293,7 +1402,7 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
1293
1402
  this.#executor,
1294
1403
  this.#decoder,
1295
1404
  this.#name,
1296
- { ...this.#config, nonce: this.#nonce },
1405
+ { ...this.#config, idempotencyKey: this.#idempotencyKey },
1297
1406
  this.#schemaNamespaceMap,
1298
1407
  );
1299
1408
  child.#coordinator.setAsRestricted(this, this.#coordinator);
@@ -1394,8 +1503,8 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
1394
1503
  return this.#name;
1395
1504
  }
1396
1505
 
1397
- get nonce(): string {
1398
- return this.#nonce;
1506
+ get idempotencyKey(): string {
1507
+ return this.#idempotencyKey;
1399
1508
  }
1400
1509
 
1401
1510
  /**
@@ -1429,13 +1538,25 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
1429
1538
  );
1430
1539
  }
1431
1540
 
1541
+ let afterRan = false;
1542
+ let failed = false;
1432
1543
  try {
1433
1544
  // Wait for all children to signal readiness
1434
1545
  await this.#coordinator.retrievalReadinessPromise;
1435
1546
 
1547
+ const beforeInjection = await this.#runInstrumentation("beforeRetrieve");
1548
+ if (beforeInjection) {
1549
+ return this.#handleRetrieveInjection(beforeInjection);
1550
+ }
1551
+
1436
1552
  if (this.#retrievalOps.length === 0) {
1437
1553
  this.#state = "building-mutation";
1438
1554
  const emptyResults: unknown[] = [];
1555
+ afterRan = true;
1556
+ const afterInjection = await this.#runInstrumentation("afterRetrieve");
1557
+ if (afterInjection) {
1558
+ return this.#handleRetrieveInjection(afterInjection);
1559
+ }
1439
1560
  this.#retrievalPhaseDeferred.resolve(emptyResults);
1440
1561
  return emptyResults;
1441
1562
  }
@@ -1453,6 +1574,11 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
1453
1574
  if (this.#config?.dryRun) {
1454
1575
  this.#state = "executed";
1455
1576
  const emptyResults: unknown[] = [];
1577
+ afterRan = true;
1578
+ const afterInjection = await this.#runInstrumentation("afterRetrieve");
1579
+ if (afterInjection) {
1580
+ return this.#handleRetrieveInjection(afterInjection);
1581
+ }
1456
1582
  this.#retrievalPhaseDeferred.resolve(emptyResults);
1457
1583
  return emptyResults;
1458
1584
  }
@@ -1465,12 +1591,33 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
1465
1591
  this.#retrievalResults = results;
1466
1592
  this.#state = "building-mutation";
1467
1593
 
1594
+ afterRan = true;
1595
+ const afterInjection = await this.#runInstrumentation("afterRetrieve");
1596
+ if (afterInjection) {
1597
+ return this.#handleRetrieveInjection(afterInjection);
1598
+ }
1599
+
1468
1600
  this.#retrievalPhaseDeferred.resolve(this.#retrievalResults);
1469
1601
 
1470
1602
  return this.#retrievalResults;
1471
1603
  } catch (error) {
1472
1604
  this.#retrievalError = error instanceof Error ? error : new Error(String(error));
1605
+ failed = true;
1473
1606
  throw error;
1607
+ } finally {
1608
+ try {
1609
+ await this.#runInstrumentationFinalizer("afterRetrieve");
1610
+ } catch {
1611
+ // Ignore finalizer errors when unwinding failures.
1612
+ }
1613
+
1614
+ if (!afterRan && failed) {
1615
+ try {
1616
+ await this.#runInstrumentation("afterRetrieve");
1617
+ } catch {
1618
+ // Ignore after-retrieve hook errors when unwinding failures.
1619
+ }
1620
+ }
1474
1621
  }
1475
1622
  }
1476
1623
 
@@ -1487,15 +1634,23 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
1487
1634
  throw new Error(`Cannot execute mutations from state ${this.#state}.`);
1488
1635
  }
1489
1636
 
1637
+ let afterRan = false;
1638
+ let failed = false;
1490
1639
  try {
1491
1640
  // Wait for all children to signal readiness
1492
1641
  await this.#coordinator.mutationReadinessPromise;
1493
1642
 
1643
+ const beforeInjection = await this.#runInstrumentation("beforeMutate");
1644
+ if (beforeInjection) {
1645
+ return this.#handleMutationInjection(beforeInjection);
1646
+ }
1647
+
1494
1648
  // Compile mutation operations using single compiler
1495
1649
  const mutationBatch: CompiledMutation<unknown>[] = [];
1496
1650
  for (const op of this.#mutationOps) {
1497
1651
  const compiled = this.#compiler.compileMutationOperation(op);
1498
1652
  if (compiled !== null) {
1653
+ compiled.uowId = this.#idempotencyKey;
1499
1654
  this.#config?.onQuery?.(compiled);
1500
1655
  mutationBatch.push(compiled);
1501
1656
  }
@@ -1503,6 +1658,11 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
1503
1658
 
1504
1659
  if (this.#config?.dryRun) {
1505
1660
  this.#state = "executed";
1661
+ afterRan = true;
1662
+ const afterInjection = await this.#runInstrumentation("afterMutate");
1663
+ if (afterInjection) {
1664
+ return this.#handleMutationInjection(afterInjection);
1665
+ }
1506
1666
  this.#mutationPhaseDeferred.resolve();
1507
1667
  return {
1508
1668
  success: true,
@@ -1519,6 +1679,12 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
1519
1679
  this.#createdInternalIds.push(...result.createdInternalIds);
1520
1680
  }
1521
1681
 
1682
+ afterRan = true;
1683
+ const afterInjection = await this.#runInstrumentation("afterMutate");
1684
+ if (afterInjection) {
1685
+ return this.#handleMutationInjection(afterInjection);
1686
+ }
1687
+
1522
1688
  // Resolve the mutation phase promise to unblock waiting service methods
1523
1689
  this.#mutationPhaseDeferred.resolve();
1524
1690
 
@@ -1527,7 +1693,22 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
1527
1693
  };
1528
1694
  } catch (error) {
1529
1695
  this.#mutationError = error instanceof Error ? error : new Error(String(error));
1696
+ failed = true;
1530
1697
  throw error;
1698
+ } finally {
1699
+ try {
1700
+ await this.#runInstrumentationFinalizer("afterMutate");
1701
+ } catch {
1702
+ // Ignore finalizer errors when unwinding failures.
1703
+ }
1704
+
1705
+ if (!afterRan && failed) {
1706
+ try {
1707
+ await this.#runInstrumentation("afterMutate");
1708
+ } catch {
1709
+ // Ignore after-mutate hook errors when unwinding failures.
1710
+ }
1711
+ }
1531
1712
  }
1532
1713
  }
1533
1714
 
@@ -1626,6 +1807,7 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
1626
1807
  for (const op of this.#mutationOps) {
1627
1808
  const compiled = compiler.compileMutationOperation(op);
1628
1809
  if (compiled !== null) {
1810
+ compiled.uowId = this.#idempotencyKey;
1629
1811
  mutationBatch.push(compiled);
1630
1812
  }
1631
1813
  }
@@ -1651,12 +1833,12 @@ export class TypedUnitOfWork<
1651
1833
  > implements IUnitOfWork
1652
1834
  {
1653
1835
  #schema: TSchema;
1654
- #namespace?: string;
1836
+ #namespace?: string | null;
1655
1837
  #uow: UnitOfWork<TRawInput>;
1656
1838
  #operationIndices: number[] = [];
1657
1839
  #cachedRetrievalPhase?: Promise<TRetrievalResults>;
1658
1840
 
1659
- constructor(schema: TSchema, namespace: string | undefined, uow: UnitOfWork<TRawInput>) {
1841
+ constructor(schema: TSchema, namespace: string | null | undefined, uow: UnitOfWork<TRawInput>) {
1660
1842
  this.#schema = schema;
1661
1843
  this.#namespace = namespace;
1662
1844
  this.#uow = uow;
@@ -1674,8 +1856,8 @@ export class TypedUnitOfWork<
1674
1856
  return this.#uow.name;
1675
1857
  }
1676
1858
 
1677
- get nonce(): string {
1678
- return this.#uow.nonce;
1859
+ get idempotencyKey(): string {
1860
+ return this.#uow.idempotencyKey;
1679
1861
  }
1680
1862
 
1681
1863
  get state() {
@@ -1749,7 +1931,7 @@ export class TypedUnitOfWork<
1749
1931
  return this.#uow.forSchema<TOtherSchema, TOtherHooks>(schema, hooks);
1750
1932
  }
1751
1933
 
1752
- registerSchema(schema: AnySchema, namespace: string): void {
1934
+ registerSchema(schema: AnySchema, namespace: string | null): void {
1753
1935
  this.#uow.registerSchema(schema, namespace);
1754
1936
  }
1755
1937
 
@@ -1962,6 +2144,22 @@ export class TypedUnitOfWork<
1962
2144
  return this as any;
1963
2145
  }
1964
2146
 
2147
+ /**
2148
+ * Generate a new ID for a table without creating a record.
2149
+ * This is useful when you need to reference an ID before actually creating the record,
2150
+ * or when you need to pass the ID to external services.
2151
+ *
2152
+ * @example
2153
+ * ```ts
2154
+ * const userId = uow.generateId("users");
2155
+ * // Use userId in related records or pass to external services
2156
+ * uow.create("users", { id: userId, name: "John" });
2157
+ * ```
2158
+ */
2159
+ generateId<TableName extends keyof TSchema["tables"] & string>(tableName: TableName): FragnoId {
2160
+ return generateId(this.#schema, tableName);
2161
+ }
2162
+
1965
2163
  create<TableName extends keyof TSchema["tables"] & string>(
1966
2164
  tableName: TableName,
1967
2165
  values: TableToInsertValues<TSchema["tables"][TableName]>,
@@ -1976,7 +2174,7 @@ export class TypedUnitOfWork<
1976
2174
  let updatedValues = values;
1977
2175
 
1978
2176
  // Check if ID value is provided in values
1979
- const providedIdValue = (values as Record<string, unknown>)[idColumn.ormName];
2177
+ const providedIdValue = (values as Record<string, unknown>)[idColumn.name];
1980
2178
 
1981
2179
  if (providedIdValue !== undefined) {
1982
2180
  // Extract string from FragnoId or use string directly
@@ -1994,7 +2192,7 @@ export class TypedUnitOfWork<
1994
2192
  const generated = idColumn.generateDefaultValue();
1995
2193
  if (generated === undefined) {
1996
2194
  throw new Error(
1997
- `No ID value provided and ID column ${idColumn.ormName} has no default generator`,
2195
+ `No ID value provided and ID column ${idColumn.name} has no default generator`,
1998
2196
  );
1999
2197
  }
2000
2198
  externalId = generated as string;
@@ -2002,7 +2200,7 @@ export class TypedUnitOfWork<
2002
2200
  // Add the generated ID to values so it's used in the insert
2003
2201
  updatedValues = {
2004
2202
  ...values,
2005
- [idColumn.ormName]: externalId,
2203
+ [idColumn.name]: externalId,
2006
2204
  } as TableToInsertValues<TSchema["tables"][TableName]>;
2007
2205
  }
2008
2206
 
@@ -4,11 +4,12 @@ import { decodeResult } from "./value-decoding";
4
4
  import {
5
5
  SQLocalDriverConfig,
6
6
  NodePostgresDriverConfig,
7
+ PGLiteDriverConfig,
7
8
  MySQL2DriverConfig,
8
9
  } from "../adapters/generic-sql/driver-config";
9
10
 
10
11
  describe("decodeResult", () => {
11
- const testSchema = schema((s) => {
12
+ const testSchema = schema("test", (s) => {
12
13
  return s
13
14
  .addTable("users", (t) => {
14
15
  return t
@@ -40,6 +41,7 @@ describe("decodeResult", () => {
40
41
 
41
42
  const sqliteConfig = new SQLocalDriverConfig();
42
43
  const postgresqlConfig = new NodePostgresDriverConfig();
44
+ const pgliteConfig = new PGLiteDriverConfig();
43
45
  const mysqlConfig = new MySQL2DriverConfig();
44
46
 
45
47
  describe("basic decoding", () => {
@@ -105,6 +107,15 @@ describe("decodeResult", () => {
105
107
 
106
108
  expect(result["createdAt"]).toBe(date);
107
109
  });
110
+
111
+ it("should normalize Date values from pglite timestamp parsing", () => {
112
+ const localDate = new Date("2024-01-15T10:30:00");
113
+ const expected = new Date(localDate.getTime() - localDate.getTimezoneOffset() * 60_000);
114
+ const result = decodeResult({ createdAt: localDate }, usersTable, pgliteConfig);
115
+
116
+ assert.instanceOf(result["createdAt"], Date);
117
+ expect((result["createdAt"] as Date).toISOString()).toBe(expected.toISOString());
118
+ });
108
119
  });
109
120
 
110
121
  describe("nullable columns", () => {
@@ -206,7 +217,7 @@ describe("decodeResult", () => {
206
217
  });
207
218
 
208
219
  it("should handle multiple relations in same result", () => {
209
- const schemaWithMultipleRelations = schema((s) => {
220
+ const schemaWithMultipleRelations = schema("schemawithmultiplerelations", (s) => {
210
221
  return s
211
222
  .addTable("users", (t) => {
212
223
  return t.addColumn("id", idColumn()).addColumn("name", column("string"));
@@ -2,6 +2,8 @@ import type { AnyTable } from "../schema/create";
2
2
  import { createSQLSerializer } from "./serialize/create-sql-serializer";
3
3
  import { FragnoId, FragnoReference } from "../schema/create";
4
4
  import type { DriverConfig } from "../adapters/generic-sql/driver-config";
5
+ import type { SQLiteStorageMode } from "../adapters/generic-sql/sqlite-storage";
6
+ import type { NamingResolver } from "../naming/sql-naming";
5
7
 
6
8
  /**
7
9
  * Decodes a database result record to application format.
@@ -15,6 +17,7 @@ import type { DriverConfig } from "../adapters/generic-sql/driver-config";
15
17
  * @param result - The raw database result record
16
18
  * @param table - The table schema definition containing column and relation information
17
19
  * @param driverConfig - The driver configuration containing database type information
20
+ * @param sqliteStorageMode - Optional SQLite storage mode override
18
21
  * @returns A record in application format with deserialized values
19
22
  *
20
23
  * @example
@@ -31,11 +34,14 @@ export function decodeResult(
31
34
  result: Record<string, unknown>,
32
35
  table: AnyTable,
33
36
  driverConfig: DriverConfig,
37
+ sqliteStorageMode?: SQLiteStorageMode,
38
+ resolver?: NamingResolver,
34
39
  ): Record<string, unknown> {
35
- const serializer = createSQLSerializer(driverConfig);
40
+ const serializer = createSQLSerializer(driverConfig, sqliteStorageMode);
36
41
  const output: Record<string, unknown> = {};
37
42
  // First pass: collect all column values
38
43
  const columnValues: Record<string, unknown> = {};
44
+ const columnMap = resolver ? resolver.getColumnNameMap(table) : undefined;
39
45
 
40
46
  // Collect all relation data (including nested) keyed by relation name
41
47
  const relationData: Record<string, Record<string, unknown>> = {};
@@ -46,13 +52,14 @@ export function decodeResult(
46
52
 
47
53
  // Direct column (no colon)
48
54
  if (colonIndex === -1) {
49
- const col = table.columns[k];
55
+ const logicalName = columnMap?.[k] ?? k;
56
+ const col = table.columns[logicalName];
50
57
  if (!col) {
51
58
  continue;
52
59
  }
53
60
 
54
61
  // Store all column values (including hidden ones for FragnoId creation)
55
- columnValues[k] = serializer.deserialize(value, col);
62
+ columnValues[logicalName] = serializer.deserialize(value, col);
56
63
  continue;
57
64
  }
58
65
 
@@ -78,7 +85,13 @@ export function decodeResult(
78
85
  }
79
86
 
80
87
  // Recursively decode the relation data
81
- output[relationName] = decodeResult(relationData[relationName], relation.table, driverConfig);
88
+ output[relationName] = decodeResult(
89
+ relationData[relationName],
90
+ relation.table,
91
+ driverConfig,
92
+ sqliteStorageMode,
93
+ resolver,
94
+ );
82
95
  }
83
96
 
84
97
  // Second pass: create output with FragnoId objects where appropriate