@fragno-dev/db 0.2.2 → 0.4.1

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 (587) hide show
  1. package/.turbo/turbo-build.log +404 -175
  2. package/CHANGELOG.md +109 -0
  3. package/README.md +54 -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 +24 -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 +60 -22
  14. package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -1
  15. package/dist/adapters/generic-sql/generic-sql-uow-executor.js +169 -3
  16. package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -1
  17. package/dist/adapters/generic-sql/migration/cold-kysely.js.map +1 -1
  18. package/dist/adapters/generic-sql/migration/dialect/mysql.js +25 -6
  19. package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -1
  20. package/dist/adapters/generic-sql/migration/dialect/postgres.js +7 -6
  21. package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -1
  22. package/dist/adapters/generic-sql/migration/dialect/sqlite.js +193 -16
  23. package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -1
  24. package/dist/adapters/generic-sql/migration/executor.d.ts.map +1 -1
  25. package/dist/adapters/generic-sql/migration/executor.js +30 -3
  26. package/dist/adapters/generic-sql/migration/executor.js.map +1 -1
  27. package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -1
  28. package/dist/adapters/generic-sql/migration/prepared-migrations.js +9 -9
  29. package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -1
  30. package/dist/adapters/generic-sql/migration/sql-generator.js +75 -52
  31. package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -1
  32. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +7 -6
  33. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -1
  34. package/dist/adapters/generic-sql/query/cursor-utils.js +42 -4
  35. package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -1
  36. package/dist/adapters/generic-sql/query/db-now-sql.js +27 -0
  37. package/dist/adapters/generic-sql/query/db-now-sql.js.map +1 -0
  38. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +32 -21
  39. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -1
  40. package/dist/adapters/generic-sql/query/select-builder.js +5 -3
  41. package/dist/adapters/generic-sql/query/select-builder.js.map +1 -1
  42. package/dist/adapters/generic-sql/query/sql-query-compiler.js +49 -18
  43. package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -1
  44. package/dist/adapters/generic-sql/query/where-builder.js +43 -29
  45. package/dist/adapters/generic-sql/query/where-builder.js.map +1 -1
  46. package/dist/adapters/generic-sql/sqlite-storage.d.ts +13 -0
  47. package/dist/adapters/generic-sql/sqlite-storage.d.ts.map +1 -0
  48. package/dist/adapters/generic-sql/sqlite-storage.js +15 -0
  49. package/dist/adapters/generic-sql/sqlite-storage.js.map +1 -0
  50. package/dist/adapters/generic-sql/uow-decoder.js +6 -2
  51. package/dist/adapters/generic-sql/uow-decoder.js.map +1 -1
  52. package/dist/adapters/generic-sql/uow-encoder.js +27 -8
  53. package/dist/adapters/generic-sql/uow-encoder.js.map +1 -1
  54. package/dist/adapters/in-memory/condition-evaluator.js +135 -0
  55. package/dist/adapters/in-memory/condition-evaluator.js.map +1 -0
  56. package/dist/adapters/in-memory/errors.d.ts +13 -0
  57. package/dist/adapters/in-memory/errors.d.ts.map +1 -0
  58. package/dist/adapters/in-memory/errors.js +23 -0
  59. package/dist/adapters/in-memory/errors.js.map +1 -0
  60. package/dist/adapters/in-memory/in-memory-adapter.d.ts +27 -0
  61. package/dist/adapters/in-memory/in-memory-adapter.d.ts.map +1 -0
  62. package/dist/adapters/in-memory/in-memory-adapter.js +196 -0
  63. package/dist/adapters/in-memory/in-memory-adapter.js.map +1 -0
  64. package/dist/adapters/in-memory/in-memory-uow.js +871 -0
  65. package/dist/adapters/in-memory/in-memory-uow.js.map +1 -0
  66. package/dist/adapters/in-memory/index.d.ts +4 -0
  67. package/dist/adapters/in-memory/index.js +4 -0
  68. package/dist/adapters/in-memory/options.d.ts +30 -0
  69. package/dist/adapters/in-memory/options.d.ts.map +1 -0
  70. package/dist/adapters/in-memory/options.js +62 -0
  71. package/dist/adapters/in-memory/options.js.map +1 -0
  72. package/dist/adapters/in-memory/reference-resolution.js +26 -0
  73. package/dist/adapters/in-memory/reference-resolution.js.map +1 -0
  74. package/dist/adapters/in-memory/sorted-array-index.js +129 -0
  75. package/dist/adapters/in-memory/sorted-array-index.js.map +1 -0
  76. package/dist/adapters/in-memory/store.js +71 -0
  77. package/dist/adapters/in-memory/store.js.map +1 -0
  78. package/dist/adapters/in-memory/value-comparison.js +28 -0
  79. package/dist/adapters/in-memory/value-comparison.js.map +1 -0
  80. package/dist/adapters/shared/from-unit-of-work-compiler.js +51 -24
  81. package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -1
  82. package/dist/adapters/shared/uow-operation-compiler.js +11 -11
  83. package/dist/adapters/shared/uow-operation-compiler.js.map +1 -1
  84. package/dist/adapters/sql/index.d.ts +5 -0
  85. package/dist/adapters/sql/index.js +4 -0
  86. package/dist/browser/adapters/adapters.d.ts +61 -0
  87. package/dist/browser/adapters/adapters.d.ts.map +1 -0
  88. package/dist/browser/adapters/generic-sql/migration/executor.d.ts +15 -0
  89. package/dist/browser/adapters/generic-sql/migration/executor.d.ts.map +1 -0
  90. package/dist/browser/adapters/generic-sql/migration/prepared-migrations.d.ts +66 -0
  91. package/dist/browser/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -0
  92. package/dist/browser/adapters/generic-sql/sqlite-storage.d.ts +11 -0
  93. package/dist/browser/adapters/generic-sql/sqlite-storage.d.ts.map +1 -0
  94. package/dist/browser/adapters/in-memory/in-memory-adapter.d.ts +5 -0
  95. package/dist/browser/adapters/in-memory/index.d.ts +2 -0
  96. package/dist/browser/adapters/in-memory/options.d.ts +1 -0
  97. package/dist/browser/db-fragment-definition-builder.d.ts +237 -0
  98. package/dist/browser/db-fragment-definition-builder.d.ts.map +1 -0
  99. package/dist/browser/durable-hooks.d.ts +3 -0
  100. package/dist/browser/fragments/internal-fragment.d.ts +317 -0
  101. package/dist/browser/fragments/internal-fragment.d.ts.map +1 -0
  102. package/dist/browser/fragments/internal-fragment.schema.d.ts +1 -0
  103. package/dist/browser/hooks/durable-hooks-logger.d.ts +10 -0
  104. package/dist/browser/hooks/durable-hooks-logger.d.ts.map +1 -0
  105. package/dist/browser/hooks/hooks.d.ts +146 -0
  106. package/dist/browser/hooks/hooks.d.ts.map +1 -0
  107. package/dist/browser/id.js +1 -0
  108. package/dist/browser/internal/adapter-registry.d.ts +4 -0
  109. package/dist/browser/internal/outbox-state.d.ts +2 -0
  110. package/dist/browser/mod.d.ts +15 -0
  111. package/dist/browser/mod.d.ts.map +1 -0
  112. package/dist/browser/mod.js +17 -0
  113. package/dist/browser/mod.js.map +1 -0
  114. package/dist/browser/mod2.d.ts +48 -0
  115. package/dist/browser/mod2.d.ts.map +1 -0
  116. package/dist/browser/naming/sql-naming.d.ts +19 -0
  117. package/dist/browser/naming/sql-naming.d.ts.map +1 -0
  118. package/dist/browser/outbox/outbox.d.ts +21 -0
  119. package/dist/browser/outbox/outbox.d.ts.map +1 -0
  120. package/dist/browser/query/column-defaults.js +1 -0
  121. package/dist/browser/query/condition-builder.d.ts +44 -0
  122. package/dist/browser/query/condition-builder.d.ts.map +1 -0
  123. package/dist/browser/query/condition-builder.js +97 -0
  124. package/dist/browser/query/condition-builder.js.map +1 -0
  125. package/dist/browser/query/cursor.d.ts +105 -0
  126. package/dist/browser/query/cursor.d.ts.map +1 -0
  127. package/dist/browser/query/cursor.js +150 -0
  128. package/dist/browser/query/cursor.js.map +1 -0
  129. package/dist/browser/query/db-now.d.ts +22 -0
  130. package/dist/browser/query/db-now.d.ts.map +1 -0
  131. package/dist/browser/query/db-now.js +33 -0
  132. package/dist/browser/query/db-now.js.map +1 -0
  133. package/dist/browser/query/orm/orm.d.ts +18 -0
  134. package/dist/browser/query/orm/orm.d.ts.map +1 -0
  135. package/dist/browser/query/simple-query-interface.d.ts +108 -0
  136. package/dist/browser/query/simple-query-interface.d.ts.map +1 -0
  137. package/dist/browser/query/unit-of-work/execute-unit-of-work.d.ts +423 -0
  138. package/dist/browser/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -0
  139. package/dist/browser/query/unit-of-work/execute-unit-of-work.js +507 -0
  140. package/dist/browser/query/unit-of-work/execute-unit-of-work.js.map +1 -0
  141. package/dist/browser/query/unit-of-work/retry-policy.d.ts +23 -0
  142. package/dist/browser/query/unit-of-work/retry-policy.d.ts.map +1 -0
  143. package/dist/browser/query/unit-of-work/retry-policy.js +40 -0
  144. package/dist/browser/query/unit-of-work/retry-policy.js.map +1 -0
  145. package/dist/browser/query/unit-of-work/unit-of-work.d.ts +703 -0
  146. package/dist/browser/query/unit-of-work/unit-of-work.d.ts.map +1 -0
  147. package/dist/browser/query/unit-of-work/unit-of-work.js +1206 -0
  148. package/dist/browser/query/unit-of-work/unit-of-work.js.map +1 -0
  149. package/dist/browser/query/value-encoding.js +38 -0
  150. package/dist/browser/query/value-encoding.js.map +1 -0
  151. package/dist/browser/schema/create.d.ts +326 -0
  152. package/dist/browser/schema/create.d.ts.map +1 -0
  153. package/dist/browser/schema/create.js +89 -0
  154. package/dist/browser/schema/create.js.map +1 -0
  155. package/dist/browser/schema/generate-id.js +28 -0
  156. package/dist/browser/schema/generate-id.js.map +1 -0
  157. package/dist/browser/shared/providers.d.ts +6 -0
  158. package/dist/browser/shared/providers.d.ts.map +1 -0
  159. package/dist/browser/sql-driver/connection/connection-provider.d.ts +13 -0
  160. package/dist/browser/sql-driver/connection/connection-provider.d.ts.map +1 -0
  161. package/dist/browser/sql-driver/dialect-adapter/dialect-adapter.d.ts +7 -0
  162. package/dist/browser/sql-driver/dialect-adapter/dialect-adapter.d.ts.map +1 -0
  163. package/dist/browser/sql-driver/driver/runtime-driver.d.ts +23 -0
  164. package/dist/browser/sql-driver/driver/runtime-driver.d.ts.map +1 -0
  165. package/dist/browser/sql-driver/query-executor/plugin.d.ts +17 -0
  166. package/dist/browser/sql-driver/query-executor/plugin.d.ts.map +1 -0
  167. package/dist/browser/sql-driver/query-executor/query-executor.d.ts +36 -0
  168. package/dist/browser/sql-driver/query-executor/query-executor.d.ts.map +1 -0
  169. package/dist/browser/sql-driver/sql-driver-adapter.d.ts +29 -0
  170. package/dist/browser/sql-driver/sql-driver-adapter.d.ts.map +1 -0
  171. package/dist/browser/sql-driver/sql-driver.d.ts +38 -0
  172. package/dist/browser/sql-driver/sql-driver.d.ts.map +1 -0
  173. package/dist/browser/sync/commands.d.ts +15 -0
  174. package/dist/browser/sync/commands.d.ts.map +1 -0
  175. package/dist/browser/sync/commands.js +27 -0
  176. package/dist/browser/sync/commands.js.map +1 -0
  177. package/dist/browser/sync/types.d.ts +63 -0
  178. package/dist/browser/sync/types.d.ts.map +1 -0
  179. package/dist/browser/util/types.d.ts +8 -0
  180. package/dist/browser/util/types.d.ts.map +1 -0
  181. package/dist/browser/with-database.d.ts +29 -0
  182. package/dist/browser/with-database.d.ts.map +1 -0
  183. package/dist/client.d.ts +4 -0
  184. package/dist/client.js +5 -0
  185. package/dist/db-fragment-definition-builder.d.ts +101 -33
  186. package/dist/db-fragment-definition-builder.d.ts.map +1 -1
  187. package/dist/db-fragment-definition-builder.js +450 -60
  188. package/dist/db-fragment-definition-builder.js.map +1 -1
  189. package/dist/dispatchers/cloudflare-do/dispatcher.d.ts +20 -0
  190. package/dist/dispatchers/cloudflare-do/dispatcher.d.ts.map +1 -0
  191. package/dist/dispatchers/cloudflare-do/dispatcher.js +147 -0
  192. package/dist/dispatchers/cloudflare-do/dispatcher.js.map +1 -0
  193. package/dist/dispatchers/cloudflare-do/index.d.ts +11 -0
  194. package/dist/dispatchers/cloudflare-do/index.d.ts.map +1 -0
  195. package/dist/dispatchers/cloudflare-do/index.js +31 -0
  196. package/dist/dispatchers/cloudflare-do/index.js.map +1 -0
  197. package/dist/dispatchers/node/dispatcher.d.ts +14 -0
  198. package/dist/dispatchers/node/dispatcher.d.ts.map +1 -0
  199. package/dist/dispatchers/node/dispatcher.js +80 -0
  200. package/dist/dispatchers/node/dispatcher.js.map +1 -0
  201. package/dist/dispatchers/node/index.d.ts +12 -0
  202. package/dist/dispatchers/node/index.d.ts.map +1 -0
  203. package/dist/dispatchers/node/index.js +27 -0
  204. package/dist/dispatchers/node/index.js.map +1 -0
  205. package/dist/durable-hooks.d.ts +31 -0
  206. package/dist/durable-hooks.d.ts.map +1 -0
  207. package/dist/durable-hooks.js +23 -0
  208. package/dist/durable-hooks.js.map +1 -0
  209. package/dist/fragments/internal-fragment.d.ts +186 -8
  210. package/dist/fragments/internal-fragment.d.ts.map +1 -1
  211. package/dist/fragments/internal-fragment.js +203 -38
  212. package/dist/fragments/internal-fragment.js.map +1 -1
  213. package/dist/fragments/internal-fragment.routes.js +164 -0
  214. package/dist/fragments/internal-fragment.routes.js.map +1 -0
  215. package/dist/fragments/internal-fragment.schema.d.ts +15 -0
  216. package/dist/fragments/internal-fragment.schema.d.ts.map +1 -0
  217. package/dist/fragments/internal-fragment.schema.js +39 -0
  218. package/dist/fragments/internal-fragment.schema.js.map +1 -0
  219. package/dist/hooks/durable-hooks-logger.d.ts +10 -0
  220. package/dist/hooks/durable-hooks-logger.d.ts.map +1 -0
  221. package/dist/hooks/durable-hooks-logger.js +75 -0
  222. package/dist/hooks/durable-hooks-logger.js.map +1 -0
  223. package/dist/hooks/durable-hooks-processor.d.ts +1 -0
  224. package/dist/hooks/durable-hooks-processor.js +80 -0
  225. package/dist/hooks/durable-hooks-processor.js.map +1 -0
  226. package/dist/hooks/durable-hooks-runtime.js +44 -0
  227. package/dist/hooks/durable-hooks-runtime.js.map +1 -0
  228. package/dist/hooks/hooks.d.ts +100 -1
  229. package/dist/hooks/hooks.d.ts.map +1 -1
  230. package/dist/hooks/hooks.js +254 -27
  231. package/dist/hooks/hooks.js.map +1 -1
  232. package/dist/id.d.ts +2 -2
  233. package/dist/id.js +2 -2
  234. package/dist/internal/adapter-registry.d.ts +11 -0
  235. package/dist/internal/adapter-registry.d.ts.map +1 -0
  236. package/dist/internal/adapter-registry.js +135 -0
  237. package/dist/internal/adapter-registry.js.map +1 -0
  238. package/dist/internal/outbox-state.d.ts +2 -0
  239. package/dist/internal/outbox-state.js +26 -0
  240. package/dist/internal/outbox-state.js.map +1 -0
  241. package/dist/migration-engine/auto-from-schema.d.ts +33 -0
  242. package/dist/migration-engine/auto-from-schema.d.ts.map +1 -0
  243. package/dist/migration-engine/auto-from-schema.js +223 -37
  244. package/dist/migration-engine/auto-from-schema.js.map +1 -1
  245. package/dist/migration-engine/generation-engine.d.ts +16 -10
  246. package/dist/migration-engine/generation-engine.d.ts.map +1 -1
  247. package/dist/migration-engine/generation-engine.js +86 -35
  248. package/dist/migration-engine/generation-engine.js.map +1 -1
  249. package/dist/migration-engine/shared.d.ts +113 -0
  250. package/dist/migration-engine/shared.d.ts.map +1 -0
  251. package/dist/migration-engine/shared.js.map +1 -1
  252. package/dist/mod.d.ts +20 -12
  253. package/dist/mod.d.ts.map +1 -1
  254. package/dist/mod.js +18 -12
  255. package/dist/mod.js.map +1 -1
  256. package/dist/naming/sql-naming.d.ts +19 -0
  257. package/dist/naming/sql-naming.d.ts.map +1 -0
  258. package/dist/naming/sql-naming.js +116 -0
  259. package/dist/naming/sql-naming.js.map +1 -0
  260. package/dist/outbox/outbox-builder.js +156 -0
  261. package/dist/outbox/outbox-builder.js.map +1 -0
  262. package/dist/outbox/outbox.d.ts +54 -0
  263. package/dist/outbox/outbox.d.ts.map +1 -0
  264. package/dist/outbox/outbox.js +37 -0
  265. package/dist/outbox/outbox.js.map +1 -0
  266. package/dist/query/column-defaults.js +20 -4
  267. package/dist/query/column-defaults.js.map +1 -1
  268. package/dist/query/condition-builder.d.ts +7 -1
  269. package/dist/query/condition-builder.d.ts.map +1 -1
  270. package/dist/query/condition-builder.js +5 -1
  271. package/dist/query/condition-builder.js.map +1 -1
  272. package/dist/query/cursor-client.d.ts +105 -0
  273. package/dist/query/cursor-client.d.ts.map +1 -0
  274. package/dist/query/cursor-client.js +165 -0
  275. package/dist/query/cursor-client.js.map +1 -0
  276. package/dist/query/cursor.d.ts +3 -1
  277. package/dist/query/cursor.d.ts.map +1 -1
  278. package/dist/query/cursor.js +51 -14
  279. package/dist/query/cursor.js.map +1 -1
  280. package/dist/query/db-now.d.ts +22 -0
  281. package/dist/query/db-now.d.ts.map +1 -0
  282. package/dist/query/db-now.js +35 -0
  283. package/dist/query/db-now.js.map +1 -0
  284. package/dist/query/orm/orm.js.map +1 -1
  285. package/dist/query/serialize/create-sql-serializer.js +5 -4
  286. package/dist/query/serialize/create-sql-serializer.js.map +1 -1
  287. package/dist/query/serialize/dialect/mysql-serializer.js +12 -6
  288. package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -1
  289. package/dist/query/serialize/dialect/postgres-serializer.js +25 -7
  290. package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -1
  291. package/dist/query/serialize/dialect/sqlite-serializer.js +60 -12
  292. package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -1
  293. package/dist/query/serialize/sql-serializer.js +2 -2
  294. package/dist/query/serialize/sql-serializer.js.map +1 -1
  295. package/dist/query/simple-query-interface.d.ts +13 -4
  296. package/dist/query/simple-query-interface.d.ts.map +1 -1
  297. package/dist/query/unit-of-work/execute-unit-of-work.d.ts +37 -2
  298. package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -1
  299. package/dist/query/unit-of-work/execute-unit-of-work.js +50 -24
  300. package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -1
  301. package/dist/query/unit-of-work/unit-of-work.d.ts +92 -30
  302. package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
  303. package/dist/query/unit-of-work/unit-of-work.js +136 -11
  304. package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
  305. package/dist/query/value-decoding.js +16 -6
  306. package/dist/query/value-decoding.js.map +1 -1
  307. package/dist/query/value-encoding.js +29 -9
  308. package/dist/query/value-encoding.js.map +1 -1
  309. package/dist/schema/create.d.ts +103 -35
  310. package/dist/schema/create.d.ts.map +1 -1
  311. package/dist/schema/create.js +172 -58
  312. package/dist/schema/create.js.map +1 -1
  313. package/dist/schema/generate-id.js +2 -2
  314. package/dist/schema/generate-id.js.map +1 -1
  315. package/dist/schema/type-conversion/create-sql-type-mapper.js +4 -3
  316. package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -1
  317. package/dist/schema/type-conversion/dialect/sqlite.js +9 -0
  318. package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -1
  319. package/dist/schema/validator.d.ts +10 -0
  320. package/dist/schema/validator.d.ts.map +1 -0
  321. package/dist/schema/validator.js +123 -0
  322. package/dist/schema/validator.js.map +1 -0
  323. package/dist/schema-output/drizzle.d.ts +30 -0
  324. package/dist/schema-output/drizzle.d.ts.map +1 -0
  325. package/dist/{adapters/drizzle/generate.js → schema-output/drizzle.js} +88 -60
  326. package/dist/schema-output/drizzle.js.map +1 -0
  327. package/dist/schema-output/prisma.d.ts +17 -0
  328. package/dist/schema-output/prisma.d.ts.map +1 -0
  329. package/dist/schema-output/prisma.js +307 -0
  330. package/dist/schema-output/prisma.js.map +1 -0
  331. package/dist/sql-driver/dialects/durable-object-dialect.js +3 -9
  332. package/dist/sql-driver/dialects/durable-object-dialect.js.map +1 -1
  333. package/dist/sql-driver/query-executor/default-query-executor.js.map +1 -1
  334. package/dist/sql-driver/query-executor/query-executor-base.js.map +1 -1
  335. package/dist/sql-driver/sql-driver-adapter.js.map +1 -1
  336. package/dist/sql-driver/sql.js.map +1 -1
  337. package/dist/sync/commands.d.ts +15 -0
  338. package/dist/sync/commands.d.ts.map +1 -0
  339. package/dist/sync/commands.js +27 -0
  340. package/dist/sync/commands.js.map +1 -0
  341. package/dist/sync/index.d.ts +4 -0
  342. package/dist/sync/index.js +4 -0
  343. package/dist/sync/read-tracking.d.ts +25 -0
  344. package/dist/sync/read-tracking.d.ts.map +1 -0
  345. package/dist/sync/read-tracking.js +148 -0
  346. package/dist/sync/read-tracking.js.map +1 -0
  347. package/dist/sync/submit.js +213 -0
  348. package/dist/sync/submit.js.map +1 -0
  349. package/dist/sync/types.d.ts +63 -0
  350. package/dist/sync/types.d.ts.map +1 -0
  351. package/dist/util/default-database-adapter.js +66 -0
  352. package/dist/util/default-database-adapter.js.map +1 -0
  353. package/dist/with-database.d.ts +3 -6
  354. package/dist/with-database.d.ts.map +1 -1
  355. package/dist/with-database.js +8 -7
  356. package/dist/with-database.js.map +1 -1
  357. package/package.json +62 -55
  358. package/src/adapters/adapters.ts +33 -26
  359. package/src/adapters/drizzle/migrate-drizzle.test.ts +99 -41
  360. package/src/adapters/drizzle/migration-parity-drizzle-kit.test.ts +601 -0
  361. package/src/adapters/drizzle/test-utils.ts +13 -8
  362. package/src/adapters/generic-sql/driver-config.ts +38 -0
  363. package/src/adapters/generic-sql/generic-sql-adapter.test.ts +10 -8
  364. package/src/adapters/generic-sql/generic-sql-adapter.ts +117 -34
  365. package/src/adapters/generic-sql/generic-sql-uow-executor.test.ts +55 -0
  366. package/src/adapters/generic-sql/generic-sql-uow-executor.ts +297 -3
  367. package/src/adapters/generic-sql/migration/adapter-migration-parity.test.ts +120 -0
  368. package/src/adapters/generic-sql/migration/cold-kysely.ts +1 -0
  369. package/src/adapters/generic-sql/migration/dialect/mysql.test.ts +27 -8
  370. package/src/adapters/generic-sql/migration/dialect/mysql.ts +47 -8
  371. package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +28 -9
  372. package/src/adapters/generic-sql/migration/dialect/postgres.ts +9 -4
  373. package/src/adapters/generic-sql/migration/dialect/sqlite.test.ts +839 -8
  374. package/src/adapters/generic-sql/migration/dialect/sqlite.ts +396 -53
  375. package/src/adapters/generic-sql/migration/executor.test.ts +52 -0
  376. package/src/adapters/generic-sql/migration/executor.ts +47 -4
  377. package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +238 -46
  378. package/src/adapters/generic-sql/migration/prepared-migrations.ts +21 -13
  379. package/src/adapters/generic-sql/migration/sql-generator.ts +145 -66
  380. package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +11 -8
  381. package/src/adapters/generic-sql/query/cursor-utils.test.ts +272 -0
  382. package/src/adapters/generic-sql/query/cursor-utils.ts +42 -7
  383. package/src/adapters/generic-sql/query/db-now-sql.ts +49 -0
  384. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +171 -35
  385. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +53 -40
  386. package/src/adapters/generic-sql/query/select-builder.test.ts +16 -11
  387. package/src/adapters/generic-sql/query/select-builder.ts +7 -3
  388. package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +75 -6
  389. package/src/adapters/generic-sql/query/sql-query-compiler.ts +129 -24
  390. package/src/adapters/generic-sql/query/where-builder.test.ts +96 -20
  391. package/src/adapters/generic-sql/query/where-builder.ts +112 -41
  392. package/src/adapters/{kysely/kysely-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-migrations.test.ts} +11 -20
  393. package/src/adapters/generic-sql/sql-adapter-pglite-pagination.test.ts +851 -0
  394. package/src/adapters/{drizzle/drizzle-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-queries.test.ts} +18 -15
  395. package/src/adapters/generic-sql/{test/generic-drizzle-adapter-sqlite3.test.ts → sql-adapter-sqlite3-driver.test.ts} +282 -14
  396. package/src/adapters/{drizzle/drizzle-adapter-sqlite3.test.ts → generic-sql/sql-adapter-sqlite3-uow.test.ts} +129 -12
  397. package/src/adapters/{kysely/kysely-adapter-sqlocal.test.ts → generic-sql/sql-adapter-sqlocal.test.ts} +9 -7
  398. package/src/adapters/generic-sql/sqlite-storage.ts +20 -0
  399. package/src/adapters/generic-sql/uow-decoder.test.ts +5 -4
  400. package/src/adapters/generic-sql/uow-decoder.ts +23 -5
  401. package/src/adapters/generic-sql/uow-encoder.test.ts +36 -3
  402. package/src/adapters/generic-sql/uow-encoder.ts +48 -13
  403. package/src/adapters/in-memory/condition-evaluator.test.ts +194 -0
  404. package/src/adapters/in-memory/condition-evaluator.ts +280 -0
  405. package/src/adapters/in-memory/errors.ts +20 -0
  406. package/src/adapters/in-memory/in-memory-adapter.ts +388 -0
  407. package/src/adapters/in-memory/in-memory-uow.mutations.test.ts +344 -0
  408. package/src/adapters/in-memory/in-memory-uow.retrieval.test.ts +255 -0
  409. package/src/adapters/in-memory/in-memory-uow.ts +1724 -0
  410. package/src/adapters/in-memory/index.ts +3 -0
  411. package/src/adapters/in-memory/options.test.ts +42 -0
  412. package/src/adapters/in-memory/options.ts +91 -0
  413. package/src/adapters/in-memory/outbox.test.ts +361 -0
  414. package/src/adapters/in-memory/reference-resolution.test.ts +51 -0
  415. package/src/adapters/in-memory/reference-resolution.ts +67 -0
  416. package/src/adapters/in-memory/sorted-array-index.test.ts +124 -0
  417. package/src/adapters/in-memory/sorted-array-index.ts +228 -0
  418. package/src/adapters/in-memory/store.test.ts +69 -0
  419. package/src/adapters/in-memory/store.ts +145 -0
  420. package/src/adapters/in-memory/value-comparison.ts +53 -0
  421. package/src/adapters/in-memory/value-normalization.test.ts +58 -0
  422. package/src/adapters/prisma/prisma-adapter-sqlite3.test.ts +1207 -0
  423. package/src/adapters/shared/from-unit-of-work-compiler.ts +159 -47
  424. package/src/adapters/shared/uow-operation-compiler.ts +28 -18
  425. package/src/adapters/sql/index.ts +12 -0
  426. package/src/browser/mod.ts +64 -0
  427. package/src/client.ts +19 -0
  428. package/src/db-fragment-definition-builder.test.ts +845 -53
  429. package/src/db-fragment-definition-builder.ts +911 -95
  430. package/src/db-fragment-instantiator.test.ts +210 -94
  431. package/src/db-fragment-integration.test.ts +17 -12
  432. package/src/dispatchers/cloudflare-do/dispatcher.ts +204 -0
  433. package/src/dispatchers/cloudflare-do/index.test.ts +206 -0
  434. package/src/dispatchers/cloudflare-do/index.ts +63 -0
  435. package/src/dispatchers/node/dispatcher.ts +112 -0
  436. package/src/dispatchers/node/index.test.ts +120 -0
  437. package/src/dispatchers/node/index.ts +50 -0
  438. package/src/durable-hooks.test.ts +80 -0
  439. package/src/durable-hooks.ts +67 -0
  440. package/src/fragments/internal-fragment.routes.test.ts +570 -0
  441. package/src/fragments/internal-fragment.routes.ts +334 -0
  442. package/src/fragments/internal-fragment.schema.ts +95 -0
  443. package/src/fragments/internal-fragment.test.ts +505 -83
  444. package/src/fragments/internal-fragment.ts +453 -70
  445. package/src/hooks/durable-hooks-logger.ts +126 -0
  446. package/src/hooks/durable-hooks-processor.pglite.test.ts +87 -0
  447. package/src/hooks/durable-hooks-processor.test.ts +282 -0
  448. package/src/hooks/durable-hooks-processor.ts +173 -0
  449. package/src/hooks/durable-hooks-runtime.test.ts +65 -0
  450. package/src/hooks/durable-hooks-runtime.ts +81 -0
  451. package/src/hooks/hooks.test.ts +455 -34
  452. package/src/hooks/hooks.ts +501 -34
  453. package/src/id.test.ts +34 -0
  454. package/src/id.ts +1 -3
  455. package/src/internal/adapter-registry.test.ts +93 -0
  456. package/src/internal/adapter-registry.ts +239 -0
  457. package/src/internal/outbox-state.ts +43 -0
  458. package/src/migration-engine/auto-from-schema.test.ts +107 -14
  459. package/src/migration-engine/auto-from-schema.ts +365 -44
  460. package/src/migration-engine/create.test.ts +4 -3
  461. package/src/migration-engine/create.ts +1 -1
  462. package/src/migration-engine/generation-engine.test.ts +292 -110
  463. package/src/migration-engine/generation-engine.ts +117 -66
  464. package/src/migration-engine/shared.ts +14 -0
  465. package/src/mod.ts +95 -39
  466. package/src/naming/sql-naming.ts +181 -0
  467. package/src/outbox/outbox-builder.ts +241 -0
  468. package/src/outbox/outbox.test.ts +424 -0
  469. package/src/outbox/outbox.ts +139 -0
  470. package/src/query/column-defaults.ts +42 -4
  471. package/src/query/condition-builder.test.ts +18 -3
  472. package/src/query/condition-builder.ts +7 -0
  473. package/src/query/cursor-client.test.ts +70 -0
  474. package/src/query/cursor-client.ts +263 -0
  475. package/src/query/cursor.test.ts +119 -20
  476. package/src/query/cursor.ts +88 -27
  477. package/src/query/db-now.ts +73 -0
  478. package/src/query/orm/orm.ts +2 -2
  479. package/src/query/query-type.test.ts +4 -3
  480. package/src/query/serialize/create-sql-serializer.ts +10 -5
  481. package/src/query/serialize/dialect/mysql-serializer.ts +13 -5
  482. package/src/query/serialize/dialect/postgres-serializer.ts +35 -5
  483. package/src/query/serialize/dialect/sqlite-serializer.test.ts +90 -3
  484. package/src/query/serialize/dialect/sqlite-serializer.ts +108 -12
  485. package/src/query/serialize/sql-serializer.ts +4 -4
  486. package/src/query/simple-query-interface.ts +15 -4
  487. package/src/query/unit-of-work/execute-unit-of-work.test.ts +372 -10
  488. package/src/query/unit-of-work/execute-unit-of-work.ts +87 -27
  489. package/src/query/unit-of-work/retry-policy.test.ts +1 -0
  490. package/src/query/unit-of-work/tx-builder.test.ts +73 -1
  491. package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +17 -16
  492. package/src/query/unit-of-work/unit-of-work-types.test.ts +42 -12
  493. package/src/query/unit-of-work/unit-of-work.test.ts +196 -39
  494. package/src/query/unit-of-work/unit-of-work.ts +309 -38
  495. package/src/query/value-decoding.test.ts +63 -4
  496. package/src/query/value-decoding.ts +32 -6
  497. package/src/query/value-encoding.test.ts +86 -2
  498. package/src/query/value-encoding.ts +56 -6
  499. package/src/schema/create.test.ts +293 -47
  500. package/src/schema/create.ts +406 -70
  501. package/src/schema/generate-id.test.ts +3 -2
  502. package/src/schema/generate-id.ts +2 -2
  503. package/src/schema/serialize.test.ts +18 -5
  504. package/src/schema/type-conversion/create-sql-type-mapper.ts +8 -3
  505. package/src/schema/type-conversion/dialect/sqlite.ts +18 -0
  506. package/src/schema/type-conversion/type-mapping.test.ts +26 -1
  507. package/src/schema/validator.test.ts +199 -0
  508. package/src/schema/validator.ts +232 -0
  509. package/src/{adapters/drizzle/generate.test.ts → schema-output/drizzle.test.ts} +232 -129
  510. package/src/{adapters/drizzle/generate.ts → schema-output/drizzle.ts} +155 -99
  511. package/src/schema-output/prisma.test.ts +694 -0
  512. package/src/schema-output/prisma.ts +593 -0
  513. package/src/sql-driver/better-sqlite3.test.ts +5 -3
  514. package/src/sql-driver/dialects/durable-object-dialect.ts +3 -8
  515. package/src/sql-driver/query-executor/default-query-executor.ts +1 -1
  516. package/src/sql-driver/query-executor/query-executor-base.ts +1 -1
  517. package/src/sql-driver/query-executor/query-executor.ts +1 -1
  518. package/src/sql-driver/sql-driver-adapter.ts +2 -2
  519. package/src/sql-driver/sql.ts +2 -1
  520. package/src/sql-driver/sqlocal.test.ts +4 -2
  521. package/src/sync/commands.test.ts +39 -0
  522. package/src/sync/commands.ts +51 -0
  523. package/src/sync/conflict-checker.test.ts +450 -0
  524. package/src/sync/conflict-checker.ts +248 -0
  525. package/src/sync/index.ts +14 -0
  526. package/src/sync/plan.ts +9 -0
  527. package/src/sync/read-tracking.test.ts +177 -0
  528. package/src/sync/read-tracking.ts +287 -0
  529. package/src/sync/submit.test.ts +205 -0
  530. package/src/sync/submit.ts +328 -0
  531. package/src/sync/types.ts +80 -0
  532. package/src/util/default-database-adapter.ts +119 -0
  533. package/src/with-database.ts +20 -31
  534. package/tsconfig.json +1 -1
  535. package/tsdown.config.ts +38 -24
  536. package/vitest.config.ts +1 -0
  537. package/dist/adapters/drizzle/drizzle-adapter.d.ts +0 -20
  538. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +0 -1
  539. package/dist/adapters/drizzle/drizzle-adapter.js +0 -27
  540. package/dist/adapters/drizzle/drizzle-adapter.js.map +0 -1
  541. package/dist/adapters/drizzle/generate.d.ts +0 -30
  542. package/dist/adapters/drizzle/generate.d.ts.map +0 -1
  543. package/dist/adapters/drizzle/generate.js.map +0 -1
  544. package/dist/adapters/kysely/kysely-adapter.d.ts +0 -19
  545. package/dist/adapters/kysely/kysely-adapter.d.ts.map +0 -1
  546. package/dist/adapters/kysely/kysely-adapter.js +0 -17
  547. package/dist/adapters/kysely/kysely-adapter.js.map +0 -1
  548. package/dist/adapters/shared/table-name-mapper.d.ts +0 -12
  549. package/dist/adapters/shared/table-name-mapper.d.ts.map +0 -1
  550. package/dist/adapters/shared/table-name-mapper.js +0 -43
  551. package/dist/adapters/shared/table-name-mapper.js.map +0 -1
  552. package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js +0 -165
  553. package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js.map +0 -1
  554. package/dist/packages/fragno/dist/api/bind-services.js +0 -20
  555. package/dist/packages/fragno/dist/api/bind-services.js.map +0 -1
  556. package/dist/packages/fragno/dist/api/error.js +0 -48
  557. package/dist/packages/fragno/dist/api/error.js.map +0 -1
  558. package/dist/packages/fragno/dist/api/fragment-definition-builder.js +0 -320
  559. package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +0 -1
  560. package/dist/packages/fragno/dist/api/fragment-instantiator.js +0 -525
  561. package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +0 -1
  562. package/dist/packages/fragno/dist/api/fragno-response.js +0 -73
  563. package/dist/packages/fragno/dist/api/fragno-response.js.map +0 -1
  564. package/dist/packages/fragno/dist/api/internal/response-stream.js +0 -81
  565. package/dist/packages/fragno/dist/api/internal/response-stream.js.map +0 -1
  566. package/dist/packages/fragno/dist/api/internal/route.js +0 -10
  567. package/dist/packages/fragno/dist/api/internal/route.js.map +0 -1
  568. package/dist/packages/fragno/dist/api/mutable-request-state.js +0 -97
  569. package/dist/packages/fragno/dist/api/mutable-request-state.js.map +0 -1
  570. package/dist/packages/fragno/dist/api/request-context-storage.js +0 -43
  571. package/dist/packages/fragno/dist/api/request-context-storage.js.map +0 -1
  572. package/dist/packages/fragno/dist/api/request-input-context.js +0 -118
  573. package/dist/packages/fragno/dist/api/request-input-context.js.map +0 -1
  574. package/dist/packages/fragno/dist/api/request-middleware.js +0 -83
  575. package/dist/packages/fragno/dist/api/request-middleware.js.map +0 -1
  576. package/dist/packages/fragno/dist/api/request-output-context.js +0 -119
  577. package/dist/packages/fragno/dist/api/request-output-context.js.map +0 -1
  578. package/dist/packages/fragno/dist/api/route.js +0 -17
  579. package/dist/packages/fragno/dist/api/route.js.map +0 -1
  580. package/dist/packages/fragno/dist/internal/symbols.js +0 -10
  581. package/dist/packages/fragno/dist/internal/symbols.js.map +0 -1
  582. package/dist/schema-generator/schema-generator.d.ts +0 -15
  583. package/dist/schema-generator/schema-generator.d.ts.map +0 -1
  584. package/src/adapters/drizzle/drizzle-adapter.ts +0 -39
  585. package/src/adapters/kysely/kysely-adapter.ts +0 -27
  586. package/src/adapters/shared/table-name-mapper.ts +0 -50
  587. package/src/schema-generator/schema-generator.ts +0 -12
