@fragno-dev/db 0.3.0 → 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 (516) hide show
  1. package/.turbo/turbo-build.log +327 -160
  2. package/CHANGELOG.md +74 -0
  3. package/README.md +24 -0
  4. package/dist/adapters/adapters.d.ts +1 -1
  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/generic-sql-adapter.d.ts +0 -3
  8. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -1
  9. package/dist/adapters/generic-sql/generic-sql-adapter.js +11 -12
  10. package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -1
  11. package/dist/adapters/generic-sql/generic-sql-uow-executor.js +46 -6
  12. package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -1
  13. package/dist/adapters/generic-sql/migration/cold-kysely.js.map +1 -1
  14. package/dist/adapters/generic-sql/migration/dialect/mysql.js +1 -1
  15. package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -1
  16. package/dist/adapters/generic-sql/migration/dialect/postgres.js +1 -1
  17. package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -1
  18. package/dist/adapters/generic-sql/migration/dialect/sqlite.js +185 -19
  19. package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -1
  20. package/dist/adapters/generic-sql/migration/executor.d.ts.map +1 -1
  21. package/dist/adapters/generic-sql/migration/executor.js +30 -3
  22. package/dist/adapters/generic-sql/migration/executor.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 +3 -3
  25. package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -1
  26. package/dist/adapters/generic-sql/migration/sql-generator.js +1 -1
  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 +1 -1
  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.map +1 -1
  31. package/dist/adapters/generic-sql/query/db-now-sql.js +27 -0
  32. package/dist/adapters/generic-sql/query/db-now-sql.js.map +1 -0
  33. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +9 -6
  34. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -1
  35. package/dist/adapters/generic-sql/query/select-builder.js.map +1 -1
  36. package/dist/adapters/generic-sql/query/sql-query-compiler.js +37 -9
  37. package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -1
  38. package/dist/adapters/generic-sql/query/where-builder.js +24 -20
  39. package/dist/adapters/generic-sql/query/where-builder.js.map +1 -1
  40. package/dist/adapters/generic-sql/uow-decoder.js +1 -1
  41. package/dist/adapters/generic-sql/uow-decoder.js.map +1 -1
  42. package/dist/adapters/generic-sql/uow-encoder.js +8 -9
  43. package/dist/adapters/generic-sql/uow-encoder.js.map +1 -1
  44. package/dist/adapters/in-memory/condition-evaluator.js +10 -6
  45. package/dist/adapters/in-memory/condition-evaluator.js.map +1 -1
  46. package/dist/adapters/in-memory/in-memory-adapter.d.ts.map +1 -1
  47. package/dist/adapters/in-memory/in-memory-adapter.js +45 -25
  48. package/dist/adapters/in-memory/in-memory-adapter.js.map +1 -1
  49. package/dist/adapters/in-memory/in-memory-uow.js +236 -13
  50. package/dist/adapters/in-memory/in-memory-uow.js.map +1 -1
  51. package/dist/adapters/in-memory/options.d.ts +2 -0
  52. package/dist/adapters/in-memory/options.d.ts.map +1 -1
  53. package/dist/adapters/in-memory/options.js +3 -2
  54. package/dist/adapters/in-memory/options.js.map +1 -1
  55. package/dist/adapters/in-memory/reference-resolution.js.map +1 -1
  56. package/dist/adapters/in-memory/store.js +1 -1
  57. package/dist/adapters/in-memory/store.js.map +1 -1
  58. package/dist/adapters/shared/from-unit-of-work-compiler.js +51 -24
  59. package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -1
  60. package/dist/adapters/shared/uow-operation-compiler.js.map +1 -1
  61. package/dist/browser/adapters/adapters.d.ts +61 -0
  62. package/dist/browser/adapters/adapters.d.ts.map +1 -0
  63. package/dist/browser/adapters/generic-sql/migration/executor.d.ts +15 -0
  64. package/dist/browser/adapters/generic-sql/migration/executor.d.ts.map +1 -0
  65. package/dist/browser/adapters/generic-sql/migration/prepared-migrations.d.ts +66 -0
  66. package/dist/browser/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -0
  67. package/dist/browser/adapters/generic-sql/sqlite-storage.d.ts +11 -0
  68. package/dist/browser/adapters/generic-sql/sqlite-storage.d.ts.map +1 -0
  69. package/dist/browser/adapters/in-memory/in-memory-adapter.d.ts +5 -0
  70. package/dist/browser/adapters/in-memory/index.d.ts +2 -0
  71. package/dist/browser/adapters/in-memory/options.d.ts +1 -0
  72. package/dist/browser/db-fragment-definition-builder.d.ts +237 -0
  73. package/dist/browser/db-fragment-definition-builder.d.ts.map +1 -0
  74. package/dist/browser/durable-hooks.d.ts +3 -0
  75. package/dist/browser/fragments/internal-fragment.d.ts +317 -0
  76. package/dist/browser/fragments/internal-fragment.d.ts.map +1 -0
  77. package/dist/browser/fragments/internal-fragment.schema.d.ts +1 -0
  78. package/dist/browser/hooks/durable-hooks-logger.d.ts +10 -0
  79. package/dist/browser/hooks/durable-hooks-logger.d.ts.map +1 -0
  80. package/dist/browser/hooks/hooks.d.ts +146 -0
  81. package/dist/browser/hooks/hooks.d.ts.map +1 -0
  82. package/dist/browser/id.js +1 -0
  83. package/dist/browser/internal/adapter-registry.d.ts +4 -0
  84. package/dist/browser/internal/outbox-state.d.ts +2 -0
  85. package/dist/browser/mod.d.ts +15 -0
  86. package/dist/browser/mod.d.ts.map +1 -0
  87. package/dist/browser/mod.js +17 -0
  88. package/dist/browser/mod.js.map +1 -0
  89. package/dist/browser/mod2.d.ts +48 -0
  90. package/dist/browser/mod2.d.ts.map +1 -0
  91. package/dist/browser/naming/sql-naming.d.ts +19 -0
  92. package/dist/browser/naming/sql-naming.d.ts.map +1 -0
  93. package/dist/browser/outbox/outbox.d.ts +21 -0
  94. package/dist/browser/outbox/outbox.d.ts.map +1 -0
  95. package/dist/browser/query/column-defaults.js +1 -0
  96. package/dist/browser/query/condition-builder.d.ts +44 -0
  97. package/dist/browser/query/condition-builder.d.ts.map +1 -0
  98. package/dist/browser/query/condition-builder.js +97 -0
  99. package/dist/browser/query/condition-builder.js.map +1 -0
  100. package/dist/browser/query/cursor.d.ts +105 -0
  101. package/dist/browser/query/cursor.d.ts.map +1 -0
  102. package/dist/browser/query/cursor.js +150 -0
  103. package/dist/browser/query/cursor.js.map +1 -0
  104. package/dist/browser/query/db-now.d.ts +22 -0
  105. package/dist/browser/query/db-now.d.ts.map +1 -0
  106. package/dist/browser/query/db-now.js +33 -0
  107. package/dist/browser/query/db-now.js.map +1 -0
  108. package/dist/browser/query/orm/orm.d.ts +18 -0
  109. package/dist/browser/query/orm/orm.d.ts.map +1 -0
  110. package/dist/browser/query/simple-query-interface.d.ts +108 -0
  111. package/dist/browser/query/simple-query-interface.d.ts.map +1 -0
  112. package/dist/browser/query/unit-of-work/execute-unit-of-work.d.ts +423 -0
  113. package/dist/browser/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -0
  114. package/dist/browser/query/unit-of-work/execute-unit-of-work.js +507 -0
  115. package/dist/browser/query/unit-of-work/execute-unit-of-work.js.map +1 -0
  116. package/dist/browser/query/unit-of-work/retry-policy.d.ts +23 -0
  117. package/dist/browser/query/unit-of-work/retry-policy.d.ts.map +1 -0
  118. package/dist/browser/query/unit-of-work/retry-policy.js +40 -0
  119. package/dist/browser/query/unit-of-work/retry-policy.js.map +1 -0
  120. package/dist/browser/query/unit-of-work/unit-of-work.d.ts +703 -0
  121. package/dist/browser/query/unit-of-work/unit-of-work.d.ts.map +1 -0
  122. package/dist/browser/query/unit-of-work/unit-of-work.js +1206 -0
  123. package/dist/browser/query/unit-of-work/unit-of-work.js.map +1 -0
  124. package/dist/browser/query/value-encoding.js +38 -0
  125. package/dist/browser/query/value-encoding.js.map +1 -0
  126. package/dist/browser/schema/create.d.ts +326 -0
  127. package/dist/browser/schema/create.d.ts.map +1 -0
  128. package/dist/browser/schema/create.js +89 -0
  129. package/dist/browser/schema/create.js.map +1 -0
  130. package/dist/browser/schema/generate-id.js +28 -0
  131. package/dist/browser/schema/generate-id.js.map +1 -0
  132. package/dist/browser/shared/providers.d.ts +6 -0
  133. package/dist/browser/shared/providers.d.ts.map +1 -0
  134. package/dist/browser/sql-driver/connection/connection-provider.d.ts +13 -0
  135. package/dist/browser/sql-driver/connection/connection-provider.d.ts.map +1 -0
  136. package/dist/browser/sql-driver/dialect-adapter/dialect-adapter.d.ts +7 -0
  137. package/dist/browser/sql-driver/dialect-adapter/dialect-adapter.d.ts.map +1 -0
  138. package/dist/browser/sql-driver/driver/runtime-driver.d.ts +23 -0
  139. package/dist/browser/sql-driver/driver/runtime-driver.d.ts.map +1 -0
  140. package/dist/browser/sql-driver/query-executor/plugin.d.ts +17 -0
  141. package/dist/browser/sql-driver/query-executor/plugin.d.ts.map +1 -0
  142. package/dist/browser/sql-driver/query-executor/query-executor.d.ts +36 -0
  143. package/dist/browser/sql-driver/query-executor/query-executor.d.ts.map +1 -0
  144. package/dist/browser/sql-driver/sql-driver-adapter.d.ts +29 -0
  145. package/dist/browser/sql-driver/sql-driver-adapter.d.ts.map +1 -0
  146. package/dist/browser/sql-driver/sql-driver.d.ts +38 -0
  147. package/dist/browser/sql-driver/sql-driver.d.ts.map +1 -0
  148. package/dist/browser/sync/commands.d.ts +15 -0
  149. package/dist/browser/sync/commands.d.ts.map +1 -0
  150. package/dist/browser/sync/commands.js +27 -0
  151. package/dist/browser/sync/commands.js.map +1 -0
  152. package/dist/browser/sync/types.d.ts +63 -0
  153. package/dist/browser/sync/types.d.ts.map +1 -0
  154. package/dist/browser/util/types.d.ts +8 -0
  155. package/dist/browser/util/types.d.ts.map +1 -0
  156. package/dist/browser/with-database.d.ts +29 -0
  157. package/dist/browser/with-database.d.ts.map +1 -0
  158. package/dist/client.d.ts +4 -0
  159. package/dist/client.js +5 -0
  160. package/dist/db-fragment-definition-builder.d.ts +85 -28
  161. package/dist/db-fragment-definition-builder.d.ts.map +1 -1
  162. package/dist/db-fragment-definition-builder.js +374 -46
  163. package/dist/db-fragment-definition-builder.js.map +1 -1
  164. package/dist/dispatchers/cloudflare-do/dispatcher.d.ts +20 -0
  165. package/dist/dispatchers/cloudflare-do/dispatcher.d.ts.map +1 -0
  166. package/dist/dispatchers/cloudflare-do/dispatcher.js +147 -0
  167. package/dist/dispatchers/cloudflare-do/dispatcher.js.map +1 -0
  168. package/dist/dispatchers/cloudflare-do/index.d.ts +5 -20
  169. package/dist/dispatchers/cloudflare-do/index.d.ts.map +1 -1
  170. package/dist/dispatchers/cloudflare-do/index.js +23 -55
  171. package/dist/dispatchers/cloudflare-do/index.js.map +1 -1
  172. package/dist/dispatchers/node/dispatcher.d.ts +14 -0
  173. package/dist/dispatchers/node/dispatcher.d.ts.map +1 -0
  174. package/dist/dispatchers/node/dispatcher.js +80 -0
  175. package/dist/dispatchers/node/dispatcher.js.map +1 -0
  176. package/dist/dispatchers/node/index.d.ts +5 -10
  177. package/dist/dispatchers/node/index.d.ts.map +1 -1
  178. package/dist/dispatchers/node/index.js +21 -53
  179. package/dist/dispatchers/node/index.js.map +1 -1
  180. package/dist/durable-hooks.d.ts +31 -0
  181. package/dist/durable-hooks.d.ts.map +1 -0
  182. package/dist/durable-hooks.js +23 -0
  183. package/dist/durable-hooks.js.map +1 -0
  184. package/dist/fragments/internal-fragment.d.ts +128 -27
  185. package/dist/fragments/internal-fragment.d.ts.map +1 -1
  186. package/dist/fragments/internal-fragment.js +125 -78
  187. package/dist/fragments/internal-fragment.js.map +1 -1
  188. package/dist/fragments/internal-fragment.routes.js +138 -3
  189. package/dist/fragments/internal-fragment.routes.js.map +1 -1
  190. package/dist/fragments/internal-fragment.schema.d.ts +7 -1
  191. package/dist/fragments/internal-fragment.schema.d.ts.map +1 -1
  192. package/dist/fragments/internal-fragment.schema.js +18 -1
  193. package/dist/fragments/internal-fragment.schema.js.map +1 -1
  194. package/dist/hooks/durable-hooks-logger.d.ts +10 -0
  195. package/dist/hooks/durable-hooks-logger.d.ts.map +1 -0
  196. package/dist/hooks/durable-hooks-logger.js +75 -0
  197. package/dist/hooks/durable-hooks-logger.js.map +1 -0
  198. package/dist/hooks/durable-hooks-processor.d.ts +1 -14
  199. package/dist/hooks/durable-hooks-processor.js +58 -10
  200. package/dist/hooks/durable-hooks-processor.js.map +1 -1
  201. package/dist/hooks/durable-hooks-runtime.js +44 -0
  202. package/dist/hooks/durable-hooks-runtime.js.map +1 -0
  203. package/dist/hooks/hooks.d.ts +60 -2
  204. package/dist/hooks/hooks.d.ts.map +1 -1
  205. package/dist/hooks/hooks.js +214 -53
  206. package/dist/hooks/hooks.js.map +1 -1
  207. package/dist/id.d.ts +2 -2
  208. package/dist/id.js +2 -2
  209. package/dist/internal/adapter-registry.d.ts +11 -0
  210. package/dist/internal/adapter-registry.d.ts.map +1 -0
  211. package/dist/internal/adapter-registry.js +135 -0
  212. package/dist/internal/adapter-registry.js.map +1 -0
  213. package/dist/internal/outbox-state.d.ts +2 -0
  214. package/dist/internal/outbox-state.js +26 -0
  215. package/dist/internal/outbox-state.js.map +1 -0
  216. package/dist/migration-engine/auto-from-schema.d.ts +33 -0
  217. package/dist/migration-engine/auto-from-schema.d.ts.map +1 -0
  218. package/dist/migration-engine/auto-from-schema.js +210 -27
  219. package/dist/migration-engine/auto-from-schema.js.map +1 -1
  220. package/dist/migration-engine/generation-engine.d.ts.map +1 -1
  221. package/dist/migration-engine/generation-engine.js +17 -5
  222. package/dist/migration-engine/generation-engine.js.map +1 -1
  223. package/dist/migration-engine/shared.d.ts +113 -0
  224. package/dist/migration-engine/shared.d.ts.map +1 -0
  225. package/dist/migration-engine/shared.js.map +1 -1
  226. package/dist/mod.d.ts +12 -11
  227. package/dist/mod.d.ts.map +1 -1
  228. package/dist/mod.js +10 -10
  229. package/dist/mod.js.map +1 -1
  230. package/dist/naming/sql-naming.d.ts.map +1 -1
  231. package/dist/naming/sql-naming.js.map +1 -1
  232. package/dist/outbox/outbox-builder.js.map +1 -1
  233. package/dist/outbox/outbox.d.ts +3 -1
  234. package/dist/outbox/outbox.d.ts.map +1 -1
  235. package/dist/outbox/outbox.js.map +1 -1
  236. package/dist/query/column-defaults.js.map +1 -1
  237. package/dist/query/condition-builder.d.ts +7 -1
  238. package/dist/query/condition-builder.d.ts.map +1 -1
  239. package/dist/query/condition-builder.js +5 -1
  240. package/dist/query/condition-builder.js.map +1 -1
  241. package/dist/query/cursor-client.d.ts +105 -0
  242. package/dist/query/cursor-client.d.ts.map +1 -0
  243. package/dist/query/cursor-client.js +165 -0
  244. package/dist/query/cursor-client.js.map +1 -0
  245. package/dist/query/cursor.d.ts.map +1 -1
  246. package/dist/query/cursor.js +7 -1
  247. package/dist/query/cursor.js.map +1 -1
  248. package/dist/query/db-now.d.ts +15 -1
  249. package/dist/query/db-now.d.ts.map +1 -1
  250. package/dist/query/db-now.js +30 -2
  251. package/dist/query/db-now.js.map +1 -1
  252. package/dist/query/orm/orm.js.map +1 -1
  253. package/dist/query/serialize/create-sql-serializer.js +2 -2
  254. package/dist/query/serialize/create-sql-serializer.js.map +1 -1
  255. package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -1
  256. package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -1
  257. package/dist/query/serialize/dialect/sqlite-serializer.js +6 -2
  258. package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -1
  259. package/dist/query/simple-query-interface.d.ts +7 -3
  260. package/dist/query/simple-query-interface.d.ts.map +1 -1
  261. package/dist/query/unit-of-work/execute-unit-of-work.d.ts +37 -2
  262. package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -1
  263. package/dist/query/unit-of-work/execute-unit-of-work.js +39 -18
  264. package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -1
  265. package/dist/query/unit-of-work/unit-of-work.d.ts +42 -16
  266. package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
  267. package/dist/query/unit-of-work/unit-of-work.js +50 -6
  268. package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
  269. package/dist/query/value-decoding.js +8 -1
  270. package/dist/query/value-decoding.js.map +1 -1
  271. package/dist/query/value-encoding.js.map +1 -1
  272. package/dist/schema/create.d.ts +69 -25
  273. package/dist/schema/create.d.ts.map +1 -1
  274. package/dist/schema/create.js +91 -16
  275. package/dist/schema/create.js.map +1 -1
  276. package/dist/schema/type-conversion/create-sql-type-mapper.js +1 -1
  277. package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -1
  278. package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -1
  279. package/dist/schema/validator.d.ts.map +1 -1
  280. package/dist/schema/validator.js.map +1 -1
  281. package/dist/schema-output/drizzle.d.ts.map +1 -1
  282. package/dist/schema-output/drizzle.js +8 -6
  283. package/dist/schema-output/drizzle.js.map +1 -1
  284. package/dist/schema-output/prisma.d.ts.map +1 -1
  285. package/dist/schema-output/prisma.js +21 -10
  286. package/dist/schema-output/prisma.js.map +1 -1
  287. package/dist/sql-driver/dialects/durable-object-dialect.js +3 -9
  288. package/dist/sql-driver/dialects/durable-object-dialect.js.map +1 -1
  289. package/dist/sql-driver/query-executor/default-query-executor.js.map +1 -1
  290. package/dist/sql-driver/query-executor/query-executor-base.js.map +1 -1
  291. package/dist/sql-driver/sql-driver-adapter.js.map +1 -1
  292. package/dist/sql-driver/sql.js.map +1 -1
  293. package/dist/sync/commands.d.ts +15 -0
  294. package/dist/sync/commands.d.ts.map +1 -0
  295. package/dist/sync/commands.js +27 -0
  296. package/dist/sync/commands.js.map +1 -0
  297. package/dist/sync/index.d.ts +4 -0
  298. package/dist/sync/index.js +4 -0
  299. package/dist/sync/read-tracking.d.ts +25 -0
  300. package/dist/sync/read-tracking.d.ts.map +1 -0
  301. package/dist/sync/read-tracking.js +148 -0
  302. package/dist/sync/read-tracking.js.map +1 -0
  303. package/dist/sync/submit.js +213 -0
  304. package/dist/sync/submit.js.map +1 -0
  305. package/dist/sync/types.d.ts +63 -0
  306. package/dist/sync/types.d.ts.map +1 -0
  307. package/dist/util/default-database-adapter.js +6 -1
  308. package/dist/util/default-database-adapter.js.map +1 -1
  309. package/dist/with-database.d.ts +3 -6
  310. package/dist/with-database.d.ts.map +1 -1
  311. package/dist/with-database.js +7 -15
  312. package/dist/with-database.js.map +1 -1
  313. package/package.json +33 -41
  314. package/src/adapters/adapters.ts +5 -4
  315. package/src/adapters/drizzle/migrate-drizzle.test.ts +46 -9
  316. package/src/adapters/drizzle/migration-parity-drizzle-kit.test.ts +5 -3
  317. package/src/adapters/drizzle/test-utils.ts +2 -1
  318. package/src/adapters/generic-sql/generic-sql-adapter.test.ts +5 -3
  319. package/src/adapters/generic-sql/generic-sql-adapter.ts +21 -24
  320. package/src/adapters/generic-sql/generic-sql-uow-executor.test.ts +1 -0
  321. package/src/adapters/generic-sql/generic-sql-uow-executor.ts +81 -15
  322. package/src/adapters/generic-sql/migration/adapter-migration-parity.test.ts +4 -2
  323. package/src/adapters/generic-sql/migration/cold-kysely.ts +1 -0
  324. package/src/adapters/generic-sql/migration/dialect/mysql.test.ts +3 -2
  325. package/src/adapters/generic-sql/migration/dialect/mysql.ts +1 -0
  326. package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +5 -4
  327. package/src/adapters/generic-sql/migration/dialect/postgres.ts +2 -1
  328. package/src/adapters/generic-sql/migration/dialect/sqlite.test.ts +795 -3
  329. package/src/adapters/generic-sql/migration/dialect/sqlite.ts +385 -57
  330. package/src/adapters/generic-sql/migration/executor.test.ts +52 -0
  331. package/src/adapters/generic-sql/migration/executor.ts +47 -4
  332. package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +117 -14
  333. package/src/adapters/generic-sql/migration/prepared-migrations.ts +9 -8
  334. package/src/adapters/generic-sql/migration/sql-generator.ts +5 -3
  335. package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +3 -3
  336. package/src/adapters/generic-sql/query/cursor-utils.test.ts +3 -2
  337. package/src/adapters/generic-sql/query/cursor-utils.ts +1 -1
  338. package/src/adapters/generic-sql/query/db-now-sql.ts +49 -0
  339. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +144 -8
  340. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +16 -17
  341. package/src/adapters/generic-sql/query/select-builder.test.ts +1 -0
  342. package/src/adapters/generic-sql/query/select-builder.ts +2 -2
  343. package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +24 -5
  344. package/src/adapters/generic-sql/query/sql-query-compiler.ts +83 -13
  345. package/src/adapters/generic-sql/query/where-builder.test.ts +7 -5
  346. package/src/adapters/generic-sql/query/where-builder.ts +48 -29
  347. package/src/adapters/generic-sql/sql-adapter-pglite-migrations.test.ts +6 -15
  348. package/src/adapters/generic-sql/sql-adapter-pglite-pagination.test.ts +52 -7
  349. package/src/adapters/generic-sql/sql-adapter-pglite-queries.test.ts +9 -6
  350. package/src/adapters/generic-sql/sql-adapter-sqlite3-driver.test.ts +273 -5
  351. package/src/adapters/generic-sql/sql-adapter-sqlite3-uow.test.ts +123 -6
  352. package/src/adapters/generic-sql/sql-adapter-sqlocal.test.ts +4 -2
  353. package/src/adapters/generic-sql/uow-decoder.test.ts +4 -3
  354. package/src/adapters/generic-sql/uow-decoder.ts +3 -3
  355. package/src/adapters/generic-sql/uow-encoder.test.ts +4 -2
  356. package/src/adapters/generic-sql/uow-encoder.ts +14 -18
  357. package/src/adapters/in-memory/condition-evaluator.test.ts +2 -1
  358. package/src/adapters/in-memory/condition-evaluator.ts +9 -4
  359. package/src/adapters/in-memory/in-memory-adapter.ts +155 -44
  360. package/src/adapters/in-memory/in-memory-uow.mutations.test.ts +50 -2
  361. package/src/adapters/in-memory/in-memory-uow.retrieval.test.ts +158 -3
  362. package/src/adapters/in-memory/in-memory-uow.ts +402 -26
  363. package/src/adapters/in-memory/options.test.ts +1 -0
  364. package/src/adapters/in-memory/options.ts +5 -1
  365. package/src/adapters/in-memory/outbox.test.ts +361 -0
  366. package/src/adapters/in-memory/reference-resolution.test.ts +3 -2
  367. package/src/adapters/in-memory/reference-resolution.ts +2 -2
  368. package/src/adapters/in-memory/sorted-array-index.test.ts +1 -0
  369. package/src/adapters/in-memory/store.test.ts +1 -0
  370. package/src/adapters/in-memory/store.ts +3 -3
  371. package/src/adapters/in-memory/value-normalization.test.ts +1 -0
  372. package/src/adapters/prisma/prisma-adapter-sqlite3.test.ts +51 -7
  373. package/src/adapters/shared/from-unit-of-work-compiler.ts +156 -46
  374. package/src/adapters/shared/uow-operation-compiler.ts +3 -3
  375. package/src/browser/mod.ts +64 -0
  376. package/src/client.ts +19 -0
  377. package/src/db-fragment-definition-builder.test.ts +821 -47
  378. package/src/db-fragment-definition-builder.ts +857 -110
  379. package/src/db-fragment-instantiator.test.ts +114 -90
  380. package/src/db-fragment-integration.test.ts +9 -6
  381. package/src/dispatchers/cloudflare-do/dispatcher.ts +204 -0
  382. package/src/dispatchers/cloudflare-do/index.test.ts +145 -12
  383. package/src/dispatchers/cloudflare-do/index.ts +49 -90
  384. package/src/dispatchers/node/dispatcher.ts +112 -0
  385. package/src/dispatchers/node/index.test.ts +43 -14
  386. package/src/dispatchers/node/index.ts +38 -75
  387. package/src/durable-hooks.test.ts +80 -0
  388. package/src/durable-hooks.ts +67 -0
  389. package/src/fragments/internal-fragment.routes.test.ts +570 -0
  390. package/src/fragments/internal-fragment.routes.ts +297 -5
  391. package/src/fragments/internal-fragment.schema.ts +45 -1
  392. package/src/fragments/internal-fragment.test.ts +223 -251
  393. package/src/fragments/internal-fragment.ts +278 -154
  394. package/src/hooks/durable-hooks-logger.ts +126 -0
  395. package/src/hooks/durable-hooks-processor.pglite.test.ts +87 -0
  396. package/src/hooks/durable-hooks-processor.test.ts +179 -14
  397. package/src/hooks/durable-hooks-processor.ts +120 -14
  398. package/src/hooks/durable-hooks-runtime.test.ts +65 -0
  399. package/src/hooks/durable-hooks-runtime.ts +81 -0
  400. package/src/hooks/hooks.test.ts +314 -53
  401. package/src/hooks/hooks.ts +360 -81
  402. package/src/id.test.ts +34 -0
  403. package/src/id.ts +1 -3
  404. package/src/internal/adapter-registry.test.ts +93 -0
  405. package/src/internal/adapter-registry.ts +239 -0
  406. package/src/internal/outbox-state.ts +43 -0
  407. package/src/migration-engine/auto-from-schema.test.ts +93 -0
  408. package/src/migration-engine/auto-from-schema.ts +360 -42
  409. package/src/migration-engine/create.test.ts +2 -1
  410. package/src/migration-engine/create.ts +1 -1
  411. package/src/migration-engine/generation-engine.test.ts +66 -9
  412. package/src/migration-engine/generation-engine.ts +31 -10
  413. package/src/migration-engine/shared.ts +13 -0
  414. package/src/mod.ts +45 -27
  415. package/src/naming/sql-naming.ts +1 -0
  416. package/src/outbox/outbox-builder.ts +2 -2
  417. package/src/outbox/outbox.test.ts +216 -45
  418. package/src/outbox/outbox.ts +3 -1
  419. package/src/query/column-defaults.ts +1 -1
  420. package/src/query/condition-builder.test.ts +15 -0
  421. package/src/query/condition-builder.ts +7 -0
  422. package/src/query/cursor-client.test.ts +70 -0
  423. package/src/query/cursor-client.ts +263 -0
  424. package/src/query/cursor.test.ts +3 -2
  425. package/src/query/cursor.ts +15 -3
  426. package/src/query/db-now.ts +69 -2
  427. package/src/query/orm/orm.ts +2 -2
  428. package/src/query/query-type.test.ts +2 -1
  429. package/src/query/serialize/create-sql-serializer.ts +3 -3
  430. package/src/query/serialize/dialect/mysql-serializer.ts +1 -1
  431. package/src/query/serialize/dialect/postgres-serializer.ts +1 -1
  432. package/src/query/serialize/dialect/sqlite-serializer.test.ts +39 -2
  433. package/src/query/serialize/dialect/sqlite-serializer.ts +18 -5
  434. package/src/query/simple-query-interface.ts +10 -4
  435. package/src/query/unit-of-work/execute-unit-of-work.test.ts +347 -9
  436. package/src/query/unit-of-work/execute-unit-of-work.ts +63 -20
  437. package/src/query/unit-of-work/retry-policy.test.ts +1 -0
  438. package/src/query/unit-of-work/tx-builder.test.ts +73 -1
  439. package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +5 -4
  440. package/src/query/unit-of-work/unit-of-work-types.test.ts +41 -11
  441. package/src/query/unit-of-work/unit-of-work.test.ts +28 -2
  442. package/src/query/unit-of-work/unit-of-work.ts +105 -19
  443. package/src/query/value-decoding.test.ts +50 -2
  444. package/src/query/value-decoding.ts +17 -4
  445. package/src/query/value-encoding.test.ts +1 -0
  446. package/src/query/value-encoding.ts +1 -1
  447. package/src/schema/create.test.ts +164 -5
  448. package/src/schema/create.ts +222 -24
  449. package/src/schema/generate-id.test.ts +1 -0
  450. package/src/schema/serialize.test.ts +4 -3
  451. package/src/schema/type-conversion/create-sql-type-mapper.ts +1 -1
  452. package/src/schema/type-conversion/dialect/sqlite.ts +2 -2
  453. package/src/schema/type-conversion/type-mapping.test.ts +2 -1
  454. package/src/schema/validator.test.ts +4 -2
  455. package/src/schema/validator.ts +1 -0
  456. package/src/schema-output/drizzle.test.ts +72 -19
  457. package/src/schema-output/drizzle.ts +24 -18
  458. package/src/schema-output/prisma.test.ts +172 -14
  459. package/src/schema-output/prisma.ts +34 -14
  460. package/src/sql-driver/better-sqlite3.test.ts +5 -3
  461. package/src/sql-driver/dialects/durable-object-dialect.ts +3 -8
  462. package/src/sql-driver/query-executor/default-query-executor.ts +1 -1
  463. package/src/sql-driver/query-executor/query-executor-base.ts +1 -1
  464. package/src/sql-driver/query-executor/query-executor.ts +1 -1
  465. package/src/sql-driver/sql-driver-adapter.ts +2 -2
  466. package/src/sql-driver/sql.ts +2 -1
  467. package/src/sql-driver/sqlocal.test.ts +4 -2
  468. package/src/sync/commands.test.ts +39 -0
  469. package/src/sync/commands.ts +51 -0
  470. package/src/sync/conflict-checker.test.ts +450 -0
  471. package/src/sync/conflict-checker.ts +248 -0
  472. package/src/sync/index.ts +14 -0
  473. package/src/sync/plan.ts +9 -0
  474. package/src/sync/read-tracking.test.ts +177 -0
  475. package/src/sync/read-tracking.ts +287 -0
  476. package/src/sync/submit.test.ts +205 -0
  477. package/src/sync/submit.ts +328 -0
  478. package/src/sync/types.ts +80 -0
  479. package/src/util/default-database-adapter.ts +15 -2
  480. package/src/with-database.ts +20 -50
  481. package/tsconfig.json +1 -1
  482. package/tsdown.config.ts +38 -26
  483. package/vitest.config.ts +1 -0
  484. package/dist/hooks/durable-hooks-processor.d.ts.map +0 -1
  485. package/dist/node_modules/.pnpm/rou3@0.7.12/node_modules/rou3/dist/index.js +0 -168
  486. package/dist/node_modules/.pnpm/rou3@0.7.12/node_modules/rou3/dist/index.js.map +0 -1
  487. package/dist/packages/fragno/dist/api/bind-services.js +0 -20
  488. package/dist/packages/fragno/dist/api/bind-services.js.map +0 -1
  489. package/dist/packages/fragno/dist/api/error.js +0 -48
  490. package/dist/packages/fragno/dist/api/error.js.map +0 -1
  491. package/dist/packages/fragno/dist/api/fragment-definition-builder.js +0 -321
  492. package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +0 -1
  493. package/dist/packages/fragno/dist/api/fragment-instantiator.js +0 -669
  494. package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +0 -1
  495. package/dist/packages/fragno/dist/api/fragno-response.js +0 -73
  496. package/dist/packages/fragno/dist/api/fragno-response.js.map +0 -1
  497. package/dist/packages/fragno/dist/api/internal/response-stream.js +0 -81
  498. package/dist/packages/fragno/dist/api/internal/response-stream.js.map +0 -1
  499. package/dist/packages/fragno/dist/api/internal/route.js +0 -10
  500. package/dist/packages/fragno/dist/api/internal/route.js.map +0 -1
  501. package/dist/packages/fragno/dist/api/mutable-request-state.js +0 -97
  502. package/dist/packages/fragno/dist/api/mutable-request-state.js.map +0 -1
  503. package/dist/packages/fragno/dist/api/request-context-storage.js +0 -43
  504. package/dist/packages/fragno/dist/api/request-context-storage.js.map +0 -1
  505. package/dist/packages/fragno/dist/api/request-input-context.js +0 -185
  506. package/dist/packages/fragno/dist/api/request-input-context.js.map +0 -1
  507. package/dist/packages/fragno/dist/api/request-middleware.js +0 -83
  508. package/dist/packages/fragno/dist/api/request-middleware.js.map +0 -1
  509. package/dist/packages/fragno/dist/api/request-output-context.js +0 -119
  510. package/dist/packages/fragno/dist/api/request-output-context.js.map +0 -1
  511. package/dist/packages/fragno/dist/api/route.js +0 -30
  512. package/dist/packages/fragno/dist/api/route.js.map +0 -1
  513. package/dist/packages/fragno/dist/internal/symbols.js +0 -10
  514. package/dist/packages/fragno/dist/internal/symbols.js.map +0 -1
  515. package/dist/packages/fragno/dist/internal/trace-context.js +0 -12
  516. package/dist/packages/fragno/dist/internal/trace-context.js.map +0 -1
