@fragno-dev/db 0.2.2 → 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 (355) hide show
  1. package/.turbo/turbo-build.log +202 -140
  2. package/CHANGELOG.md +35 -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 +39 -29
  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 +18 -7
  80. package/dist/db-fragment-definition-builder.d.ts.map +1 -1
  81. package/dist/db-fragment-definition-builder.js +116 -54
  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 +79 -2
  92. package/dist/fragments/internal-fragment.d.ts.map +1 -1
  93. package/dist/fragments/internal-fragment.js +150 -32
  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 +42 -1
  106. package/dist/hooks/hooks.d.ts.map +1 -1
  107. package/dist/hooks/hooks.js +72 -6
  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 +15 -8
  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.map +1 -1
  165. package/dist/query/unit-of-work/execute-unit-of-work.js +11 -6
  166. package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -1
  167. package/dist/query/unit-of-work/unit-of-work.d.ts +50 -14
  168. package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
  169. package/dist/query/unit-of-work/unit-of-work.js +86 -5
  170. package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
  171. package/dist/query/value-decoding.js +9 -6
  172. package/dist/query/value-decoding.js.map +1 -1
  173. package/dist/query/value-encoding.js +29 -9
  174. package/dist/query/value-encoding.js.map +1 -1
  175. package/dist/schema/create.d.ts +38 -14
  176. package/dist/schema/create.d.ts.map +1 -1
  177. package/dist/schema/create.js +81 -42
  178. package/dist/schema/create.js.map +1 -1
  179. package/dist/schema/generate-id.js +2 -2
  180. package/dist/schema/generate-id.js.map +1 -1
  181. package/dist/schema/type-conversion/create-sql-type-mapper.js +3 -2
  182. package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -1
  183. package/dist/schema/type-conversion/dialect/sqlite.js +9 -0
  184. package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -1
  185. package/dist/schema/validator.d.ts +10 -0
  186. package/dist/schema/validator.d.ts.map +1 -0
  187. package/dist/schema/validator.js +123 -0
  188. package/dist/schema/validator.js.map +1 -0
  189. package/dist/schema-output/drizzle.d.ts +30 -0
  190. package/dist/schema-output/drizzle.d.ts.map +1 -0
  191. package/dist/{adapters/drizzle/generate.js → schema-output/drizzle.js} +82 -56
  192. package/dist/schema-output/drizzle.js.map +1 -0
  193. package/dist/schema-output/prisma.d.ts +17 -0
  194. package/dist/schema-output/prisma.d.ts.map +1 -0
  195. package/dist/schema-output/prisma.js +296 -0
  196. package/dist/schema-output/prisma.js.map +1 -0
  197. package/dist/util/default-database-adapter.js +61 -0
  198. package/dist/util/default-database-adapter.js.map +1 -0
  199. package/dist/with-database.d.ts +1 -1
  200. package/dist/with-database.d.ts.map +1 -1
  201. package/dist/with-database.js +12 -3
  202. package/dist/with-database.js.map +1 -1
  203. package/package.json +43 -28
  204. package/src/adapters/adapters.ts +30 -24
  205. package/src/adapters/drizzle/migrate-drizzle.test.ts +54 -33
  206. package/src/adapters/drizzle/migration-parity-drizzle-kit.test.ts +599 -0
  207. package/src/adapters/drizzle/test-utils.ts +12 -8
  208. package/src/adapters/generic-sql/driver-config.ts +38 -0
  209. package/src/adapters/generic-sql/generic-sql-adapter.test.ts +5 -5
  210. package/src/adapters/generic-sql/generic-sql-adapter.ts +110 -24
  211. package/src/adapters/generic-sql/generic-sql-uow-executor.test.ts +54 -0
  212. package/src/adapters/generic-sql/generic-sql-uow-executor.ts +231 -3
  213. package/src/adapters/generic-sql/migration/adapter-migration-parity.test.ts +118 -0
  214. package/src/adapters/generic-sql/migration/dialect/mysql.test.ts +26 -8
  215. package/src/adapters/generic-sql/migration/dialect/mysql.ts +46 -8
  216. package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +25 -7
  217. package/src/adapters/generic-sql/migration/dialect/postgres.ts +8 -4
  218. package/src/adapters/generic-sql/migration/dialect/sqlite.test.ts +47 -8
  219. package/src/adapters/generic-sql/migration/dialect/sqlite.ts +27 -12
  220. package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +128 -39
  221. package/src/adapters/generic-sql/migration/prepared-migrations.ts +15 -8
  222. package/src/adapters/generic-sql/migration/sql-generator.ts +142 -65
  223. package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +9 -6
  224. package/src/adapters/generic-sql/query/cursor-utils.test.ts +271 -0
  225. package/src/adapters/generic-sql/query/cursor-utils.ts +41 -6
  226. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +27 -27
  227. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +38 -24
  228. package/src/adapters/generic-sql/query/select-builder.test.ts +15 -11
  229. package/src/adapters/generic-sql/query/select-builder.ts +6 -2
  230. package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +52 -2
  231. package/src/adapters/generic-sql/query/sql-query-compiler.ts +50 -15
  232. package/src/adapters/generic-sql/query/where-builder.test.ts +91 -17
  233. package/src/adapters/generic-sql/query/where-builder.ts +90 -38
  234. package/src/adapters/{kysely/kysely-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-migrations.test.ts} +6 -6
  235. package/src/adapters/generic-sql/sql-adapter-pglite-pagination.test.ts +806 -0
  236. package/src/adapters/{drizzle/drizzle-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-queries.test.ts} +11 -11
  237. package/src/adapters/generic-sql/{test/generic-drizzle-adapter-sqlite3.test.ts → sql-adapter-sqlite3-driver.test.ts} +10 -10
  238. package/src/adapters/{drizzle/drizzle-adapter-sqlite3.test.ts → generic-sql/sql-adapter-sqlite3-uow.test.ts} +7 -7
  239. package/src/adapters/{kysely/kysely-adapter-sqlocal.test.ts → generic-sql/sql-adapter-sqlocal.test.ts} +6 -6
  240. package/src/adapters/generic-sql/sqlite-storage.ts +20 -0
  241. package/src/adapters/generic-sql/uow-decoder.test.ts +1 -1
  242. package/src/adapters/generic-sql/uow-decoder.ts +21 -3
  243. package/src/adapters/generic-sql/uow-encoder.test.ts +33 -2
  244. package/src/adapters/generic-sql/uow-encoder.ts +50 -11
  245. package/src/adapters/in-memory/condition-evaluator.test.ts +193 -0
  246. package/src/adapters/in-memory/condition-evaluator.ts +275 -0
  247. package/src/adapters/in-memory/errors.ts +20 -0
  248. package/src/adapters/in-memory/in-memory-adapter.ts +277 -0
  249. package/src/adapters/in-memory/in-memory-uow.mutations.test.ts +296 -0
  250. package/src/adapters/in-memory/in-memory-uow.retrieval.test.ts +100 -0
  251. package/src/adapters/in-memory/in-memory-uow.ts +1348 -0
  252. package/src/adapters/in-memory/index.ts +3 -0
  253. package/src/adapters/in-memory/options.test.ts +41 -0
  254. package/src/adapters/in-memory/options.ts +87 -0
  255. package/src/adapters/in-memory/reference-resolution.test.ts +50 -0
  256. package/src/adapters/in-memory/reference-resolution.ts +67 -0
  257. package/src/adapters/in-memory/sorted-array-index.test.ts +123 -0
  258. package/src/adapters/in-memory/sorted-array-index.ts +228 -0
  259. package/src/adapters/in-memory/store.test.ts +68 -0
  260. package/src/adapters/in-memory/store.ts +145 -0
  261. package/src/adapters/in-memory/value-comparison.ts +53 -0
  262. package/src/adapters/in-memory/value-normalization.test.ts +57 -0
  263. package/src/adapters/prisma/prisma-adapter-sqlite3.test.ts +1163 -0
  264. package/src/adapters/shared/from-unit-of-work-compiler.ts +3 -1
  265. package/src/adapters/shared/uow-operation-compiler.ts +26 -16
  266. package/src/adapters/sql/index.ts +12 -0
  267. package/src/db-fragment-definition-builder.test.ts +30 -12
  268. package/src/db-fragment-definition-builder.ts +142 -73
  269. package/src/db-fragment-instantiator.test.ts +105 -13
  270. package/src/db-fragment-integration.test.ts +9 -7
  271. package/src/dispatchers/cloudflare-do/index.test.ts +73 -0
  272. package/src/dispatchers/cloudflare-do/index.ts +104 -0
  273. package/src/dispatchers/node/index.test.ts +91 -0
  274. package/src/dispatchers/node/index.ts +87 -0
  275. package/src/fragments/internal-fragment.routes.ts +42 -0
  276. package/src/fragments/internal-fragment.schema.ts +51 -0
  277. package/src/fragments/internal-fragment.test.ts +458 -8
  278. package/src/fragments/internal-fragment.ts +322 -63
  279. package/src/hooks/durable-hooks-processor.test.ts +117 -0
  280. package/src/hooks/durable-hooks-processor.ts +67 -0
  281. package/src/hooks/hooks.test.ts +165 -5
  282. package/src/hooks/hooks.ts +197 -9
  283. package/src/migration-engine/auto-from-schema.test.ts +14 -14
  284. package/src/migration-engine/auto-from-schema.ts +5 -2
  285. package/src/migration-engine/create.test.ts +2 -2
  286. package/src/migration-engine/generation-engine.test.ts +229 -104
  287. package/src/migration-engine/generation-engine.ts +94 -64
  288. package/src/migration-engine/shared.ts +1 -0
  289. package/src/mod.ts +64 -26
  290. package/src/naming/sql-naming.ts +180 -0
  291. package/src/outbox/outbox-builder.ts +241 -0
  292. package/src/outbox/outbox.test.ts +253 -0
  293. package/src/outbox/outbox.ts +137 -0
  294. package/src/query/column-defaults.ts +41 -3
  295. package/src/query/condition-builder.test.ts +3 -3
  296. package/src/query/cursor.test.ts +116 -18
  297. package/src/query/cursor.ts +75 -26
  298. package/src/query/db-now.ts +6 -0
  299. package/src/query/query-type.test.ts +2 -2
  300. package/src/query/serialize/create-sql-serializer.ts +7 -2
  301. package/src/query/serialize/dialect/mysql-serializer.ts +12 -4
  302. package/src/query/serialize/dialect/postgres-serializer.ts +34 -4
  303. package/src/query/serialize/dialect/sqlite-serializer.test.ts +51 -1
  304. package/src/query/serialize/dialect/sqlite-serializer.ts +92 -9
  305. package/src/query/serialize/sql-serializer.ts +4 -4
  306. package/src/query/simple-query-interface.ts +5 -0
  307. package/src/query/unit-of-work/execute-unit-of-work.test.ts +25 -1
  308. package/src/query/unit-of-work/execute-unit-of-work.ts +25 -8
  309. package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +12 -12
  310. package/src/query/unit-of-work/unit-of-work-types.test.ts +1 -1
  311. package/src/query/unit-of-work/unit-of-work.test.ts +168 -37
  312. package/src/query/unit-of-work/unit-of-work.ts +203 -18
  313. package/src/query/value-decoding.test.ts +13 -2
  314. package/src/query/value-decoding.ts +17 -4
  315. package/src/query/value-encoding.test.ts +85 -2
  316. package/src/query/value-encoding.ts +56 -6
  317. package/src/schema/create.test.ts +129 -42
  318. package/src/schema/create.ts +185 -47
  319. package/src/schema/generate-id.test.ts +2 -2
  320. package/src/schema/generate-id.ts +2 -2
  321. package/src/schema/serialize.test.ts +14 -2
  322. package/src/schema/type-conversion/create-sql-type-mapper.ts +7 -2
  323. package/src/schema/type-conversion/dialect/sqlite.ts +18 -0
  324. package/src/schema/type-conversion/type-mapping.test.ts +25 -1
  325. package/src/schema/validator.test.ts +197 -0
  326. package/src/schema/validator.ts +231 -0
  327. package/src/{adapters/drizzle/generate.test.ts → schema-output/drizzle.test.ts} +179 -129
  328. package/src/{adapters/drizzle/generate.ts → schema-output/drizzle.ts} +143 -93
  329. package/src/schema-output/prisma.test.ts +536 -0
  330. package/src/schema-output/prisma.ts +573 -0
  331. package/src/util/default-database-adapter.ts +106 -0
  332. package/src/with-database.ts +22 -3
  333. package/tsdown.config.ts +6 -4
  334. package/dist/adapters/drizzle/drizzle-adapter.d.ts +0 -20
  335. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +0 -1
  336. package/dist/adapters/drizzle/drizzle-adapter.js +0 -27
  337. package/dist/adapters/drizzle/drizzle-adapter.js.map +0 -1
  338. package/dist/adapters/drizzle/generate.d.ts +0 -30
  339. package/dist/adapters/drizzle/generate.d.ts.map +0 -1
  340. package/dist/adapters/drizzle/generate.js.map +0 -1
  341. package/dist/adapters/kysely/kysely-adapter.d.ts +0 -19
  342. package/dist/adapters/kysely/kysely-adapter.d.ts.map +0 -1
  343. package/dist/adapters/kysely/kysely-adapter.js +0 -17
  344. package/dist/adapters/kysely/kysely-adapter.js.map +0 -1
  345. package/dist/adapters/shared/table-name-mapper.d.ts +0 -12
  346. package/dist/adapters/shared/table-name-mapper.d.ts.map +0 -1
  347. package/dist/adapters/shared/table-name-mapper.js +0 -43
  348. package/dist/adapters/shared/table-name-mapper.js.map +0 -1
  349. package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js.map +0 -1
  350. package/dist/schema-generator/schema-generator.d.ts +0 -15
  351. package/dist/schema-generator/schema-generator.d.ts.map +0 -1
  352. package/src/adapters/drizzle/drizzle-adapter.ts +0 -39
  353. package/src/adapters/kysely/kysely-adapter.ts +0 -27
  354. package/src/adapters/shared/table-name-mapper.ts +0 -50
  355. package/src/schema-generator/schema-generator.ts +0 -12
