@fragno-dev/db 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (362) hide show
  1. package/.turbo/turbo-build.log +206 -140
  2. package/CHANGELOG.md +67 -0
  3. package/README.md +30 -9
  4. package/dist/adapters/adapters.d.ts +23 -21
  5. package/dist/adapters/adapters.d.ts.map +1 -1
  6. package/dist/adapters/adapters.js.map +1 -1
  7. package/dist/adapters/generic-sql/driver-config.d.ts +16 -1
  8. package/dist/adapters/generic-sql/driver-config.d.ts.map +1 -1
  9. package/dist/adapters/generic-sql/driver-config.js +23 -1
  10. package/dist/adapters/generic-sql/driver-config.js.map +1 -1
  11. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts +27 -9
  12. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -1
  13. package/dist/adapters/generic-sql/generic-sql-adapter.js +55 -16
  14. package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -1
  15. package/dist/adapters/generic-sql/generic-sql-uow-executor.js +129 -3
  16. package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -1
  17. package/dist/adapters/generic-sql/migration/dialect/mysql.js +24 -5
  18. package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -1
  19. package/dist/adapters/generic-sql/migration/dialect/postgres.js +6 -5
  20. package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -1
  21. package/dist/adapters/generic-sql/migration/dialect/sqlite.js +21 -10
  22. package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -1
  23. package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -1
  24. package/dist/adapters/generic-sql/migration/prepared-migrations.js +8 -8
  25. package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -1
  26. package/dist/adapters/generic-sql/migration/sql-generator.js +74 -51
  27. package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -1
  28. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +6 -5
  29. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -1
  30. package/dist/adapters/generic-sql/query/cursor-utils.js +42 -4
  31. package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -1
  32. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +25 -17
  33. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -1
  34. package/dist/adapters/generic-sql/query/select-builder.js +5 -3
  35. package/dist/adapters/generic-sql/query/select-builder.js.map +1 -1
  36. package/dist/adapters/generic-sql/query/sql-query-compiler.js +15 -12
  37. package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -1
  38. package/dist/adapters/generic-sql/query/where-builder.js +38 -28
  39. package/dist/adapters/generic-sql/query/where-builder.js.map +1 -1
  40. package/dist/adapters/generic-sql/sqlite-storage.d.ts +13 -0
  41. package/dist/adapters/generic-sql/sqlite-storage.d.ts.map +1 -0
  42. package/dist/adapters/generic-sql/sqlite-storage.js +15 -0
  43. package/dist/adapters/generic-sql/sqlite-storage.js.map +1 -0
  44. package/dist/adapters/generic-sql/uow-decoder.js +7 -3
  45. package/dist/adapters/generic-sql/uow-decoder.js.map +1 -1
  46. package/dist/adapters/generic-sql/uow-encoder.js +28 -8
  47. package/dist/adapters/generic-sql/uow-encoder.js.map +1 -1
  48. package/dist/adapters/in-memory/condition-evaluator.js +131 -0
  49. package/dist/adapters/in-memory/condition-evaluator.js.map +1 -0
  50. package/dist/adapters/in-memory/errors.d.ts +13 -0
  51. package/dist/adapters/in-memory/errors.d.ts.map +1 -0
  52. package/dist/adapters/in-memory/errors.js +23 -0
  53. package/dist/adapters/in-memory/errors.js.map +1 -0
  54. package/dist/adapters/in-memory/in-memory-adapter.d.ts +27 -0
  55. package/dist/adapters/in-memory/in-memory-adapter.d.ts.map +1 -0
  56. package/dist/adapters/in-memory/in-memory-adapter.js +176 -0
  57. package/dist/adapters/in-memory/in-memory-adapter.js.map +1 -0
  58. package/dist/adapters/in-memory/in-memory-uow.js +648 -0
  59. package/dist/adapters/in-memory/in-memory-uow.js.map +1 -0
  60. package/dist/adapters/in-memory/index.d.ts +4 -0
  61. package/dist/adapters/in-memory/index.js +4 -0
  62. package/dist/adapters/in-memory/options.d.ts +28 -0
  63. package/dist/adapters/in-memory/options.d.ts.map +1 -0
  64. package/dist/adapters/in-memory/options.js +61 -0
  65. package/dist/adapters/in-memory/options.js.map +1 -0
  66. package/dist/adapters/in-memory/reference-resolution.js +26 -0
  67. package/dist/adapters/in-memory/reference-resolution.js.map +1 -0
  68. package/dist/adapters/in-memory/sorted-array-index.js +129 -0
  69. package/dist/adapters/in-memory/sorted-array-index.js.map +1 -0
  70. package/dist/adapters/in-memory/store.js +71 -0
  71. package/dist/adapters/in-memory/store.js.map +1 -0
  72. package/dist/adapters/in-memory/value-comparison.js +28 -0
  73. package/dist/adapters/in-memory/value-comparison.js.map +1 -0
  74. package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -1
  75. package/dist/adapters/shared/uow-operation-compiler.js +11 -11
  76. package/dist/adapters/shared/uow-operation-compiler.js.map +1 -1
  77. package/dist/adapters/sql/index.d.ts +5 -0
  78. package/dist/adapters/sql/index.js +4 -0
  79. package/dist/db-fragment-definition-builder.d.ts +45 -96
  80. package/dist/db-fragment-definition-builder.d.ts.map +1 -1
  81. package/dist/db-fragment-definition-builder.js +121 -99
  82. package/dist/db-fragment-definition-builder.js.map +1 -1
  83. package/dist/dispatchers/cloudflare-do/index.d.ts +26 -0
  84. package/dist/dispatchers/cloudflare-do/index.d.ts.map +1 -0
  85. package/dist/dispatchers/cloudflare-do/index.js +63 -0
  86. package/dist/dispatchers/cloudflare-do/index.js.map +1 -0
  87. package/dist/dispatchers/node/index.d.ts +17 -0
  88. package/dist/dispatchers/node/index.d.ts.map +1 -0
  89. package/dist/dispatchers/node/index.js +59 -0
  90. package/dist/dispatchers/node/index.js.map +1 -0
  91. package/dist/fragments/internal-fragment.d.ts +172 -9
  92. package/dist/fragments/internal-fragment.d.ts.map +1 -1
  93. package/dist/fragments/internal-fragment.js +193 -74
  94. package/dist/fragments/internal-fragment.js.map +1 -1
  95. package/dist/fragments/internal-fragment.routes.js +29 -0
  96. package/dist/fragments/internal-fragment.routes.js.map +1 -0
  97. package/dist/fragments/internal-fragment.schema.d.ts +9 -0
  98. package/dist/fragments/internal-fragment.schema.d.ts.map +1 -0
  99. package/dist/fragments/internal-fragment.schema.js +22 -0
  100. package/dist/fragments/internal-fragment.schema.js.map +1 -0
  101. package/dist/hooks/durable-hooks-processor.d.ts +14 -0
  102. package/dist/hooks/durable-hooks-processor.d.ts.map +1 -0
  103. package/dist/hooks/durable-hooks-processor.js +32 -0
  104. package/dist/hooks/durable-hooks-processor.js.map +1 -0
  105. package/dist/hooks/hooks.d.ts +47 -4
  106. package/dist/hooks/hooks.d.ts.map +1 -1
  107. package/dist/hooks/hooks.js +106 -39
  108. package/dist/hooks/hooks.js.map +1 -1
  109. package/dist/migration-engine/auto-from-schema.js +14 -11
  110. package/dist/migration-engine/auto-from-schema.js.map +1 -1
  111. package/dist/migration-engine/generation-engine.d.ts +16 -10
  112. package/dist/migration-engine/generation-engine.d.ts.map +1 -1
  113. package/dist/migration-engine/generation-engine.js +72 -33
  114. package/dist/migration-engine/generation-engine.js.map +1 -1
  115. package/dist/migration-engine/shared.js.map +1 -1
  116. package/dist/mod.d.ts +17 -10
  117. package/dist/mod.d.ts.map +1 -1
  118. package/dist/mod.js +14 -8
  119. package/dist/mod.js.map +1 -1
  120. package/dist/naming/sql-naming.d.ts +19 -0
  121. package/dist/naming/sql-naming.d.ts.map +1 -0
  122. package/dist/naming/sql-naming.js +116 -0
  123. package/dist/naming/sql-naming.js.map +1 -0
  124. package/dist/node_modules/.pnpm/{rou3@0.7.10 → rou3@0.7.12}/node_modules/rou3/dist/index.js +8 -5
  125. package/dist/node_modules/.pnpm/rou3@0.7.12/node_modules/rou3/dist/index.js.map +1 -0
  126. package/dist/outbox/outbox-builder.js +156 -0
  127. package/dist/outbox/outbox-builder.js.map +1 -0
  128. package/dist/outbox/outbox.d.ts +52 -0
  129. package/dist/outbox/outbox.d.ts.map +1 -0
  130. package/dist/outbox/outbox.js +37 -0
  131. package/dist/outbox/outbox.js.map +1 -0
  132. package/dist/packages/fragno/dist/api/fragment-definition-builder.js +3 -2
  133. package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +1 -1
  134. package/dist/packages/fragno/dist/api/fragment-instantiator.js +164 -20
  135. package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -1
  136. package/dist/packages/fragno/dist/api/request-input-context.js +67 -0
  137. package/dist/packages/fragno/dist/api/request-input-context.js.map +1 -1
  138. package/dist/packages/fragno/dist/api/route.js +14 -1
  139. package/dist/packages/fragno/dist/api/route.js.map +1 -1
  140. package/dist/packages/fragno/dist/internal/trace-context.js +12 -0
  141. package/dist/packages/fragno/dist/internal/trace-context.js.map +1 -0
  142. package/dist/query/column-defaults.js +20 -4
  143. package/dist/query/column-defaults.js.map +1 -1
  144. package/dist/query/cursor.d.ts +3 -1
  145. package/dist/query/cursor.d.ts.map +1 -1
  146. package/dist/query/cursor.js +45 -14
  147. package/dist/query/cursor.js.map +1 -1
  148. package/dist/query/db-now.d.ts +8 -0
  149. package/dist/query/db-now.d.ts.map +1 -0
  150. package/dist/query/db-now.js +7 -0
  151. package/dist/query/db-now.js.map +1 -0
  152. package/dist/query/serialize/create-sql-serializer.js +3 -2
  153. package/dist/query/serialize/create-sql-serializer.js.map +1 -1
  154. package/dist/query/serialize/dialect/mysql-serializer.js +12 -6
  155. package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -1
  156. package/dist/query/serialize/dialect/postgres-serializer.js +25 -7
  157. package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -1
  158. package/dist/query/serialize/dialect/sqlite-serializer.js +55 -11
  159. package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -1
  160. package/dist/query/serialize/sql-serializer.js +2 -2
  161. package/dist/query/serialize/sql-serializer.js.map +1 -1
  162. package/dist/query/simple-query-interface.d.ts +6 -1
  163. package/dist/query/simple-query-interface.d.ts.map +1 -1
  164. package/dist/query/unit-of-work/execute-unit-of-work.d.ts +351 -100
  165. package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -1
  166. package/dist/query/unit-of-work/execute-unit-of-work.js +440 -267
  167. package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -1
  168. package/dist/query/unit-of-work/unit-of-work.d.ts +67 -22
  169. package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
  170. package/dist/query/unit-of-work/unit-of-work.js +110 -13
  171. package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
  172. package/dist/query/value-decoding.js +8 -5
  173. package/dist/query/value-decoding.js.map +1 -1
  174. package/dist/query/value-encoding.js +29 -9
  175. package/dist/query/value-encoding.js.map +1 -1
  176. package/dist/schema/create.d.ts +40 -14
  177. package/dist/schema/create.d.ts.map +1 -1
  178. package/dist/schema/create.js +82 -42
  179. package/dist/schema/create.js.map +1 -1
  180. package/dist/schema/generate-id.d.ts +20 -0
  181. package/dist/schema/generate-id.d.ts.map +1 -0
  182. package/dist/schema/generate-id.js +28 -0
  183. package/dist/schema/generate-id.js.map +1 -0
  184. package/dist/schema/type-conversion/create-sql-type-mapper.js +3 -2
  185. package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -1
  186. package/dist/schema/type-conversion/dialect/sqlite.js +9 -0
  187. package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -1
  188. package/dist/schema/validator.d.ts +10 -0
  189. package/dist/schema/validator.d.ts.map +1 -0
  190. package/dist/schema/validator.js +123 -0
  191. package/dist/schema/validator.js.map +1 -0
  192. package/dist/schema-output/drizzle.d.ts +30 -0
  193. package/dist/schema-output/drizzle.d.ts.map +1 -0
  194. package/dist/{adapters/drizzle/generate.js → schema-output/drizzle.js} +82 -56
  195. package/dist/schema-output/drizzle.js.map +1 -0
  196. package/dist/schema-output/prisma.d.ts +17 -0
  197. package/dist/schema-output/prisma.d.ts.map +1 -0
  198. package/dist/schema-output/prisma.js +296 -0
  199. package/dist/schema-output/prisma.js.map +1 -0
  200. package/dist/util/default-database-adapter.js +61 -0
  201. package/dist/util/default-database-adapter.js.map +1 -0
  202. package/dist/with-database.d.ts +1 -1
  203. package/dist/with-database.d.ts.map +1 -1
  204. package/dist/with-database.js +12 -3
  205. package/dist/with-database.js.map +1 -1
  206. package/package.json +43 -28
  207. package/src/adapters/adapters.ts +30 -24
  208. package/src/adapters/drizzle/migrate-drizzle.test.ts +54 -33
  209. package/src/adapters/drizzle/migration-parity-drizzle-kit.test.ts +599 -0
  210. package/src/adapters/drizzle/test-utils.ts +12 -8
  211. package/src/adapters/generic-sql/driver-config.ts +38 -0
  212. package/src/adapters/generic-sql/generic-sql-adapter.test.ts +5 -5
  213. package/src/adapters/generic-sql/generic-sql-adapter.ts +110 -24
  214. package/src/adapters/generic-sql/generic-sql-uow-executor.test.ts +54 -0
  215. package/src/adapters/generic-sql/generic-sql-uow-executor.ts +231 -3
  216. package/src/adapters/generic-sql/migration/adapter-migration-parity.test.ts +118 -0
  217. package/src/adapters/generic-sql/migration/dialect/mysql.test.ts +26 -8
  218. package/src/adapters/generic-sql/migration/dialect/mysql.ts +46 -8
  219. package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +25 -7
  220. package/src/adapters/generic-sql/migration/dialect/postgres.ts +8 -4
  221. package/src/adapters/generic-sql/migration/dialect/sqlite.test.ts +47 -8
  222. package/src/adapters/generic-sql/migration/dialect/sqlite.ts +27 -12
  223. package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +128 -39
  224. package/src/adapters/generic-sql/migration/prepared-migrations.ts +15 -8
  225. package/src/adapters/generic-sql/migration/sql-generator.ts +142 -65
  226. package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +9 -6
  227. package/src/adapters/generic-sql/query/cursor-utils.test.ts +271 -0
  228. package/src/adapters/generic-sql/query/cursor-utils.ts +41 -6
  229. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +27 -27
  230. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +38 -24
  231. package/src/adapters/generic-sql/query/select-builder.test.ts +15 -11
  232. package/src/adapters/generic-sql/query/select-builder.ts +6 -2
  233. package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +52 -2
  234. package/src/adapters/generic-sql/query/sql-query-compiler.ts +50 -15
  235. package/src/adapters/generic-sql/query/where-builder.test.ts +91 -17
  236. package/src/adapters/generic-sql/query/where-builder.ts +90 -38
  237. package/src/adapters/{kysely/kysely-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-migrations.test.ts} +6 -6
  238. package/src/adapters/generic-sql/sql-adapter-pglite-pagination.test.ts +806 -0
  239. package/src/adapters/{drizzle/drizzle-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-queries.test.ts} +11 -11
  240. package/src/adapters/generic-sql/{test/generic-drizzle-adapter-sqlite3.test.ts → sql-adapter-sqlite3-driver.test.ts} +49 -35
  241. package/src/adapters/{drizzle/drizzle-adapter-sqlite3.test.ts → generic-sql/sql-adapter-sqlite3-uow.test.ts} +48 -32
  242. package/src/adapters/{kysely/kysely-adapter-sqlocal.test.ts → generic-sql/sql-adapter-sqlocal.test.ts} +6 -6
  243. package/src/adapters/generic-sql/sqlite-storage.ts +20 -0
  244. package/src/adapters/generic-sql/uow-decoder.test.ts +1 -1
  245. package/src/adapters/generic-sql/uow-decoder.ts +21 -3
  246. package/src/adapters/generic-sql/uow-encoder.test.ts +33 -2
  247. package/src/adapters/generic-sql/uow-encoder.ts +50 -11
  248. package/src/adapters/in-memory/condition-evaluator.test.ts +193 -0
  249. package/src/adapters/in-memory/condition-evaluator.ts +275 -0
  250. package/src/adapters/in-memory/errors.ts +20 -0
  251. package/src/adapters/in-memory/in-memory-adapter.ts +277 -0
  252. package/src/adapters/in-memory/in-memory-uow.mutations.test.ts +296 -0
  253. package/src/adapters/in-memory/in-memory-uow.retrieval.test.ts +100 -0
  254. package/src/adapters/in-memory/in-memory-uow.ts +1348 -0
  255. package/src/adapters/in-memory/index.ts +3 -0
  256. package/src/adapters/in-memory/options.test.ts +41 -0
  257. package/src/adapters/in-memory/options.ts +87 -0
  258. package/src/adapters/in-memory/reference-resolution.test.ts +50 -0
  259. package/src/adapters/in-memory/reference-resolution.ts +67 -0
  260. package/src/adapters/in-memory/sorted-array-index.test.ts +123 -0
  261. package/src/adapters/in-memory/sorted-array-index.ts +228 -0
  262. package/src/adapters/in-memory/store.test.ts +68 -0
  263. package/src/adapters/in-memory/store.ts +145 -0
  264. package/src/adapters/in-memory/value-comparison.ts +53 -0
  265. package/src/adapters/in-memory/value-normalization.test.ts +57 -0
  266. package/src/adapters/prisma/prisma-adapter-sqlite3.test.ts +1163 -0
  267. package/src/adapters/shared/from-unit-of-work-compiler.ts +3 -1
  268. package/src/adapters/shared/uow-operation-compiler.ts +26 -16
  269. package/src/adapters/sql/index.ts +12 -0
  270. package/src/db-fragment-definition-builder.test.ts +88 -54
  271. package/src/db-fragment-definition-builder.ts +201 -322
  272. package/src/db-fragment-instantiator.test.ts +169 -101
  273. package/src/db-fragment-integration.test.ts +301 -149
  274. package/src/dispatchers/cloudflare-do/index.test.ts +73 -0
  275. package/src/dispatchers/cloudflare-do/index.ts +104 -0
  276. package/src/dispatchers/node/index.test.ts +91 -0
  277. package/src/dispatchers/node/index.ts +87 -0
  278. package/src/fragments/internal-fragment.routes.ts +42 -0
  279. package/src/fragments/internal-fragment.schema.ts +51 -0
  280. package/src/fragments/internal-fragment.test.ts +730 -274
  281. package/src/fragments/internal-fragment.ts +447 -154
  282. package/src/hooks/durable-hooks-processor.test.ts +117 -0
  283. package/src/hooks/durable-hooks-processor.ts +67 -0
  284. package/src/hooks/hooks.test.ts +411 -259
  285. package/src/hooks/hooks.ts +265 -66
  286. package/src/migration-engine/auto-from-schema.test.ts +14 -14
  287. package/src/migration-engine/auto-from-schema.ts +5 -2
  288. package/src/migration-engine/create.test.ts +2 -2
  289. package/src/migration-engine/generation-engine.test.ts +229 -104
  290. package/src/migration-engine/generation-engine.ts +94 -64
  291. package/src/migration-engine/shared.ts +1 -0
  292. package/src/mod.ts +78 -30
  293. package/src/naming/sql-naming.ts +180 -0
  294. package/src/outbox/outbox-builder.ts +241 -0
  295. package/src/outbox/outbox.test.ts +253 -0
  296. package/src/outbox/outbox.ts +137 -0
  297. package/src/query/column-defaults.ts +41 -3
  298. package/src/query/condition-builder.test.ts +3 -3
  299. package/src/query/cursor.test.ts +116 -18
  300. package/src/query/cursor.ts +75 -26
  301. package/src/query/db-now.ts +6 -0
  302. package/src/query/query-type.test.ts +2 -2
  303. package/src/query/serialize/create-sql-serializer.ts +7 -2
  304. package/src/query/serialize/dialect/mysql-serializer.ts +12 -4
  305. package/src/query/serialize/dialect/postgres-serializer.ts +34 -4
  306. package/src/query/serialize/dialect/sqlite-serializer.test.ts +51 -1
  307. package/src/query/serialize/dialect/sqlite-serializer.ts +92 -9
  308. package/src/query/serialize/sql-serializer.ts +4 -4
  309. package/src/query/simple-query-interface.ts +5 -0
  310. package/src/query/unit-of-work/execute-unit-of-work.test.ts +1512 -1458
  311. package/src/query/unit-of-work/execute-unit-of-work.ts +1708 -596
  312. package/src/query/unit-of-work/tx-builder.test.ts +1041 -0
  313. package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +32 -32
  314. package/src/query/unit-of-work/unit-of-work-types.test.ts +1 -1
  315. package/src/query/unit-of-work/unit-of-work.test.ts +231 -36
  316. package/src/query/unit-of-work/unit-of-work.ts +229 -31
  317. package/src/query/value-decoding.test.ts +13 -2
  318. package/src/query/value-decoding.ts +17 -4
  319. package/src/query/value-encoding.test.ts +85 -2
  320. package/src/query/value-encoding.ts +56 -6
  321. package/src/schema/create.test.ts +129 -42
  322. package/src/schema/create.ts +187 -47
  323. package/src/schema/generate-id.test.ts +57 -0
  324. package/src/schema/generate-id.ts +38 -0
  325. package/src/schema/serialize.test.ts +14 -2
  326. package/src/schema/type-conversion/create-sql-type-mapper.ts +7 -2
  327. package/src/schema/type-conversion/dialect/sqlite.ts +18 -0
  328. package/src/schema/type-conversion/type-mapping.test.ts +25 -1
  329. package/src/schema/validator.test.ts +197 -0
  330. package/src/schema/validator.ts +231 -0
  331. package/src/{adapters/drizzle/generate.test.ts → schema-output/drizzle.test.ts} +179 -129
  332. package/src/{adapters/drizzle/generate.ts → schema-output/drizzle.ts} +143 -93
  333. package/src/schema-output/prisma.test.ts +536 -0
  334. package/src/schema-output/prisma.ts +573 -0
  335. package/src/util/default-database-adapter.ts +106 -0
  336. package/src/with-database.ts +22 -3
  337. package/tsdown.config.ts +6 -4
  338. package/dist/adapters/drizzle/drizzle-adapter.d.ts +0 -20
  339. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +0 -1
  340. package/dist/adapters/drizzle/drizzle-adapter.js +0 -27
  341. package/dist/adapters/drizzle/drizzle-adapter.js.map +0 -1
  342. package/dist/adapters/drizzle/generate.d.ts +0 -30
  343. package/dist/adapters/drizzle/generate.d.ts.map +0 -1
  344. package/dist/adapters/drizzle/generate.js.map +0 -1
  345. package/dist/adapters/kysely/kysely-adapter.d.ts +0 -19
  346. package/dist/adapters/kysely/kysely-adapter.d.ts.map +0 -1
  347. package/dist/adapters/kysely/kysely-adapter.js +0 -17
  348. package/dist/adapters/kysely/kysely-adapter.js.map +0 -1
  349. package/dist/adapters/shared/table-name-mapper.d.ts +0 -12
  350. package/dist/adapters/shared/table-name-mapper.d.ts.map +0 -1
  351. package/dist/adapters/shared/table-name-mapper.js +0 -43
  352. package/dist/adapters/shared/table-name-mapper.js.map +0 -1
  353. package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js.map +0 -1
  354. package/dist/schema-generator/schema-generator.d.ts +0 -15
  355. package/dist/schema-generator/schema-generator.d.ts.map +0 -1
  356. package/src/adapters/drizzle/drizzle-adapter.ts +0 -39
  357. package/src/adapters/kysely/kysely-adapter.ts +0 -27
  358. package/src/adapters/shared/table-name-mapper.ts +0 -50
  359. package/src/schema-generator/schema-generator.ts +0 -12
  360. package/src/shared/config.ts +0 -10
  361. package/src/shared/connection-pool.ts +0 -24
  362. package/src/shared/prisma.ts +0 -45
