@fragno-dev/db 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) hide show
  1. package/.turbo/turbo-build.log +202 -140
  2. package/CHANGELOG.md +35 -0
  3. package/README.md +30 -9
  4. package/dist/adapters/adapters.d.ts +23 -21
  5. package/dist/adapters/adapters.d.ts.map +1 -1
  6. package/dist/adapters/adapters.js.map +1 -1
  7. package/dist/adapters/generic-sql/driver-config.d.ts +16 -1
  8. package/dist/adapters/generic-sql/driver-config.d.ts.map +1 -1
  9. package/dist/adapters/generic-sql/driver-config.js +23 -1
  10. package/dist/adapters/generic-sql/driver-config.js.map +1 -1
  11. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts +27 -9
  12. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -1
  13. package/dist/adapters/generic-sql/generic-sql-adapter.js +55 -16
  14. package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -1
  15. package/dist/adapters/generic-sql/generic-sql-uow-executor.js +129 -3
  16. package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -1
  17. package/dist/adapters/generic-sql/migration/dialect/mysql.js +24 -5
  18. package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -1
  19. package/dist/adapters/generic-sql/migration/dialect/postgres.js +6 -5
  20. package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -1
  21. package/dist/adapters/generic-sql/migration/dialect/sqlite.js +21 -10
  22. package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -1
  23. package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -1
  24. package/dist/adapters/generic-sql/migration/prepared-migrations.js +8 -8
  25. package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -1
  26. package/dist/adapters/generic-sql/migration/sql-generator.js +74 -51
  27. package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -1
  28. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +6 -5
  29. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -1
  30. package/dist/adapters/generic-sql/query/cursor-utils.js +42 -4
  31. package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -1
  32. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +25 -17
  33. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -1
  34. package/dist/adapters/generic-sql/query/select-builder.js +5 -3
  35. package/dist/adapters/generic-sql/query/select-builder.js.map +1 -1
  36. package/dist/adapters/generic-sql/query/sql-query-compiler.js +15 -12
  37. package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -1
  38. package/dist/adapters/generic-sql/query/where-builder.js +39 -29
  39. package/dist/adapters/generic-sql/query/where-builder.js.map +1 -1
  40. package/dist/adapters/generic-sql/sqlite-storage.d.ts +13 -0
  41. package/dist/adapters/generic-sql/sqlite-storage.d.ts.map +1 -0
  42. package/dist/adapters/generic-sql/sqlite-storage.js +15 -0
  43. package/dist/adapters/generic-sql/sqlite-storage.js.map +1 -0
  44. package/dist/adapters/generic-sql/uow-decoder.js +7 -3
  45. package/dist/adapters/generic-sql/uow-decoder.js.map +1 -1
  46. package/dist/adapters/generic-sql/uow-encoder.js +28 -8
  47. package/dist/adapters/generic-sql/uow-encoder.js.map +1 -1
  48. package/dist/adapters/in-memory/condition-evaluator.js +131 -0
  49. package/dist/adapters/in-memory/condition-evaluator.js.map +1 -0
  50. package/dist/adapters/in-memory/errors.d.ts +13 -0
  51. package/dist/adapters/in-memory/errors.d.ts.map +1 -0
  52. package/dist/adapters/in-memory/errors.js +23 -0
  53. package/dist/adapters/in-memory/errors.js.map +1 -0
  54. package/dist/adapters/in-memory/in-memory-adapter.d.ts +27 -0
  55. package/dist/adapters/in-memory/in-memory-adapter.d.ts.map +1 -0
  56. package/dist/adapters/in-memory/in-memory-adapter.js +176 -0
  57. package/dist/adapters/in-memory/in-memory-adapter.js.map +1 -0
  58. package/dist/adapters/in-memory/in-memory-uow.js +648 -0
  59. package/dist/adapters/in-memory/in-memory-uow.js.map +1 -0
  60. package/dist/adapters/in-memory/index.d.ts +4 -0
  61. package/dist/adapters/in-memory/index.js +4 -0
  62. package/dist/adapters/in-memory/options.d.ts +28 -0
  63. package/dist/adapters/in-memory/options.d.ts.map +1 -0
  64. package/dist/adapters/in-memory/options.js +61 -0
  65. package/dist/adapters/in-memory/options.js.map +1 -0
  66. package/dist/adapters/in-memory/reference-resolution.js +26 -0
  67. package/dist/adapters/in-memory/reference-resolution.js.map +1 -0
  68. package/dist/adapters/in-memory/sorted-array-index.js +129 -0
  69. package/dist/adapters/in-memory/sorted-array-index.js.map +1 -0
  70. package/dist/adapters/in-memory/store.js +71 -0
  71. package/dist/adapters/in-memory/store.js.map +1 -0
  72. package/dist/adapters/in-memory/value-comparison.js +28 -0
  73. package/dist/adapters/in-memory/value-comparison.js.map +1 -0
  74. package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -1
  75. package/dist/adapters/shared/uow-operation-compiler.js +11 -11
  76. package/dist/adapters/shared/uow-operation-compiler.js.map +1 -1
  77. package/dist/adapters/sql/index.d.ts +5 -0
  78. package/dist/adapters/sql/index.js +4 -0
  79. package/dist/db-fragment-definition-builder.d.ts +18 -7
  80. package/dist/db-fragment-definition-builder.d.ts.map +1 -1
  81. package/dist/db-fragment-definition-builder.js +116 -54
  82. package/dist/db-fragment-definition-builder.js.map +1 -1
  83. package/dist/dispatchers/cloudflare-do/index.d.ts +26 -0
  84. package/dist/dispatchers/cloudflare-do/index.d.ts.map +1 -0
  85. package/dist/dispatchers/cloudflare-do/index.js +63 -0
  86. package/dist/dispatchers/cloudflare-do/index.js.map +1 -0
  87. package/dist/dispatchers/node/index.d.ts +17 -0
  88. package/dist/dispatchers/node/index.d.ts.map +1 -0
  89. package/dist/dispatchers/node/index.js +59 -0
  90. package/dist/dispatchers/node/index.js.map +1 -0
  91. package/dist/fragments/internal-fragment.d.ts +79 -2
  92. package/dist/fragments/internal-fragment.d.ts.map +1 -1
  93. package/dist/fragments/internal-fragment.js +150 -32
  94. package/dist/fragments/internal-fragment.js.map +1 -1
  95. package/dist/fragments/internal-fragment.routes.js +29 -0
  96. package/dist/fragments/internal-fragment.routes.js.map +1 -0
  97. package/dist/fragments/internal-fragment.schema.d.ts +9 -0
  98. package/dist/fragments/internal-fragment.schema.d.ts.map +1 -0
  99. package/dist/fragments/internal-fragment.schema.js +22 -0
  100. package/dist/fragments/internal-fragment.schema.js.map +1 -0
  101. package/dist/hooks/durable-hooks-processor.d.ts +14 -0
  102. package/dist/hooks/durable-hooks-processor.d.ts.map +1 -0
  103. package/dist/hooks/durable-hooks-processor.js +32 -0
  104. package/dist/hooks/durable-hooks-processor.js.map +1 -0
  105. package/dist/hooks/hooks.d.ts +42 -1
  106. package/dist/hooks/hooks.d.ts.map +1 -1
  107. package/dist/hooks/hooks.js +72 -6
  108. package/dist/hooks/hooks.js.map +1 -1
  109. package/dist/migration-engine/auto-from-schema.js +14 -11
  110. package/dist/migration-engine/auto-from-schema.js.map +1 -1
  111. package/dist/migration-engine/generation-engine.d.ts +16 -10
  112. package/dist/migration-engine/generation-engine.d.ts.map +1 -1
  113. package/dist/migration-engine/generation-engine.js +72 -33
  114. package/dist/migration-engine/generation-engine.js.map +1 -1
  115. package/dist/migration-engine/shared.js.map +1 -1
  116. package/dist/mod.d.ts +15 -8
  117. package/dist/mod.d.ts.map +1 -1
  118. package/dist/mod.js +14 -8
  119. package/dist/mod.js.map +1 -1
  120. package/dist/naming/sql-naming.d.ts +19 -0
  121. package/dist/naming/sql-naming.d.ts.map +1 -0
  122. package/dist/naming/sql-naming.js +116 -0
  123. package/dist/naming/sql-naming.js.map +1 -0
  124. package/dist/node_modules/.pnpm/{rou3@0.7.10 → rou3@0.7.12}/node_modules/rou3/dist/index.js +8 -5
  125. package/dist/node_modules/.pnpm/rou3@0.7.12/node_modules/rou3/dist/index.js.map +1 -0
  126. package/dist/outbox/outbox-builder.js +156 -0
  127. package/dist/outbox/outbox-builder.js.map +1 -0
  128. package/dist/outbox/outbox.d.ts +52 -0
  129. package/dist/outbox/outbox.d.ts.map +1 -0
  130. package/dist/outbox/outbox.js +37 -0
  131. package/dist/outbox/outbox.js.map +1 -0
  132. package/dist/packages/fragno/dist/api/fragment-definition-builder.js +3 -2
  133. package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +1 -1
  134. package/dist/packages/fragno/dist/api/fragment-instantiator.js +164 -20
  135. package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -1
  136. package/dist/packages/fragno/dist/api/request-input-context.js +67 -0
  137. package/dist/packages/fragno/dist/api/request-input-context.js.map +1 -1
  138. package/dist/packages/fragno/dist/api/route.js +14 -1
  139. package/dist/packages/fragno/dist/api/route.js.map +1 -1
  140. package/dist/packages/fragno/dist/internal/trace-context.js +12 -0
  141. package/dist/packages/fragno/dist/internal/trace-context.js.map +1 -0
  142. package/dist/query/column-defaults.js +20 -4
  143. package/dist/query/column-defaults.js.map +1 -1
  144. package/dist/query/cursor.d.ts +3 -1
  145. package/dist/query/cursor.d.ts.map +1 -1
  146. package/dist/query/cursor.js +45 -14
  147. package/dist/query/cursor.js.map +1 -1
  148. package/dist/query/db-now.d.ts +8 -0
  149. package/dist/query/db-now.d.ts.map +1 -0
  150. package/dist/query/db-now.js +7 -0
  151. package/dist/query/db-now.js.map +1 -0
  152. package/dist/query/serialize/create-sql-serializer.js +3 -2
  153. package/dist/query/serialize/create-sql-serializer.js.map +1 -1
  154. package/dist/query/serialize/dialect/mysql-serializer.js +12 -6
  155. package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -1
  156. package/dist/query/serialize/dialect/postgres-serializer.js +25 -7
  157. package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -1
  158. package/dist/query/serialize/dialect/sqlite-serializer.js +55 -11
  159. package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -1
  160. package/dist/query/serialize/sql-serializer.js +2 -2
  161. package/dist/query/serialize/sql-serializer.js.map +1 -1
  162. package/dist/query/simple-query-interface.d.ts +6 -1
  163. package/dist/query/simple-query-interface.d.ts.map +1 -1
  164. package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -1
  165. package/dist/query/unit-of-work/execute-unit-of-work.js +11 -6
  166. package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -1
  167. package/dist/query/unit-of-work/unit-of-work.d.ts +50 -14
  168. package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
  169. package/dist/query/unit-of-work/unit-of-work.js +86 -5
  170. package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
  171. package/dist/query/value-decoding.js +9 -6
  172. package/dist/query/value-decoding.js.map +1 -1
  173. package/dist/query/value-encoding.js +29 -9
  174. package/dist/query/value-encoding.js.map +1 -1
  175. package/dist/schema/create.d.ts +38 -14
  176. package/dist/schema/create.d.ts.map +1 -1
  177. package/dist/schema/create.js +81 -42
  178. package/dist/schema/create.js.map +1 -1
  179. package/dist/schema/generate-id.js +2 -2
  180. package/dist/schema/generate-id.js.map +1 -1
  181. package/dist/schema/type-conversion/create-sql-type-mapper.js +3 -2
  182. package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -1
  183. package/dist/schema/type-conversion/dialect/sqlite.js +9 -0
  184. package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -1
  185. package/dist/schema/validator.d.ts +10 -0
  186. package/dist/schema/validator.d.ts.map +1 -0
  187. package/dist/schema/validator.js +123 -0
  188. package/dist/schema/validator.js.map +1 -0
  189. package/dist/schema-output/drizzle.d.ts +30 -0
  190. package/dist/schema-output/drizzle.d.ts.map +1 -0
  191. package/dist/{adapters/drizzle/generate.js → schema-output/drizzle.js} +82 -56
  192. package/dist/schema-output/drizzle.js.map +1 -0
  193. package/dist/schema-output/prisma.d.ts +17 -0
  194. package/dist/schema-output/prisma.d.ts.map +1 -0
  195. package/dist/schema-output/prisma.js +296 -0
  196. package/dist/schema-output/prisma.js.map +1 -0
  197. package/dist/util/default-database-adapter.js +61 -0
  198. package/dist/util/default-database-adapter.js.map +1 -0
  199. package/dist/with-database.d.ts +1 -1
  200. package/dist/with-database.d.ts.map +1 -1
  201. package/dist/with-database.js +12 -3
  202. package/dist/with-database.js.map +1 -1
  203. package/package.json +43 -28
  204. package/src/adapters/adapters.ts +30 -24
  205. package/src/adapters/drizzle/migrate-drizzle.test.ts +54 -33
  206. package/src/adapters/drizzle/migration-parity-drizzle-kit.test.ts +599 -0
  207. package/src/adapters/drizzle/test-utils.ts +12 -8
  208. package/src/adapters/generic-sql/driver-config.ts +38 -0
  209. package/src/adapters/generic-sql/generic-sql-adapter.test.ts +5 -5
  210. package/src/adapters/generic-sql/generic-sql-adapter.ts +110 -24
  211. package/src/adapters/generic-sql/generic-sql-uow-executor.test.ts +54 -0
  212. package/src/adapters/generic-sql/generic-sql-uow-executor.ts +231 -3
  213. package/src/adapters/generic-sql/migration/adapter-migration-parity.test.ts +118 -0
  214. package/src/adapters/generic-sql/migration/dialect/mysql.test.ts +26 -8
  215. package/src/adapters/generic-sql/migration/dialect/mysql.ts +46 -8
  216. package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +25 -7
  217. package/src/adapters/generic-sql/migration/dialect/postgres.ts +8 -4
  218. package/src/adapters/generic-sql/migration/dialect/sqlite.test.ts +47 -8
  219. package/src/adapters/generic-sql/migration/dialect/sqlite.ts +27 -12
  220. package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +128 -39
  221. package/src/adapters/generic-sql/migration/prepared-migrations.ts +15 -8
  222. package/src/adapters/generic-sql/migration/sql-generator.ts +142 -65
  223. package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +9 -6
  224. package/src/adapters/generic-sql/query/cursor-utils.test.ts +271 -0
  225. package/src/adapters/generic-sql/query/cursor-utils.ts +41 -6
  226. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +27 -27
  227. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +38 -24
  228. package/src/adapters/generic-sql/query/select-builder.test.ts +15 -11
  229. package/src/adapters/generic-sql/query/select-builder.ts +6 -2
  230. package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +52 -2
  231. package/src/adapters/generic-sql/query/sql-query-compiler.ts +50 -15
  232. package/src/adapters/generic-sql/query/where-builder.test.ts +91 -17
  233. package/src/adapters/generic-sql/query/where-builder.ts +90 -38
  234. package/src/adapters/{kysely/kysely-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-migrations.test.ts} +6 -6
  235. package/src/adapters/generic-sql/sql-adapter-pglite-pagination.test.ts +806 -0
  236. package/src/adapters/{drizzle/drizzle-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-queries.test.ts} +11 -11
  237. package/src/adapters/generic-sql/{test/generic-drizzle-adapter-sqlite3.test.ts → sql-adapter-sqlite3-driver.test.ts} +10 -10
  238. package/src/adapters/{drizzle/drizzle-adapter-sqlite3.test.ts → generic-sql/sql-adapter-sqlite3-uow.test.ts} +7 -7
  239. package/src/adapters/{kysely/kysely-adapter-sqlocal.test.ts → generic-sql/sql-adapter-sqlocal.test.ts} +6 -6
  240. package/src/adapters/generic-sql/sqlite-storage.ts +20 -0
  241. package/src/adapters/generic-sql/uow-decoder.test.ts +1 -1
  242. package/src/adapters/generic-sql/uow-decoder.ts +21 -3
  243. package/src/adapters/generic-sql/uow-encoder.test.ts +33 -2
  244. package/src/adapters/generic-sql/uow-encoder.ts +50 -11
  245. package/src/adapters/in-memory/condition-evaluator.test.ts +193 -0
  246. package/src/adapters/in-memory/condition-evaluator.ts +275 -0
  247. package/src/adapters/in-memory/errors.ts +20 -0
  248. package/src/adapters/in-memory/in-memory-adapter.ts +277 -0
  249. package/src/adapters/in-memory/in-memory-uow.mutations.test.ts +296 -0
  250. package/src/adapters/in-memory/in-memory-uow.retrieval.test.ts +100 -0
  251. package/src/adapters/in-memory/in-memory-uow.ts +1348 -0
  252. package/src/adapters/in-memory/index.ts +3 -0
  253. package/src/adapters/in-memory/options.test.ts +41 -0
  254. package/src/adapters/in-memory/options.ts +87 -0
  255. package/src/adapters/in-memory/reference-resolution.test.ts +50 -0
  256. package/src/adapters/in-memory/reference-resolution.ts +67 -0
  257. package/src/adapters/in-memory/sorted-array-index.test.ts +123 -0
  258. package/src/adapters/in-memory/sorted-array-index.ts +228 -0
  259. package/src/adapters/in-memory/store.test.ts +68 -0
  260. package/src/adapters/in-memory/store.ts +145 -0
  261. package/src/adapters/in-memory/value-comparison.ts +53 -0
  262. package/src/adapters/in-memory/value-normalization.test.ts +57 -0
  263. package/src/adapters/prisma/prisma-adapter-sqlite3.test.ts +1163 -0
  264. package/src/adapters/shared/from-unit-of-work-compiler.ts +3 -1
  265. package/src/adapters/shared/uow-operation-compiler.ts +26 -16
  266. package/src/adapters/sql/index.ts +12 -0
  267. package/src/db-fragment-definition-builder.test.ts +30 -12
  268. package/src/db-fragment-definition-builder.ts +142 -73
  269. package/src/db-fragment-instantiator.test.ts +105 -13
  270. package/src/db-fragment-integration.test.ts +9 -7
  271. package/src/dispatchers/cloudflare-do/index.test.ts +73 -0
  272. package/src/dispatchers/cloudflare-do/index.ts +104 -0
  273. package/src/dispatchers/node/index.test.ts +91 -0
  274. package/src/dispatchers/node/index.ts +87 -0
  275. package/src/fragments/internal-fragment.routes.ts +42 -0
  276. package/src/fragments/internal-fragment.schema.ts +51 -0
  277. package/src/fragments/internal-fragment.test.ts +458 -8
  278. package/src/fragments/internal-fragment.ts +322 -63
  279. package/src/hooks/durable-hooks-processor.test.ts +117 -0
  280. package/src/hooks/durable-hooks-processor.ts +67 -0
  281. package/src/hooks/hooks.test.ts +165 -5
  282. package/src/hooks/hooks.ts +197 -9
  283. package/src/migration-engine/auto-from-schema.test.ts +14 -14
  284. package/src/migration-engine/auto-from-schema.ts +5 -2
  285. package/src/migration-engine/create.test.ts +2 -2
  286. package/src/migration-engine/generation-engine.test.ts +229 -104
  287. package/src/migration-engine/generation-engine.ts +94 -64
  288. package/src/migration-engine/shared.ts +1 -0
  289. package/src/mod.ts +64 -26
  290. package/src/naming/sql-naming.ts +180 -0
  291. package/src/outbox/outbox-builder.ts +241 -0
  292. package/src/outbox/outbox.test.ts +253 -0
  293. package/src/outbox/outbox.ts +137 -0
  294. package/src/query/column-defaults.ts +41 -3
  295. package/src/query/condition-builder.test.ts +3 -3
  296. package/src/query/cursor.test.ts +116 -18
  297. package/src/query/cursor.ts +75 -26
  298. package/src/query/db-now.ts +6 -0
  299. package/src/query/query-type.test.ts +2 -2
  300. package/src/query/serialize/create-sql-serializer.ts +7 -2
  301. package/src/query/serialize/dialect/mysql-serializer.ts +12 -4
  302. package/src/query/serialize/dialect/postgres-serializer.ts +34 -4
  303. package/src/query/serialize/dialect/sqlite-serializer.test.ts +51 -1
  304. package/src/query/serialize/dialect/sqlite-serializer.ts +92 -9
  305. package/src/query/serialize/sql-serializer.ts +4 -4
  306. package/src/query/simple-query-interface.ts +5 -0
  307. package/src/query/unit-of-work/execute-unit-of-work.test.ts +25 -1
  308. package/src/query/unit-of-work/execute-unit-of-work.ts +25 -8
  309. package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +12 -12
  310. package/src/query/unit-of-work/unit-of-work-types.test.ts +1 -1
  311. package/src/query/unit-of-work/unit-of-work.test.ts +168 -37
  312. package/src/query/unit-of-work/unit-of-work.ts +203 -18
  313. package/src/query/value-decoding.test.ts +13 -2
  314. package/src/query/value-decoding.ts +17 -4
  315. package/src/query/value-encoding.test.ts +85 -2
  316. package/src/query/value-encoding.ts +56 -6
  317. package/src/schema/create.test.ts +129 -42
  318. package/src/schema/create.ts +185 -47
  319. package/src/schema/generate-id.test.ts +2 -2
  320. package/src/schema/generate-id.ts +2 -2
  321. package/src/schema/serialize.test.ts +14 -2
  322. package/src/schema/type-conversion/create-sql-type-mapper.ts +7 -2
  323. package/src/schema/type-conversion/dialect/sqlite.ts +18 -0
  324. package/src/schema/type-conversion/type-mapping.test.ts +25 -1
  325. package/src/schema/validator.test.ts +197 -0
  326. package/src/schema/validator.ts +231 -0
  327. package/src/{adapters/drizzle/generate.test.ts → schema-output/drizzle.test.ts} +179 -129
  328. package/src/{adapters/drizzle/generate.ts → schema-output/drizzle.ts} +143 -93
  329. package/src/schema-output/prisma.test.ts +536 -0
  330. package/src/schema-output/prisma.ts +573 -0
  331. package/src/util/default-database-adapter.ts +106 -0
  332. package/src/with-database.ts +22 -3
  333. package/tsdown.config.ts +6 -4
  334. package/dist/adapters/drizzle/drizzle-adapter.d.ts +0 -20
  335. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +0 -1
  336. package/dist/adapters/drizzle/drizzle-adapter.js +0 -27
  337. package/dist/adapters/drizzle/drizzle-adapter.js.map +0 -1
  338. package/dist/adapters/drizzle/generate.d.ts +0 -30
  339. package/dist/adapters/drizzle/generate.d.ts.map +0 -1
  340. package/dist/adapters/drizzle/generate.js.map +0 -1
  341. package/dist/adapters/kysely/kysely-adapter.d.ts +0 -19
  342. package/dist/adapters/kysely/kysely-adapter.d.ts.map +0 -1
  343. package/dist/adapters/kysely/kysely-adapter.js +0 -17
  344. package/dist/adapters/kysely/kysely-adapter.js.map +0 -1
  345. package/dist/adapters/shared/table-name-mapper.d.ts +0 -12
  346. package/dist/adapters/shared/table-name-mapper.d.ts.map +0 -1
  347. package/dist/adapters/shared/table-name-mapper.js +0 -43
  348. package/dist/adapters/shared/table-name-mapper.js.map +0 -1
  349. package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js.map +0 -1
  350. package/dist/schema-generator/schema-generator.d.ts +0 -15
  351. package/dist/schema-generator/schema-generator.d.ts.map +0 -1
  352. package/src/adapters/drizzle/drizzle-adapter.ts +0 -39
  353. package/src/adapters/kysely/kysely-adapter.ts +0 -27
  354. package/src/adapters/shared/table-name-mapper.ts +0 -50
  355. package/src/schema-generator/schema-generator.ts +0 -12