@@ -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,21 +1,21 @@
1
1
  import SQLite from "better-sqlite3";
2
2
  import { beforeAll, describe, expect, expectTypeOf, it } from "vitest";
3
- import { column, idColumn, referenceColumn, schema, type FragnoId } from "../../../schema/create";
3
+ import { column, idColumn, referenceColumn, schema, type FragnoId } from "../../schema/create";
4
4
  import {
5
5
  Cursor,
6
6
  createServiceTxBuilder,
7
7
  createHandlerTxBuilder,
8
8
  ExponentialBackoffRetryPolicy,
9
9
  type DatabaseAdapter,
10
- } from "../../../mod";
10
+ } from "../../mod";
11
11
  import { SqliteDialect } from "kysely";
12
- import { SqlDriverAdapter } from "../../../sql-driver/sql-driver-adapter";
13
- import { BetterSQLite3DriverConfig } from "../driver-config";
14
- import { GenericSQLAdapter } from "../generic-sql-adapter";
15
- 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";
16
16
 
17
- describe("GenericSQLAdapter with DrizzleAdapter better-sqlite3", () => {
18
- const testSchema = schema((s) => {
17
+ describe("SqlAdapter with better-sqlite3", () => {
18
+ const testSchema = schema("test", (s) => {
19
19
  return s
20
20
  .addTable("users", (t) => {
21
21
  return t
@@ -73,7 +73,7 @@ describe("GenericSQLAdapter with DrizzleAdapter better-sqlite3", () => {
73
73
  });
74
74
 
75
75
  // Second schema for multi-schema testing
76
- const schema2 = schema((s) => {
76
+ const schema2 = schema("schema2", (s) => {
77
77
  return s
78
78
  .addTable("products", (t) => {
79
79
  return t
@@ -105,7 +105,7 @@ describe("GenericSQLAdapter with DrizzleAdapter better-sqlite3", () => {
105
105
  });
106
106
  const sqlAdapter = new SqlDriverAdapter(dialect);
107
107
  const driverConfig = new BetterSQLite3DriverConfig();
108
- const genericAdapter = new GenericSQLAdapter({ dialect, driverConfig });
108
+ const genericAdapter = new SqlAdapter({ dialect, driverConfig });
109
109
 
110
110
  {
111
111
  const migrations = genericAdapter.prepareMigrations(internalSchema, "");
@@ -1,6 +1,6 @@
1
1
  import SQLite from "better-sqlite3";
2
2
  import { SqliteDialect } from "kysely";
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, type FragnoId } from "../../schema/create";
6
6
  import { Cursor } from "../../query/cursor";
@@ -9,11 +9,11 @@ import {
9
9
  createHandlerTxBuilder,
10
10
  } from "../../query/unit-of-work/execute-unit-of-work";
11
11
  import { ExponentialBackoffRetryPolicy } from "../../query/unit-of-work/retry-policy";
12
- import { BetterSQLite3DriverConfig } from "../generic-sql/driver-config";
12
+ import { BetterSQLite3DriverConfig } from "./driver-config";
13
13
  import { internalSchema } from "../../fragments/internal-fragment";
14
14
 
15
- describe("DrizzleAdapter SQLite", () => {
16
- const testSchema = schema((s) => {
15
+ describe("SqlAdapter SQLite", () => {
16
+ const testSchema = schema("test", (s) => {
17
17
  return s
18
18
  .addTable("users", (t) => {
19
19
  return t
@@ -71,7 +71,7 @@ describe("DrizzleAdapter SQLite", () => {
71
71
  });
72
72
 
73
73
  // Second schema for multi-schema testing
74
- const schema2 = schema((s) => {
74
+ const schema2 = schema("schema2", (s) => {
75
75
  return s
76
76
  .addTable("products", (t) => {
77
77
  return t
@@ -94,7 +94,7 @@ describe("DrizzleAdapter SQLite", () => {
94
94
  });
95
95
  });
96
96
 
97
- let adapter: DrizzleAdapter;
97
+ let adapter: SqlAdapter;
98
98
  let sqliteDatabase: InstanceType<typeof SQLite>;
99
99
 
100
100
  beforeAll(async () => {
@@ -104,7 +104,7 @@ describe("DrizzleAdapter SQLite", () => {
104
104
  database: sqliteDatabase,
105
105
  });
106
106
 
107
- adapter = new DrizzleAdapter({
107
+ adapter = new SqlAdapter({
108
108
  dialect,
109
109
  driverConfig: new BetterSQLite3DriverConfig(),
110
110
  });
@@ -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
  }
@@ -0,0 +1,193 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { column, idColumn, referenceColumn, schema } from "../../schema/create";
3
+ import type { Condition } from "../../query/condition-builder";
4
+ import { buildCondition } from "../../query/condition-builder";
5
+ import { evaluateCondition } from "./condition-evaluator";
6
+ import { createNamespaceStore } from "./store";
7
+
8
+ describe("in-memory condition evaluator", () => {
9
+ it("evaluates SQLite-normalized comparisons and LIKE semantics", () => {
10
+ const testSchema = schema("test", (s) =>
11
+ s.addTable("events", (t) =>
12
+ t
13
+ .addColumn("id", idColumn())
14
+ .addColumn("name", column("string"))
15
+ .addColumn("createdAt", column("timestamp"))
16
+ .addColumn("isActive", column("bool"))
17
+ .addColumn("payload", column("json"))
18
+ .addColumn("size", column("bigint")),
19
+ ),
20
+ );
21
+
22
+ const table = testSchema.tables.events;
23
+ const createdAt = new Date("2024-01-01T00:00:00.000Z");
24
+ const payload = { ok: true, count: 2 };
25
+ const row = {
26
+ id: "evt_1",
27
+ name: "Test User",
28
+ createdAt,
29
+ isActive: true,
30
+ payload,
31
+ size: 9n,
32
+ };
33
+
34
+ expect(
35
+ evaluateCondition(
36
+ buildCondition(table.columns, (eb) => eb("createdAt", "=", createdAt)),
37
+ table,
38
+ row,
39
+ ),
40
+ ).toBe(true);
41
+ const numericBooleanCondition: Condition = {
42
+ type: "compare",
43
+ a: table.columns.isActive,
44
+ operator: "=",
45
+ b: 1,
46
+ };
47
+ expect(evaluateCondition(numericBooleanCondition, table, row)).toBe(true);
48
+ expect(
49
+ evaluateCondition(
50
+ buildCondition(table.columns, (eb) => eb("payload", "=", payload)),
51
+ table,
52
+ row,
53
+ ),
54
+ ).toBe(true);
55
+ expect(
56
+ evaluateCondition(
57
+ buildCondition(table.columns, (eb) => eb("size", ">", 8n)),
58
+ table,
59
+ row,
60
+ ),
61
+ ).toBe(true);
62
+ expect(
63
+ evaluateCondition(
64
+ buildCondition(table.columns, (eb) => eb("name", "contains", "test")),
65
+ table,
66
+ row,
67
+ ),
68
+ ).toBe(true);
69
+ expect(
70
+ evaluateCondition(
71
+ buildCondition(table.columns, (eb) => eb("name", "starts with", "TEST")),
72
+ table,
73
+ row,
74
+ ),
75
+ ).toBe(true);
76
+ expect(
77
+ evaluateCondition(
78
+ buildCondition(table.columns, (eb) => eb("name", "ends with", "user")),
79
+ table,
80
+ row,
81
+ ),
82
+ ).toBe(true);
83
+ });
84
+
85
+ it("handles null and IN semantics", () => {
86
+ const testSchema = schema("test", (s) =>
87
+ s.addTable("events", (t) =>
88
+ t
89
+ .addColumn("id", idColumn())
90
+ .addColumn("age", column("integer").nullable())
91
+ .addColumn("size", column("bigint")),
92
+ ),
93
+ );
94
+
95
+ const table = testSchema.tables.events;
96
+ const row = {
97
+ id: "evt_2",
98
+ age: null,
99
+ size: 9n,
100
+ };
101
+
102
+ expect(
103
+ evaluateCondition(
104
+ buildCondition(table.columns, (eb) => eb("age", "is", null)),
105
+ table,
106
+ row,
107
+ ),
108
+ ).toBe(true);
109
+ expect(
110
+ evaluateCondition(
111
+ buildCondition(table.columns, (eb) => eb("age", "=", null)),
112
+ table,
113
+ row,
114
+ ),
115
+ ).toBe(false);
116
+ expect(
117
+ evaluateCondition(
118
+ buildCondition(table.columns, (eb) => eb("age", "is not", null)),
119
+ table,
120
+ row,
121
+ ),
122
+ ).toBe(false);
123
+
124
+ const inCondition: Condition = {
125
+ type: "compare",
126
+ a: table.columns.size,
127
+ operator: "in",
128
+ b: [1n, null],
129
+ };
130
+ const notInCondition: Condition = {
131
+ type: "compare",
132
+ a: table.columns.size,
133
+ operator: "not in",
134
+ b: [1n, null],
135
+ };
136
+
137
+ expect(evaluateCondition(inCondition, table, row)).toBe(false);
138
+ expect(evaluateCondition(notInCondition, table, row)).toBe(false);
139
+ expect(
140
+ evaluateCondition(
141
+ buildCondition(table.columns, (eb) => eb("size", "not in", [1n, 2n])),
142
+ table,
143
+ row,
144
+ ),
145
+ ).toBe(true);
146
+ });
147
+
148
+ it("resolves reference values against the namespace store", () => {
149
+ const refSchema = schema("ref", (s) =>
150
+ s
151
+ .addTable("users", (t) =>
152
+ t.addColumn("id", idColumn()).addColumn("email", column("string")),
153
+ )
154
+ .addTable("posts", (t) =>
155
+ t
156
+ .addColumn("id", idColumn())
157
+ .addColumn("title", column("string"))
158
+ .addColumn("userId", referenceColumn()),
159
+ )
160
+ .addReference("author", {
161
+ type: "one",
162
+ from: { table: "posts", column: "userId" },
163
+ to: { table: "users", column: "id" },
164
+ }),
165
+ );
166
+
167
+ const namespaceStore = createNamespaceStore(refSchema);
168
+ const usersStore = namespaceStore.tables.get("users");
169
+ const postsTable = refSchema.tables.posts;
170
+
171
+ if (!usersStore) {
172
+ throw new Error("users table missing from namespace store");
173
+ }
174
+
175
+ usersStore.rows.set(1n, {
176
+ id: "user_1",
177
+ email: "user@example.com",
178
+ _internalId: 1n,
179
+ _version: 0,
180
+ });
181
+
182
+ const postRow = {
183
+ id: "post_1",
184
+ title: "Hello",
185
+ userId: 1n,
186
+ _internalId: 10n,
187
+ _version: 0,
188
+ };
189
+
190
+ const condition = buildCondition(postsTable.columns, (eb) => eb("userId", "=", "user_1"));
191
+ expect(evaluateCondition(condition, postsTable, postRow, namespaceStore)).toBe(true);
192
+ });
193
+ });