@@ -0,0 +1,424 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import { KyselyPGlite } from "kysely-pglite";
4
+ import { SQLocalKysely } from "sqlocal/kysely";
5
+ import superjson, { type SuperJSONResult } from "superjson";
6
+
7
+ import { defineFragment, instantiate } from "@fragno-dev/core";
8
+
9
+ import { PGlite } from "@electric-sql/pglite";
10
+
11
+ import { PGLiteDriverConfig, SQLocalDriverConfig } from "../adapters/generic-sql/driver-config";
12
+ import { SqlAdapter } from "../adapters/generic-sql/generic-sql-adapter";
13
+ import { internalSchema, type InternalFragmentInstance } from "../fragments/internal-fragment";
14
+ import { getInternalFragment } from "../internal/adapter-registry";
15
+ import type { AnyFragnoInstantiatedDatabaseFragment, DatabaseRequestContext } from "../mod";
16
+ import type { AnySchema } from "../schema/create";
17
+ import { schema, idColumn, column, referenceColumn, FragnoReference } from "../schema/create";
18
+ import { withDatabase } from "../with-database";
19
+ import type { OutboxEntry, OutboxPayload } from "./outbox";
20
+
21
+ const outboxSchema = schema("outbox", (s) => {
22
+ return s
23
+ .addTable("users", (t) => {
24
+ return t
25
+ .addColumn("id", idColumn())
26
+ .addColumn("email", column("string"))
27
+ .createIndex("idx_users_email", ["email"], { unique: true });
28
+ })
29
+ .addTable("posts", (t) => {
30
+ return t
31
+ .addColumn("id", idColumn())
32
+ .addColumn("authorId", referenceColumn())
33
+ .addColumn("title", column("string"));
34
+ })
35
+ .addReference("author", {
36
+ type: "one",
37
+ from: { table: "posts", column: "authorId" },
38
+ to: { table: "users", column: "id" },
39
+ });
40
+ });
41
+
42
+ const alphaSchema = schema("alpha", (s) =>
43
+ s.addTable("alpha_items", (t) =>
44
+ t.addColumn("id", idColumn()).addColumn("name", column("string")),
45
+ ),
46
+ );
47
+
48
+ const betaSchema = schema("beta", (s) =>
49
+ s.addTable("beta_items", (t) =>
50
+ t.addColumn("id", idColumn()).addColumn("title", column("string")),
51
+ ),
52
+ );
53
+
54
+ const outboxFragmentName = "outbox-test";
55
+ const outboxFragmentDef = defineFragment(outboxFragmentName)
56
+ .extend(withDatabase(outboxSchema))
57
+ .build();
58
+
59
+ type OutboxAdapterConfig =
60
+ | { type: "kysely-sqlite"; outboxEnabled?: boolean }
61
+ | { type: "kysely-pglite"; outboxEnabled?: boolean };
62
+
63
+ type OutboxTestContext = {
64
+ fragment: AnyFragnoInstantiatedDatabaseFragment<typeof outboxSchema>;
65
+ internalFragment: InternalFragmentInstance;
66
+ cleanup: () => Promise<void>;
67
+ };
68
+
69
+ async function migrateSchema(
70
+ adapter: SqlAdapter,
71
+ schemaToMigrate: AnySchema,
72
+ namespace: string,
73
+ ): Promise<void> {
74
+ const migrations = adapter.prepareMigrations(schemaToMigrate, namespace);
75
+ await migrations.executeWithDriver(adapter.driver, 0);
76
+ }
77
+
78
+ async function createAdapter(config: OutboxAdapterConfig): Promise<{
79
+ adapter: SqlAdapter;
80
+ cleanup: () => Promise<void>;
81
+ }> {
82
+ if (config.type === "kysely-sqlite") {
83
+ const { dialect } = new SQLocalKysely(":memory:");
84
+ const adapter = new SqlAdapter({
85
+ dialect,
86
+ driverConfig: new SQLocalDriverConfig(),
87
+ });
88
+
89
+ await migrateSchema(adapter, internalSchema, "");
90
+ await migrateSchema(adapter, outboxSchema, outboxSchema.name);
91
+
92
+ return {
93
+ adapter,
94
+ cleanup: async () => {
95
+ await adapter.close();
96
+ },
97
+ };
98
+ }
99
+
100
+ const pgliteDatabase = new PGlite();
101
+ const { dialect } = new KyselyPGlite(pgliteDatabase);
102
+ const adapter = new SqlAdapter({
103
+ dialect,
104
+ driverConfig: new PGLiteDriverConfig(),
105
+ });
106
+
107
+ await migrateSchema(adapter, internalSchema, "");
108
+ await migrateSchema(adapter, outboxSchema, outboxSchema.name);
109
+
110
+ return {
111
+ adapter,
112
+ cleanup: async () => {
113
+ await adapter.close();
114
+ },
115
+ };
116
+ }
117
+
118
+ async function buildOutboxTest(adapterConfig: OutboxAdapterConfig): Promise<OutboxTestContext> {
119
+ const { adapter, cleanup } = await createAdapter(adapterConfig);
120
+ const fragment = instantiate(outboxFragmentDef)
121
+ .withConfig({})
122
+ .withRoutes([])
123
+ .withOptions({
124
+ databaseAdapter: adapter,
125
+ outbox: adapterConfig.outboxEnabled ? { enabled: true } : undefined,
126
+ })
127
+ .build();
128
+
129
+ return {
130
+ fragment,
131
+ internalFragment: getInternalFragment(adapter),
132
+ cleanup,
133
+ };
134
+ }
135
+
136
+ async function listOutbox(
137
+ internalFragment: InternalFragmentInstance,
138
+ options?: { afterVersionstamp?: string; limit?: number },
139
+ ): Promise<OutboxEntry[]> {
140
+ return internalFragment.inContext(async function (this: DatabaseRequestContext) {
141
+ return (await this.handlerTx()
142
+ .withServiceCalls(() => [internalFragment.services.outboxService.list(options)] as const)
143
+ .transform(({ serviceResult: [result] }) => result)
144
+ .execute()) as OutboxEntry[];
145
+ });
146
+ }
147
+
148
+ async function listOutboxMutations(internalFragment: InternalFragmentInstance): Promise<
149
+ Array<{
150
+ entryVersionstamp: string;
151
+ mutationVersionstamp: string;
152
+ uowId: string;
153
+ schema: string;
154
+ table: string;
155
+ externalId: string;
156
+ op: string;
157
+ }>
158
+ > {
159
+ return internalFragment.inContext(async function (this: DatabaseRequestContext) {
160
+ return await this.handlerTx()
161
+ .retrieve(({ forSchema }) =>
162
+ forSchema(internalSchema).find("fragno_db_outbox_mutations", (b) =>
163
+ b
164
+ .whereIndex("idx_outbox_mutations_entry")
165
+ .orderByIndex("idx_outbox_mutations_entry", "asc"),
166
+ ),
167
+ )
168
+ .transformRetrieve(([result]) => result)
169
+ .execute();
170
+ });
171
+ }
172
+
173
+ async function createUser(
174
+ fragment: AnyFragnoInstantiatedDatabaseFragment<typeof outboxSchema>,
175
+ email: string,
176
+ ) {
177
+ return fragment.inContext(async function (this: DatabaseRequestContext) {
178
+ await this.handlerTx()
179
+ .mutate(({ forSchema }) => forSchema(outboxSchema).create("users", { email }))
180
+ .execute();
181
+
182
+ const user = await this.handlerTx()
183
+ .retrieve(({ forSchema }) =>
184
+ forSchema(outboxSchema).findFirst("users", (b) =>
185
+ b.whereIndex("idx_users_email", (eb) => eb("email", "=", email)),
186
+ ),
187
+ )
188
+ .transformRetrieve(([result]) => result)
189
+ .execute();
190
+
191
+ if (!user) {
192
+ throw new Error("Expected user to be created.");
193
+ }
194
+
195
+ return user.id;
196
+ });
197
+ }
198
+
199
+ async function createPost(
200
+ fragment: AnyFragnoInstantiatedDatabaseFragment<typeof outboxSchema>,
201
+ title: string,
202
+ authorId: FragnoReference,
203
+ ) {
204
+ return fragment.inContext(async function (this: DatabaseRequestContext) {
205
+ return await this.handlerTx()
206
+ .mutate(({ forSchema }) => forSchema(outboxSchema).create("posts", { title, authorId }))
207
+ .transform(({ mutateResult }) => mutateResult)
208
+ .execute();
209
+ });
210
+ }
211
+
212
+ const adapterConfigs = [{ type: "kysely-sqlite" as const }, { type: "kysely-pglite" as const }];
213
+
214
+ describe("Fragno DB Outbox", () => {
215
+ it("does not write outbox entries when disabled", async () => {
216
+ const { fragment, internalFragment, cleanup } = await buildOutboxTest({
217
+ type: "kysely-sqlite",
218
+ });
219
+
220
+ await createUser(fragment, "disabled@example.com");
221
+
222
+ const entries = await listOutbox(internalFragment);
223
+ expect(entries).toHaveLength(0);
224
+ const mutations = await listOutboxMutations(internalFragment);
225
+ expect(mutations).toHaveLength(0);
226
+
227
+ await cleanup();
228
+ });
229
+
230
+ it("stores refMap placeholders and lists entries in order", async () => {
231
+ const { fragment, internalFragment, cleanup } = await buildOutboxTest({
232
+ type: "kysely-sqlite",
233
+ outboxEnabled: true,
234
+ });
235
+
236
+ const userId = await createUser(fragment, "alpha@example.com");
237
+ expect(userId.internalId).toBeDefined();
238
+
239
+ await createPost(fragment, "Hello", FragnoReference.fromInternal(userId.internalId!));
240
+
241
+ const entries = await listOutbox(internalFragment);
242
+ expect(entries).toHaveLength(2);
243
+ expect(entries[0].versionstamp < entries[1].versionstamp).toBe(true);
244
+
245
+ const filtered = await listOutbox(internalFragment, {
246
+ afterVersionstamp: entries[0].versionstamp,
247
+ limit: 1,
248
+ });
249
+ expect(filtered).toHaveLength(1);
250
+ expect(filtered[0].versionstamp).toBe(entries[1].versionstamp);
251
+
252
+ const payload = superjson.deserialize(entries[1].payload as SuperJSONResult) as OutboxPayload;
253
+ expect(payload.version).toBe(1);
254
+ expect(payload.mutations).toHaveLength(1);
255
+ const [mutation] = payload.mutations;
256
+ if (mutation.op !== "create") {
257
+ throw new Error("Expected create mutation in outbox payload.");
258
+ }
259
+ expect(mutation.values).toMatchObject({
260
+ authorId: { __fragno_ref: "0.authorId" },
261
+ });
262
+ expect(entries[1].refMap).toEqual({
263
+ "0.authorId": userId.externalId,
264
+ });
265
+
266
+ await internalFragment.inContext(async function (this: DatabaseRequestContext) {
267
+ await this.handlerTx()
268
+ .withServiceCalls(() => [
269
+ internalFragment.services.settingsService.set("outbox-test", "noop", "1"),
270
+ ])
271
+ .execute();
272
+ });
273
+
274
+ const afterInternal = await listOutbox(internalFragment);
275
+ expect(afterInternal).toHaveLength(2);
276
+
277
+ await cleanup();
278
+ });
279
+
280
+ it("writes mutation log rows for each outbox entry", async () => {
281
+ const { fragment, internalFragment, cleanup } = await buildOutboxTest({
282
+ type: "kysely-sqlite",
283
+ outboxEnabled: true,
284
+ });
285
+
286
+ const userId = await createUser(fragment, "log-alpha@example.com");
287
+ expect(userId.internalId).toBeDefined();
288
+
289
+ await createPost(fragment, "Log", FragnoReference.fromInternal(userId.internalId!));
290
+
291
+ const entries = await listOutbox(internalFragment);
292
+ const mutations = await listOutboxMutations(internalFragment);
293
+
294
+ expect(entries).toHaveLength(2);
295
+ expect(mutations).toHaveLength(2);
296
+
297
+ const entryByVersion = new Map(entries.map((entry) => [entry.versionstamp, entry]));
298
+
299
+ for (const entry of entries) {
300
+ const payload = superjson.deserialize(entry.payload as SuperJSONResult) as OutboxPayload;
301
+ expect(payload.mutations).toHaveLength(1);
302
+ }
303
+
304
+ for (const mutationRow of mutations) {
305
+ const entry = entryByVersion.get(mutationRow.entryVersionstamp);
306
+ expect(entry).toBeDefined();
307
+ const payload = superjson.deserialize(entry!.payload as SuperJSONResult) as OutboxPayload;
308
+ const mutation = payload.mutations[0];
309
+ expect(mutationRow.mutationVersionstamp).toBe(mutation.versionstamp);
310
+ expect(mutationRow.uowId).toBe(entry!.uowId);
311
+ expect(mutationRow.schema).toBe(mutation.schema);
312
+ expect(mutationRow.table).toBe(mutation.table);
313
+ expect(mutationRow.externalId).toBe(mutation.externalId);
314
+ expect(mutationRow.op).toBe(mutation.op);
315
+ }
316
+
317
+ await cleanup();
318
+ });
319
+
320
+ it("orders outbox entries by commit order across concurrent UOWs", async () => {
321
+ const { fragment, internalFragment, cleanup } = await buildOutboxTest({
322
+ type: "kysely-sqlite",
323
+ outboxEnabled: true,
324
+ });
325
+
326
+ const createUow = fragment.$internal.deps.createUnitOfWork;
327
+ const uow1 = createUow();
328
+ const uow2 = createUow();
329
+ const uow1Id = uow1.idempotencyKey;
330
+ const uow2Id = uow2.idempotencyKey;
331
+
332
+ uow1.forSchema(outboxSchema).create("users", { email: "order-1@example.com" });
333
+ uow2.forSchema(outboxSchema).create("users", { email: "order-2@example.com" });
334
+
335
+ const completionOrder: string[] = [];
336
+ await Promise.all([
337
+ uow1.executeMutations().then(() => completionOrder.push(uow1Id)),
338
+ uow2.executeMutations().then(() => completionOrder.push(uow2Id)),
339
+ ]);
340
+
341
+ const entries = await listOutbox(internalFragment);
342
+ expect(entries.map((entry) => entry.uowId)).toEqual(completionOrder);
343
+ expect(entries[0].versionstamp < entries[1].versionstamp).toBe(true);
344
+
345
+ await cleanup();
346
+ });
347
+
348
+ it("only writes outbox entries for schemas that opt in", async () => {
349
+ const { dialect } = new SQLocalKysely(":memory:");
350
+ const adapter = new SqlAdapter({
351
+ dialect,
352
+ driverConfig: new SQLocalDriverConfig(),
353
+ });
354
+
355
+ try {
356
+ await migrateSchema(adapter, internalSchema, "");
357
+ await migrateSchema(adapter, alphaSchema, alphaSchema.name);
358
+ await migrateSchema(adapter, betaSchema, betaSchema.name);
359
+
360
+ const alphaDef = defineFragment("alpha-fragment").extend(withDatabase(alphaSchema)).build();
361
+ const betaDef = defineFragment("beta-fragment").extend(withDatabase(betaSchema)).build();
362
+
363
+ const alphaFragment = instantiate(alphaDef)
364
+ .withConfig({})
365
+ .withRoutes([])
366
+ .withOptions({ databaseAdapter: adapter, outbox: { enabled: true } })
367
+ .build();
368
+
369
+ const betaFragment = instantiate(betaDef)
370
+ .withConfig({})
371
+ .withRoutes([])
372
+ .withOptions({ databaseAdapter: adapter })
373
+ .build();
374
+
375
+ await alphaFragment.inContext(async function (this: DatabaseRequestContext) {
376
+ await this.handlerTx()
377
+ .mutate(({ forSchema }) =>
378
+ forSchema(alphaSchema).create("alpha_items", { name: "alpha" }),
379
+ )
380
+ .execute();
381
+ });
382
+
383
+ await betaFragment.inContext(async function (this: DatabaseRequestContext) {
384
+ await this.handlerTx()
385
+ .mutate(({ forSchema }) => forSchema(betaSchema).create("beta_items", { title: "beta" }))
386
+ .execute();
387
+ });
388
+
389
+ const entries = await listOutbox(getInternalFragment(adapter));
390
+ const mutationSchemas = entries
391
+ .map((entry) => superjson.deserialize(entry.payload as SuperJSONResult) as OutboxPayload)
392
+ .flatMap((payload) => payload.mutations.map((mutation) => mutation.schema));
393
+
394
+ expect(mutationSchemas).toContain(alphaSchema.name);
395
+ expect(mutationSchemas).not.toContain(betaSchema.name);
396
+ } finally {
397
+ await adapter.close();
398
+ }
399
+ });
400
+
401
+ describe.each(adapterConfigs)("adapter opt-in (%s)", (adapterConfig) => {
402
+ it("writes outbox rows only when enabled", async () => {
403
+ const { fragment, internalFragment, cleanup } = await buildOutboxTest(adapterConfig);
404
+
405
+ await createUser(fragment, "disabled@example.com");
406
+ const disabledEntries = await listOutbox(internalFragment);
407
+ expect(disabledEntries).toHaveLength(0);
408
+ await cleanup();
409
+
410
+ const {
411
+ fragment: enabledFragment,
412
+ internalFragment: enabledInternal,
413
+ cleanup: enabledCleanup,
414
+ } = await buildOutboxTest({
415
+ ...adapterConfig,
416
+ outboxEnabled: true,
417
+ });
418
+ await createUser(enabledFragment, "enabled@example.com");
419
+ const enabledEntries = await listOutbox(enabledInternal);
420
+ expect(enabledEntries).toHaveLength(1);
421
+ await enabledCleanup();
422
+ }, 10_000);
423
+ });
424
+ });
@@ -0,0 +1,139 @@
1
+ import type { MutationOperation } from "../query/unit-of-work/unit-of-work";
2
+ import type { AnySchema, AnyTable, FragnoId } from "../schema/create";
3
+
4
+ export type OutboxConfig = {
5
+ enabled: boolean;
6
+ shouldInclude?: (operation: MutationOperation<AnySchema>) => boolean;
7
+ };
8
+
9
+ export type OutboxVersionstampStrategy =
10
+ | "update-returning"
11
+ | "insert-on-conflict-returning"
12
+ | "insert-on-duplicate-last-insert-id";
13
+
14
+ export type OutboxPayload = {
15
+ version: 1;
16
+ mutations: OutboxMutation[];
17
+ };
18
+
19
+ export type OutboxMutation =
20
+ | {
21
+ op: "create";
22
+ schema: string;
23
+ namespace?: string;
24
+ table: string;
25
+ externalId: string;
26
+ versionstamp: string;
27
+ values: Record<string, unknown>;
28
+ }
29
+ | {
30
+ op: "update";
31
+ schema: string;
32
+ namespace?: string;
33
+ table: string;
34
+ externalId: string;
35
+ versionstamp: string;
36
+ set: Record<string, unknown>;
37
+ checkVersion?: number;
38
+ }
39
+ | {
40
+ op: "delete";
41
+ schema: string;
42
+ namespace?: string;
43
+ table: string;
44
+ externalId: string;
45
+ versionstamp: string;
46
+ checkVersion?: number;
47
+ };
48
+
49
+ export type OutboxRefMap = Record<string, string>;
50
+
51
+ export type OutboxPayloadSerialized = {
52
+ json: unknown;
53
+ meta?: Record<string, unknown>;
54
+ };
55
+
56
+ export type OutboxEntry = {
57
+ id: FragnoId;
58
+ versionstamp: string;
59
+ uowId: string;
60
+ payload: OutboxPayloadSerialized;
61
+ refMap?: OutboxRefMap;
62
+ createdAt: Date;
63
+ };
64
+
65
+ export type OutboxRefLookup = {
66
+ key: string;
67
+ internalId: bigint | number;
68
+ table: AnyTable;
69
+ namespace?: string;
70
+ };
71
+
72
+ export function encodeVersionstamp(transactionVersion: bigint, userVersion: number): Uint8Array {
73
+ if (userVersion < 0 || userVersion > 0xffff) {
74
+ throw new Error(`Invalid outbox user version: ${userVersion}`);
75
+ }
76
+
77
+ const txBytes = bigintToBytes(transactionVersion, 10);
78
+ const userBytes = new Uint8Array(2);
79
+ userBytes[0] = (userVersion >> 8) & 0xff;
80
+ userBytes[1] = userVersion & 0xff;
81
+
82
+ const combined = new Uint8Array(12);
83
+ combined.set(txBytes, 0);
84
+ combined.set(userBytes, 10);
85
+
86
+ return combined;
87
+ }
88
+
89
+ export function versionstampToHex(bytes: Uint8Array): string {
90
+ let hex = "";
91
+ for (const byte of bytes) {
92
+ hex += byte.toString(16).padStart(2, "0");
93
+ }
94
+ return hex;
95
+ }
96
+
97
+ export function hexToVersionstamp(hex: string): Uint8Array {
98
+ if (hex.length % 2 !== 0) {
99
+ throw new Error(`Invalid versionstamp hex length: ${hex.length}`);
100
+ }
101
+
102
+ const bytes = new Uint8Array(hex.length / 2);
103
+ for (let i = 0; i < hex.length; i += 2) {
104
+ bytes[i / 2] = Number.parseInt(hex.slice(i, i + 2), 16);
105
+ }
106
+ return bytes;
107
+ }
108
+
109
+ export function parseOutboxVersionValue(value: unknown): bigint {
110
+ if (typeof value === "bigint") {
111
+ return value;
112
+ }
113
+
114
+ if (typeof value === "number") {
115
+ return BigInt(value);
116
+ }
117
+
118
+ if (typeof value === "string") {
119
+ return BigInt(value);
120
+ }
121
+
122
+ throw new Error(`Invalid outbox version value: ${String(value)}`);
123
+ }
124
+
125
+ function bigintToBytes(value: bigint, length: number): Uint8Array {
126
+ const bytes = new Uint8Array(length);
127
+ let remaining = value;
128
+
129
+ for (let i = length - 1; i >= 0; i -= 1) {
130
+ bytes[i] = Number(remaining & 0xffn);
131
+ remaining >>= 8n;
132
+ }
133
+
134
+ if (remaining !== 0n) {
135
+ throw new Error(`Outbox version ${value} exceeds ${length * 8} bits`);
136
+ }
137
+
138
+ return bytes;
139
+ }
@@ -1,5 +1,10 @@
1
- import type { AnyColumn } from "../schema/create";
2
1
  import { createId } from "../id";