@@ -1,4 +1,11 @@
1
1
  import { describe, expect, expectTypeOf, it } from "vitest";
2
+
3
+ import type {
4
+ RawColumnValues,
5
+ TableToColumnValues,
6
+ TableToInsertValues,
7
+ TableToUpdateValues,
8
+ } from "../query/simple-query-interface";
2
9
  import {
3
10
  column,
4
11
  FragnoId,
@@ -8,11 +15,6 @@ import {
8
15
  schema,
9
16
  SchemaBuilder,
10
17
  } from "./create";
11
- import type {
12
- RawColumnValues,
13
- TableToColumnValues,
14
- TableToInsertValues,
15
- } from "../query/simple-query-interface";
16
18
 
17
19
  describe("create", () => {
18
20
  it("should create a table with columns using callback pattern", () => {
@@ -296,6 +298,135 @@ describe("create", () => {
296
298
  expect(addReferenceOps[0].config.to).toEqual({ table: "users", column: "_internalId" });
297
299
  });
298
300
 
301
+ it("should coerce external-id target columns to _internalId in addReference operations", () => {
302
+ const catalogSchema = schema("catalog", (s) => {
303
+ return s
304
+ .addTable("products", (t) => {
305
+ return t.addColumn("productId", idColumn()).addColumn("name", column("string"));
306
+ })
307
+ .addTable("orders", (t) => {
308
+ return t.addColumn("id", idColumn()).addColumn("productRef", referenceColumn());
309
+ })
310
+ .addReference("product", {
311
+ type: "one",
312
+ from: { table: "orders", column: "productRef" },
313
+ to: { table: "products", column: "productId" },
314
+ });
315
+ });
316
+
317
+ const addReferenceOps = catalogSchema.operations.filter((op) => op.type === "add-reference");
318
+ expect(addReferenceOps).toHaveLength(1);
319
+ expect(addReferenceOps[0].config.to).toEqual({ table: "products", column: "_internalId" });
320
+ });
321
+
322
+ it("should support join-only references with foreignKey:false", () => {
323
+ const userSchema = schema("user", (s) => {
324
+ return s
325
+ .addTable("users", (t) => {
326
+ return t
327
+ .addColumn("id", idColumn())
328
+ .addColumn("email", column("string"))
329
+ .createIndex("idx_users_email", ["email"]);
330
+ })
331
+ .addTable("invitations", (t) => {
332
+ return t
333
+ .addColumn("id", idColumn())
334
+ .addColumn("email", column("string"))
335
+ .createIndex("idx_inv_email", ["email"]);
336
+ })
337
+ .addReference("invitedUser", {
338
+ type: "one",
339
+ from: { table: "invitations", column: "email" },
340
+ to: { table: "users", column: "email" },
341
+ foreignKey: false,
342
+ });
343
+ });
344
+
345
+ const invitationsTable = userSchema.tables.invitations;
346
+ const invitedRelation = invitationsTable.relations["invitedUser"];
347
+ expect(invitedRelation).toBeDefined();
348
+ expect(invitedRelation.foreignKey).toBe(false);
349
+ expect(invitedRelation.on).toEqual([["email", "email"]]);
350
+
351
+ const addReferenceOps = userSchema.operations.filter((op) => op.type === "add-reference");
352
+ expect(addReferenceOps).toHaveLength(1);
353
+ expect(addReferenceOps[0].config.to).toEqual({ table: "users", column: "email" });
354
+ expect(addReferenceOps[0].config.foreignKey).toBe(false);
355
+ });
356
+
357
+ it("should coerce id to _internalId for join-only references", () => {
358
+ const userSchema = schema("user", (s) => {
359
+ return s
360
+ .addTable("users", (t) => {
361
+ return t.addColumn("id", idColumn()).addColumn("name", column("string"));
362
+ })
363
+ .addTable("sessions", (t) => {
364
+ return t
365
+ .addColumn("id", idColumn())
366
+ .addColumn("userId", referenceColumn())
367
+ .createIndex("idx_sessions_user", ["userId"]);
368
+ })
369
+ .addReference("sessionUser", {
370
+ type: "one",
371
+ from: { table: "sessions", column: "userId" },
372
+ to: { table: "users", column: "id" },
373
+ foreignKey: false,
374
+ });
375
+ });
376
+
377
+ const addReferenceOps = userSchema.operations.filter((op) => op.type === "add-reference");
378
+ expect(addReferenceOps).toHaveLength(1);
379
+ expect(addReferenceOps[0].config.to).toEqual({ table: "users", column: "_internalId" });
380
+ });
381
+
382
+ it("should coerce left-side id to _internalId for join-only references", () => {
383
+ const userSchema = schema("user", (s) => {
384
+ return s
385
+ .addTable("users", (t) => {
386
+ return t.addColumn("id", idColumn()).addColumn("name", column("string"));
387
+ })
388
+ .addTable("memberships", (t) => {
389
+ return t
390
+ .addColumn("id", idColumn())
391
+ .addColumn("userId", referenceColumn())
392
+ .createIndex("idx_memberships_user", ["userId"]);
393
+ })
394
+ .addReference("memberships", {
395
+ type: "many",
396
+ from: { table: "users", column: "id" },
397
+ to: { table: "memberships", column: "userId" },
398
+ foreignKey: false,
399
+ });
400
+ });
401
+
402
+ const addReferenceOps = userSchema.operations.filter((op) => op.type === "add-reference");
403
+ expect(addReferenceOps).toHaveLength(1);
404
+ expect(addReferenceOps[0].config.from).toEqual({ table: "users", column: "_internalId" });
405
+
406
+ const userRelation = userSchema.tables.users.relations["memberships"];
407
+ expect(userRelation.on).toEqual([["_internalId", "userId"]]);
408
+ });
409
+
410
+ it("should require indexes for join-only references", () => {
411
+ expect(() =>
412
+ schema("user", (s) => {
413
+ return s
414
+ .addTable("users", (t) => {
415
+ return t.addColumn("id", idColumn()).addColumn("email", column("string"));
416
+ })
417
+ .addTable("invitations", (t) => {
418
+ return t.addColumn("id", idColumn()).addColumn("email", column("string"));
419
+ })
420
+ .addReference("invitedUser", {
421
+ type: "one",
422
+ from: { table: "invitations", column: "email" },
423
+ to: { table: "users", column: "email" },
424
+ foreignKey: false,
425
+ });
426
+ }),
427
+ ).toThrow(/indexed join columns/);
428
+ });
429
+
299
430
  it("should support multiple references by calling addReference multiple times", () => {
300
431
  const userSchema = schema("user", (s) => {
301
432
  return s
@@ -489,6 +620,34 @@ describe("create", () => {
489
620
  expect(userSchema.version).toBe(3);
490
621
  });
491
622
 
623
+ it("should preserve user-defined columns after alterTable type updates", () => {
624
+ const userSchema = schema("user", (s) => {
625
+ return s
626
+ .addTable("users", (t) => {
627
+ return t
628
+ .addColumn("id", idColumn())
629
+ .addColumn("email", column("string"))
630
+ .addColumn("passwordHash", column("string"));
631
+ })
632
+ .alterTable("users", (t) => {
633
+ expectTypeOf(t.alterColumn).parameter(0).toEqualTypeOf<"email" | "passwordHash">();
634
+ return t.alterColumn("passwordHash").nullable();
635
+ });
636
+ });
637
+
638
+ type UserColumns = typeof userSchema.tables.users.columns;
639
+ type UserColumnKeys = keyof UserColumns;
640
+
641
+ expectTypeOf<UserColumnKeys>().not.toEqualTypeOf<string>();
642
+ expectTypeOf<UserColumnKeys>().toEqualTypeOf<"id" | "email" | "passwordHash">();
643
+
644
+ type UpdateValues = TableToUpdateValues<typeof userSchema.tables.users>;
645
+ expectTypeOf<UpdateValues>().toMatchObjectType<{
646
+ email?: string;
647
+ passwordHash?: string | null;
648
+ }>();
649
+ });
650
+
492
651
  it("should preserve indexes when altering a table", () => {
493
652
  const userSchema = schema("user", (s) => {
494
653
  return s
@@ -1,4 +1,5 @@
1
1
  import type { StandardSchemaV1 } from "@standard-schema/spec";
2
+
2
3
  import { createId } from "../id";
3
4
  import type { DbNow } from "../query/db-now";
4
5
  import type { Prettify } from "../util/types";
@@ -25,6 +26,16 @@ export type AnyColumn =
25
26
  export type TableSubOperation =
26
27
  | { type: "add-column"; columnName: string; column: AnyColumn }
27
28
  | { type: "add-index"; name: string; columns: string[]; unique: boolean }
29
+ | { type: "rename-column"; from: string; to: string }
30
+ | { type: "drop-column"; name: string }
31
+ | {
32
+ type: "update-column";
33
+ columnName: string;
34
+ column: AnyColumn;
35
+ updateNullable: boolean;
36
+ updateDefault: boolean;
37
+ updateDataType: boolean;
38
+ }
28
39
  | {
29
40
  type: "add-foreign-key";
30
41
  name: string;
@@ -56,6 +67,7 @@ export type SchemaOperation =
56
67
  type: "one" | "many";
57
68
  from: { table: string; column: string };
58
69
  to: { table: string; column: string };
70
+ foreignKey?: boolean;
59
71
  };
60
72
  };
61
73
 
@@ -77,11 +89,18 @@ class RelationInit<
77
89
  referencedTable: TTables[TTableName];
78
90
  referencer: AnyTable;
79
91
  on: [string, string][] = [];
92
+ foreignKey: boolean;
80
93
 
81
- constructor(type: TRelationType, referencedTable: TTables[TTableName], referencer: AnyTable) {
94
+ constructor(
95
+ type: TRelationType,
96
+ referencedTable: TTables[TTableName],
97
+ referencer: AnyTable,
98
+ options?: { foreignKey?: boolean },
99
+ ) {
82
100
  this.type = type;
83
101
  this.referencedTable = referencedTable;
84
102
  this.referencer = referencer;
103
+ this.foreignKey = options?.foreignKey ?? true;
85
104
  }
86
105
  }
87
106
 
@@ -110,6 +129,7 @@ export class ExplicitRelationInit<
110
129
  referencer: this.referencer,
111
130
  table: this.referencedTable,
112
131
  type: this.type,
132
+ foreignKey: this.foreignKey,
113
133
  };
114
134
  }
115
135
  }
@@ -121,6 +141,7 @@ export interface Relation<
121
141
  id: string;
122
142
  name: string;
123
143
  type: TRelationType;
144
+ foreignKey?: boolean;
124
145
 
125
146
  table: TTable;
126
147
  referencer: AnyTable;
@@ -464,6 +485,29 @@ export class VersionColumn<TIn = unknown, TOut = unknown> extends Column<"intege
464
485
  }
465
486
  }
466
487
 
488
+ function cloneColumn<TColumn extends AnyColumn>(col: TColumn): TColumn {
489
+ let clonedCol: AnyColumn;
490
+
491
+ if (col instanceof InternalIdColumn) {
492
+ clonedCol = new InternalIdColumn();
493
+ } else if (col instanceof VersionColumn) {
494
+ clonedCol = new VersionColumn();
495
+ } else if (col instanceof IdColumn) {
496
+ clonedCol = new IdColumn(col.type);
497
+ } else {
498
+ clonedCol = new Column(col.type);
499
+ }
500
+
501
+ clonedCol.name = col.name;
502
+ clonedCol.isNullable = col.isNullable;
503
+ clonedCol.role = col.role;
504
+ clonedCol.isHidden = col.isHidden;
505
+ clonedCol.default = col.default;
506
+ clonedCol.tableName = col.tableName;
507
+
508
+ return clonedCol as TColumn;
509
+ }
510
+
467
511
  type ColumnInput<TType extends keyof TypeMap> =
468
512
  | TypeMap[TType]
469
513
  | (TType extends "timestamp" | "date" ? DbNow : never);
@@ -496,8 +540,8 @@ export function referenceColumn(): Column<
496
540
  * This is a CUID string that can be auto-generated or user-provided.
497
541
  * Input accepts string | FragnoId | null, output returns FragnoId.
498
542
  */
499
- export function idColumn(): IdColumn<"varchar(30)", string | FragnoId | null, FragnoId> {
500
- const col = new IdColumn<"varchar(30)", string | FragnoId | null, FragnoId>("varchar(30)");
543
+ export function idColumn(): IdColumn<"varchar(128)", string | FragnoId | null, FragnoId> {
544
+ const col = new IdColumn<"varchar(128)", string | FragnoId | null, FragnoId>("varchar(128)");
501
545
  col.role = "external-id";
502
546
  col.defaultTo$((b) => b.cuid());
503
547
  return col;
@@ -711,6 +755,32 @@ export class TableBuilder<
711
755
  >;
712
756
  }
713
757
 
758
+ /**
759
+ * Alter an existing column.
760
+ */
761
+ alterColumn<TColumnName extends NonIdColumnName<TColumns>>(
762
+ name: TColumnName,
763
+ ): ColumnAlterer<TColumns, TRelations, TIndexes, TColumnName> {
764
+ return {
765
+ nullable: <TNullable extends boolean = true>(nullable?: TNullable) => {
766
+ const column = this.#columns[name];
767
+ if (!column) {
768
+ throw new Error(`Unknown column name ${String(name)}`);
769
+ }
770
+
771
+ const cloned = cloneColumn(column) as Column<keyof TypeMap>;
772
+ const updated = cloned.nullable(nullable ?? true);
773
+ this.#columns[name] = updated as unknown as TColumns[TColumnName];
774
+
775
+ return this as unknown as TableBuilder<
776
+ UpdateColumn<TColumns, TColumnName, NullableColumn<TColumns[TColumnName], TNullable>>,
777
+ TRelations,
778
+ TIndexes
779
+ >;
780
+ },
781
+ };
782
+ }
783
+
714
784
  /**
715
785
  * Create an index on the specified columns.
716
786
  */
@@ -898,6 +968,45 @@ type ColumnsToTuple<
898
968
  : never;
899
969
  } & AnyColumn[];
900
970
 
971
+ type UpdateColumn<
972
+ TColumns extends Record<string, AnyColumn>,
973
+ TColumnName extends keyof TColumns,
974
+ TUpdatedColumn extends AnyColumn,
975
+ > = Prettify<Omit<TColumns, TColumnName> & Record<TColumnName, TUpdatedColumn>>;
976
+
977
+ type NonIdColumnName<TColumns extends Record<string, AnyColumn>> = {
978
+ [K in keyof TColumns]: TColumns[K] extends
979
+ | IdColumn<IdColumnType, unknown, unknown>
980
+ | InternalIdColumn<unknown, unknown>
981
+ | VersionColumn<unknown, unknown>
982
+ ? never
983
+ : K;
984
+ }[keyof TColumns];
985
+
986
+ type NullableColumn<TColumn extends AnyColumn, TNullable extends boolean> =
987
+ TColumn extends Column<infer TType, infer TIn, infer TOut>
988
+ ? Column<
989
+ TType,
990
+ TNullable extends true ? TIn | null : Exclude<TIn, null>,
991
+ TNullable extends true ? TOut | null : Exclude<TOut, null>
992
+ >
993
+ : TColumn;
994
+
995
+ type ColumnAlterer<
996
+ TColumns extends Record<string, AnyColumn>,
997
+ TRelations extends Record<string, AnyRelation>,
998
+ TIndexes extends Record<string, Index>,
999
+ TColumnName extends keyof TColumns,
1000
+ > = {
1001
+ nullable<TNullable extends boolean = true>(
1002
+ nullable?: TNullable,
1003
+ ): TableBuilder<
1004
+ UpdateColumn<TColumns, TColumnName, NullableColumn<TColumns[TColumnName], TNullable>>,
1005
+ TRelations,
1006
+ TIndexes
1007
+ >;
1008
+ };
1009
+
901
1010
  export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
902
1011
  #name: string;
903
1012
  #tables: TTables;
@@ -940,6 +1049,31 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
940
1049
  this.#indexNames.add(name);
941
1050
  }
942
1051
 
1052
+ #rebindRelations(tableName: string, newTable: AnyTable): void {
1053
+ for (const table of Object.values(this.#tables)) {
1054
+ for (const relation of Object.values(table.relations)) {
1055
+ if (relation.table.name === tableName) {
1056
+ relation.table = newTable;
1057
+ }
1058
+ if (relation.referencer.name === tableName) {
1059
+ relation.referencer = newTable;
1060
+ }
1061
+ }
1062
+ }
1063
+ }
1064
+
1065
+ #isJoinColumnIndexed(table: AnyTable, columnName: string): boolean {
1066
+ const idColumnName = table.getIdColumn().name;
1067
+ const internalIdColumnName = table.getInternalIdColumn().name;
1068
+ if (columnName === idColumnName || columnName === internalIdColumnName) {
1069
+ return true;
1070
+ }
1071
+
1072
+ return Object.values(table.indexes).some((index) =>
1073
+ index.columnNames.some((name) => name === columnName),
1074
+ );
1075
+ }
1076
+
943
1077
  /**
944
1078
  * Add an existing schema to this builder.
945
1079
  * Merges tables and operations from the provided schema.
@@ -995,11 +1129,7 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
995
1129
  >(
996
1130
  name: TTableName,
997
1131
  callback: (
998
- builder: TableBuilder<
999
- Record<string, AnyColumn>,
1000
- Record<string, AnyRelation>,
1001
- Record<string, Index>
1002
- >,
1132
+ builder: TableBuilder<{}, Record<string, AnyRelation>, Record<string, Index>>,
1003
1133
  ) => TableBuilder<TColumns, TRelations, TIndexes>,
1004
1134
  ): SchemaBuilder<TTables & Record<TTableName, Table<TColumns, TRelations, TIndexes>>> {
1005
1135
  this.#version++;
@@ -1008,7 +1138,9 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1008
1138
  throw new Error(`Duplicate table name "${name}" in schema "${this.#name}".`);
1009
1139
  }
1010
1140
 
1011
- const tableBuilder = new TableBuilder(name);
1141
+ const tableBuilder = new TableBuilder<{}, Record<string, AnyRelation>, Record<string, Index>>(
1142
+ name,
1143
+ );
1012
1144
  const result = callback(tableBuilder);
1013
1145
  const builtTable = result.build();
1014
1146
  const indexNames = result.getIndexes().map((idx) => idx.name);
@@ -1031,7 +1163,7 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1031
1163
  subOperations.push({
1032
1164
  type: "add-column",
1033
1165
  columnName: colName,
1034
- column: col,
1166
+ column: cloneColumn(col),
1035
1167
  });
1036
1168
  }
1037
1169
 
@@ -1040,14 +1172,14 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1040
1172
  subOperations.push({
1041
1173
  type: "add-column",
1042
1174
  columnName: "_internalId",
1043
- column: builtTable.columns["_internalId"],
1175
+ column: cloneColumn(builtTable.columns["_internalId"]),
1044
1176
  });
1045
1177
  }
1046
1178
  if (builtTable.columns["_version"]) {
1047
1179
  subOperations.push({
1048
1180
  type: "add-column",
1049
1181
  columnName: "_version",
1050
- column: builtTable.columns["_version"],
1182
+ column: cloneColumn(builtTable.columns["_version"]),
1051
1183
  });
1052
1184
  }
1053
1185
 
@@ -1115,6 +1247,14 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1115
1247
  * from: { table: "users", column: "invitedBy" },
1116
1248
  * to: { table: "users", column: "id" },
1117
1249
  * })
1250
+ *
1251
+ * // Join-only relation (no foreign key)
1252
+ * .addReference("invitedUser", {
1253
+ * type: "one",
1254
+ * from: { table: "invitations", column: "email" },
1255
+ * to: { table: "users", column: "email" },
1256
+ * foreignKey: false,
1257
+ * })
1118
1258
  * ```
1119
1259
  */
1120
1260
  addReference<
@@ -1134,6 +1274,12 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1134
1274
  table: TToTableName;
1135
1275
  column: keyof TTables[TToTableName]["columns"];
1136
1276
  };
1277
+ /**
1278
+ * When false, defines a join-only relation without foreign key migrations.
1279
+ * References to external-id columns still coerce to `_internalId`
1280
+ * (including left-side external IDs for join-only).
1281
+ */
1282
+ foreignKey?: boolean;
1137
1283
  },
1138
1284
  ): SchemaBuilder<
1139
1285
  UpdateTableRelations<TTables, TFromTableName, TReferenceName, TToTableName, TRelationType>
@@ -1156,17 +1302,25 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1156
1302
 
1157
1303
  const columnName = config.from.column as string;
1158
1304
  const targetColumnName = config.to.column as string;
1159
-
1160
- // Foreign keys always reference internal IDs, not external IDs
1161
- // If user specifies "id", translate to "_internalId" for the actual FK
1162
- const actualTargetColumnName = targetColumnName === "id" ? "_internalId" : targetColumnName;
1305
+ const foreignKey = config.foreignKey !== false;
1163
1306
 
1164
1307
  const column = table.columns[columnName];
1165
- const referencedColumn = referencedTable.columns[actualTargetColumnName];
1308
+ const targetColumn = referencedTable.columns[targetColumnName];
1166
1309
 
1167
1310
  if (!column) {
1168
1311
  throw new Error(`Column ${columnName} not found in table ${config.from.table}`);
1169
1312
  }
1313
+ if (!targetColumn) {
1314
+ throw new Error(`Column ${targetColumnName} not found in table ${config.to.table}`);
1315
+ }
1316
+
1317
+ // External-id columns always target the internal ID column.
1318
+ const actualTargetColumnName =
1319
+ targetColumn.role === "external-id"
1320
+ ? referencedTable.getInternalIdColumn().name
1321
+ : targetColumnName;
1322
+
1323
+ const referencedColumn = referencedTable.columns[actualTargetColumnName];
1170
1324
  if (!referencedColumn) {
1171
1325
  throw new Error(`Column ${actualTargetColumnName} not found in table ${config.to.table}`);
1172
1326
  }
@@ -1182,9 +1336,28 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1182
1336
  );
1183
1337
  }