@@ -1,4 +1,11 @@
1
+ import type { StandardSchemaV1 } from "@standard-schema/spec";
1
2
  import { createId } from "../id";
3
+ import type { DbNow } from "../query/db-now";
4
+ import type { Prettify } from "../util/types";
5
+ import { createTableStandardSchemaProps, createTableValidator } from "./validator";
6
+
7
+ export { generateId } from "./generate-id";
8
+ export { FragnoDbValidationError } from "./validator";
2
9
 
3
10
  export type AnySchema = Schema<Record<string, AnyTable>>;
4
11
 
@@ -93,13 +100,13 @@ export class ExplicitRelationInit<
93
100
  TTables extends Record<string, AnyTable>,
94
101
  TTableName extends keyof TTables,
95
102
  > extends RelationInit<TRelationType, TTables, TTableName> {
96
- init(ormName: string): Relation<TRelationType, TTables[TTableName]> {
97
- const id = `${this.referencer.ormName}_${this.referencedTable.ormName}`;
103
+ init(name: string): Relation<TRelationType, TTables[TTableName]> {
104
+ const id = `${this.referencer.name}_${this.referencedTable.name}`;
98
105
 
99
106
  return {
100
107
  id,
101
108
  on: this.on,
102
- name: ormName,
109
+ name,
103
110
  referencer: this.referencer,
104
111
  table: this.referencedTable,
105
112
  type: this.type,
@@ -121,18 +128,57 @@ export interface Relation<
121
128
  on: [string, string][];
122
129
  }
123
130
 
131
+ type PickNullable<T> = {
132
+ [P in keyof T as null extends T[P] ? P : never]: T[P];
133
+ };
134
+
135
+ type PickNotNullable<T> = {
136
+ [P in keyof T as null extends T[P] ? never : P]: T[P];
137
+ };
138
+
139
+ type RawInsertValuesFromColumns<TColumns extends Record<string, AnyColumn>> = {
140
+ [K in keyof TColumns as string extends K ? never : K]: TColumns[K]["$in"];
141
+ };
142
+
143
+ type TableInsertValuesFromColumns<TColumns extends Record<string, AnyColumn>> = Prettify<
144
+ Partial<PickNullable<RawInsertValuesFromColumns<TColumns>>> &
145
+ PickNotNullable<RawInsertValuesFromColumns<TColumns>>
146
+ >;
147
+
148
+ export type TableInsertValues<T extends AnyTable> = TableInsertValuesFromColumns<T["columns"]>;
149
+
150
+ export type TableUnknownKeysMode = "strip" | "strict";
151
+
152
+ export type TableValidationOptions = {
153
+ unknownKeys?: TableUnknownKeysMode;
154
+ };
155
+
124
156
  export interface Table<
125
157
  TColumns extends Record<string, AnyColumn> = Record<string, AnyColumn>,
126
158
  TRelations extends Record<string, AnyRelation> = Record<string, AnyRelation>,
127
159
  TIndexes extends Record<string, Index> = Record<string, Index>,
128
160
  > {
161
+ /**
162
+ * Standard Schema-compatible validator for insert values.
163
+ */
164
+ "~standard": StandardSchemaV1.Props<
165
+ TableInsertValuesFromColumns<TColumns>,
166
+ TableInsertValuesFromColumns<TColumns>
167
+ >;
129
168
  name: string;
130
- ormName: string;
131
169
 
132
170
  columns: TColumns;
133
171
  relations: TRelations;
134
172
  indexes: TIndexes;
135
173
 
174
+ /**
175
+ * Validate insert values at runtime.
176
+ */
177
+ validate: (
178
+ value: unknown,
179
+ options?: TableValidationOptions,
180
+ ) => TableInsertValuesFromColumns<TColumns>;
181
+
136
182
  /**
137
183
  * Get column by name
138
184
  */
@@ -201,7 +247,6 @@ export type TypeMap = {
201
247
  export class Column<TType extends keyof TypeMap, TIn = unknown, TOut = unknown> {
202
248
  type: TType;
203
249
  name: string = "";
204
- ormName: string = "";
205
250
  isNullable: boolean = false;
206
251
  role: "external-id" | "internal-id" | "version" | "reference" | "regular" = "regular";
207
252
  isHidden: boolean = false;
@@ -419,9 +464,13 @@ export class VersionColumn<TIn = unknown, TOut = unknown> extends Column<"intege
419
464
  }
420
465
  }
421
466
 
467
+ type ColumnInput<TType extends keyof TypeMap> =
468
+ | TypeMap[TType]
469
+ | (TType extends "timestamp" | "date" ? DbNow : never);
470
+
422
471
  export function column<TType extends keyof TypeMap>(
423
472
  type: TType,
424
- ): Column<TType, TypeMap[TType], TypeMap[TType]> {
473
+ ): Column<TType, ColumnInput<TType>, TypeMap[TType]> {
425
474
  return new Column(type);
426
475
  }
427
476
 
@@ -577,6 +626,8 @@ export class FragnoReference {
577
626
  }
578
627
  }
579
628
 
629
+ const validationClasses = { FragnoId, FragnoReference };
630
+
580
631
  type RelationType = "one" | "many";
581
632
 
582
633
  export class TableBuilder<
@@ -588,7 +639,6 @@ export class TableBuilder<
588
639
  #columns: TColumns;
589
640
  #relations: TRelations;
590
641
  #indexes: TIndexes;
591
- #ormName: string = "";
592
642
  #columnOrder: string[] = [];
593
643
 
594
644
  constructor(name: string) {
@@ -624,7 +674,7 @@ export class TableBuilder<
624
674
  * Add a column to the table.
625
675
  */
626
676
  addColumn<TColumnName extends string, TColumn extends AnyColumn>(
627
- ormName: TColumnName,
677
+ name: TColumnName,
628
678
  col: TColumn,
629
679
  ): TableBuilder<TColumns & Record<TColumnName, TColumn>, TRelations, TIndexes>;
630
680
 
@@ -632,28 +682,27 @@ export class TableBuilder<
632
682
  * Add a column to the table with simplified syntax.
633
683
  */
634
684
  addColumn<TColumnName extends string, TType extends keyof TypeMap>(
635
- ormName: TColumnName,
685
+ name: TColumnName,
636
686
  type: TType,
637
687
  ): TableBuilder<
638
- TColumns & Record<TColumnName, Column<TType, TypeMap[TType], TypeMap[TType]>>,
688
+ TColumns & Record<TColumnName, Column<TType, ColumnInput<TType>, TypeMap[TType]>>,
639
689
  TRelations,
640
690
  TIndexes
641
691
  >;
642
692
 
643
693
  addColumn<TColumnName extends string, TColumn extends AnyColumn, TType extends keyof TypeMap>(
644
- ormName: TColumnName,
694
+ name: TColumnName,
645
695
  colOrType: TColumn | TType,
646
696
  ): TableBuilder<TColumns & Record<TColumnName, TColumn>, TRelations, TIndexes> {
647
697
  // Create the column if a type string was provided
648
698
  const col = typeof colOrType === "string" ? column(colOrType) : colOrType;
649
699
 
650
700
  // Set column metadata
651
- col.ormName = ormName;
652
- col.name = ormName;
701
+ col.name = name;
653
702
 
654
703
  // Add column directly to this builder
655
- this.#columns[ormName] = col as unknown as TColumns[TColumnName];
656
- this.#columnOrder.push(ormName);
704
+ this.#columns[name] = col as unknown as TColumns[TColumnName];
705
+ this.#columnOrder.push(name);
657
706
 
658
707
  return this as unknown as TableBuilder<
659
708
  TColumns & Record<TColumnName, TColumn>,
@@ -714,7 +763,6 @@ export class TableBuilder<
714
763
  // Auto-add _internalId and _version columns if not already present
715
764
  if (!this.#columns["_internalId"]) {
716
765
  const col = internalIdColumn();
717
- col.ormName = "_internalId";
718
766
  col.name = "_internalId";
719
767
  // Safe: we're adding system columns to the internal columns object
720
768
  (this.#columns as Record<string, AnyColumn>)["_internalId"] = col;
@@ -722,18 +770,13 @@ export class TableBuilder<
722
770
 
723
771
  if (!this.#columns["_version"]) {
724
772
  const col = versionColumn();
725
- col.ormName = "_version";
726
773
  col.name = "_version";
727
774
  // Safe: we're adding system columns to the internal columns object
728
775
  (this.#columns as Record<string, AnyColumn>)["_version"] = col;
729
776
  }
730
777
 
731
- // Use name as ormName if ormName is not set
732
- const ormName = this.#ormName || this.#name;
733
-
734
- const table: Table<TColumns, TRelations, TIndexes> = {
778
+ const table = {
735
779
  name: this.#name,
736
- ormName,
737
780
  columns: this.#columns,
738
781
  relations: this.#relations,
739
782
  indexes: this.#indexes,
@@ -749,7 +792,10 @@ export class TableBuilder<
749
792
  getVersionColumn: () => {
750
793
  return versionCol!;
751
794
  },
752
- };
795
+ } as Table<TColumns, TRelations, TIndexes>;
796
+
797
+ table["~standard"] = createTableStandardSchemaProps(table, validationClasses);
798
+ table.validate = createTableValidator(table, validationClasses);
753
799
 
754
800
  // Set table reference and find special columns
755
801
  for (const k in this.#columns) {
@@ -785,6 +831,10 @@ export class TableBuilder<
785
831
  }
786
832
 
787
833
  export interface Schema<TTables extends Record<string, AnyTable> = Record<string, AnyTable>> {
834
+ /**
835
+ * @description The name of the schema (required).
836
+ */
837
+ name: string;
788
838
  /**
789
839
  * @description The version of the schema, automatically incremented on each change.
790
840
  */
@@ -849,11 +899,15 @@ type ColumnsToTuple<
849
899
  } & AnyColumn[];
850
900
 
851
901
  export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
902
+ #name: string;
852
903
  #tables: TTables;
853
904
  #version: number = 0;
854
905
  #operations: SchemaOperation[] = [];
906
+ #tableNames: Set<string> = new Set();
907
+ #indexNames: Set<string> = new Set();
855
908
 
856
- constructor(existingSchema?: Schema<TTables>) {
909
+ constructor(name: string, existingSchema?: Schema<TTables>) {
910
+ this.#name = name;
857
911
  if (existingSchema) {
858
912
  this.#tables = existingSchema.tables;
859
913
  this.#version = existingSchema.version;
@@ -861,6 +915,29 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
861
915
  } else {
862
916
  this.#tables = {} as TTables;
863
917
  }
918
+
919
+ for (const table of Object.values(this.#tables)) {
920
+ this.#registerTableName(table.name);
921
+ for (const index of Object.values(table.indexes)) {
922
+ this.#registerIndexName(index.name, table.name);
923
+ }
924
+ }
925
+ }
926
+
927
+ #registerTableName(name: string): void {
928
+ if (this.#tableNames.has(name)) {
929
+ throw new Error(`Duplicate table name "${name}" in schema "${this.#name}".`);
930
+ }
931
+ this.#tableNames.add(name);
932
+ }
933
+
934
+ #registerIndexName(name: string, tableName: string): void {
935
+ if (this.#indexNames.has(name)) {
936
+ throw new Error(
937
+ `Duplicate index name "${name}" in schema "${this.#name}". Index names must be unique across tables (conflict on "${tableName}").`,
938
+ );
939
+ }
940
+ this.#indexNames.add(name);
864
941
  }
865
942
 
866
943
  /**
@@ -869,7 +946,7 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
869
946
  *
870
947
  * @example
871
948
  * ```ts
872
- * const builder = new SchemaBuilder()
949
+ * const builder = new SchemaBuilder("combined")
873
950
  * .add(userSchema)
874
951
  * .add(postSchema)
875
952
  * .addTable("comments", ...);
@@ -878,10 +955,32 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
878
955
  mergeWithExistingSchema<TNewTables extends Record<string, AnyTable>>(
879
956
  schema: Schema<TNewTables>,
880
957
  ): SchemaBuilder<TTables & TNewTables> {
958
+ for (const table of Object.values(schema.tables)) {
959
+ if (this.#tableNames.has(table.name)) {
960
+ throw new Error(
961
+ `Duplicate table name "${table.name}" in schema "${this.#name}" when merging.`,
962
+ );
963
+ }
964
+ for (const index of Object.values(table.indexes)) {
965
+ if (this.#indexNames.has(index.name)) {
966
+ throw new Error(
967
+ `Duplicate index name "${index.name}" in schema "${this.#name}" when merging (conflict on "${table.name}").`,
968
+ );
969
+ }
970
+ }
971
+ }
972
+
881
973
  this.#tables = { ...this.#tables, ...schema.tables } as TTables & TNewTables;
882
974
  this.#operations = [...this.#operations, ...schema.operations];
883
975
  this.#version += schema.version;
884
976
 
977
+ for (const table of Object.values(schema.tables)) {
978
+ this.#tableNames.add(table.name);
979
+ for (const index of Object.values(table.indexes)) {
980
+ this.#indexNames.add(index.name);
981
+ }
982
+ }
983
+
885
984
  return this as unknown as SchemaBuilder<TTables & TNewTables>;
886
985
  }
887
986
 
@@ -894,7 +993,7 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
894
993
  TRelations extends Record<string, AnyRelation>,
895
994
  TIndexes extends Record<string, Index> = Record<string, Index>,
896
995
  >(
897
- ormName: TTableName,
996
+ name: TTableName,
898
997
  callback: (
899
998
  builder: TableBuilder<
900
999
  Record<string, AnyColumn>,
@@ -905,10 +1004,22 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
905
1004
  ): SchemaBuilder<TTables & Record<TTableName, Table<TColumns, TRelations, TIndexes>>> {
906
1005
  this.#version++;
907
1006
 
908
- const tableBuilder = new TableBuilder(ormName);
1007
+ if (this.#tableNames.has(name)) {
1008
+ throw new Error(`Duplicate table name "${name}" in schema "${this.#name}".`);
1009
+ }
1010
+
1011
+ const tableBuilder = new TableBuilder(name);
909
1012
  const result = callback(tableBuilder);
910
1013
  const builtTable = result.build();
911
- builtTable.ormName = ormName;
1014
+ const indexNames = result.getIndexes().map((idx) => idx.name);
1015
+
1016
+ for (const indexName of indexNames) {
1017
+ if (this.#indexNames.has(indexName)) {
1018
+ throw new Error(
1019
+ `Duplicate index name "${indexName}" in schema "${this.#name}". Index names must be unique across tables (conflict on "${name}").`,
1020
+ );
1021
+ }
1022
+ }
912
1023
 
913
1024
  // Collect sub-operations in order
914
1025
  const subOperations: TableSubOperation[] = [];
@@ -945,7 +1056,7 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
945
1056
  subOperations.push({
946
1057
  type: "add-index",
947
1058
  name: idx.name,
948
- columns: idx.columns.map((c) => c.ormName),
1059
+ columns: idx.columns.map((c) => c.name),
949
1060
  unique: idx.unique,
950
1061
  });
951
1062
  }
@@ -953,13 +1064,17 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
953
1064
  // Add the add-table operation
954
1065
  this.#operations.push({
955
1066
  type: "add-table",
956
- tableName: ormName,
1067
+ tableName: name,
957
1068
  operations: subOperations,
958
1069
  });
959
1070
 
960
1071
  // Update tables map
961
- this.#tables = { ...this.#tables, [ormName]: builtTable } as TTables &
1072
+ this.#tables = { ...this.#tables, [name]: builtTable } as TTables &
962
1073
  Record<TTableName, Table<TColumns, TRelations, TIndexes>>;
1074
+ this.#tableNames.add(name);
1075
+ for (const indexName of indexNames) {
1076
+ this.#indexNames.add(indexName);
1077
+ }
963
1078
 
964
1079
  return this as unknown as SchemaBuilder<
965
1080
  TTables & Record<TTableName, Table<TColumns, TRelations, TIndexes>>
@@ -975,7 +1090,7 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
975
1090
  * @example
976
1091
  * ```ts
977
1092
  * // One-to-one or many-to-one: post -> user
978
- * schema(s => s
1093
+ * schema("blog", s => s
979
1094
  * .addTable("users", t => t.addColumn("id", idColumn()))
980
1095
  * .addTable("posts", t => t
981
1096
  * .addColumn("id", idColumn())
@@ -1028,6 +1143,10 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1028
1143
  const table = this.#tables[config.from.table];
1029
1144
  const referencedTable = this.#tables[config.to.table];
1030
1145
 
1146
+ if (!referenceName || referenceName.trim().length === 0) {
1147
+ throw new Error(`referenceName is required for addReference on ${config.from.table}`);
1148
+ }
1149
+
1031
1150
  if (!table) {
1032
1151
  throw new Error(`Table ${config.from.table} not found in schema`);
1033
1152
  }
@@ -1052,6 +1171,10 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1052
1171
  throw new Error(`Column ${actualTargetColumnName} not found in table ${config.to.table}`);
1053
1172
  }
1054
1173
 
1174
+ if (table.relations[referenceName]) {
1175
+ throw new Error(`Reference ${referenceName} already exists on table ${config.from.table}`);
1176
+ }
1177
+
1055
1178
  // Verify that reference columns are bigint (matching internal ID type)
1056
1179
  if (column.role === "reference" && column.type !== "bigint") {
1057
1180
  throw new Error(
@@ -1096,7 +1219,7 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1096
1219
  * @example
1097
1220
  * ```ts
1098
1221
  * // Add a new column to an existing table
1099
- * schema(s => s
1222
+ * schema("blog", s => s
1100
1223
  * .addTable("users", t => t
1101
1224
  * .addColumn("id", idColumn())
1102
1225
  * .addColumn("name", column("string")))
@@ -1166,10 +1289,15 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1166
1289
  // Add only new indexes
1167
1290
  for (const idx of resultBuilder.getIndexes()) {
1168
1291
  if (!existingIndexes.has(idx.name)) {
1292
+ if (this.#indexNames.has(idx.name)) {
1293
+ throw new Error(
1294
+ `Duplicate index name "${idx.name}" in schema "${this.#name}". Index names must be unique across tables (conflict on "${tableName}").`,
1295
+ );
1296
+ }
1169
1297
  subOperations.push({
1170
1298
  type: "add-index",
1171
1299
  name: idx.name,
1172
- columns: idx.columns.map((c) => c.ormName),
1300
+ columns: idx.columns.map((c) => c.name),
1173
1301
  unique: idx.unique,
1174
1302
  });
1175
1303
  }
@@ -1186,6 +1314,11 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1186
1314
 
1187
1315
  // Update table reference in schema
1188
1316
  this.#tables[tableName] = newTable as unknown as TTables[TTableName];
1317
+ for (const idx of resultBuilder.getIndexes()) {
1318
+ if (!existingIndexes.has(idx.name)) {
1319
+ this.#indexNames.add(idx.name);
1320
+ }
1321
+ }
1189
1322
 
1190
1323
  // Set table name for all columns
1191
1324
  for (const col of Object.values(newTable.columns)) {
@@ -1206,6 +1339,7 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1206
1339
  const tables = this.#tables;
1207
1340
 
1208
1341
  const schema: Schema<TTables> = {
1342
+ name: this.#name,
1209
1343
  version,
1210
1344
  tables,
1211
1345
  operations,
@@ -1229,7 +1363,6 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1229
1363
  }
1230
1364
 
1231
1365
  clonedCol.name = col.name;
1232
- clonedCol.ormName = col.ormName;
1233
1366
  clonedCol.isNullable = col.isNullable;
1234
1367
  clonedCol.role = col.role;
1235
1368
  clonedCol.isHidden = col.isHidden;
@@ -1238,20 +1371,28 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1238
1371
  clonedColumns[colName] = clonedCol;
1239
1372
  }
1240
1373
 
1241
- cloneTables[k] = {
1374
+ const clonedTable = {
1242
1375
  ...v,
1243
1376
  columns: clonedColumns,
1244
- };
1377
+ } as AnyTable;
1378
+
1379
+ clonedTable["~standard"] = createTableStandardSchemaProps(clonedTable, validationClasses);
1380
+ clonedTable.validate = createTableValidator(clonedTable, validationClasses);
1381
+
1382
+ cloneTables[k] = clonedTable;
1245
1383
  }
1246
1384
 
1247
- return new SchemaBuilder<TTables>({
1385
+ const clonedSchema: Schema<TTables> = {
1386
+ name: this.#name,
1248
1387
  version,
1249
1388
  tables: cloneTables as TTables,
1250
1389
  operations: [...operations],
1251
1390
  clone: () => {
1252
1391
  throw new Error("Cannot clone during clone");
1253
1392
  },
1254
- }).build();
1393
+ };
1394
+
1395
+ return new SchemaBuilder<TTables>(this.#name, clonedSchema).build();
1255
1396
  },
1256
1397
  };
1257
1398
 
@@ -1270,19 +1411,18 @@ export class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {
1270
1411
  * Create a new schema with callback pattern.
1271
1412
  */
1272
1413
  export function schema<const TTables extends Record<string, AnyTable> = {}>(
1414
+ name: string,
1273
1415
  callback: (builder: SchemaBuilder<{}>) => SchemaBuilder<TTables>,
1274
1416
  ): Schema<TTables> {
1275
- return callback(new SchemaBuilder()).build();
1417
+ return callback(new SchemaBuilder(name)).build();
1276
1418
  }
1277
1419
 
1278
- export function compileForeignKey(key: ForeignKey, nameType: "sql" | "orm" = "orm") {
1420
+ export function compileForeignKey(key: ForeignKey) {
1279
1421
  return {
1280
1422
  name: key.name,
1281
- table: nameType === "sql" ? key.table.name : key.table.ormName,
1282
- referencedTable: nameType === "sql" ? key.referencedTable.name : key.referencedTable.ormName,
1283
- referencedColumns: key.referencedColumns.map((col) =>
1284
- nameType === "sql" ? col.name : col.ormName,
1285
- ),
1286
- columns: key.columns.map((col) => (nameType === "sql" ? col.name : col.ormName)),
1423
+ table: key.table.name,
1424
+ referencedTable: key.referencedTable.name,
1425
+ referencedColumns: key.referencedColumns.map((col) => col.name),
1426
+ columns: key.columns.map((col) => col.name),
1287
1427
  };
1288
1428
  }
@@ -0,0 +1,57 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { schema, idColumn, FragnoId } from "./create";
3
+ import { generateId } from "./generate-id";
4
+
5
+ describe("generateId", () => {
6
+ const testSchema = schema("test", (s) =>
7
+ s.addTable("users", (t) =>
8
+ t.addColumn("id", idColumn()).addColumn("email", "string").addColumn("name", "string"),
9
+ ),
10
+ );
11
+
12
+ it("should generate a new FragnoId", () => {
13
+ const id = generateId(testSchema, "users");
14
+
15
+ expect(id).toBeInstanceOf(FragnoId);
16
+ expect(id.externalId).toBeDefined();
17
+ expect(typeof id.externalId).toBe("string");
18
+ expect(id.externalId.length).toBeGreaterThan(0);
19
+ expect(id.version).toBe(0);
20
+ });
21
+
22
+ it("should generate unique IDs on each call", () => {
23
+ const id1 = generateId(testSchema, "users");
24
+ const id2 = generateId(testSchema, "users");
25
+
26
+ expect(id1.externalId).not.toBe(id2.externalId);
27
+ });
28
+
29
+ it("should throw for non-existent table", () => {
30
+ expect(() => {
31
+ // @ts-expect-error - testing runtime error for non-existent table
32
+ generateId(testSchema, "nonexistent");
33
+ }).toThrow("Table nonexistent not found in schema");
34
+ });
35
+
36
+ it("should work with multiple tables", () => {
37
+ const multiTableSchema = schema("multitable", (s) =>
38
+ s
39
+ .addTable("users", (t) =>
40
+ t.addColumn("id", idColumn()).addColumn("email", "string").addColumn("name", "string"),
41
+ )
42
+ .addTable("posts", (t) =>
43
+ t
44
+ .addColumn("id", idColumn())
45
+ .addColumn("title", "string")
46
+ .addColumn("authorId", "string"),
47
+ ),
48
+ );
49
+
50
+ const userId = generateId(multiTableSchema, "users");
51
+ const postId = generateId(multiTableSchema, "posts");
52
+
53
+ expect(userId).toBeInstanceOf(FragnoId);
54
+ expect(postId).toBeInstanceOf(FragnoId);
55
+ expect(userId.externalId).not.toBe(postId.externalId);
56
+ });
57
+ });
@@ -0,0 +1,38 @@
1
+ import type { AnySchema } from "./create";
2
+ import { FragnoId } from "./create";
3
+
4
+ /**
5
+ * Generate a new ID for a table without creating a record.
6
+ * This is useful when you need to reference an ID before actually creating the record,
7
+ * or when you need to pass the ID to external services.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const userId = generateId(mySchema, "users");
12
+ * // Use userId in related records or pass to external services
13
+ * uow.create("users", { id: userId, name: "John" });
14
+ * ```
15
+ */
16
+ export function generateId<
17
+ TSchema extends AnySchema,
18
+ TableName extends keyof TSchema["tables"] & string,
19
+ >(schema: TSchema, tableName: TableName): FragnoId {
20
+ const tableSchema = schema.tables[tableName];
21
+ if (!tableSchema) {
22
+ throw new Error(`Table ${tableName} not found in schema`);
23
+ }
24
+
25
+ const idColumn = tableSchema.getIdColumn();
26
+ const generated = idColumn.generateDefaultValue();
27
+ if (generated === undefined) {
28
+ throw new Error(`ID column ${idColumn.name} on table ${tableName} has no default generator`);
29
+ }
30
+
31
+ if (typeof generated !== "string") {
32
+ throw new Error(
33
+ `ID column ${idColumn.name} on table ${tableName} has no default generator that generates a string.`,
34
+ );
35
+ }
36
+
37
+ return FragnoId.fromExternal(generated, 0);
38
+ }
@@ -131,7 +131,17 @@ describe("serialize", () => {
131
131
  it("should convert string timestamps to Date", () => {
132
132
  const timestampCol = column("timestamp");
133
133
  const time = "2024-01-01 12:30:45.123";
134
- expect(deserialize(time, timestampCol, "postgresql")).toEqual(new Date(time));
134
+ const result = deserialize(time, timestampCol, "postgresql");
135
+ assert.instanceOf(result, Date);
136
+ expect(result.toISOString()).toBe("2024-01-01T12:30:45.123Z");
137
+ });
138
+
139
+ it("should treat timezone-less ISO timestamps as UTC", () => {
140
+ const timestampCol = column("timestamp");
141
+ const time = "2024-01-01T12:30:45.123";
142
+ const result = deserialize(time, timestampCol, "postgresql");
143
+ assert.instanceOf(result, Date);
144
+ expect(result.toISOString()).toBe("2024-01-01T12:30:45.123Z");
135
145
  });
136
146
 
137
147
  it("should convert ISO string timestamps to Date", () => {
@@ -262,7 +272,9 @@ describe("serialize", () => {
262
272
  it("should convert string timestamps to Date", () => {
263
273
  const timestampCol = column("timestamp");
264
274
  const time = "2024-01-01 12:30:45.123";
265
- expect(deserialize(time, timestampCol, "cockroachdb")).toEqual(new Date(time));
275
+ const result = deserialize(time, timestampCol, "cockroachdb");
276
+ assert.instanceOf(result, Date);
277
+ expect(result.toISOString()).toBe("2024-01-01T12:30:45.123Z");
266
278
  });
267
279
 
268
280
  it("should convert date strings to Date", () => {
@@ -1,4 +1,5 @@
1
1
  import type { SupportedDatabase } from "../../adapters/generic-sql/driver-config";
2
+ import type { SQLiteStorageMode } from "../../adapters/generic-sql/sqlite-storage";
2
3
  import { PostgreSQLTypeMapper } from "./dialect/postgres";
3
4
  import { MySQLTypeMapper } from "./dialect/mysql";
4
5
  import { SQLiteTypeMapper } from "./dialect/sqlite";
@@ -10,16 +11,20 @@ import { SQLiteTypeMapper } from "./dialect/sqlite";
10
11
  * (PostgreSQL, MySQL, or SQLite).
11
12
  *
12
13
  * @param database - The database type (sqlite, postgresql, or mysql)
14
+ * @param sqliteStorageMode - Optional SQLite storage mode override
13
15
  * @returns Dialect-specific SQLTypeMapper instance
14
16
  */
15
- export function createSQLTypeMapper(database: SupportedDatabase) {
17
+ export function createSQLTypeMapper(
18
+ database: SupportedDatabase,
19
+ sqliteStorageMode?: SQLiteStorageMode,
20
+ ) {
16
21
  switch (database) {
17
22
  case "postgresql":
18
23
  return new PostgreSQLTypeMapper(database);
19
24
  case "mysql":
20
25
  return new MySQLTypeMapper(database);
21
26
  case "sqlite":
22
- return new SQLiteTypeMapper(database);
27
+ return new SQLiteTypeMapper(database, sqliteStorageMode);
23
28
  default: {
24
29
  const exhaustiveCheck: never = database;
25
30
  throw new Error(`Unsupported database type: ${exhaustiveCheck}`);