neoorm 0.8.0 → 0.8.2

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 (380) hide show
  1. package/README.md +13 -6
  2. package/dist/bin/neoorm.d.ts +1 -1
  3. package/dist/bin/neoorm.d.ts.map +1 -1
  4. package/dist/bin/neoorm.js +148 -75
  5. package/dist/bin/neoorm.js.map +1 -1
  6. package/dist/codegen/diff-manifest.d.ts.map +1 -1
  7. package/dist/codegen/diff-manifest.js +106 -4
  8. package/dist/codegen/diff-manifest.js.map +1 -1
  9. package/dist/codegen/generate-summary.d.ts +5 -1
  10. package/dist/codegen/generate-summary.d.ts.map +1 -1
  11. package/dist/codegen/generate-summary.js +10 -1
  12. package/dist/codegen/generate-summary.js.map +1 -1
  13. package/dist/codegen/generate.d.ts +24 -4
  14. package/dist/codegen/generate.d.ts.map +1 -1
  15. package/dist/codegen/generate.js +150 -13
  16. package/dist/codegen/generate.js.map +1 -1
  17. package/dist/codegen/manifest-relations.d.ts +2 -0
  18. package/dist/codegen/manifest-relations.d.ts.map +1 -1
  19. package/dist/codegen/manifest-relations.js +2 -1
  20. package/dist/codegen/manifest-relations.js.map +1 -1
  21. package/dist/codegen/schema-to-manifest.d.ts +1 -1
  22. package/dist/codegen/schema-to-manifest.d.ts.map +1 -1
  23. package/dist/codegen/schema-to-manifest.js +349 -29
  24. package/dist/codegen/schema-to-manifest.js.map +1 -1
  25. package/dist/codegen/validation/emit-elysia.d.ts +4 -0
  26. package/dist/codegen/validation/emit-elysia.d.ts.map +1 -0
  27. package/dist/codegen/validation/emit-elysia.js +304 -0
  28. package/dist/codegen/validation/emit-elysia.js.map +1 -0
  29. package/dist/codegen/validation/emit-typebox.d.ts +4 -0
  30. package/dist/codegen/validation/emit-typebox.d.ts.map +1 -0
  31. package/dist/codegen/validation/emit-typebox.js +360 -0
  32. package/dist/codegen/validation/emit-typebox.js.map +1 -0
  33. package/dist/codegen/validation/emit-zod.d.ts +4 -0
  34. package/dist/codegen/validation/emit-zod.d.ts.map +1 -0
  35. package/dist/codegen/validation/emit-zod.js +288 -0
  36. package/dist/codegen/validation/emit-zod.js.map +1 -0
  37. package/dist/codegen/validation/from-manifest.d.ts +5 -0
  38. package/dist/codegen/validation/from-manifest.d.ts.map +1 -0
  39. package/dist/codegen/validation/from-manifest.js +284 -0
  40. package/dist/codegen/validation/from-manifest.js.map +1 -0
  41. package/dist/codegen/validation/infer.d.ts +47 -0
  42. package/dist/codegen/validation/infer.d.ts.map +1 -0
  43. package/dist/codegen/validation/infer.js +2 -0
  44. package/dist/codegen/validation/infer.js.map +1 -0
  45. package/dist/codegen/validation/json-generic-types.d.ts +7 -0
  46. package/dist/codegen/validation/json-generic-types.d.ts.map +1 -0
  47. package/dist/codegen/validation/json-generic-types.js +295 -0
  48. package/dist/codegen/validation/json-generic-types.js.map +1 -0
  49. package/dist/codegen/validation/types.d.ts +84 -0
  50. package/dist/codegen/validation/types.d.ts.map +1 -0
  51. package/dist/codegen/validation/types.js +6 -0
  52. package/dist/codegen/validation/types.js.map +1 -0
  53. package/dist/config.d.ts +8 -0
  54. package/dist/config.d.ts.map +1 -1
  55. package/dist/config.js +30 -0
  56. package/dist/config.js.map +1 -1
  57. package/dist/datasource-provider.d.ts +5 -1
  58. package/dist/datasource-provider.d.ts.map +1 -1
  59. package/dist/datasource-provider.js +21 -2
  60. package/dist/datasource-provider.js.map +1 -1
  61. package/dist/dialect/column-kind-support.d.ts +9 -0
  62. package/dist/dialect/column-kind-support.d.ts.map +1 -0
  63. package/dist/dialect/column-kind-support.js +25 -0
  64. package/dist/dialect/column-kind-support.js.map +1 -0
  65. package/dist/dialect/fk.d.ts +30 -1
  66. package/dist/dialect/fk.d.ts.map +1 -1
  67. package/dist/dialect/fk.js +113 -0
  68. package/dist/dialect/fk.js.map +1 -1
  69. package/dist/dialect/index.d.ts +6 -1
  70. package/dist/dialect/index.d.ts.map +1 -1
  71. package/dist/dialect/index.js +5 -0
  72. package/dist/dialect/index.js.map +1 -1
  73. package/dist/dialect/mariadb.d.ts +4 -0
  74. package/dist/dialect/mariadb.d.ts.map +1 -0
  75. package/dist/dialect/mariadb.js +15 -0
  76. package/dist/dialect/mariadb.js.map +1 -0
  77. package/dist/dialect/mariadb.test.d.ts +2 -0
  78. package/dist/dialect/mariadb.test.d.ts.map +1 -0
  79. package/dist/dialect/mariadb.test.js +151 -0
  80. package/dist/dialect/mariadb.test.js.map +1 -0
  81. package/dist/dialect/mysql-family.d.ts +14 -0
  82. package/dist/dialect/mysql-family.d.ts.map +1 -0
  83. package/dist/dialect/mysql-family.js +453 -0
  84. package/dist/dialect/mysql-family.js.map +1 -0
  85. package/dist/dialect/mysql.d.ts +6 -0
  86. package/dist/dialect/mysql.d.ts.map +1 -0
  87. package/dist/dialect/mysql.js +16 -0
  88. package/dist/dialect/mysql.js.map +1 -0
  89. package/dist/dialect/mysql.test.d.ts +2 -0
  90. package/dist/dialect/mysql.test.d.ts.map +1 -0
  91. package/dist/dialect/mysql.test.js +211 -0
  92. package/dist/dialect/mysql.test.js.map +1 -0
  93. package/dist/dialect/placeholders.d.ts +7 -0
  94. package/dist/dialect/placeholders.d.ts.map +1 -0
  95. package/dist/dialect/placeholders.js +18 -0
  96. package/dist/dialect/placeholders.js.map +1 -0
  97. package/dist/dialect/postgres.d.ts +2 -1
  98. package/dist/dialect/postgres.d.ts.map +1 -1
  99. package/dist/dialect/postgres.js +93 -30
  100. package/dist/dialect/postgres.js.map +1 -1
  101. package/dist/dialect/resolve.d.ts +13 -0
  102. package/dist/dialect/resolve.d.ts.map +1 -0
  103. package/dist/dialect/resolve.js +66 -0
  104. package/dist/dialect/resolve.js.map +1 -0
  105. package/dist/dialect/shared.d.ts +8 -1
  106. package/dist/dialect/shared.d.ts.map +1 -1
  107. package/dist/dialect/shared.js +37 -0
  108. package/dist/dialect/shared.js.map +1 -1
  109. package/dist/dialect/sqlite.d.ts.map +1 -1
  110. package/dist/dialect/sqlite.js +50 -18
  111. package/dist/dialect/sqlite.js.map +1 -1
  112. package/dist/dialect/sqlite.test.js +43 -1
  113. package/dist/dialect/sqlite.test.js.map +1 -1
  114. package/dist/dialect/types.d.ts +60 -3
  115. package/dist/dialect/types.d.ts.map +1 -1
  116. package/dist/docs/pages.d.ts.map +1 -1
  117. package/dist/docs/pages.js +5 -0
  118. package/dist/docs/pages.js.map +1 -1
  119. package/dist/docs/render.js +1 -1
  120. package/dist/index.d.ts +6 -3
  121. package/dist/index.d.ts.map +1 -1
  122. package/dist/index.js +5 -2
  123. package/dist/index.js.map +1 -1
  124. package/dist/init/scaffold.d.ts +2 -1
  125. package/dist/init/scaffold.d.ts.map +1 -1
  126. package/dist/init/scaffold.js.map +1 -1
  127. package/dist/init/templates.d.ts +3 -2
  128. package/dist/init/templates.d.ts.map +1 -1
  129. package/dist/init/templates.js +19 -9
  130. package/dist/init/templates.js.map +1 -1
  131. package/dist/introspect/group-fks.d.ts +24 -0
  132. package/dist/introspect/group-fks.d.ts.map +1 -0
  133. package/dist/introspect/group-fks.js +48 -0
  134. package/dist/introspect/group-fks.js.map +1 -0
  135. package/dist/introspect/mysql/to-manifest.d.ts +4 -0
  136. package/dist/introspect/mysql/to-manifest.d.ts.map +1 -0
  137. package/dist/introspect/mysql/to-manifest.js +317 -0
  138. package/dist/introspect/mysql/to-manifest.js.map +1 -0
  139. package/dist/introspect/pull.d.ts +1 -0
  140. package/dist/introspect/pull.d.ts.map +1 -1
  141. package/dist/introspect/pull.js +186 -9
  142. package/dist/introspect/pull.js.map +1 -1
  143. package/dist/introspect/queries.d.ts +11 -1
  144. package/dist/introspect/queries.d.ts.map +1 -1
  145. package/dist/introspect/queries.js +43 -12
  146. package/dist/introspect/queries.js.map +1 -1
  147. package/dist/introspect/sqlite/to-manifest.d.ts.map +1 -1
  148. package/dist/introspect/sqlite/to-manifest.js +99 -26
  149. package/dist/introspect/sqlite/to-manifest.js.map +1 -1
  150. package/dist/introspect/to-manifest.d.ts.map +1 -1
  151. package/dist/introspect/to-manifest.js +154 -28
  152. package/dist/introspect/to-manifest.js.map +1 -1
  153. package/dist/migrate/dev-lock.d.ts +15 -0
  154. package/dist/migrate/dev-lock.d.ts.map +1 -0
  155. package/dist/migrate/dev-lock.js +101 -0
  156. package/dist/migrate/dev-lock.js.map +1 -0
  157. package/dist/migrate/runner.d.ts.map +1 -1
  158. package/dist/migrate/runner.js +143 -51
  159. package/dist/migrate/runner.js.map +1 -1
  160. package/dist/plugins/builtin.d.ts +62 -12
  161. package/dist/plugins/builtin.d.ts.map +1 -1
  162. package/dist/plugins/builtin.js +378 -30
  163. package/dist/plugins/builtin.js.map +1 -1
  164. package/dist/plugins/index.d.ts +1 -0
  165. package/dist/plugins/index.d.ts.map +1 -1
  166. package/dist/plugins/index.js.map +1 -1
  167. package/dist/plugins/json/operators.d.ts.map +1 -1
  168. package/dist/plugins/json/operators.js +69 -3
  169. package/dist/plugins/json/operators.js.map +1 -1
  170. package/dist/plugins/postgis/columns.d.ts.map +1 -1
  171. package/dist/plugins/postgis/columns.js +52 -0
  172. package/dist/plugins/postgis/columns.js.map +1 -1
  173. package/dist/plugins/postgis/columns.test.js +13 -0
  174. package/dist/plugins/postgis/columns.test.js.map +1 -1
  175. package/dist/plugins/postgis/operators.d.ts.map +1 -1
  176. package/dist/plugins/postgis/operators.js +15 -3
  177. package/dist/plugins/postgis/operators.js.map +1 -1
  178. package/dist/plugins/types.d.ts +3 -0
  179. package/dist/plugins/types.d.ts.map +1 -1
  180. package/dist/runtime/client.d.ts +31 -4
  181. package/dist/runtime/client.d.ts.map +1 -1
  182. package/dist/runtime/client.js +131 -6
  183. package/dist/runtime/client.js.map +1 -1
  184. package/dist/runtime/driver.d.ts +2 -0
  185. package/dist/runtime/driver.d.ts.map +1 -1
  186. package/dist/runtime/driver.js +12 -0
  187. package/dist/runtime/driver.js.map +1 -1
  188. package/dist/runtime/error-hints.d.ts.map +1 -1
  189. package/dist/runtime/error-hints.js +37 -10
  190. package/dist/runtime/error-hints.js.map +1 -1
  191. package/dist/runtime/executor.d.ts +1 -0
  192. package/dist/runtime/executor.d.ts.map +1 -1
  193. package/dist/runtime/executor.js +7 -1
  194. package/dist/runtime/executor.js.map +1 -1
  195. package/dist/runtime/mariadb-driver.d.ts +25 -0
  196. package/dist/runtime/mariadb-driver.d.ts.map +1 -0
  197. package/dist/runtime/mariadb-driver.js +103 -0
  198. package/dist/runtime/mariadb-driver.js.map +1 -0
  199. package/dist/runtime/mysql-driver.d.ts +25 -0
  200. package/dist/runtime/mysql-driver.d.ts.map +1 -0
  201. package/dist/runtime/mysql-driver.js +101 -0
  202. package/dist/runtime/mysql-driver.js.map +1 -0
  203. package/dist/runtime/mysql-error.d.ts +15 -0
  204. package/dist/runtime/mysql-error.d.ts.map +1 -0
  205. package/dist/runtime/mysql-error.js +119 -0
  206. package/dist/runtime/mysql-error.js.map +1 -0
  207. package/dist/runtime/mysql-family-pool.d.ts +50 -0
  208. package/dist/runtime/mysql-family-pool.d.ts.map +1 -0
  209. package/dist/runtime/mysql-family-pool.js +52 -0
  210. package/dist/runtime/mysql-family-pool.js.map +1 -0
  211. package/dist/runtime/mysql-family-pool.test.d.ts +2 -0
  212. package/dist/runtime/mysql-family-pool.test.d.ts.map +1 -0
  213. package/dist/runtime/mysql-family-pool.test.js +169 -0
  214. package/dist/runtime/mysql-family-pool.test.js.map +1 -0
  215. package/dist/runtime/mysql-placeholders.d.ts +18 -0
  216. package/dist/runtime/mysql-placeholders.d.ts.map +1 -0
  217. package/dist/runtime/mysql-placeholders.js +133 -0
  218. package/dist/runtime/mysql-placeholders.js.map +1 -0
  219. package/dist/runtime/mysql-placeholders.test.d.ts +2 -0
  220. package/dist/runtime/mysql-placeholders.test.d.ts.map +1 -0
  221. package/dist/runtime/mysql-placeholders.test.js +33 -0
  222. package/dist/runtime/mysql-placeholders.test.js.map +1 -0
  223. package/dist/runtime/query/aggregate.d.ts.map +1 -1
  224. package/dist/runtime/query/aggregate.js +3 -3
  225. package/dist/runtime/query/aggregate.js.map +1 -1
  226. package/dist/runtime/query/compile-aggregate.d.ts +1 -1
  227. package/dist/runtime/query/compile-aggregate.d.ts.map +1 -1
  228. package/dist/runtime/query/compile-aggregate.js +33 -28
  229. package/dist/runtime/query/compile-aggregate.js.map +1 -1
  230. package/dist/runtime/query/compile-where.d.ts +9 -9
  231. package/dist/runtime/query/compile-where.d.ts.map +1 -1
  232. package/dist/runtime/query/compile-where.js +108 -76
  233. package/dist/runtime/query/compile-where.js.map +1 -1
  234. package/dist/runtime/query/compile-write.d.ts +9 -9
  235. package/dist/runtime/query/compile-write.d.ts.map +1 -1
  236. package/dist/runtime/query/compile-write.js +77 -63
  237. package/dist/runtime/query/compile-write.js.map +1 -1
  238. package/dist/runtime/query/count.d.ts.map +1 -1
  239. package/dist/runtime/query/count.js +4 -1
  240. package/dist/runtime/query/count.js.map +1 -1
  241. package/dist/runtime/query/create.d.ts.map +1 -1
  242. package/dist/runtime/query/create.js +38 -12
  243. package/dist/runtime/query/create.js.map +1 -1
  244. package/dist/runtime/query/cursor.d.ts +1 -1
  245. package/dist/runtime/query/cursor.d.ts.map +1 -1
  246. package/dist/runtime/query/cursor.js +6 -7
  247. package/dist/runtime/query/cursor.js.map +1 -1
  248. package/dist/runtime/query/delete.d.ts.map +1 -1
  249. package/dist/runtime/query/delete.js +41 -15
  250. package/dist/runtime/query/delete.js.map +1 -1
  251. package/dist/runtime/query/execute.d.ts +1 -0
  252. package/dist/runtime/query/execute.d.ts.map +1 -1
  253. package/dist/runtime/query/execute.js +23 -8
  254. package/dist/runtime/query/execute.js.map +1 -1
  255. package/dist/runtime/query/find-or-create.d.ts +1 -1
  256. package/dist/runtime/query/find-or-create.d.ts.map +1 -1
  257. package/dist/runtime/query/find-or-create.js +16 -8
  258. package/dist/runtime/query/find-or-create.js.map +1 -1
  259. package/dist/runtime/query/find.d.ts +2 -0
  260. package/dist/runtime/query/find.d.ts.map +1 -1
  261. package/dist/runtime/query/find.js +116 -68
  262. package/dist/runtime/query/find.js.map +1 -1
  263. package/dist/runtime/query/group-by.d.ts.map +1 -1
  264. package/dist/runtime/query/group-by.js.map +1 -1
  265. package/dist/runtime/query/mutation-returning.d.ts +10 -0
  266. package/dist/runtime/query/mutation-returning.d.ts.map +1 -0
  267. package/dist/runtime/query/mutation-returning.js +85 -0
  268. package/dist/runtime/query/mutation-returning.js.map +1 -0
  269. package/dist/runtime/query/paginate.d.ts.map +1 -1
  270. package/dist/runtime/query/paginate.js +3 -3
  271. package/dist/runtime/query/paginate.js.map +1 -1
  272. package/dist/runtime/query/projection.d.ts.map +1 -1
  273. package/dist/runtime/query/projection.js +1 -1
  274. package/dist/runtime/query/projection.js.map +1 -1
  275. package/dist/runtime/query/relation-join.d.ts +5 -0
  276. package/dist/runtime/query/relation-join.d.ts.map +1 -0
  277. package/dist/runtime/query/relation-join.js +26 -0
  278. package/dist/runtime/query/relation-join.js.map +1 -0
  279. package/dist/runtime/query/relation-planner.d.ts +1 -1
  280. package/dist/runtime/query/relation-planner.d.ts.map +1 -1
  281. package/dist/runtime/query/relation-planner.js +72 -58
  282. package/dist/runtime/query/relation-planner.js.map +1 -1
  283. package/dist/runtime/query/relation-writes.d.ts +2 -2
  284. package/dist/runtime/query/relation-writes.d.ts.map +1 -1
  285. package/dist/runtime/query/relation-writes.js +272 -116
  286. package/dist/runtime/query/relation-writes.js.map +1 -1
  287. package/dist/runtime/query/table-index.d.ts +1 -1
  288. package/dist/runtime/query/table-index.d.ts.map +1 -1
  289. package/dist/runtime/query/table-index.js +17 -10
  290. package/dist/runtime/query/table-index.js.map +1 -1
  291. package/dist/runtime/query/unique.d.ts +3 -0
  292. package/dist/runtime/query/unique.d.ts.map +1 -1
  293. package/dist/runtime/query/unique.js +26 -6
  294. package/dist/runtime/query/unique.js.map +1 -1
  295. package/dist/runtime/query/unique.test.js +110 -7
  296. package/dist/runtime/query/unique.test.js.map +1 -1
  297. package/dist/runtime/query/update.d.ts.map +1 -1
  298. package/dist/runtime/query/update.js +89 -23
  299. package/dist/runtime/query/update.js.map +1 -1
  300. package/dist/runtime/query/updated-at.js +2 -2
  301. package/dist/runtime/query/updated-at.js.map +1 -1
  302. package/dist/runtime/query/upsert.d.ts.map +1 -1
  303. package/dist/runtime/query/upsert.js +29 -5
  304. package/dist/runtime/query/upsert.js.map +1 -1
  305. package/dist/runtime/sqlite-open.js +1 -1
  306. package/dist/runtime/sqlite-open.js.map +1 -1
  307. package/dist/runtime/transaction.d.ts +1 -0
  308. package/dist/runtime/transaction.d.ts.map +1 -1
  309. package/dist/runtime/transaction.js +8 -0
  310. package/dist/runtime/transaction.js.map +1 -1
  311. package/dist/runtime/types.d.ts +10 -2
  312. package/dist/runtime/types.d.ts.map +1 -1
  313. package/dist/schema/column-constraints.d.ts +26 -0
  314. package/dist/schema/column-constraints.d.ts.map +1 -0
  315. package/dist/schema/column-constraints.js +143 -0
  316. package/dist/schema/column-constraints.js.map +1 -0
  317. package/dist/schema/column.d.ts +92 -3
  318. package/dist/schema/column.d.ts.map +1 -1
  319. package/dist/schema/column.js +17 -11
  320. package/dist/schema/column.js.map +1 -1
  321. package/dist/schema/index.d.ts +9 -6
  322. package/dist/schema/index.d.ts.map +1 -1
  323. package/dist/schema/index.js +8 -2
  324. package/dist/schema/index.js.map +1 -1
  325. package/dist/schema/json-column.d.ts +9 -0
  326. package/dist/schema/json-column.d.ts.map +1 -0
  327. package/dist/schema/json-column.js +11 -0
  328. package/dist/schema/json-column.js.map +1 -0
  329. package/dist/schema/many-to-many.d.ts +1 -1
  330. package/dist/schema/many-to-many.d.ts.map +1 -1
  331. package/dist/schema/nested-relation-types.d.ts +10 -9
  332. package/dist/schema/nested-relation-types.d.ts.map +1 -1
  333. package/dist/schema/relation-types.d.ts +80 -19
  334. package/dist/schema/relation-types.d.ts.map +1 -1
  335. package/dist/schema/relation.d.ts +11 -1
  336. package/dist/schema/relation.d.ts.map +1 -1
  337. package/dist/schema/relation.js +6 -0
  338. package/dist/schema/relation.js.map +1 -1
  339. package/dist/schema/table.d.ts +74 -11
  340. package/dist/schema/table.d.ts.map +1 -1
  341. package/dist/schema/table.js +93 -7
  342. package/dist/schema/table.js.map +1 -1
  343. package/dist/schema/types.d.ts +7 -6
  344. package/dist/schema/types.d.ts.map +1 -1
  345. package/dist/sql/builder.d.ts +13 -3
  346. package/dist/sql/builder.d.ts.map +1 -1
  347. package/dist/sql/builder.js +155 -5
  348. package/dist/sql/builder.js.map +1 -1
  349. package/dist/sql/index.d.ts +1 -0
  350. package/dist/sql/index.d.ts.map +1 -1
  351. package/dist/sql/index.js.map +1 -1
  352. package/dist/sql/qualify-tables.d.ts +15 -0
  353. package/dist/sql/qualify-tables.d.ts.map +1 -0
  354. package/dist/sql/qualify-tables.js +206 -0
  355. package/dist/sql/qualify-tables.js.map +1 -0
  356. package/dist/sql/template.d.ts +5 -0
  357. package/dist/sql/template.d.ts.map +1 -1
  358. package/dist/sql/template.js +23 -3
  359. package/dist/sql/template.js.map +1 -1
  360. package/dist/utils/load-ts.d.ts +2 -1
  361. package/dist/utils/load-ts.d.ts.map +1 -1
  362. package/dist/utils/load-ts.js +13 -1
  363. package/dist/utils/load-ts.js.map +1 -1
  364. package/docs/cli.md +4 -4
  365. package/docs/configuration.md +12 -5
  366. package/docs/elysia.md +131 -0
  367. package/docs/errors.md +1 -1
  368. package/docs/examples.md +4 -2
  369. package/docs/getting-started.md +28 -2
  370. package/docs/mariadb.md +149 -0
  371. package/docs/migrations.md +5 -3
  372. package/docs/mysql.md +134 -0
  373. package/docs/plugins.md +2 -0
  374. package/docs/queries.md +14 -11
  375. package/docs/relations.md +19 -4
  376. package/docs/schema.md +100 -9
  377. package/docs/sqlite.md +14 -2
  378. package/docs/typebox.md +139 -0
  379. package/docs/zod.md +128 -0
  380. package/package.json +33 -3