1184
1338
 
1185
- // Create the relation (use the user-facing column name for the relation)
1186
- const init = new ExplicitRelationInit(config.type, referencedTable, table);
1187
- init.on.push([columnName, targetColumnName]);
1339
+ if (!foreignKey) {
1340
+ const missingIndexes: string[] = [];
1341
+ if (!this.#isJoinColumnIndexed(table, columnName)) {
1342
+ missingIndexes.push(`${table.name}.${columnName}`);
1343
+ }
1344
+ if (!this.#isJoinColumnIndexed(referencedTable, actualTargetColumnName)) {
1345
+ missingIndexes.push(`${referencedTable.name}.${actualTargetColumnName}`);
1346
+ }
1347
+ if (missingIndexes.length > 0) {
1348
+ throw new Error(
1349
+ `Join-only relation "${referenceName}" requires indexed join columns: ${missingIndexes.join(", ")}.`,
1350
+ );
1351
+ }
1352
+ }
1353
+
1354
+ // Join-only relations treat external IDs as internal IDs on the left side.
1355
+ const actualFromColumnName =
1356
+ !foreignKey && column.role === "external-id" ? table.getInternalIdColumn().name : columnName;
1357
+
1358
+ // Create the relation (use user-facing right-side column name)
1359
+ const init = new ExplicitRelationInit(config.type, referencedTable, table, { foreignKey });
1360
+ init.on.push([actualFromColumnName, targetColumnName]);
1188
1361
  const relation = init.init(referenceName);