2
+ import type { AnyColumn } from "../schema/create";
3
+
4
+ export type RuntimeDefaultContext = {
5
+ now?: () => Date;
6
+ createId?: () => string;
7
+ };
3
8
 
4
9
  /**
5
10
  * Generate a runtime default value for a column that has defaultTo$()
@@ -12,7 +17,10 @@ import { createId } from "../id";
12
17
  *
13
18
  * @internal
14
19
  */
15
- export function generateRuntimeDefault(column: AnyColumn): unknown {
20
+ export function generateRuntimeDefault(
21
+ column: AnyColumn,
22
+ context: RuntimeDefaultContext = {},
23
+ ): unknown {
16
24
  // Check if column has a default value configuration
17
25
  if (!column.default) {
18
26
  return undefined;
@@ -34,11 +42,11 @@ export function generateRuntimeDefault(column: AnyColumn): unknown {
34
42
  const runtime = column.default.runtime;
35
43
 
36
44
  if (runtime === "cuid") {
37
- return createId();
45
+ return (context.createId ?? createId)();
38
46
  }
39
47
 
40
48
  if (runtime === "now") {
41
- return new Date();
49
+ return (context.now ?? (() => new Date()))();
42
50
  }
43
51
 
44
52
  if (typeof runtime === "function") {
@@ -47,3 +55,33 @@ export function generateRuntimeDefault(column: AnyColumn): unknown {
47
55
 
48
56
  return undefined;
49
57
  }
58
+
59
+ /**
60
+ * Generate a fallback value for database-level defaults.
61
+ *
62
+ * This is used by adapters that cannot rely on database DEFAULT constraints,
63
+ * such as the in-memory adapter.
64
+ *
65
+ * @internal
66
+ */
67
+ export function generateDatabaseDefault(
68
+ column: AnyColumn,
69
+ context: RuntimeDefaultContext = {},
70
+ ): unknown {
71
+ if (!column.default) {
72
+ return undefined;
73
+ }
74
+
75
+ if ("value" in column.default) {
76
+ return column.default.value;
77
+ }
78
+
79
+ if ("dbSpecial" in column.default) {
80
+ if (column.default.dbSpecial === "now") {
81
+ return (context.now ?? (() => new Date()))();
82
+ }
83
+ return undefined;
84
+ }
85
+
86
+ return undefined;
87
+ }
@@ -1,9 +1,10 @@
1
1
  import { describe, expect, it } from "vitest";
2
+
2
3
  import { column, idColumn, schema } from "../schema/create";
3
4
  import { createBuilder, createIndexedBuilder } from "./condition-builder";
4
5
 
5
6
  describe("ConditionBuilder", () => {
6
- const testSchema = schema((s) =>
7
+ const testSchema = schema("test", (s) =>
7
8
  s
8
9
  .addTable("users", (t) =>
9
10
  t
@@ -11,7 +12,7 @@ describe("ConditionBuilder", () => {
11
12
  .addColumn("email", column("string"))
12
13
  .addColumn("name", column("string"))
13
14
  .addColumn("age", column("integer").nullable())
14
- .createIndex("_primary", ["id"], { unique: true })
15
+ .createIndex("idx_users_primary", ["id"], { unique: true })
15
16
  .createIndex("idx_email", ["email"], { unique: true })
16
17
  .createIndex("idx_name_age", ["name", "age"]),
17
18
  )
@@ -21,7 +22,7 @@ describe("ConditionBuilder", () => {
21
22
  .addColumn("title", column("string"))
22
23
  .addColumn("content", column("string"))
23
24
  .addColumn("published", column("bool"))
24
- .createIndex("_primary", ["id"], { unique: true })
25
+ .createIndex("idx_posts_primary", ["id"], { unique: true })
25
26
  .createIndex("idx_published", ["published"]),
26
27
  ),
27
28
  );
@@ -101,6 +102,20 @@ describe("ConditionBuilder", () => {
101
102
  });
102
103
  });
103
104
 
105
+ it("should expose db now helper", () => {
106
+ const builder = createBuilder(usersTable.columns);
107
+
108
+ const now = builder.now();
109
+ expect(now).toMatchObject({ tag: "db-now" });
110
+ expect(typeof now.plus).toBe("function");
111
+ expect(now.plus({ seconds: 1 })).toMatchObject({ tag: "db-now", offsetMs: 1000 });
112
+ expect(now.plus({ seconds: 1 }).plus({ minutes: 1 })).toMatchObject({
113
+ tag: "db-now",
114
+ offsetMs: 61_000,
115
+ });
116
+ expect(builder.interval({ minutes: 1 })).toEqual({ tag: "db-interval", ms: 60_000 });
117
+ });
118
+
104
119
  it("should support boolean columns", () => {
105
120
  const postsTable = testSchema.tables.posts;
106
121
  const builder = createBuilder(postsTable.columns);