@@ -1,19 +1,22 @@
1
- import { isSqliteProvider, } from "../datasource-provider.js";
1
+ import { isMariadbProvider, isMysqlFamilyProvider, isSqliteProvider, } from "../datasource-provider.js";
2
+ import { MYSQL_UNSUPPORTED_COLUMN_KINDS, mysqlUnsupportedColumnKindMessage, SQLITE_UNSUPPORTED_COLUMN_KINDS, sqliteUnsupportedColumnKindMessage, } from "../dialect/column-kind-support.js";
2
3
  import { parseFkTarget } from "../dialect/fk.js";
3
4
  import { resolveIndexSqlName } from "../dialect/postgres.js";
4
5
  import { collectExtensionsForKinds, getColumnType, getPluginRegistry, } from "../plugins/registry.js";
5
6
  import { schemaError } from "../runtime/error-builders.js";
6
7
  import { formatCandidateList, listColumnTsNames, listTableAccessors, suggestSchemaColumn, suggestSchemaTableAccessor, } from "../runtime/error-hints.js";
7
8
  import { resolveFkTargetSqlColumn } from "../runtime/query/primary-key.js";
9
+ import { compileColumnCheckConstraints, quoteSqlColumn, } from "../schema/column-constraints.js";
8
10
  import { fk, resolveFkAccessorTarget, } from "../schema/relation.js";