1189
1362
 
1190
1363
  // Add relation to the table
@@ -1197,8 +1370,9 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1197
1370
  referenceName,
1198
1371
  config: {
1199
1372
  type: config.type,
1200
- from: { table: config.from.table, column: columnName },
1373
+ from: { table: config.from.table, column: actualFromColumnName },
1201
1374
  to: { table: config.to.table, column: actualTargetColumnName },
1375
+ foreignKey,
1202
1376
  },
1203
1377
  });
1204
1378
 
@@ -1210,8 +1384,8 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1210
1384
  }
1211
1385
 
1212
1386
  /**
1213
- * Alter an existing table by adding columns or indexes.
1214
- * This is used for append-only schema modifications.
1387
+ * Alter an existing table by adding columns, altering columns, or adding indexes.
1388
+ * This is used for forward-only schema modifications.
1215
1389
  *
1216
1390
  * @param tableName - The name of the table to modify
1217
1391
  * @param callback - A callback that receives a table builder for adding columns/indexes
@@ -1224,6 +1398,7 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1224
1398
  * .addColumn("id", idColumn())
1225
1399
  * .addColumn("name", column("string")))
1226
1400
  * .alterTable("users", t => t
1401
+ * .alterColumn("name").nullable()
1227
1402
  * .addColumn("email", column("string"))
1228
1403
  * .addColumn("age", column("integer").nullable())
1229
1404
  * .createIndex("idx_email", ["email"]))
@@ -1260,6 +1435,10 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1260
1435
  // Track existing columns and indexes
1261
1436
  const existingColumns = new Set(Object.keys(table.columns));
1262
1437
  const existingIndexes = new Set(Object.keys(table.indexes));
1438
+ const existingColumnState = new Map<string, { isNullable: boolean }>();
1439
+ for (const [colName, col] of Object.entries(table.columns)) {
1440
+ existingColumnState.set(colName, { isNullable: col.isNullable });
1441
+ }
1263
1442
 
1264
1443
  // Apply modifications
1265
1444
  const resultBuilder = callback(
@@ -1281,7 +1460,25 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1281
1460
  subOperations.push({
1282
1461
  type: "add-column",
1283
1462
  columnName: colName,
1284
- column: newTable.columns[colName],
1463
+ column: cloneColumn(newTable.columns[colName]),
1464
+ });
1465
+ }
1466
+ }
1467
+
1468
+ // Track updates to existing columns
1469
+ for (const [colName, previousState] of existingColumnState.entries()) {
1470
+ const updatedColumn = newTable.columns[colName];
1471
+ if (!updatedColumn) {
1472
+ continue;
1473
+ }
1474
+ if (previousState.isNullable !== updatedColumn.isNullable) {
1475
+ subOperations.push({
1476
+ type: "update-column",
1477
+ columnName: colName,
1478
+ column: cloneColumn(updatedColumn),
1479
+ updateNullable: true,
1480
+ updateDefault: false,
1481
+ updateDataType: false,
1285
1482
  });
1286
1483
  }
1287
1484
  }
@@ -1314,6 +1511,7 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1314
1511
 
1315
1512
  // Update table reference in schema
1316
1513
  this.#tables[tableName] = newTable as unknown as TTables[TTableName];
1514
+ this.#rebindRelations(tableName, newTable as unknown as AnyTable);
1317
1515
  for (const idx of resultBuilder.getIndexes()) {
1318
1516
  if (!existingIndexes.has(idx.name)) {
1319
1517
  this.#indexNames.add(idx.name);
@@ -1,4 +1,5 @@
1
1
  import { describe, it, expect } from "vitest";
2
+
2
3
  import { schema, idColumn, FragnoId } from "./create";
3
4
  import { generateId } from "./generate-id";
4
5
 
@@ -1,13 +1,14 @@
1
1
  import { assert, describe, expect, it } from "vitest";
2
- import { column, referenceColumn, internalIdColumn } from "./create";
3
- import { createSQLSerializer } from "../query/serialize/create-sql-serializer";
4
- import type { AnyColumn } from "./create";
2
+
5
3
  import type { DriverConfig } from "../adapters/generic-sql/driver-config";
6
4
  import {
7
5
  BetterSQLite3DriverConfig,
8
6
  NodePostgresDriverConfig,
9
7
  MySQL2DriverConfig,
10
8
  } from "../adapters/generic-sql/driver-config";
9
+ import { createSQLSerializer } from "../query/serialize/create-sql-serializer";
10
+ import { column, referenceColumn, internalIdColumn } from "./create";
11
+ import type { AnyColumn } from "./create";
11
12
 
12
13
  function createMockDriverConfig(provider: string): DriverConfig {
13
14
  if (provider === "postgresql" || provider === "cockroachdb") {
@@ -1,7 +1,7 @@
1
1
  import type { SupportedDatabase } from "../../adapters/generic-sql/driver-config";
2
2
  import type { SQLiteStorageMode } from "../../adapters/generic-sql/sqlite-storage";
3
- import { PostgreSQLTypeMapper } from "./dialect/postgres";
4
3
  import { MySQLTypeMapper } from "./dialect/mysql";
4
+ import { PostgreSQLTypeMapper } from "./dialect/postgres";
5
5
  import { SQLiteTypeMapper } from "./dialect/sqlite";
6
6
 
7
7
  /**
@@ -1,7 +1,7 @@
1
- import type { AnyColumn } from "../../create";
2
- import { SQLTypeMapper, type SQLiteDatabaseType } from "../type-mapping";
3
1
  import type { SQLiteStorageMode } from "../../../adapters/generic-sql/sqlite-storage";
4
2
  import { sqliteStorageDefault } from "../../../adapters/generic-sql/sqlite-storage";
3
+ import type { AnyColumn } from "../../create";
4
+ import { SQLTypeMapper, type SQLiteDatabaseType } from "../type-mapping";
5
5
 
6
6
  /**
7
7
  * SQLite-specific type mapper.
@@ -1,7 +1,8 @@
1
1
  import { describe, expect, it } from "vitest";
2
+
3
+ import { sqliteStoragePrisma } from "../../adapters/generic-sql/sqlite-storage";
2
4
  import { column, referenceColumn } from "../create";
3
5
  import { createSQLTypeMapper } from "./create-sql-type-mapper";
4
- import { sqliteStoragePrisma } from "../../adapters/generic-sql/sqlite-storage";
5
6
 
6
7
  describe("SQLTypeMapper", () => {
7
8
  describe("error handling", () => {