@@ -0,0 +1,536 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { column, idColumn, referenceColumn, schema } from "../schema/create";
3
+ import { internalSchema } from "../fragments/internal-fragment";
4
+ import { generatePrismaSchema } from "./prisma";
5
+ import { sqliteStorageDefault, sqliteStoragePrisma } from "../adapters/generic-sql/sqlite-storage";
6
+
7
+ const blogSchema = schema("blog", (s) => {
8
+ return s
9
+ .addTable("users", (t) => {
10
+ return t
11
+ .addColumn("id", idColumn())
12
+ .addColumn("email", column("string"))
13
+ .addColumn(
14
+ "createdAt",
15
+ column("timestamp").defaultTo((b) => b.now()),
16
+ )
17
+ .addColumn("birthDate", column("date").nullable())
18
+ .addColumn("profile", column("json").nullable())
19
+ .addColumn("bigScore", column("bigint"))
20
+ .addColumn("reputation", column("decimal"))
21
+ .addColumn("invitedBy", referenceColumn().nullable())
22
+ .createIndex("idx_email", ["email"], { unique: true });
23
+ })
24
+ .addTable("posts", (t) => {
25
+ return t
26
+ .addColumn("id", idColumn())
27
+ .addColumn("title", column("string"))
28
+ .addColumn("authorId", referenceColumn())
29
+ .addColumn("editorId", referenceColumn().nullable())
30
+ .addColumn("publishedAt", column("timestamp").nullable())
31
+ .createIndex("idx_title", ["title"]);
32
+ })
33
+ .addReference("author", {
34
+ type: "one",
35
+ from: { table: "posts", column: "authorId" },
36
+ to: { table: "users", column: "id" },
37
+ })
38
+ .addReference("editor", {
39
+ type: "one",
40
+ from: { table: "posts", column: "editorId" },
41
+ to: { table: "users", column: "id" },
42
+ })
43
+ .addReference("inviter", {
44
+ type: "one",
45
+ from: { table: "users", column: "invitedBy" },
46
+ to: { table: "users", column: "id" },
47
+ })
48
+ .addReference("posts", {
49
+ type: "many",
50
+ from: { table: "users", column: "id" },
51
+ to: { table: "posts", column: "authorId" },
52
+ });
53
+ });
54
+
55
+ const weirdNamesSchema = schema("weirdnames", (s) => {
56
+ return s.addTable("user-profiles", (t) => {
57
+ return t
58
+ .addColumn("id", idColumn())
59
+ .addColumn("user-id", column("string"))
60
+ .addColumn("display name", column("string").nullable())
61
+ .createIndex("user-id-index", ["user-id"]);
62
+ });
63
+ });
64
+
65
+ const relationNamingSchema = schema("relationnaming", (s) => {
66
+ return s
67
+ .addTable("users", (t) => {
68
+ return t.addColumn("id", idColumn()).addColumn("name", column("string"));
69
+ })
70
+ .addTable("posts", (t) => {
71
+ return t
72
+ .addColumn("id", idColumn())
73
+ .addColumn("author_id", referenceColumn())
74
+ .addColumn("editor_id", referenceColumn().nullable());
75
+ })
76
+ .addTable("comments", (t) => {
77
+ return t
78
+ .addColumn("id", idColumn())
79
+ .addColumn("post_id", referenceColumn())
80
+ .addColumn("parent_id", referenceColumn().nullable());
81
+ })
82
+ .addTable("follows", (t) => {
83
+ return t
84
+ .addColumn("id", idColumn())
85
+ .addColumn("follower_id", referenceColumn())
86
+ .addColumn("followee_id", referenceColumn());
87
+ })
88
+ .addReference("author", {
89
+ type: "one",
90
+ from: { table: "posts", column: "author_id" },
91
+ to: { table: "users", column: "id" },
92
+ })
93
+ .addReference("editor", {
94
+ type: "one",
95
+ from: { table: "posts", column: "editor_id" },
96
+ to: { table: "users", column: "id" },
97
+ })
98
+ .addReference("post", {
99
+ type: "one",
100
+ from: { table: "comments", column: "post_id" },
101
+ to: { table: "posts", column: "id" },
102
+ })
103
+ .addReference("parent", {
104
+ type: "one",
105
+ from: { table: "comments", column: "parent_id" },
106
+ to: { table: "comments", column: "id" },
107
+ })
108
+ .addReference("follower", {
109
+ type: "one",
110
+ from: { table: "follows", column: "follower_id" },
111
+ to: { table: "users", column: "id" },
112
+ })
113
+ .addReference("followee", {
114
+ type: "one",
115
+ from: { table: "follows", column: "followee_id" },
116
+ to: { table: "users", column: "id" },
117
+ })
118
+ .addReference("posts", {
119
+ type: "many",
120
+ from: { table: "users", column: "id" },
121
+ to: { table: "posts", column: "author_id" },
122
+ })
123
+ .addReference("editedPosts", {
124
+ type: "many",
125
+ from: { table: "users", column: "id" },
126
+ to: { table: "posts", column: "editor_id" },
127
+ });
128
+ });
129
+
130
+ describe("generatePrismaSchema", () => {
131
+ it("should generate stable ordering for internal models and namespaces", () => {
132
+ const alphaSchema = schema("alpha", (s) => {
133
+ return s
134
+ .addTable("zeta", (t) => t.addColumn("id", idColumn()))
135
+ .addTable("alpha", (t) => t.addColumn("id", idColumn()));
136
+ });
137
+
138
+ const bravoSchema = schema("bravo", (s) => {
139
+ return s.addTable("bravo", (t) => t.addColumn("id", idColumn()));
140
+ });
141
+
142
+ const generated = generatePrismaSchema(
143
+ [
144
+ { namespace: "bravo", schema: bravoSchema },
145
+ { namespace: null, schema: internalSchema },
146
+ { namespace: "alpha", schema: alphaSchema },
147
+ ],
148
+ "sqlite",
149
+ { sqliteStorageMode: sqliteStoragePrisma },
150
+ );
151
+
152
+ const settingsIndex = generated.indexOf("model FragnoDbSettings");
153
+ const hooksIndex = generated.indexOf("model FragnoHooks");
154
+ const outboxIndex = generated.indexOf("model FragnoDbOutbox");
155
+ const alphaIndex = generated.indexOf("model Alpha_alpha");
156
+ const zetaIndex = generated.indexOf("model Zeta_alpha");
157
+ const bravoIndex = generated.indexOf("model Bravo_bravo");
158
+
159
+ expect(settingsIndex).toBeGreaterThanOrEqual(0);
160
+ expect(hooksIndex).toBeGreaterThanOrEqual(0);
161
+ expect(outboxIndex).toBeGreaterThanOrEqual(0);
162
+ expect(alphaIndex).toBeGreaterThanOrEqual(0);
163
+ expect(zetaIndex).toBeGreaterThanOrEqual(0);
164
+ expect(bravoIndex).toBeGreaterThanOrEqual(0);
165
+
166
+ expect(outboxIndex).toBeLessThan(settingsIndex);
167
+ expect(settingsIndex).toBeLessThan(hooksIndex);
168
+ expect(hooksIndex).toBeLessThan(alphaIndex);
169
+ expect(alphaIndex).toBeLessThan(zetaIndex);
170
+ expect(zetaIndex).toBeLessThan(bravoIndex);
171
+ });
172
+ it("should generate SQLite Prisma schema", () => {
173
+ const generated = generatePrismaSchema(
174
+ [
175
+ { namespace: null, schema: internalSchema },
176
+ { namespace: "blog", schema: blogSchema },
177
+ ],
178
+ "sqlite",
179
+ { sqliteStorageMode: sqliteStoragePrisma },
180
+ );
181
+
182
+ expect(generated).toMatchInlineSnapshot(`
183
+ "// Generated by Fragno Prisma adapter.
184
+ // Provider: sqlite
185
+ // Namespaces: blog
186
+
187
+ model FragnoDbOutbox {
188
+ id String @unique @default(cuid())
189
+ versionstamp String
190
+ uowId String
191
+ payload Json
192
+ refMap Json?
193
+ createdAt DateTime @default(now())
194
+ _internalId Int @id @default(autoincrement())
195
+ _version Int @default(0)
196
+ @@index([uowId], map: "idx_fragno_db_outbox_idx_outbox_uow_733c7f90")
197
+ @@unique([versionstamp], map: "uidx_fragno_db_outbox_idx_outbox_versionstamp_37972a68")
198
+ @@map("fragno_db_outbox")
199
+ }
200
+
201
+ model FragnoDbSettings {
202
+ id String @unique @default(cuid())
203
+ key String
204
+ value String
205
+ _internalId Int @id @default(autoincrement())
206
+ _version Int @default(0)
207
+ @@unique([key], map: "uidx_fragno_db_settings_unique_key_09269db3")
208
+ @@map("fragno_db_settings")
209
+ }
210
+
211
+ model FragnoHooks {
212
+ id String @unique @default(cuid())
213
+ namespace String
214
+ hookName String
215
+ payload Json
216
+ status String
217
+ attempts Int @default(0)
218
+ maxAttempts Int @default(5)
219
+ lastAttemptAt DateTime?
220
+ nextRetryAt DateTime?
221
+ error String?
222
+ createdAt DateTime @default(now())
223
+ nonce String
224
+ _internalId Int @id @default(autoincrement())
225
+ _version Int @default(0)
226
+ @@index([namespace, status, nextRetryAt], map: "idx_fragno_hooks_idx_namespace_status_retry_b66b1168")
227
+ @@index([nonce], map: "idx_fragno_hooks_idx_nonce_90c97cf1")
228
+ @@map("fragno_hooks")
229
+ }
230
+
231
+ model Posts_blog {
232
+ id String @unique @default(cuid())
233
+ title String
234
+ authorId Int
235
+ editorId Int?
236
+ publishedAt DateTime?
237
+ _internalId Int @id @default(autoincrement())
238
+ _version Int @default(0)
239
+ author Users_blog @relation("blog_posts_author_users", fields: [authorId], references: [_internalId], map: "fk_posts_users_author_blog_d01fe02e")
240
+ editor Users_blog? @relation("blog_posts_editor_users", fields: [editorId], references: [_internalId], map: "fk_posts_users_editor_blog_d7abc235")
241
+ @@index([title], map: "idx_posts_idx_title_blog_f90cbb7e")
242
+ @@map("posts_blog")
243
+ }
244
+
245
+ model Users_blog {
246
+ id String @unique @default(cuid())
247
+ email String
248
+ createdAt DateTime @default(now())
249
+ birthDate DateTime?
250
+ profile Json?
251
+ bigScore BigInt
252
+ reputation Float
253
+ invitedBy Int?
254
+ _internalId Int @id @default(autoincrement())
255
+ _version Int @default(0)
256
+ inviter Users_blog? @relation("blog_users_inviter_users", fields: [invitedBy], references: [_internalId], map: "fk_users_users_inviter_blog_631afc1c")
257
+ posts Posts_blog[] @relation("blog_posts_author_users")
258
+ posts_editor Posts_blog[] @relation("blog_posts_editor_users")
259
+ users Users_blog[] @relation("blog_users_inviter_users")
260
+ @@unique([email], map: "uidx_users_idx_email_blog_4468050e")
261
+ @@map("users_blog")
262
+ }"
263
+ `);
264
+ });
265
+
266
+ it("should generate SQLite Prisma schema for default storage mode", () => {
267
+ const generated = generatePrismaSchema(
268
+ [
269
+ { namespace: null, schema: internalSchema },
270
+ { namespace: "blog", schema: blogSchema },
271
+ ],
272
+ "sqlite",
273
+ { sqliteStorageMode: sqliteStorageDefault },
274
+ );
275
+
276
+ expect(generated).toMatchInlineSnapshot(`
277
+ "// Generated by Fragno Prisma adapter.
278
+ // Provider: sqlite
279
+ // Namespaces: blog
280
+
281
+ model FragnoDbOutbox {
282
+ id String @unique @default(cuid())
283
+ versionstamp String
284
+ uowId String
285
+ payload Json
286
+ refMap Json?
287
+ createdAt Int @default(dbgenerated("CURRENT_TIMESTAMP"))
288
+ _internalId Int @id @default(autoincrement())
289
+ _version Int @default(0)
290
+ @@index([uowId], map: "idx_fragno_db_outbox_idx_outbox_uow_733c7f90")
291
+ @@unique([versionstamp], map: "uidx_fragno_db_outbox_idx_outbox_versionstamp_37972a68")
292
+ @@map("fragno_db_outbox")
293
+ }
294
+
295
+ model FragnoDbSettings {
296
+ id String @unique @default(cuid())
297
+ key String
298
+ value String
299
+ _internalId Int @id @default(autoincrement())
300
+ _version Int @default(0)
301
+ @@unique([key], map: "uidx_fragno_db_settings_unique_key_09269db3")
302
+ @@map("fragno_db_settings")
303
+ }
304
+
305
+ model FragnoHooks {
306
+ id String @unique @default(cuid())
307
+ namespace String
308
+ hookName String
309
+ payload Json
310
+ status String
311
+ attempts Int @default(0)
312
+ maxAttempts Int @default(5)
313
+ lastAttemptAt Int?
314
+ nextRetryAt Int?
315
+ error String?
316
+ createdAt Int @default(dbgenerated("CURRENT_TIMESTAMP"))
317
+ nonce String
318
+ _internalId Int @id @default(autoincrement())
319
+ _version Int @default(0)
320
+ @@index([namespace, status, nextRetryAt], map: "idx_fragno_hooks_idx_namespace_status_retry_b66b1168")
321
+ @@index([nonce], map: "idx_fragno_hooks_idx_nonce_90c97cf1")
322
+ @@map("fragno_hooks")
323
+ }
324
+
325
+ model Posts_blog {
326
+ id String @unique @default(cuid())
327
+ title String
328
+ authorId Int
329
+ editorId Int?
330
+ publishedAt Int?
331
+ _internalId Int @id @default(autoincrement())
332
+ _version Int @default(0)
333
+ author Users_blog @relation("blog_posts_author_users", fields: [authorId], references: [_internalId], map: "fk_posts_users_author_blog_d01fe02e")
334
+ editor Users_blog? @relation("blog_posts_editor_users", fields: [editorId], references: [_internalId], map: "fk_posts_users_editor_blog_d7abc235")
335
+ @@index([title], map: "idx_posts_idx_title_blog_f90cbb7e")
336
+ @@map("posts_blog")
337
+ }
338
+
339
+ model Users_blog {
340
+ id String @unique @default(cuid())
341
+ email String
342
+ createdAt Int @default(dbgenerated("CURRENT_TIMESTAMP"))
343
+ birthDate Int?
344
+ profile Json?
345
+ bigScore Bytes
346
+ reputation Float
347
+ invitedBy Int?
348
+ _internalId Int @id @default(autoincrement())
349
+ _version Int @default(0)
350
+ inviter Users_blog? @relation("blog_users_inviter_users", fields: [invitedBy], references: [_internalId], map: "fk_users_users_inviter_blog_631afc1c")
351
+ posts Posts_blog[] @relation("blog_posts_author_users")
352
+ posts_editor Posts_blog[] @relation("blog_posts_editor_users")
353
+ users Users_blog[] @relation("blog_users_inviter_users")
354
+ @@unique([email], map: "uidx_users_idx_email_blog_4468050e")
355
+ @@map("users_blog")
356
+ }"
357
+ `);
358
+ });
359
+
360
+ it("should generate PostgreSQL (PGLite) Prisma schema", () => {
361
+ const generated = generatePrismaSchema(
362
+ [
363
+ { namespace: null, schema: internalSchema },
364
+ { namespace: "blog", schema: blogSchema },
365
+ ],
366
+ "postgresql",
367
+ );
368
+
369
+ expect(generated).toMatchInlineSnapshot(`
370
+ "// Generated by Fragno Prisma adapter.
371
+ // Provider: postgresql
372
+ // Namespaces: blog
373
+
374
+ model FragnoDbOutbox {
375
+ id String @unique @default(cuid()) @db.VarChar(30)
376
+ versionstamp String
377
+ uowId String
378
+ payload Json @db.Json
379
+ refMap Json? @db.Json
380
+ createdAt DateTime @default(now())
381
+ _internalId BigInt @id @default(autoincrement())
382
+ _version Int @default(0)
383
+ @@index([uowId], map: "idx_outbox_uow")
384
+ @@unique([versionstamp], map: "idx_outbox_versionstamp")
385
+ @@map("fragno_db_outbox")
386
+ }
387
+
388
+ model FragnoDbSettings {
389
+ id String @unique @default(cuid()) @db.VarChar(30)
390
+ key String
391
+ value String
392
+ _internalId BigInt @id @default(autoincrement())
393
+ _version Int @default(0)
394
+ @@unique([key], map: "unique_key")
395
+ @@map("fragno_db_settings")
396
+ }
397
+
398
+ model FragnoHooks {
399
+ id String @unique @default(cuid()) @db.VarChar(30)
400
+ namespace String
401
+ hookName String
402
+ payload Json @db.Json
403
+ status String
404
+ attempts Int @default(0)
405
+ maxAttempts Int @default(5)
406
+ lastAttemptAt DateTime?
407
+ nextRetryAt DateTime?
408
+ error String?
409
+ createdAt DateTime @default(now())
410
+ nonce String
411
+ _internalId BigInt @id @default(autoincrement())
412
+ _version Int @default(0)
413
+ @@index([namespace, status, nextRetryAt], map: "idx_namespace_status_retry")
414
+ @@index([nonce], map: "idx_nonce")
415
+ @@map("fragno_hooks")
416
+ }
417
+
418
+ model Posts_blog {
419
+ id String @unique @default(cuid()) @db.VarChar(30)
420
+ title String
421
+ authorId BigInt
422
+ editorId BigInt?
423
+ publishedAt DateTime?
424
+ _internalId BigInt @id @default(autoincrement())
425
+ _version Int @default(0)
426
+ author Users_blog @relation("blog_posts_author_users", fields: [authorId], references: [_internalId], map: "fk_posts_users_author")
427
+ editor Users_blog? @relation("blog_posts_editor_users", fields: [editorId], references: [_internalId], map: "fk_posts_users_editor")
428
+ @@index([title], map: "idx_title")
429
+ @@map("posts")
430
+ }
431
+
432
+ model Users_blog {
433
+ id String @unique @default(cuid()) @db.VarChar(30)
434
+ email String
435
+ createdAt DateTime @default(now())
436
+ birthDate DateTime? @db.Date
437
+ profile Json? @db.Json
438
+ bigScore BigInt
439
+ reputation Decimal
440
+ invitedBy BigInt?
441
+ _internalId BigInt @id @default(autoincrement())
442
+ _version Int @default(0)
443
+ inviter Users_blog? @relation("blog_users_inviter_users", fields: [invitedBy], references: [_internalId], map: "fk_users_users_inviter")
444
+ posts Posts_blog[] @relation("blog_posts_author_users")
445
+ posts_editor Posts_blog[] @relation("blog_posts_editor_users")
446
+ users Users_blog[] @relation("blog_users_inviter_users")
447
+ @@unique([email], map: "idx_email")
448
+ @@map("users")
449
+ }"
450
+ `);
451
+ });
452
+
453
+ it("should sanitize namespaces and map invalid identifiers for SQLite", () => {
454
+ const generated = generatePrismaSchema(
455
+ [{ namespace: "my-app", schema: weirdNamesSchema }],
456
+ "sqlite",
457
+ { sqliteStorageMode: sqliteStoragePrisma },
458
+ );
459
+
460
+ expect(generated).toMatchInlineSnapshot(`
461
+ "// Generated by Fragno Prisma adapter.
462
+ // Provider: sqlite
463
+ // Namespaces: my-app
464
+
465
+ model UserProfiles_my_app {
466
+ id String @unique @default(cuid())
467
+ user_id String @map("user-id")
468
+ display_name String? @map("display name")
469
+ _internalId Int @id @default(autoincrement())
470
+ _version Int @default(0)
471
+ @@index([user_id], map: "idx_user-profiles_user-id-index_my-app_c295d8f4")
472
+ @@map("user-profiles_my-app")
473
+ }"
474
+ `);
475
+ });
476
+
477
+ it("should sanitize namespaces and map invalid identifiers for PostgreSQL", () => {
478
+ const generated = generatePrismaSchema(
479
+ [{ namespace: "my-app", schema: weirdNamesSchema }],
480
+ "postgresql",
481
+ );
482
+
483
+ expect(generated).toMatchInlineSnapshot(`
484
+ "// Generated by Fragno Prisma adapter.
485
+ // Provider: postgresql
486
+ // Namespaces: my-app
487
+
488
+ model UserProfiles_my_app {
489
+ id String @unique @default(cuid()) @db.VarChar(30)
490
+ user_id String @map("user-id")
491
+ display_name String? @map("display name")
492
+ _internalId BigInt @id @default(autoincrement())
493
+ _version Int @default(0)
494
+ @@index([user_id], map: "user-id-index")
495
+ @@map("user-profiles")
496
+ }"
497
+ `);
498
+ });
499
+
500
+ it("should disambiguate inverse relations for SQLite", () => {
501
+ const generated = generatePrismaSchema(
502
+ [{ namespace: "test", schema: relationNamingSchema }],
503
+ "sqlite",
504
+ { sqliteStorageMode: sqliteStoragePrisma },
505
+ );
506
+
507
+ expect(generated).toContain('posts Posts_test[] @relation("test_posts_author_users")');
508
+ expect(generated).toContain('editedPosts Posts_test[] @relation("test_posts_editor_users")');
509
+ expect(generated).toContain('comments Comments_test[] @relation("test_comments_post_posts")');
510
+ expect(generated).toContain(
511
+ 'comments Comments_test[] @relation("test_comments_parent_comments")',
512
+ );
513
+ expect(generated).toContain('follows Follows_test[] @relation("test_follows_followee_users")');
514
+ expect(generated).toContain(
515
+ 'follows_follower Follows_test[] @relation("test_follows_follower_users")',
516
+ );
517
+ });
518
+
519
+ it("should disambiguate inverse relations for PostgreSQL", () => {
520
+ const generated = generatePrismaSchema(
521
+ [{ namespace: "test", schema: relationNamingSchema }],
522
+ "postgresql",
523
+ );
524
+
525
+ expect(generated).toContain('posts Posts_test[] @relation("test_posts_author_users")');
526
+ expect(generated).toContain('editedPosts Posts_test[] @relation("test_posts_editor_users")');
527
+ expect(generated).toContain('comments Comments_test[] @relation("test_comments_post_posts")');
528
+ expect(generated).toContain(
529
+ 'comments Comments_test[] @relation("test_comments_parent_comments")',
530
+ );
531
+ expect(generated).toContain('follows Follows_test[] @relation("test_follows_followee_users")');
532
+ expect(generated).toContain(
533
+ 'follows_follower Follows_test[] @relation("test_follows_follower_users")',
534
+ );
535
+ });
536
+ });