9
- import { findPrimaryKeyColumn, } from "../schema/table.js";
11
+ import { findPrimaryKeyColumn, isIndexExpr, } from "../schema/table.js";
10
12
  import { resolveSqlColumnName } from "../utils/case.js";
11
13
  import { singularize } from "../utils/inflect.js";
12
- function buildEnumCheckExpression(sqlName, values) {
14
+ const POSTGIS_COLUMN_KINDS = new Set(["geometry", "geography", "point"]);
15
+ function buildEnumCheckExpression(sqlName, values, provider) {
13
16
  const quoted = values
14
17
  .map((value) => `'${value.replace(/'/g, "''")}'`)
15
18
  .join(", ");
16
- return `"${sqlName.replace(/"/g, '""')}" IN (${quoted})`;
19
+ return `${quoteSqlColumn(sqlName, provider)} IN (${quoted})`;
17
20
  }
18
21
  function resolveEnumTypeName(tableSqlName, columnSqlName, explicitName) {
19
22
  return explicitName ?? `${tableSqlName}_${columnSqlName}`;
@@ -28,7 +31,7 @@ function requireColumnDef(columns, tsName, tableAccessor) {
28
31
  function inferFkAs(tsName) {
29
32
  return tsName.replace(/_(Id|id)$/, "").replace(/Id$/, "");
30
33
  }
31
- function pluralize(word) {
34
+ function _pluralize(word) {
32
35
  if (/(s|x|z|ch|sh)$/.test(word)) {
33
36
  return `${word}es`;
34
37
  }
@@ -40,11 +43,11 @@ function pluralize(word) {
40
43
  function autoJunctionName(leftSql, rightSql) {
41
44
  return [leftSql, rightSql].sort().join("_");
42
45
  }
43
- function finalizeEnumColumns(manifestTables, enumMode) {
46
+ function finalizeEnumColumns(manifestTables, enumMode, provider) {
44
47
  const enumTypes = {};
45
48
  for (const table of Object.values(manifestTables)) {
46
49
  for (const col of table.columns) {
47
- if (col.kind !== "enum") {
50
+ if (col.kind !== "enum" && col.kind !== "enumArray") {
48
51
  continue;
49
52
  }
50
53
  const values = col.typeOptions?.values;
@@ -52,7 +55,10 @@ function finalizeEnumColumns(manifestTables, enumMode) {
52
55
  continue;
53
56
  }
54
57
  if (enumMode === "check") {
55
- const enumCheck = buildEnumCheckExpression(col.sqlName, values);
58
+ if (col.kind === "enumArray") {
59
+ continue;
60
+ }
61
+ const enumCheck = buildEnumCheckExpression(col.sqlName, values, provider);
56
62
  col.checkExpression = col.checkExpression
57
63
  ? `(${col.checkExpression}) AND (${enumCheck})`
58
64
  : enumCheck;
@@ -92,7 +98,7 @@ function resolveSqlName(tsName, col, columnNaming) {
92
98
  const mapName = "_meta" in col ? col._meta.mapName : undefined;
93
99
  return resolveSqlColumnName(tsName, columnNaming, mapName);
94
100
  }
95
- function resolveFkTargetSql(col, tables, defaultColumnNaming, sourceColumnNaming) {
101
+ function resolveFkTargetSql(col, tables, defaultColumnNaming, _sourceColumnNaming) {
96
102
  const { accessor, column } = resolveFkAccessorTarget(col._meta, tables);
97
103
  const targetTable = tables[accessor];
98
104
  if (!targetTable) {
@@ -117,12 +123,14 @@ function compileIndexWhere(where, columns, columnNaming, provider) {
117
123
  for (const [tsName, value] of Object.entries(where)) {
118
124
  const col = requireColumnDef(columns, tsName);
119
125
  const sqlName = resolveSqlName(tsName, col, columnNaming);
120
- const quoted = `"${sqlName.replace(/"/g, '""')}"`;
126
+ const quoted = isMysqlFamilyProvider(provider)
127
+ ? `\`${sqlName.replace(/`/g, "``")}\``
128
+ : `"${sqlName.replace(/"/g, '""')}"`;
121
129
  if (value === null) {
122
130
  parts.push(`${quoted} IS NULL`);
123
131
  }
124
132
  else if (typeof value === "boolean") {
125
- parts.push(isSqliteProvider(provider)
133
+ parts.push(isSqliteProvider(provider) || isMysqlFamilyProvider(provider)
126
134
  ? `${quoted} = ${value ? 1 : 0}`
127
135
  : `${quoted} = ${value}`);
128
136
  }
@@ -135,7 +143,7 @@ function compileIndexWhere(where, columns, columnNaming, provider) {
135
143
  }
136
144
  return parts.join(" AND ");
137
145
  }
138
- function columnToManifest(tsName, col, columnNaming, tables, defaultColumnNaming) {
146
+ function columnToManifest(tsName, col, columnNaming, tables, defaultColumnNaming, provider) {
139
147
  if (isFkBuilder(col)) {
140
148
  const meta = col._meta;
141
149
  const fkTarget = resolveFkTargetSql(col, tables, defaultColumnNaming, columnNaming);
@@ -162,6 +170,15 @@ function columnToManifest(tsName, col, columnNaming, tables, defaultColumnNaming
162
170
  if (meta.onDelete !== undefined) {
163
171
  result.onDelete = meta.onDelete;
164
172
  }
173
+ if (meta.onUpdate !== undefined) {
174
+ result.onUpdate = meta.onUpdate;
175
+ }
176
+ if (meta.deferrable !== undefined) {
177
+ if (isMysqlFamilyProvider(provider)) {
178
+ throw schemaError("invalid_column", `${isMariadbProvider(provider) ? "MariaDB" : "MySQL"} does not support deferrable foreign keys`);
179
+ }
180
+ result.deferrable = meta.deferrable;
181
+ }
165
182
  if (meta.hidden === true) {
166
183
  result.hidden = true;
167
184
  }
@@ -177,6 +194,18 @@ function columnToManifest(tsName, col, columnNaming, tables, defaultColumnNaming
177
194
  if ("updatedAt" in meta && meta.updatedAt === true) {
178
195
  validateUpdatedAtColumn(tsName, meta.kind);
179
196
  }
197
+ if (isMysqlFamilyProvider(provider) &&
198
+ POSTGIS_COLUMN_KINDS.has(meta.kind)) {
199
+ throw schemaError("invalid_column", `PostGIS column kind "${meta.kind}" is not supported on ${isMariadbProvider(provider) ? "MariaDB" : "MySQL"}`);
200
+ }
201
+ if (isMysqlFamilyProvider(provider) &&
202
+ MYSQL_UNSUPPORTED_COLUMN_KINDS.has(meta.kind)) {
203
+ throw schemaError("invalid_column", mysqlUnsupportedColumnKindMessage(meta.kind, isMariadbProvider(provider) ? "MariaDB" : "MySQL"));
204
+ }
205
+ if (isSqliteProvider(provider) &&
206
+ SQLITE_UNSUPPORTED_COLUMN_KINDS.has(meta.kind)) {
207
+ throw schemaError("invalid_column", sqliteUnsupportedColumnKindMessage(meta.kind));
208
+ }
180
209
  const result = {
181
210
  tsName,
182
211
  sqlName: resolveSqlName(tsName, col, columnNaming),
@@ -204,28 +233,130 @@ function columnToManifest(tsName, col, columnNaming, tables, defaultColumnNaming
204
233
  if (meta.hidden === true) {
205
234
  result.hidden = true;
206
235
  }
207
- if (meta.checkExpression) {
208
- result.checkExpression = meta.checkExpression;
236
+ const compiledCheck = compileColumnCheckConstraints(result, meta, provider);
237
+ if (compiledCheck !== undefined) {
238
+ result.checkExpression = compiledCheck;
209
239
  }
240
+ copyStructuredConstraints(result, meta);
210
241
  return result;
211
242
  }
243
+ function jsonSafeConstraint(value) {
244
+ return typeof value === "bigint" ? value.toString() : value;
245
+ }
246
+ function copyStructuredConstraints(result, meta) {
247
+ if (meta.checkMin !== undefined) {
248
+ result.checkMin = jsonSafeConstraint(meta.checkMin);
249
+ }
250
+ if (meta.checkMax !== undefined) {
251
+ result.checkMax = jsonSafeConstraint(meta.checkMax);
252
+ }
253
+ if (meta.checkPositive === true) {
254
+ result.checkPositive = true;
255
+ }
256
+ if (meta.checkMinLength !== undefined) {
257
+ result.checkMinLength = meta.checkMinLength;
258
+ }
259
+ if (meta.checkMaxLength !== undefined) {
260
+ result.checkMaxLength = meta.checkMaxLength;
261
+ }
262
+ if (meta.checkNotEmpty === true) {
263
+ result.checkNotEmpty = true;
264
+ }
265
+ if (meta.checkEmail === true) {
266
+ result.checkEmail = true;
267
+ }
268
+ if (meta.checkUrl === true) {
269
+ result.checkUrl = true;
270
+ }
271
+ if (meta.validation !== undefined) {
272
+ result.validation = meta.validation;
273
+ }
274
+ }
275
+ function extraIndexUsing(extra) {
276
+ if (extra.kind !== "index")
277
+ return undefined;
278
+ if ("using" in extra && typeof extra.using === "string") {
279
+ return extra.using;
280
+ }
281
+ if ("_using" in extra && typeof extra._using === "string") {
282
+ return extra._using;
283
+ }
284
+ return undefined;
285
+ }
286
+ function extraIndexOpclass(extra) {
287
+ if (extra.kind !== "index")
288
+ return undefined;
289
+ if ("opclass" in extra && typeof extra.opclass === "string") {
290
+ return extra.opclass;
291
+ }
292
+ if ("_opclass" in extra && typeof extra._opclass === "string") {
293
+ return extra._opclass;
294
+ }
295
+ return undefined;
296
+ }
297
+ function extraIndexKeys(extra) {
298
+ if (extra.kind !== "index")
299
+ return [];
300
+ if ("keys" in extra && extra.keys)
301
+ return extra.keys;
302
+ return extra.columns;
303
+ }
304
+ function sanitizeIndexNamePart(sql) {
305
+ const token = sql
306
+ .replace(/[^A-Za-z0-9]+/g, "_")
307
+ .replace(/^_|_$/g, "")
308
+ .slice(0, 40);
309
+ return token.length > 0 ? token : "expr";
310
+ }
311
+ const NON_UNIQUE_INDEX_METHODS = new Set(["gin", "gist", "brin"]);
212
312
  function extrasToManifest(extras, columns, tableSqlName, columnNaming, provider) {
213
313
  const indexes = [];
214
314
  let primaryKey = [];
315
+ const compositeFks = [];
215
316
  for (const extra of extras) {
216
317
  if (extra.kind === "index") {
318
+ const using = extraIndexUsing(extra);
319
+ const opclass = extraIndexOpclass(extra);
320
+ if (extra.unique && using && NON_UNIQUE_INDEX_METHODS.has(using)) {
321
+ throw schemaError("invalid_column", `UNIQUE indexes cannot use ${using}`);
322
+ }
323
+ if (using && using !== "btree") {
324
+ if (isSqliteProvider(provider)) {
325
+ throw schemaError("invalid_column", `SQLite does not support ${using} indexes`);
326
+ }
327
+ if (isMysqlFamilyProvider(provider) && using !== "hash") {
328
+ throw schemaError("invalid_column", `${isMariadbProvider(provider) ? "MariaDB" : "MySQL"} does not support ${using} indexes`);
329
+ }
330
+ }
217
331
  const wherePredicate = "where" in extra &&
218
332
  extra.where !== undefined &&
219
333
  typeof extra.where !== "function"
220
334
  ? extra.where
221
335
  : undefined;
222
- const sqlColumns = extra.columns.map((tsName) => resolveSqlName(tsName, requireColumnDef(columns, tsName), columnNaming));
336
+ const keys = extraIndexKeys(extra).map((key) => {
337
+ if (isIndexExpr(key)) {
338
+ return { expr: key.sql };
339
+ }
340
+ return {
341
+ sqlName: resolveSqlName(key, requireColumnDef(columns, key), columnNaming),
342
+ };
343
+ });
344
+ const sqlColumns = keys
345
+ .map((key) => key.sqlName)
346
+ .filter((name) => name !== undefined);
347
+ const nameParts = keys.map((key) => key.sqlName ?? sanitizeIndexNamePart(key.expr ?? "expr"));
223
348
  const index = {
224
- name: sqlColumns.join("_"),
349
+ name: nameParts.join("_") || "expr",
225
350
  columns: sqlColumns,
226
351
  unique: extra.unique,
352
+ keys,
353
+ ...(using && using !== "btree" ? { using } : {}),
354
+ ...(opclass ? { opclass } : {}),
227
355
  };
228
356
  if (wherePredicate) {
357
+ if (isMysqlFamilyProvider(provider)) {
358
+ throw schemaError("invalid_column", `${isMariadbProvider(provider) ? "MariaDB" : "MySQL"} does not support partial indexes (index({ where }))`);
359
+ }
229
360
  index.whereSql = compileIndexWhere(wherePredicate, columns, columnNaming, provider);
230
361
  }
231
362
  index.sqlName = resolveIndexSqlName(tableSqlName, index);
@@ -234,8 +365,89 @@ function extrasToManifest(extras, columns, tableSqlName, columnNaming, provider)
234
365
  else if (extra.kind === "primaryKey") {
235
366
  primaryKey = extra.columns.map((tsName) => resolveSqlName(tsName, requireColumnDef(columns, tsName), columnNaming));
236
367
  }
368
+ else if (extra.kind === "foreignKey") {
369
+ compositeFks.push(extra);
370
+ }
371
+ }
372
+ return { indexes, primaryKey, compositeFks };
373
+ }
374
+ function rejectMysqlDeferrable(provider, deferrable) {
375
+ if (!deferrable)
376
+ return;
377
+ if (isMysqlFamilyProvider(provider)) {
378
+ throw schemaError("invalid_column", `${isMariadbProvider(provider) ? "MariaDB" : "MySQL"} does not support deferrable foreign keys`);
379
+ }
380
+ }
381
+ function resolveCompositeForeignKeys(args) {
382
+ const result = [];
383
+ for (const extra of args.extras) {
384
+ if (!extra._as) {
385
+ throw schemaError("invalid_column", `foreignKey() on "${args.accessor}" requires .as("relationName")`);
386
+ }
387
+ if (!extra._inverse) {
388
+ throw schemaError("invalid_column", `foreignKey() on "${args.accessor}" requires .inverse("relationName")`);
389
+ }
390
+ if (!extra.targetTable) {
391
+ throw schemaError("invalid_column", `foreignKey() on "${args.accessor}" requires .references("table", ...)`);
392
+ }
393
+ if (extra.columns.length < 2) {
394
+ throw schemaError("invalid_column", `foreignKey() on "${args.accessor}" needs at least two local columns (use fk() for a single-column relation)`);
395
+ }
396
+ if (extra.columns.length !== extra.targetColumns.length) {
397
+ throw schemaError("invalid_column", `foreignKey() on "${args.accessor}" local and referenced column counts must match`);
398
+ }
399
+ rejectMysqlDeferrable(args.provider, extra._deferrable);
400
+ const targetDef = args.schemaTables[extra.targetTable];
401
+ if (!targetDef) {
402
+ throw schemaError("unknown_fk_target", `foreignKey() on "${args.accessor}" references unknown table accessor "${extra.targetTable}"`, { tableAccessor: args.accessor }, suggestSchemaTableAccessor(extra.targetTable, args.schemaTables));
403
+ }
404
+ const localSql = [];
405
+ for (const tsName of extra.columns) {
406
+ const def = requireColumnDef(args.localDefs, tsName, args.accessor);
407
+ if (isFkBuilder(def)) {
408
+ throw schemaError("invalid_column", `foreignKey() column "${tsName}" on "${args.accessor}" must not also be fk()`);
409
+ }
410
+ localSql.push(resolveSqlName(tsName, def, args.columnNaming));
411
+ }
412
+ const targetNaming = targetDef._columnNaming ?? args.columnNaming;
413
+ const targetSql = [];
414
+ for (const tsName of extra.targetColumns) {
415
+ const def = requireColumnDef(targetDef._columns, tsName, extra.targetTable);
416
+ targetSql.push(resolveSqlName(tsName, def, targetNaming));
417
+ }
418
+ const fk = {
419
+ name: extra.constraintName ??
420
+ `${args.tableSqlName}_${localSql.join("_")}_fkey`,
421
+ columns: localSql,
422
+ targetTable: targetDef._tableName,
423
+ targetColumns: targetSql,
424
+ };
425
+ if (extra._onDelete !== undefined)
426
+ fk.onDelete = extra._onDelete;
427
+ if (extra._onUpdate !== undefined)
428
+ fk.onUpdate = extra._onUpdate;
429
+ if (extra._deferrable !== undefined)
430
+ fk.deferrable = extra._deferrable;
431
+ result.push(fk);
237
432
  }
238
- return { indexes, primaryKey };
433
+ return result;
434
+ }
435
+ function columnSetIsUnique(table, sqlNames) {
436
+ if (sqlNames.length === 0)
437
+ return false;
438
+ if (table.primaryKey.length === sqlNames.length &&
439
+ sqlNames.every((name) => table.primaryKey.includes(name))) {
440
+ return true;
441
+ }
442
+ if (sqlNames.length === 1) {
443
+ return isUniqueColumn(table, sqlNames[0] ?? "");
444
+ }
445
+ return table.indexes.some((idx) => idx.unique &&
446
+ !idx.whereSql &&
447
+ !(idx.using && idx.using !== "btree") &&
448
+ !(idx.keys?.some((key) => key.expr) ?? false) &&
449
+ idx.columns.length === sqlNames.length &&
450
+ sqlNames.every((name) => idx.columns.includes(name)));
239
451
  }
240
452
  function buildRelations(columns, sourceAccessor, sqlNameToAccessor, manifestTables) {
241
453
  const relations = [];
@@ -262,6 +474,52 @@ function buildRelations(columns, sourceAccessor, sqlNameToAccessor, manifestTabl
262
474
  if (col.onDelete !== undefined) {
263
475
  rel.onDelete = col.onDelete;
264
476
  }
477
+ if (col.onUpdate !== undefined) {
478
+ rel.onUpdate = col.onUpdate;
479
+ }
480
+ if (col.deferrable !== undefined) {
481
+ rel.deferrable = col.deferrable;
482
+ }
483
+ relations.push(rel);
484
+ }
485
+ return relations;
486
+ }
487
+ function extraFkRelations(table, schemaTable) {
488
+ const relations = [];
489
+ const extras = schemaTable._extras.filter((extra) => extra.kind === "foreignKey");
490
+ const fks = table.foreignKeys ?? [];
491
+ for (let i = 0; i < extras.length; i++) {
492
+ const extra = extras[i];
493
+ const fk = fks[i];
494
+ if (!extra || !fk)
495
+ continue;
496
+ const targetAccessor = extra.targetTable;
497
+ const localTs = extra.columns;
498
+ const firstLocal = localTs[0];
499
+ const firstSql = fk.columns[0];
500
+ const firstTarget = fk.targetColumns[0];
501
+ if (!firstLocal || !firstSql || !firstTarget)
502
+ continue;
503
+ const rel = {
504
+ name: extra._as,
505
+ targetTable: fk.targetTable,
506
+ targetAccessor,
507
+ fkColumn: firstLocal,
508
+ fkSqlColumn: firstSql,
509
+ targetColumn: firstTarget,
510
+ fkColumns: localTs,
511
+ fkSqlColumns: fk.columns,
512
+ targetColumns: fk.targetColumns,
513
+ referencedSqlColumns: fk.targetColumns,
514
+ cardinality: "one",
515
+ inverse: extra._inverse,
516
+ };
517
+ if (extra._onDelete !== undefined)
518
+ rel.onDelete = extra._onDelete;
519
+ if (extra._onUpdate !== undefined)
520
+ rel.onUpdate = extra._onUpdate;
521
+ if (extra._deferrable !== undefined)
522
+ rel.deferrable = extra._deferrable;
265
523
  relations.push(rel);
266
524
  }
267
525
  return relations;
@@ -272,8 +530,10 @@ function isUniqueColumn(table, fkSqlColumn) {
272
530
  return true;
273
531
  return table.indexes.some((idx) => idx.unique &&
274
532
  !idx.whereSql &&
533
+ !idx.using &&
275
534
  idx.columns.length === 1 &&
276
- idx.columns[0] === fkSqlColumn);
535
+ idx.columns[0] === fkSqlColumn &&
536
+ !(idx.keys?.some((key) => key.expr) ?? false));
277
537
  }
278
538
  function resolveM2M(incoming) {
279
539
  return {
@@ -298,7 +558,7 @@ function resolveM2M(incoming) {
298
558
  * @param plugins - Column type plugins (defaults to built-in registry).
299
559
  * @param options - Enum mode and datasource provider hints.
300
560
  */
301
- export function schemaToManifest(schema, plugins = getPluginRegistry(), options = {}) {
561
+ export function schemaToManifest(schema, _plugins = getPluginRegistry(), options = {}) {
302
562
  const enumMode = options.enumMode ?? "check";
303
563
  const provider = options.provider;
304
564
  const datasourceUrl = options.url;
@@ -314,8 +574,8 @@ export function schemaToManifest(schema, plugins = getPluginRegistry(), options
314
574
  const columnNaming = tableDef._columnNaming ?? defaultColumnNaming;
315
575
  const columns = Object.entries(tableDef._columns)
316
576
  .filter(([, col]) => !isManyToMany(col))
317
- .map(([name, col]) => columnToManifest(name, col, columnNaming, tables, defaultColumnNaming));
318
- const { indexes, primaryKey } = extrasToManifest(tableDef._extras, tableDef._columns, tableDef._tableName, columnNaming, provider);
577
+ .map(([name, col]) => columnToManifest(name, col, columnNaming, tables, defaultColumnNaming, provider));
578
+ const { indexes, primaryKey, compositeFks } = extrasToManifest(tableDef._extras, tableDef._columns, tableDef._tableName, columnNaming, provider);
319
579
  for (const col of columns) {
320
580
  if (!col.index)
321
581
  continue;
@@ -323,6 +583,7 @@ export function schemaToManifest(schema, plugins = getPluginRegistry(), options
323
583
  name: col.sqlName,
324
584
  columns: [col.sqlName],
325
585
  unique: false,
586
+ keys: [{ sqlName: col.sqlName }],
326
587
  };
327
588
  const already = indexes.some((idx) => !idx.unique &&
328
589
  idx.columns.length === 1 &&
@@ -358,6 +619,20 @@ export function schemaToManifest(schema, plugins = getPluginRegistry(), options
358
619
  relations: [],
359
620
  indexes,
360
621
  primaryKey: pk,
622
+ ...(compositeFks.length > 0
623
+ ? {
624
+ foreignKeys: resolveCompositeForeignKeys({
625
+ accessor,
626
+ tableSqlName: tableDef._tableName,
627
+ columns,
628
+ extras: compositeFks,
629
+ columnNaming,
630
+ localDefs: tableDef._columns,
631
+ schemaTables: tables,
632
+ ...(provider ? { provider } : {}),
633
+ }),
634
+ }
635
+ : {}),
361
636
  };
362
637
  }
363
638
  const autoJunctionAccessors = new Set();
@@ -369,6 +644,11 @@ export function schemaToManifest(schema, plugins = getPluginRegistry(), options
369
644
  columnToManifest(leftTsName, leftFk, columnNaming, tables, defaultColumnNaming),
370
645
  columnToManifest(rightTsName, rightFk, columnNaming, tables, defaultColumnNaming),
371
646
  ];
647
+ const leftCol = columns[0];
648
+ const rightCol = columns[1];
649
+ if (!leftCol || !rightCol) {
650
+ throw new Error(`M2M junction "${accessor}" must have exactly two FK columns`);
651
+ }
372
652
  const table = {
373
653
  accessor,
374
654
  sqlName,
@@ -376,7 +656,7 @@ export function schemaToManifest(schema, plugins = getPluginRegistry(), options
376
656
  columns,
377
657
  relations: [],
378
658
  indexes: [],
379
- primaryKey: [columns[0].sqlName, columns[1].sqlName],
659
+ primaryKey: [leftCol.sqlName, rightCol.sqlName],
380
660
  };
381
661
  manifestTables[accessor] = table;
382
662
  sqlNameToAccessor[sqlName] = accessor;
@@ -451,14 +731,27 @@ export function schemaToManifest(schema, plugins = getPluginRegistry(), options
451
731
  });
452
732
  }
453
733
  for (const table of Object.values(manifestTables)) {
454
- table.relations = buildRelations(table.columns, table.accessor, sqlNameToAccessor, manifestTables);
734
+ for (const fk of table.foreignKeys ?? []) {
735
+ const target = Object.values(manifestTables).find((item) => item.sqlName === fk.targetTable);
736
+ if (!target) {
737
+ throw schemaError("unknown_fk_target", `foreignKey on "${table.accessor}" references unknown table ${fk.targetTable}`);
738
+ }
739
+ if (!columnSetIsUnique(target, fk.targetColumns)) {
740
+ throw schemaError("invalid_column", `foreignKey on "${table.accessor}" target (${fk.targetColumns.join(", ")}) must be a primary key or unique index on "${target.accessor}"`);
741
+ }
742
+ }
743
+ const schemaTable = tables[table.accessor];
744
+ table.relations = [
745
+ ...buildRelations(table.columns, table.accessor, sqlNameToAccessor, manifestTables),
746
+ ...(schemaTable ? extraFkRelations(table, schemaTable) : []),
747
+ ];
455
748
  }
456
749
  for (const table of Object.values(manifestTables)) {
457
750
  if (autoJunctionAccessors.has(table.accessor))
458
751
  continue;
459
752
  const fkRelations = table.relations.filter((rel) => {
460
- const col = table.columns.find((c) => c.fkAs === rel.name);
461
- return col?.kind === "fk";
753
+ const names = rel.fkColumns ?? [rel.fkColumn];
754
+ return names.every((name) => table.columns.some((col) => col.tsName === name || col.sqlName === name));
462
755
  });
463
756
  for (const rel of fkRelations) {
464
757
  const inverseTable = manifestTables[rel.targetAccessor];
@@ -478,18 +771,36 @@ export function schemaToManifest(schema, plugins = getPluginRegistry(), options
478
771
  "Each inverse relation name must be unique on the target table",
479
772
  ]);
480
773
  }
481
- inverseTable.relations.push({
774
+ const localSql = rel.fkSqlColumns ?? [rel.fkSqlColumn];
775
+ const inverseRel = {
482
776
  name: rel.inverse,
483
777
  targetTable: table.sqlName,
484
778
  targetAccessor: table.accessor,
485
779
  fkColumn: rel.fkColumn,
486
780
  fkSqlColumn: rel.fkSqlColumn,
487
781
  targetColumn: table.primaryKey[0] ?? rel.targetColumn,
488
- cardinality: isUniqueColumn(table, rel.fkSqlColumn)
782
+ cardinality: columnSetIsUnique(table, localSql)
489
783
  ? "one"
490
784
  : "many",
491
785
  inverse: rel.name,
492
- });
786
+ };
787
+ if (rel.fkColumns)
788
+ inverseRel.fkColumns = rel.fkColumns;
789
+ if (rel.fkSqlColumns)
790
+ inverseRel.fkSqlColumns = rel.fkSqlColumns;
791
+ if (table.primaryKey.length > 1) {
792
+ inverseRel.targetColumns = table.primaryKey;
793
+ }
794
+ inverseRel.referencedSqlColumns = rel.referencedSqlColumns ??
795
+ rel.targetColumns ?? [rel.targetColumn];
796
+ if (rel.onDelete !== undefined)
797
+ inverseRel.onDelete = rel.onDelete;
798
+ if (rel.onUpdate !== undefined)
799
+ inverseRel.onUpdate = rel.onUpdate;
800
+ if (rel.deferrable !== undefined) {
801
+ inverseRel.deferrable = rel.deferrable;
802
+ }
803
+ inverseTable.relations.push(inverseRel);
493
804
  }
494
805
  }
495
806
  const manyToMany = incomingM2Ms.map(resolveM2M);
@@ -521,7 +832,7 @@ export function schemaToManifest(schema, plugins = getPluginRegistry(), options
521
832
  });
522
833
  }
523
834
  }
524
- const enumTypes = finalizeEnumColumns(manifestTables, enumMode);
835
+ const enumTypes = finalizeEnumColumns(manifestTables, enumMode, provider);
525
836
  const pluginExtensions = collectExtensionsForKinds(Object.values(manifestTables).flatMap((table) => table.columns.map((col) => col.kind)));
526
837
  const userExtensions = schema._extensions ?? [];
527
838
  const extensions = [...new Set([...pluginExtensions, ...userExtensions])];
@@ -590,6 +901,15 @@ export function validateManifest(manifest) {
590
901
  });
591
902
  }
592
903
  }
904
+ for (const fk of table.foreignKeys ?? []) {
905
+ const target = Object.values(manifest.tables).find((item) => item.sqlName === fk.targetTable);
906
+ if (!target) {
907
+ errors.push({
908
+ code: "unknown_fk_target",
909
+ message: `FK constraint ${fk.name} on ${table.accessor} references unknown table ${fk.targetTable}`,
910
+ });
911
+ }
912
+ }
593
913
  }
594
914
  return errors;
595
915
  }