joist-codegen 2.3.0-next.8 → 2.3.0-next.81

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 (420) hide show
  1. package/build/EntityDbMetadata.cjs +642 -0
  2. package/build/EntityDbMetadata.cjs.map +1 -0
  3. package/build/EntityDbMetadata.d.cts +299 -0
  4. package/build/EntityDbMetadata.d.cts.map +1 -0
  5. package/build/EntityDbMetadata.d.mts +299 -0
  6. package/build/EntityDbMetadata.d.mts.map +1 -0
  7. package/build/EntityDbMetadata.js +519 -661
  8. package/build/EntityDbMetadata.js.map +1 -1
  9. package/build/_virtual/_rolldown/runtime.cjs +23 -0
  10. package/build/_virtual/_rolldown/runtime.js +5 -0
  11. package/build/assignTags.cjs +45 -0
  12. package/build/assignTags.cjs.map +1 -0
  13. package/build/{assignTags.d.ts → assignTags.d.cts} +8 -4
  14. package/build/assignTags.d.cts.map +1 -0
  15. package/build/assignTags.d.mts +16 -0
  16. package/build/assignTags.d.mts.map +1 -0
  17. package/build/assignTags.js +37 -59
  18. package/build/assignTags.js.map +1 -1
  19. package/build/codemods/Codemod.cjs +2 -0
  20. package/build/codemods/Codemod.d.cts +17 -0
  21. package/build/codemods/Codemod.d.cts.map +1 -0
  22. package/build/codemods/Codemod.d.mts +17 -0
  23. package/build/codemods/Codemod.d.mts.map +1 -0
  24. package/build/codemods/Codemod.js +2 -3
  25. package/build/codemods/JscodeshiftMod.cjs +42 -0
  26. package/build/codemods/JscodeshiftMod.cjs.map +1 -0
  27. package/build/codemods/JscodeshiftMod.d.cts +14 -0
  28. package/build/codemods/JscodeshiftMod.d.cts.map +1 -0
  29. package/build/codemods/JscodeshiftMod.d.mts +14 -0
  30. package/build/codemods/JscodeshiftMod.d.mts.map +1 -0
  31. package/build/codemods/JscodeshiftMod.js +33 -33
  32. package/build/codemods/JscodeshiftMod.js.map +1 -1
  33. package/build/codemods/codemod_0001-rename_has_async_property.cjs +30 -0
  34. package/build/codemods/codemod_0001-rename_has_async_property.cjs.map +1 -0
  35. package/build/codemods/codemod_0001-rename_has_async_property.d.cts +9 -0
  36. package/build/codemods/codemod_0001-rename_has_async_property.d.cts.map +1 -0
  37. package/build/codemods/codemod_0001-rename_has_async_property.d.mts +9 -0
  38. package/build/codemods/codemod_0001-rename_has_async_property.d.mts.map +1 -0
  39. package/build/codemods/codemod_0001-rename_has_async_property.js +21 -25
  40. package/build/codemods/codemod_0001-rename_has_async_property.js.map +1 -1
  41. package/build/codemods/codemod_0002-rename_async_query_fields.cjs +50 -0
  42. package/build/codemods/codemod_0002-rename_async_query_fields.cjs.map +1 -0
  43. package/build/codemods/codemod_0002-rename_async_query_fields.d.cts +9 -0
  44. package/build/codemods/codemod_0002-rename_async_query_fields.d.cts.map +1 -0
  45. package/build/codemods/codemod_0002-rename_async_query_fields.d.mts +9 -0
  46. package/build/codemods/codemod_0002-rename_async_query_fields.d.mts.map +1 -0
  47. package/build/codemods/codemod_0002-rename_async_query_fields.js +38 -52
  48. package/build/codemods/codemod_0002-rename_async_query_fields.js.map +1 -1
  49. package/build/codemods/codemod_0003-rename_find_paginated.cjs +25 -0
  50. package/build/codemods/codemod_0003-rename_find_paginated.cjs.map +1 -0
  51. package/build/codemods/codemod_0003-rename_find_paginated.d.cts +9 -0
  52. package/build/codemods/codemod_0003-rename_find_paginated.d.cts.map +1 -0
  53. package/build/codemods/codemod_0003-rename_find_paginated.d.mts +9 -0
  54. package/build/codemods/codemod_0003-rename_find_paginated.d.mts.map +1 -0
  55. package/build/codemods/codemod_0003-rename_find_paginated.js +17 -26
  56. package/build/codemods/codemod_0003-rename_find_paginated.js.map +1 -1
  57. package/build/codemods/index.cjs +49 -0
  58. package/build/codemods/index.cjs.map +1 -0
  59. package/build/codemods/index.d.cts +12 -0
  60. package/build/codemods/index.d.cts.map +1 -0
  61. package/build/codemods/index.d.mts +12 -0
  62. package/build/codemods/index.d.mts.map +1 -0
  63. package/build/codemods/index.js +34 -42
  64. package/build/codemods/index.js.map +1 -1
  65. package/build/config.cjs +377 -0
  66. package/build/config.cjs.map +1 -0
  67. package/build/config.d.cts +181 -0
  68. package/build/config.d.cts.map +1 -0
  69. package/build/config.d.mts +181 -0
  70. package/build/config.d.mts.map +1 -0
  71. package/build/config.js +309 -347
  72. package/build/config.js.map +1 -1
  73. package/build/docs/cache.cjs +62 -0
  74. package/build/docs/cache.cjs.map +1 -0
  75. package/build/docs/cache.d.cts +17 -0
  76. package/build/docs/cache.d.cts.map +1 -0
  77. package/build/docs/cache.d.mts +17 -0
  78. package/build/docs/cache.d.mts.map +1 -0
  79. package/build/docs/cache.js +52 -53
  80. package/build/docs/cache.js.map +1 -1
  81. package/build/docs/generate-metadata-docs.cjs +32 -0
  82. package/build/docs/generate-metadata-docs.cjs.map +1 -0
  83. package/build/docs/generate-metadata-docs.d.cts +9 -0
  84. package/build/docs/generate-metadata-docs.d.cts.map +1 -0
  85. package/build/docs/generate-metadata-docs.d.mts +9 -0
  86. package/build/docs/generate-metadata-docs.d.mts.map +1 -0
  87. package/build/docs/generate-metadata-docs.js +19 -24
  88. package/build/docs/generate-metadata-docs.js.map +1 -1
  89. package/build/docs/index.cjs +90 -0
  90. package/build/docs/index.cjs.map +1 -0
  91. package/build/docs/index.d.cts +16 -0
  92. package/build/docs/index.d.cts.map +1 -0
  93. package/build/docs/index.d.mts +16 -0
  94. package/build/docs/index.d.mts.map +1 -0
  95. package/build/docs/index.js +75 -80
  96. package/build/docs/index.js.map +1 -1
  97. package/build/docs/markdown.cjs +181 -0
  98. package/build/docs/markdown.cjs.map +1 -0
  99. package/build/docs/{markdown.d.ts → markdown.d.cts} +14 -12
  100. package/build/docs/markdown.d.cts.map +1 -0
  101. package/build/docs/markdown.d.mts +32 -0
  102. package/build/docs/markdown.d.mts.map +1 -0
  103. package/build/docs/markdown.js +152 -220
  104. package/build/docs/markdown.js.map +1 -1
  105. package/build/docs/parsing.cjs +117 -0
  106. package/build/docs/parsing.cjs.map +1 -0
  107. package/build/docs/parsing.d.cts +48 -0
  108. package/build/docs/parsing.d.cts.map +1 -0
  109. package/build/docs/parsing.d.mts +48 -0
  110. package/build/docs/parsing.d.mts.map +1 -0
  111. package/build/docs/parsing.js +89 -88
  112. package/build/docs/parsing.js.map +1 -1
  113. package/build/findEntityScopes.cjs +119 -0
  114. package/build/findEntityScopes.cjs.map +1 -0
  115. package/build/findEntityScopes.d.cts +14 -0
  116. package/build/findEntityScopes.d.cts.map +1 -0
  117. package/build/findEntityScopes.d.mts +14 -0
  118. package/build/findEntityScopes.d.mts.map +1 -0
  119. package/build/findEntityScopes.js +83 -111
  120. package/build/findEntityScopes.js.map +1 -1
  121. package/build/foreignKeyOrdering.cjs +52 -0
  122. package/build/foreignKeyOrdering.cjs.map +1 -0
  123. package/build/foreignKeyOrdering.d.cts +8 -0
  124. package/build/foreignKeyOrdering.d.cts.map +1 -0
  125. package/build/foreignKeyOrdering.d.mts +8 -0
  126. package/build/foreignKeyOrdering.d.mts.map +1 -0
  127. package/build/foreignKeyOrdering.js +46 -55
  128. package/build/foreignKeyOrdering.js.map +1 -1
  129. package/build/generate.cjs +128 -0
  130. package/build/generate.cjs.map +1 -0
  131. package/build/generate.d.cts +17 -0
  132. package/build/generate.d.cts.map +1 -0
  133. package/build/generate.d.mts +17 -0
  134. package/build/generate.d.mts.map +1 -0
  135. package/build/generate.js +111 -124
  136. package/build/generate.js.map +1 -1
  137. package/build/generateEntitiesFile.cjs +46 -0
  138. package/build/generateEntitiesFile.cjs.map +1 -0
  139. package/build/generateEntitiesFile.d.cts +11 -0
  140. package/build/generateEntitiesFile.d.cts.map +1 -0
  141. package/build/generateEntitiesFile.d.mts +11 -0
  142. package/build/generateEntitiesFile.d.mts.map +1 -0
  143. package/build/generateEntitiesFile.js +28 -25
  144. package/build/generateEntitiesFile.js.map +1 -1
  145. package/build/generateEntityCodegenFile.cjs +1010 -0
  146. package/build/generateEntityCodegenFile.cjs.map +1 -0
  147. package/build/generateEntityCodegenFile.d.cts +16 -0
  148. package/build/generateEntityCodegenFile.d.cts.map +1 -0
  149. package/build/generateEntityCodegenFile.d.mts +16 -0
  150. package/build/generateEntityCodegenFile.d.mts.map +1 -0
  151. package/build/generateEntityCodegenFile.js +793 -827
  152. package/build/generateEntityCodegenFile.js.map +1 -1
  153. package/build/generateEntityFile.cjs +23 -0
  154. package/build/generateEntityFile.cjs.map +1 -0
  155. package/build/generateEntityFile.d.cts +9 -0
  156. package/build/generateEntityFile.d.cts.map +1 -0
  157. package/build/generateEntityFile.d.mts +9 -0
  158. package/build/generateEntityFile.d.mts.map +1 -0
  159. package/build/generateEntityFile.js +11 -8
  160. package/build/generateEntityFile.js.map +1 -1
  161. package/build/generateEntityTestFile.cjs +25 -0
  162. package/build/generateEntityTestFile.cjs.map +1 -0
  163. package/build/generateEntityTestFile.d.cts +9 -0
  164. package/build/generateEntityTestFile.d.cts.map +1 -0
  165. package/build/generateEntityTestFile.d.mts +9 -0
  166. package/build/generateEntityTestFile.d.mts.map +1 -0
  167. package/build/generateEntityTestFile.js +10 -7
  168. package/build/generateEntityTestFile.js.map +1 -1
  169. package/build/generateEnumFile.cjs +73 -0
  170. package/build/generateEnumFile.cjs.map +1 -0
  171. package/build/generateEnumFile.d.cts +9 -0
  172. package/build/generateEnumFile.d.cts.map +1 -0
  173. package/build/generateEnumFile.d.mts +9 -0
  174. package/build/generateEnumFile.d.mts.map +1 -0
  175. package/build/generateEnumFile.js +33 -43
  176. package/build/generateEnumFile.js.map +1 -1
  177. package/build/generateFactoriesFiles.cjs +28 -0
  178. package/build/generateFactoriesFiles.cjs.map +1 -0
  179. package/build/generateFactoriesFiles.d.cts +7 -0
  180. package/build/generateFactoriesFiles.d.cts.map +1 -0
  181. package/build/generateFactoriesFiles.d.mts +7 -0
  182. package/build/generateFactoriesFiles.d.mts.map +1 -0
  183. package/build/generateFactoriesFiles.js +21 -16
  184. package/build/generateFactoriesFiles.js.map +1 -1
  185. package/build/generateFlushFunction.cjs +61 -0
  186. package/build/generateFlushFunction.cjs.map +1 -0
  187. package/build/{generateFlushFunction.d.ts → generateFlushFunction.d.cts} +8 -5
  188. package/build/generateFlushFunction.d.cts.map +1 -0
  189. package/build/generateFlushFunction.d.mts +23 -0
  190. package/build/generateFlushFunction.d.mts.map +1 -0
  191. package/build/generateFlushFunction.js +32 -78
  192. package/build/generateFlushFunction.js.map +1 -1
  193. package/build/generateMetadataFile.cjs +307 -0
  194. package/build/generateMetadataFile.cjs.map +1 -0
  195. package/build/generateMetadataFile.d.cts +10 -0
  196. package/build/generateMetadataFile.d.cts.map +1 -0
  197. package/build/generateMetadataFile.d.mts +10 -0
  198. package/build/generateMetadataFile.d.mts.map +1 -0
  199. package/build/generateMetadataFile.js +148 -156
  200. package/build/generateMetadataFile.js.map +1 -1
  201. package/build/generatePgEnumFile.cjs +21 -0
  202. package/build/generatePgEnumFile.cjs.map +1 -0
  203. package/build/generatePgEnumFile.d.cts +9 -0
  204. package/build/generatePgEnumFile.d.cts.map +1 -0
  205. package/build/generatePgEnumFile.d.mts +9 -0
  206. package/build/generatePgEnumFile.d.mts.map +1 -0
  207. package/build/generatePgEnumFile.js +12 -9
  208. package/build/generatePgEnumFile.js.map +1 -1
  209. package/build/index.cjs +135 -0
  210. package/build/index.cjs.map +1 -0
  211. package/build/index.d.cts +12 -0
  212. package/build/index.d.cts.map +1 -0
  213. package/build/index.d.mts +12 -0
  214. package/build/index.d.mts.map +1 -0
  215. package/build/index.js +108 -127
  216. package/build/index.js.map +1 -1
  217. package/build/inheritance.cjs +241 -0
  218. package/build/inheritance.cjs.map +1 -0
  219. package/build/inheritance.d.cts +13 -0
  220. package/build/inheritance.d.cts.map +1 -0
  221. package/build/inheritance.d.mts +13 -0
  222. package/build/inheritance.d.mts.map +1 -0
  223. package/build/inheritance.js +221 -247
  224. package/build/inheritance.js.map +1 -1
  225. package/build/installSkills.cjs +68 -0
  226. package/build/installSkills.cjs.map +1 -0
  227. package/build/installSkills.d.cts +16 -0
  228. package/build/installSkills.d.cts.map +1 -0
  229. package/build/installSkills.d.mts +16 -0
  230. package/build/installSkills.d.mts.map +1 -0
  231. package/build/installSkills.js +67 -0
  232. package/build/installSkills.js.map +1 -0
  233. package/build/keywords.cjs +7 -0
  234. package/build/keywords.cjs.map +1 -0
  235. package/build/keywords.d.cts +5 -0
  236. package/build/keywords.d.cts.map +1 -0
  237. package/build/keywords.d.mts +5 -0
  238. package/build/keywords.d.mts.map +1 -0
  239. package/build/keywords.js +5 -4
  240. package/build/keywords.js.map +1 -1
  241. package/build/loadMetadata.cjs +39 -0
  242. package/build/loadMetadata.cjs.map +1 -0
  243. package/build/loadMetadata.d.cts +31 -0
  244. package/build/loadMetadata.d.cts.map +1 -0
  245. package/build/loadMetadata.d.mts +31 -0
  246. package/build/loadMetadata.d.mts.map +1 -0
  247. package/build/loadMetadata.js +32 -39
  248. package/build/loadMetadata.js.map +1 -1
  249. package/build/logger.cjs +28 -0
  250. package/build/logger.cjs.map +1 -0
  251. package/build/logger.d.cts +13 -0
  252. package/build/logger.d.cts.map +1 -0
  253. package/build/logger.d.mts +13 -0
  254. package/build/logger.d.mts.map +1 -0
  255. package/build/logger.js +17 -16
  256. package/build/logger.js.map +1 -1
  257. package/build/scanEntityFiles.cjs +46 -0
  258. package/build/scanEntityFiles.cjs.map +1 -0
  259. package/build/scanEntityFiles.d.cts +8 -0
  260. package/build/scanEntityFiles.d.cts.map +1 -0
  261. package/build/scanEntityFiles.d.mts +8 -0
  262. package/build/scanEntityFiles.d.mts.map +1 -0
  263. package/build/scanEntityFiles.js +37 -42
  264. package/build/scanEntityFiles.js.map +1 -1
  265. package/build/sortForeignKeys.cjs +99 -0
  266. package/build/sortForeignKeys.cjs.map +1 -0
  267. package/build/{sortForeignKeys.d.ts → sortForeignKeys.d.cts} +8 -5
  268. package/build/sortForeignKeys.d.cts.map +1 -0
  269. package/build/sortForeignKeys.d.mts +35 -0
  270. package/build/sortForeignKeys.d.mts.map +1 -0
  271. package/build/sortForeignKeys.js +88 -117
  272. package/build/sortForeignKeys.js.map +1 -1
  273. package/build/symbols.cjs +238 -0
  274. package/build/symbols.cjs.map +1 -0
  275. package/build/symbols.d.cts +120 -0
  276. package/build/symbols.d.cts.map +1 -0
  277. package/build/symbols.d.mts +120 -0
  278. package/build/symbols.d.mts.map +1 -0
  279. package/build/symbols.js +121 -113
  280. package/build/symbols.js.map +1 -1
  281. package/build/tsdoc.cjs +22 -0
  282. package/build/tsdoc.cjs.map +1 -0
  283. package/build/tsdoc.d.cts +15 -0
  284. package/build/tsdoc.d.cts.map +1 -0
  285. package/build/tsdoc.d.mts +15 -0
  286. package/build/tsdoc.d.mts.map +1 -0
  287. package/build/tsdoc.js +18 -15
  288. package/build/tsdoc.js.map +1 -1
  289. package/build/utils.cjs +173 -0
  290. package/build/utils.cjs.map +1 -0
  291. package/build/utils.d.cts +34 -0
  292. package/build/utils.d.cts.map +1 -0
  293. package/build/utils.d.mts +34 -0
  294. package/build/utils.d.mts.map +1 -0
  295. package/build/utils.js +112 -166
  296. package/build/utils.js.map +1 -1
  297. package/build/write-json-schema.cjs +23 -0
  298. package/build/write-json-schema.cjs.map +1 -0
  299. package/build/write-json-schema.d.cts +1 -0
  300. package/build/write-json-schema.d.mts +1 -0
  301. package/build/write-json-schema.js +19 -13
  302. package/build/write-json-schema.js.map +1 -1
  303. package/package.json +37 -17
  304. package/skills/joist-docs/SKILL.md +133 -0
  305. package/skills/joist-em-basics/SKILL.md +114 -0
  306. package/skills/joist-partial-updates/SKILL.md +352 -0
  307. package/skills/joist-reactive-hints/SKILL.md +150 -0
  308. package/skills/joist-test-factories/SKILL.md +397 -0
  309. package/skills/joist-upsert/SKILL.md +95 -0
  310. package/build/EntityDbMetadata.d.ts +0 -269
  311. package/build/EntityDbMetadata.d.ts.map +0 -1
  312. package/build/EntityDbMetadata.test.d.ts +0 -2
  313. package/build/EntityDbMetadata.test.d.ts.map +0 -1
  314. package/build/EntityDbMetadata.test.js +0 -211
  315. package/build/EntityDbMetadata.test.js.map +0 -1
  316. package/build/assignTags.d.ts.map +0 -1
  317. package/build/codemods/Codemod.d.ts +0 -14
  318. package/build/codemods/Codemod.d.ts.map +0 -1
  319. package/build/codemods/Codemod.js.map +0 -1
  320. package/build/codemods/JscodeshiftMod.d.ts +0 -11
  321. package/build/codemods/JscodeshiftMod.d.ts.map +0 -1
  322. package/build/codemods/__tests__/codemod_0001-rename_has_async_property.test.d.ts +0 -2
  323. package/build/codemods/__tests__/codemod_0001-rename_has_async_property.test.d.ts.map +0 -1
  324. package/build/codemods/__tests__/codemod_0001-rename_has_async_property.test.js +0 -9
  325. package/build/codemods/__tests__/codemod_0001-rename_has_async_property.test.js.map +0 -1
  326. package/build/codemods/__tests__/codemod_0002-rename_async_query_fields.test.d.ts +0 -2
  327. package/build/codemods/__tests__/codemod_0002-rename_async_query_fields.test.d.ts.map +0 -1
  328. package/build/codemods/__tests__/codemod_0002-rename_async_query_fields.test.js +0 -9
  329. package/build/codemods/__tests__/codemod_0002-rename_async_query_fields.test.js.map +0 -1
  330. package/build/codemods/__tests__/codemod_0003-rename_find_paginated.test.d.ts +0 -2
  331. package/build/codemods/__tests__/codemod_0003-rename_find_paginated.test.d.ts.map +0 -1
  332. package/build/codemods/__tests__/codemod_0003-rename_find_paginated.test.js +0 -9
  333. package/build/codemods/__tests__/codemod_0003-rename_find_paginated.test.js.map +0 -1
  334. package/build/codemods/codemod_0001-rename_has_async_property.d.ts +0 -7
  335. package/build/codemods/codemod_0001-rename_has_async_property.d.ts.map +0 -1
  336. package/build/codemods/codemod_0002-rename_async_query_fields.d.ts +0 -7
  337. package/build/codemods/codemod_0002-rename_async_query_fields.d.ts.map +0 -1
  338. package/build/codemods/codemod_0003-rename_find_paginated.d.ts +0 -7
  339. package/build/codemods/codemod_0003-rename_find_paginated.d.ts.map +0 -1
  340. package/build/codemods/index.d.ts +0 -9
  341. package/build/codemods/index.d.ts.map +0 -1
  342. package/build/codemods/index.test.d.ts +0 -2
  343. package/build/codemods/index.test.d.ts.map +0 -1
  344. package/build/codemods/index.test.js +0 -24
  345. package/build/codemods/index.test.js.map +0 -1
  346. package/build/config.d.ts +0 -167
  347. package/build/config.d.ts.map +0 -1
  348. package/build/config.test.d.ts +0 -2
  349. package/build/config.test.d.ts.map +0 -1
  350. package/build/config.test.js +0 -78
  351. package/build/config.test.js.map +0 -1
  352. package/build/docs/cache.d.ts +0 -14
  353. package/build/docs/cache.d.ts.map +0 -1
  354. package/build/docs/cache.test.d.ts +0 -2
  355. package/build/docs/cache.test.d.ts.map +0 -1
  356. package/build/docs/cache.test.js +0 -47
  357. package/build/docs/cache.test.js.map +0 -1
  358. package/build/docs/generate-metadata-docs.d.ts +0 -6
  359. package/build/docs/generate-metadata-docs.d.ts.map +0 -1
  360. package/build/docs/index.d.ts +0 -9
  361. package/build/docs/index.d.ts.map +0 -1
  362. package/build/docs/index.test.d.ts +0 -2
  363. package/build/docs/index.test.d.ts.map +0 -1
  364. package/build/docs/index.test.js +0 -100
  365. package/build/docs/index.test.js.map +0 -1
  366. package/build/docs/markdown.d.ts.map +0 -1
  367. package/build/docs/markdown.test.d.ts +0 -2
  368. package/build/docs/markdown.test.d.ts.map +0 -1
  369. package/build/docs/markdown.test.js +0 -280
  370. package/build/docs/markdown.test.js.map +0 -1
  371. package/build/docs/parsing.d.ts +0 -42
  372. package/build/docs/parsing.d.ts.map +0 -1
  373. package/build/docs/parsing.test.d.ts +0 -2
  374. package/build/docs/parsing.test.d.ts.map +0 -1
  375. package/build/docs/parsing.test.js +0 -190
  376. package/build/docs/parsing.test.js.map +0 -1
  377. package/build/findEntityScopes.d.ts +0 -11
  378. package/build/findEntityScopes.d.ts.map +0 -1
  379. package/build/foreignKeyOrdering.d.ts +0 -3
  380. package/build/foreignKeyOrdering.d.ts.map +0 -1
  381. package/build/generate.d.ts +0 -12
  382. package/build/generate.d.ts.map +0 -1
  383. package/build/generateEntitiesFile.d.ts +0 -7
  384. package/build/generateEntitiesFile.d.ts.map +0 -1
  385. package/build/generateEntityCodegenFile.d.ts +0 -11
  386. package/build/generateEntityCodegenFile.d.ts.map +0 -1
  387. package/build/generateEntityFile.d.ts +0 -6
  388. package/build/generateEntityFile.d.ts.map +0 -1
  389. package/build/generateEntityTestFile.d.ts +0 -6
  390. package/build/generateEntityTestFile.d.ts.map +0 -1
  391. package/build/generateEnumFile.d.ts +0 -5
  392. package/build/generateEnumFile.d.ts.map +0 -1
  393. package/build/generateFactoriesFiles.d.ts +0 -4
  394. package/build/generateFactoriesFiles.d.ts.map +0 -1
  395. package/build/generateFlushFunction.d.ts.map +0 -1
  396. package/build/generateMetadataFile.d.ts +0 -5
  397. package/build/generateMetadataFile.d.ts.map +0 -1
  398. package/build/generatePgEnumFile.d.ts +0 -5
  399. package/build/generatePgEnumFile.d.ts.map +0 -1
  400. package/build/index.d.ts +0 -11
  401. package/build/index.d.ts.map +0 -1
  402. package/build/inheritance.d.ts +0 -10
  403. package/build/inheritance.d.ts.map +0 -1
  404. package/build/keywords.d.ts +0 -2
  405. package/build/keywords.d.ts.map +0 -1
  406. package/build/loadMetadata.d.ts +0 -26
  407. package/build/loadMetadata.d.ts.map +0 -1
  408. package/build/logger.d.ts +0 -10
  409. package/build/logger.d.ts.map +0 -1
  410. package/build/scanEntityFiles.d.ts +0 -5
  411. package/build/scanEntityFiles.d.ts.map +0 -1
  412. package/build/sortForeignKeys.d.ts.map +0 -1
  413. package/build/symbols.d.ts +0 -108
  414. package/build/symbols.d.ts.map +0 -1
  415. package/build/tsdoc.d.ts +0 -12
  416. package/build/tsdoc.d.ts.map +0 -1
  417. package/build/utils.d.ts +0 -31
  418. package/build/utils.d.ts.map +0 -1
  419. package/build/write-json-schema.d.ts +0 -2
  420. package/build/write-json-schema.d.ts.map +0 -1
@@ -0,0 +1,46 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ require("./config.cjs");
3
+ require("./EntityDbMetadata.cjs");
4
+ let path = require("path");
5
+ let fs_promises = require("fs/promises");
6
+ //#region src/scanEntityFiles.ts
7
+ const regex = /config\.setDefault\([\s\n]*["'](\w+)["']/g;
8
+ /** Scans the entity files themselves for usage hints (like `setDefault` calls) to drive our codegen output. */
9
+ async function scanEntityFiles(config, dbMeta) {
10
+ await Promise.all(dbMeta.entities.map(async (entity) => {
11
+ try {
12
+ const tsCode = (await (0, fs_promises.readFile)((0, path.join)(config.entitiesDirectory, `${entity.name}.ts`))).toString();
13
+ const defaultableFields = recursiveDefaultableFields(dbMeta, entity);
14
+ for (const match of tsCode.matchAll(regex)) {
15
+ const field = defaultableFields.find((f) => f.fieldName === match[1]);
16
+ if (field) field.hasConfigDefault = true;
17
+ }
18
+ } catch (e) {}
19
+ }));
20
+ }
21
+ /**
22
+ * Traverse the entity inheritance tree to find all fields that can have defaults set on them.
23
+ *
24
+ * I.e. a column defined in a base CTI table like `publishers.foo_bar` having a `config.setDefault` in
25
+ * `SmallPublisher` and/or `LargePublisher`, or the same scenario for an STI table like `tasks.foo_bar`
26
+ * with `TaskNew` and/or `TaskOld`.
27
+ *
28
+ * NOTE: I suspect here could be some edge cases here that will need to be ironed out, but should work
29
+ * for simple inheritance structures. In particular, there may be unexpected side effects if a base
30
+ * class field has a default set in one subtype, but not another.
31
+ */
32
+ function recursiveDefaultableFields(dbMeta, entity) {
33
+ if (!entity) return [];
34
+ return [
35
+ ...entity.primitives,
36
+ ...entity.enums,
37
+ ...entity.pgEnums,
38
+ ...entity.manyToOnes,
39
+ ...entity.polymorphics,
40
+ ...entity.baseClassName ? recursiveDefaultableFields(dbMeta, dbMeta.entitiesByName[entity.baseClassName]) : []
41
+ ];
42
+ }
43
+ //#endregion
44
+ exports.scanEntityFiles = scanEntityFiles;
45
+
46
+ //# sourceMappingURL=scanEntityFiles.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanEntityFiles.cjs","names":["readFile","join"],"sources":["../src/scanEntityFiles.ts"],"sourcesContent":["import { readFile } from \"fs/promises\";\nimport { join } from \"path\";\n\nimport { type Config } from \"./config.ts\";\nimport {\n type DbMetadata,\n type EntityDbMetadata,\n type EnumField,\n type ManyToOneField,\n type PgEnumField,\n type PolymorphicField,\n type PrimitiveField,\n} from \"./EntityDbMetadata.ts\";\n\n// Erg, we need a regex in case the fieldName arg is wrapped onto a new line... :-/\nconst regex = /config\\.setDefault\\([\\s\\n]*[\"'](\\w+)[\"']/g;\n\n/** Scans the entity files themselves for usage hints (like `setDefault` calls) to drive our codegen output. */\nexport async function scanEntityFiles(config: Config, dbMeta: DbMetadata): Promise<void> {\n await Promise.all(\n dbMeta.entities.map(async (entity) => {\n try {\n // load the entity.ts file (as a promise with fs/promises)\n const tsCode = (await readFile(join(config.entitiesDirectory, `${entity.name}.ts`))).toString();\n const defaultableFields = recursiveDefaultableFields(dbMeta, entity);\n for (const match of tsCode.matchAll(regex)) {\n const field = defaultableFields.find((f) => f.fieldName === match[1]);\n if (field) {\n field.hasConfigDefault = true;\n }\n }\n } catch (e) {\n // Ignore file not existing yet\n }\n }),\n );\n}\n\n/**\n * Traverse the entity inheritance tree to find all fields that can have defaults set on them.\n *\n * I.e. a column defined in a base CTI table like `publishers.foo_bar` having a `config.setDefault` in\n * `SmallPublisher` and/or `LargePublisher`, or the same scenario for an STI table like `tasks.foo_bar`\n * with `TaskNew` and/or `TaskOld`.\n *\n * NOTE: I suspect here could be some edge cases here that will need to be ironed out, but should work\n * for simple inheritance structures. In particular, there may be unexpected side effects if a base\n * class field has a default set in one subtype, but not another.\n */\nfunction recursiveDefaultableFields(\n dbMeta: DbMetadata,\n entity: EntityDbMetadata | undefined,\n): Array<PrimitiveField | EnumField | PgEnumField | ManyToOneField | PolymorphicField> {\n if (!entity) return [];\n return [\n ...entity.primitives,\n ...entity.enums,\n ...entity.pgEnums,\n ...entity.manyToOnes,\n ...entity.polymorphics,\n ...(entity.baseClassName ? recursiveDefaultableFields(dbMeta, dbMeta.entitiesByName[entity.baseClassName]) : []),\n ];\n}\n"],"mappings":";;;;;;AAeA,MAAM,QAAQ;;AAGd,eAAsB,gBAAgB,QAAgB,QAAmC;CACvF,MAAM,QAAQ,IACZ,OAAO,SAAS,IAAI,OAAO,WAAW;EACpC,IAAI;GAEF,MAAM,UAAU,OAAA,GAAMA,YAAAA,SAAAA,EAAAA,GAASC,KAAAA,KAAAA,CAAK,OAAO,mBAAmB,GAAG,OAAO,KAAK,IAAI,CAAC,EAAA,CAAG,SAAS;GAC9F,MAAM,oBAAoB,2BAA2B,QAAQ,MAAM;GACnE,KAAK,MAAM,SAAS,OAAO,SAAS,KAAK,GAAG;IAC1C,MAAM,QAAQ,kBAAkB,MAAM,MAAM,EAAE,cAAc,MAAM,EAAE;IACpE,IAAI,OACF,MAAM,mBAAmB;GAE7B;EACF,SAAS,GAAG,CAEZ;CACF,CAAC,CACH;AACF;;;;;;;;;;;;AAaA,SAAS,2BACP,QACA,QACqF;CACrF,IAAI,CAAC,QAAQ,OAAO,CAAC;CACrB,OAAO;EACL,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAI,OAAO,gBAAgB,2BAA2B,QAAQ,OAAO,eAAe,OAAO,cAAc,IAAI,CAAC;CAChH;AACF"}
@@ -0,0 +1,8 @@
1
+ import { Config } from "./config.cjs";
2
+ import { DbMetadata } from "./EntityDbMetadata.cjs";
3
+ //#region src/scanEntityFiles.d.ts
4
+ /** Scans the entity files themselves for usage hints (like `setDefault` calls) to drive our codegen output. */
5
+ declare function scanEntityFiles(config: Config, dbMeta: DbMetadata): Promise<void>;
6
+ //#endregion
7
+ export { scanEntityFiles };
8
+ //# sourceMappingURL=scanEntityFiles.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanEntityFiles.d.cts","names":[],"sources":["../src/scanEntityFiles.ts"],"mappings":";;;;iBAkBsB,gBAAgB,QAAQ,QAAQ,QAAQ,aAAa"}
@@ -0,0 +1,8 @@
1
+ import { Config } from "./config.mjs";
2
+ import { DbMetadata } from "./EntityDbMetadata.mjs";
3
+ //#region src/scanEntityFiles.d.ts
4
+ /** Scans the entity files themselves for usage hints (like `setDefault` calls) to drive our codegen output. */
5
+ declare function scanEntityFiles(config: Config, dbMeta: DbMetadata): Promise<void>;
6
+ //#endregion
7
+ export { scanEntityFiles };
8
+ //# sourceMappingURL=scanEntityFiles.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanEntityFiles.d.mts","names":[],"sources":["../src/scanEntityFiles.ts"],"mappings":";;;;iBAkBsB,gBAAgB,QAAQ,QAAQ,QAAQ,aAAa"}
@@ -1,50 +1,45 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.scanEntityFiles = scanEntityFiles;
4
- const promises_1 = require("fs/promises");
5
- const path_1 = require("path");
6
- // Erg, we need a regex in case the fieldName arg is wrapped onto a new line... :-/
1
+ import "./config.js";
2
+ import "./EntityDbMetadata.js";
3
+ import { join } from "path";
4
+ import { readFile } from "fs/promises";
5
+ //#region src/scanEntityFiles.ts
7
6
  const regex = /config\.setDefault\([\s\n]*["'](\w+)["']/g;
8
7
  /** Scans the entity files themselves for usage hints (like `setDefault` calls) to drive our codegen output. */
9
8
  async function scanEntityFiles(config, dbMeta) {
10
- await Promise.all(dbMeta.entities.map(async (entity) => {
11
- try {
12
- // load the entity.ts file (as a promise with fs/promises)
13
- const tsCode = (await (0, promises_1.readFile)((0, path_1.join)(config.entitiesDirectory, `${entity.name}.ts`))).toString();
14
- const defaultableFields = recursiveDefaultableFields(dbMeta, entity);
15
- for (const match of tsCode.matchAll(regex)) {
16
- const field = defaultableFields.find((f) => f.fieldName === match[1]);
17
- if (field) {
18
- field.hasConfigDefault = true;
19
- }
20
- }
21
- }
22
- catch (e) {
23
- // Ignore file not existing yet
24
- }
25
- }));
9
+ await Promise.all(dbMeta.entities.map(async (entity) => {
10
+ try {
11
+ const tsCode = (await readFile(join(config.entitiesDirectory, `${entity.name}.ts`))).toString();
12
+ const defaultableFields = recursiveDefaultableFields(dbMeta, entity);
13
+ for (const match of tsCode.matchAll(regex)) {
14
+ const field = defaultableFields.find((f) => f.fieldName === match[1]);
15
+ if (field) field.hasConfigDefault = true;
16
+ }
17
+ } catch (e) {}
18
+ }));
26
19
  }
27
20
  /**
28
- * Traverse the entity inheritance tree to find all fields that can have defaults set on them.
29
- *
30
- * I.e. a column defined in a base CTI table like `publishers.foo_bar` having a `config.setDefault` in
31
- * `SmallPublisher` and/or `LargePublisher`, or the same scenario for an STI table like `tasks.foo_bar`
32
- * with `TaskNew` and/or `TaskOld`.
33
- *
34
- * NOTE: I suspect here could be some edge cases here that will need to be ironed out, but should work
35
- * for simple inheritance structures. In particular, there may be unexpected side effects if a base
36
- * class field has a default set in one subtype, but not another.
37
- */
21
+ * Traverse the entity inheritance tree to find all fields that can have defaults set on them.
22
+ *
23
+ * I.e. a column defined in a base CTI table like `publishers.foo_bar` having a `config.setDefault` in
24
+ * `SmallPublisher` and/or `LargePublisher`, or the same scenario for an STI table like `tasks.foo_bar`
25
+ * with `TaskNew` and/or `TaskOld`.
26
+ *
27
+ * NOTE: I suspect here could be some edge cases here that will need to be ironed out, but should work
28
+ * for simple inheritance structures. In particular, there may be unexpected side effects if a base
29
+ * class field has a default set in one subtype, but not another.
30
+ */
38
31
  function recursiveDefaultableFields(dbMeta, entity) {
39
- if (!entity)
40
- return [];
41
- return [
42
- ...entity.primitives,
43
- ...entity.enums,
44
- ...entity.pgEnums,
45
- ...entity.manyToOnes,
46
- ...entity.polymorphics,
47
- ...(entity.baseClassName ? recursiveDefaultableFields(dbMeta, dbMeta.entitiesByName[entity.baseClassName]) : []),
48
- ];
32
+ if (!entity) return [];
33
+ return [
34
+ ...entity.primitives,
35
+ ...entity.enums,
36
+ ...entity.pgEnums,
37
+ ...entity.manyToOnes,
38
+ ...entity.polymorphics,
39
+ ...entity.baseClassName ? recursiveDefaultableFields(dbMeta, dbMeta.entitiesByName[entity.baseClassName]) : []
40
+ ];
49
41
  }
42
+ //#endregion
43
+ export { scanEntityFiles };
44
+
50
45
  //# sourceMappingURL=scanEntityFiles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scanEntityFiles.js","sourceRoot":"","sources":["../src/scanEntityFiles.ts"],"names":[],"mappings":";;AAiBA,0CAkBC;AAnCD,0CAAuC;AACvC,+BAA4B;AAY5B,mFAAmF;AACnF,MAAM,KAAK,GAAG,2CAA2C,CAAC;AAE1D,+GAA+G;AACxG,KAAK,UAAU,eAAe,CAAC,MAAc,EAAE,MAAkB;IACtE,MAAM,OAAO,CAAC,GAAG,CACf,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QACnC,IAAI,CAAC;YACH,0DAA0D;YAC1D,MAAM,MAAM,GAAG,CAAC,MAAM,IAAA,mBAAQ,EAAC,IAAA,WAAI,EAAC,MAAM,CAAC,iBAAiB,EAAE,GAAG,MAAM,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;YAChG,MAAM,iBAAiB,GAAG,0BAA0B,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACrE,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC3C,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBACtE,IAAI,KAAK,EAAE,CAAC;oBACV,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,+BAA+B;QACjC,CAAC;IACH,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,0BAA0B,CACjC,MAAkB,EAClB,MAAoC;IAEpC,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IACvB,OAAO;QACL,GAAG,MAAM,CAAC,UAAU;QACpB,GAAG,MAAM,CAAC,KAAK;QACf,GAAG,MAAM,CAAC,OAAO;QACjB,GAAG,MAAM,CAAC,UAAU;QACpB,GAAG,MAAM,CAAC,YAAY;QACtB,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,0BAA0B,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KACjH,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"scanEntityFiles.js","names":[],"sources":["../src/scanEntityFiles.ts"],"sourcesContent":["import { readFile } from \"fs/promises\";\nimport { join } from \"path\";\n\nimport { type Config } from \"./config.ts\";\nimport {\n type DbMetadata,\n type EntityDbMetadata,\n type EnumField,\n type ManyToOneField,\n type PgEnumField,\n type PolymorphicField,\n type PrimitiveField,\n} from \"./EntityDbMetadata.ts\";\n\n// Erg, we need a regex in case the fieldName arg is wrapped onto a new line... :-/\nconst regex = /config\\.setDefault\\([\\s\\n]*[\"'](\\w+)[\"']/g;\n\n/** Scans the entity files themselves for usage hints (like `setDefault` calls) to drive our codegen output. */\nexport async function scanEntityFiles(config: Config, dbMeta: DbMetadata): Promise<void> {\n await Promise.all(\n dbMeta.entities.map(async (entity) => {\n try {\n // load the entity.ts file (as a promise with fs/promises)\n const tsCode = (await readFile(join(config.entitiesDirectory, `${entity.name}.ts`))).toString();\n const defaultableFields = recursiveDefaultableFields(dbMeta, entity);\n for (const match of tsCode.matchAll(regex)) {\n const field = defaultableFields.find((f) => f.fieldName === match[1]);\n if (field) {\n field.hasConfigDefault = true;\n }\n }\n } catch (e) {\n // Ignore file not existing yet\n }\n }),\n );\n}\n\n/**\n * Traverse the entity inheritance tree to find all fields that can have defaults set on them.\n *\n * I.e. a column defined in a base CTI table like `publishers.foo_bar` having a `config.setDefault` in\n * `SmallPublisher` and/or `LargePublisher`, or the same scenario for an STI table like `tasks.foo_bar`\n * with `TaskNew` and/or `TaskOld`.\n *\n * NOTE: I suspect here could be some edge cases here that will need to be ironed out, but should work\n * for simple inheritance structures. In particular, there may be unexpected side effects if a base\n * class field has a default set in one subtype, but not another.\n */\nfunction recursiveDefaultableFields(\n dbMeta: DbMetadata,\n entity: EntityDbMetadata | undefined,\n): Array<PrimitiveField | EnumField | PgEnumField | ManyToOneField | PolymorphicField> {\n if (!entity) return [];\n return [\n ...entity.primitives,\n ...entity.enums,\n ...entity.pgEnums,\n ...entity.manyToOnes,\n ...entity.polymorphics,\n ...(entity.baseClassName ? recursiveDefaultableFields(dbMeta, dbMeta.entitiesByName[entity.baseClassName]) : []),\n ];\n}\n"],"mappings":";;;;;AAeA,MAAM,QAAQ;;AAGd,eAAsB,gBAAgB,QAAgB,QAAmC;CACvF,MAAM,QAAQ,IACZ,OAAO,SAAS,IAAI,OAAO,WAAW;EACpC,IAAI;GAEF,MAAM,UAAU,MAAM,SAAS,KAAK,OAAO,mBAAmB,GAAG,OAAO,KAAK,IAAI,CAAC,EAAA,CAAG,SAAS;GAC9F,MAAM,oBAAoB,2BAA2B,QAAQ,MAAM;GACnE,KAAK,MAAM,SAAS,OAAO,SAAS,KAAK,GAAG;IAC1C,MAAM,QAAQ,kBAAkB,MAAM,MAAM,EAAE,cAAc,MAAM,EAAE;IACpE,IAAI,OACF,MAAM,mBAAmB;GAE7B;EACF,SAAS,GAAG,CAEZ;CACF,CAAC,CACH;AACF;;;;;;;;;;;;AAaA,SAAS,2BACP,QACA,QACqF;CACrF,IAAI,CAAC,QAAQ,OAAO,CAAC;CACrB,OAAO;EACL,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAI,OAAO,gBAAgB,2BAA2B,QAAQ,OAAO,eAAe,OAAO,cAAc,IAAI,CAAC;CAChH;AACF"}
@@ -0,0 +1,99 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ require("./EntityDbMetadata.cjs");
3
+ //#region src/sortForeignKeys.ts
4
+ /**
5
+ * Sorts entities by non-deferred foreign key order.
6
+ *
7
+ * Ideally databases/schemas will support/enable deferred FKs, which let us insert/delete rows
8
+ * in any arbitrary order, and the FK checks will not be applied until txn commit.
9
+ *
10
+ * However, if not enabled/support, we have to worry about two things:
11
+ *
12
+ * 1. Inserting "parents" before their children
13
+ * - And if the parent has a circular reference to not-yet-inserted cycle
14
+ * 2. Deleting "children" before their parents
15
+ * - Again if the parent has a circular reference to the child
16
+ *
17
+ * For both of these, we can just look at the FK ordering to "put the parent first",
18
+ * but run into two problems:
19
+ *
20
+ * - If there is a cycle for not-null FKs, that breaks both INSERTs and DELETEs, so we
21
+ * must warn the user about these to fix.
22
+ * - If there is a cycle with nullable FKs, we can work around that by using NULL as a
23
+ * transient/dummy value, for the initial insert, do the 2nd insert, and then "fixup" the
24
+ * first insert with a UPDATE to the actual column value.
25
+ *
26
+ * Given ^, we set the `entity.nonDeferredFkOrder` of each entity, and then also return
27
+ * two arrays of all soft-cycle (nullable, fixup-able) and hard-cycle (not-nullable, blocking)
28
+ * keys.
29
+ */
30
+ function sortByNonDeferredForeignKeys(entities) {
31
+ const graph = Object.fromEntries(entities.map((e) => [e.name, {
32
+ entity: e,
33
+ upstreamFks: /* @__PURE__ */ new Set(),
34
+ downstreamFks: /* @__PURE__ */ new Set()
35
+ }]));
36
+ const nullableCycles = [];
37
+ const notNullCycles = [];
38
+ entities.forEach((entity) => {
39
+ entity.nonDeferredFks.filter((m2o) => m2o.notNull).forEach((m2o) => {
40
+ const added = addDependency(graph, entity, m2o);
41
+ if (Array.isArray(added)) notNullCycles.push(added.join(" -> "));
42
+ });
43
+ });
44
+ entities.forEach((entity) => {
45
+ entity.nonDeferredFks.filter((m2o) => !m2o.notNull).forEach((m2o) => {
46
+ const added = addDependency(graph, entity, m2o);
47
+ if (Array.isArray(added)) nullableCycles.push(added.join(" -> "));
48
+ });
49
+ });
50
+ let queue = Object.values(graph).filter((n) => n.upstreamFks.size === 0);
51
+ let level = 1;
52
+ while (queue.length > 0) {
53
+ const nextLevel = [];
54
+ for (const current of queue) {
55
+ current.entity.nonDeferredFkOrder = level;
56
+ current.downstreamFks.forEach((node) => {
57
+ if (node.upstreamFks.delete(current) && node.upstreamFks.size === 0) nextLevel.push(node);
58
+ });
59
+ }
60
+ queue = nextLevel;
61
+ level++;
62
+ }
63
+ entities.filter((e) => e.nonDeferredFkOrder === -1).forEach((e) => e.nonDeferredFkOrder = 1e5);
64
+ return {
65
+ nullableCycles,
66
+ notNullCycles
67
+ };
68
+ }
69
+ function addDependency(graph, entity, m2o) {
70
+ const from = graph[entity.name];
71
+ const to = graph[m2o.otherEntity.name];
72
+ const cycle = willCreateCycle(graph, from, to);
73
+ if (cycle) return cycle;
74
+ from.upstreamFks.add(to);
75
+ to.downstreamFks.add(from);
76
+ return true;
77
+ }
78
+ function willCreateCycle(graph, from, to) {
79
+ return dfs(graph, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set(), [], from, to);
80
+ }
81
+ function dfs(graph, visited, stack, path, current, target) {
82
+ visited.add(current);
83
+ stack.add(current);
84
+ path.push(current);
85
+ for (const neighbor of current.downstreamFks) {
86
+ if (neighbor === target) return [...path, neighbor].map((n) => n.entity.name);
87
+ if (!visited.has(neighbor)) {
88
+ const cycle = dfs(graph, visited, stack, path, neighbor, target);
89
+ if (cycle) return cycle;
90
+ }
91
+ }
92
+ stack.delete(current);
93
+ path.pop();
94
+ return false;
95
+ }
96
+ //#endregion
97
+ exports.sortByNonDeferredForeignKeys = sortByNonDeferredForeignKeys;
98
+
99
+ //# sourceMappingURL=sortForeignKeys.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sortForeignKeys.cjs","names":[],"sources":["../src/sortForeignKeys.ts"],"sourcesContent":["import { type EntityDbMetadata, type ManyToOneField, type PolymorphicFieldComponent } from \"./EntityDbMetadata.ts\";\n\n/**\n * Sorts entities by non-deferred foreign key order.\n *\n * Ideally databases/schemas will support/enable deferred FKs, which let us insert/delete rows\n * in any arbitrary order, and the FK checks will not be applied until txn commit.\n *\n * However, if not enabled/support, we have to worry about two things:\n *\n * 1. Inserting \"parents\" before their children\n * - And if the parent has a circular reference to not-yet-inserted cycle\n * 2. Deleting \"children\" before their parents\n * - Again if the parent has a circular reference to the child\n *\n * For both of these, we can just look at the FK ordering to \"put the parent first\",\n * but run into two problems:\n *\n * - If there is a cycle for not-null FKs, that breaks both INSERTs and DELETEs, so we\n * must warn the user about these to fix.\n * - If there is a cycle with nullable FKs, we can work around that by using NULL as a\n * transient/dummy value, for the initial insert, do the 2nd insert, and then \"fixup\" the\n * first insert with a UPDATE to the actual column value.\n *\n * Given ^, we set the `entity.nonDeferredFkOrder` of each entity, and then also return\n * two arrays of all soft-cycle (nullable, fixup-able) and hard-cycle (not-nullable, blocking)\n * keys.\n */\nexport function sortByNonDeferredForeignKeys(entities: EntityDbMetadata[]): {\n nullableCycles: string[];\n notNullCycles: string[];\n} {\n // Kahn's algorithm, O(V + E)\n\n const graph: Record<string, Node> = Object.fromEntries(\n entities.map((e) => [\n e.name,\n {\n entity: e,\n upstreamFks: new Set(),\n downstreamFks: new Set(),\n },\n ]),\n );\n\n // Add all not-null deps first, as they are most important, cannot be fixed up.\n // - Failures here are fatal-ish\n // Then add nullable deps next, as they can be fixed-up\n\n const nullableCycles: string[] = [];\n const notNullCycles: string[] = [];\n\n // If we see `books.author_id`, mark `author.inDegree++`\n entities.forEach((entity) => {\n entity.nonDeferredFks\n .filter((m2o) => m2o.notNull)\n .forEach((m2o) => {\n const added = addDependency(graph, entity, m2o);\n if (Array.isArray(added)) notNullCycles.push(added.join(\" -> \"));\n });\n });\n\n // Do it again for nullable\n entities.forEach((entity) => {\n entity.nonDeferredFks\n .filter((m2o) => !m2o.notNull)\n .forEach((m2o) => {\n const added = addDependency(graph, entity, m2o);\n if (Array.isArray(added)) nullableCycles.push(added.join(\" -> \"));\n });\n });\n\n // Topological Sort\n // Enqueue entities with 0 out-degree (reverse Kahn), i.e. `authors`, they'll be at the top of the tree\n let queue = Object.values(graph).filter((n) => n.upstreamFks.size === 0);\n let level = 1;\n while (queue.length > 0) {\n // console.log(`Queue: ${queue.map((n) => n.entity.name)}`);\n const nextLevel: Node[] = [];\n for (const current of queue) {\n current.entity.nonDeferredFkOrder = level;\n current.downstreamFks.forEach((node) => {\n if (node.upstreamFks.delete(current) && node.upstreamFks.size === 0) {\n nextLevel.push(node);\n }\n });\n }\n queue = nextLevel;\n level++;\n }\n\n // Anything left with a -1 value means there is a cycle\n // Use a marker value for \"cyclic\"\n entities.filter((e) => e.nonDeferredFkOrder === -1).forEach((e) => (e.nonDeferredFkOrder = 100_000));\n\n return { nullableCycles, notNullCycles: notNullCycles };\n}\n\ntype Node = {\n entity: EntityDbMetadata;\n upstreamFks: Set<Node>;\n downstreamFks: Set<Node>;\n};\n\nfunction addDependency(\n graph: Record<string, Node>,\n entity: EntityDbMetadata,\n m2o: ManyToOneField | PolymorphicFieldComponent,\n): true | string[] {\n const from = graph[entity.name]; // i.e. books\n const to = graph[m2o.otherEntity.name]; // i.e. authors\n const cycle = willCreateCycle(graph, from, to);\n if (cycle) {\n // console.log(`Skipped ${entity.name}.${m2o.columnName} -> ${m2o.otherEntity.name}`);\n return cycle;\n }\n // console.log(`Added ${entity.name}.${m2o.columnName} -> ${m2o.otherEntity.name}`);\n from.upstreamFks.add(to);\n to.downstreamFks.add(from);\n return true;\n}\n\nfunction willCreateCycle(graph: Record<string, Node>, from: Node, to: Node): false | string[] {\n const visited: Set<Node> = new Set();\n const stack: Set<Node> = new Set();\n const path: Node[] = [];\n // If `from=books[.author_id]` pointing at `to=authors`, we want to do `to.downstreamFks.add(from)`,\n // but first make sure that none of from's dowstreams are to, because if so it would make a cycle.\n return dfs(graph, visited, stack, path, from, to);\n}\n\nfunction dfs(\n graph: Record<string, Node>,\n visited: Set<Node>,\n stack: Set<Node>,\n path: Node[],\n current: Node,\n target: Node,\n): false | string[] {\n visited.add(current);\n stack.add(current);\n path.push(current);\n for (const neighbor of current.downstreamFks) {\n if (neighbor === target) {\n return [...path, neighbor].map((n) => n.entity.name);\n }\n if (!visited.has(neighbor)) {\n const cycle = dfs(graph, visited, stack, path, neighbor, target);\n if (cycle) return cycle;\n }\n }\n stack.delete(current);\n path.pop();\n return false;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,SAAgB,6BAA6B,UAG3C;CAGA,MAAM,QAA8B,OAAO,YACzC,SAAS,KAAK,MAAM,CAClB,EAAE,MACF;EACE,QAAQ;EACR,6BAAa,IAAI,IAAI;EACrB,+BAAe,IAAI,IAAI;CACzB,CACF,CAAC,CACH;CAMA,MAAM,iBAA2B,CAAC;CAClC,MAAM,gBAA0B,CAAC;CAGjC,SAAS,SAAS,WAAW;EAC3B,OAAO,eACJ,QAAQ,QAAQ,IAAI,OAAO,CAAC,CAC5B,SAAS,QAAQ;GAChB,MAAM,QAAQ,cAAc,OAAO,QAAQ,GAAG;GAC9C,IAAI,MAAM,QAAQ,KAAK,GAAG,cAAc,KAAK,MAAM,KAAK,MAAM,CAAC;EACjE,CAAC;CACL,CAAC;CAGD,SAAS,SAAS,WAAW;EAC3B,OAAO,eACJ,QAAQ,QAAQ,CAAC,IAAI,OAAO,CAAC,CAC7B,SAAS,QAAQ;GAChB,MAAM,QAAQ,cAAc,OAAO,QAAQ,GAAG;GAC9C,IAAI,MAAM,QAAQ,KAAK,GAAG,eAAe,KAAK,MAAM,KAAK,MAAM,CAAC;EAClE,CAAC;CACL,CAAC;CAID,IAAI,QAAQ,OAAO,OAAO,KAAK,CAAC,CAAC,QAAQ,MAAM,EAAE,YAAY,SAAS,CAAC;CACvE,IAAI,QAAQ;CACZ,OAAO,MAAM,SAAS,GAAG;EAEvB,MAAM,YAAoB,CAAC;EAC3B,KAAK,MAAM,WAAW,OAAO;GAC3B,QAAQ,OAAO,qBAAqB;GACpC,QAAQ,cAAc,SAAS,SAAS;IACtC,IAAI,KAAK,YAAY,OAAO,OAAO,KAAK,KAAK,YAAY,SAAS,GAChE,UAAU,KAAK,IAAI;GAEvB,CAAC;EACH;EACA,QAAQ;EACR;CACF;CAIA,SAAS,QAAQ,MAAM,EAAE,uBAAuB,EAAE,CAAC,CAAC,SAAS,MAAO,EAAE,qBAAqB,GAAQ;CAEnG,OAAO;EAAE;EAA+B;CAAc;AACxD;AAQA,SAAS,cACP,OACA,QACA,KACiB;CACjB,MAAM,OAAO,MAAM,OAAO;CAC1B,MAAM,KAAK,MAAM,IAAI,YAAY;CACjC,MAAM,QAAQ,gBAAgB,OAAO,MAAM,EAAE;CAC7C,IAAI,OAEF,OAAO;CAGT,KAAK,YAAY,IAAI,EAAE;CACvB,GAAG,cAAc,IAAI,IAAI;CACzB,OAAO;AACT;AAEA,SAAS,gBAAgB,OAA6B,MAAY,IAA4B;CAM5F,OAAO,IAAI,uBAAO,IALa,IAKP,mBAAG,IAJE,IAIE,GAAG,CAAG,GAAG,MAAM,EAAE;AAClD;AAEA,SAAS,IACP,OACA,SACA,OACA,MACA,SACA,QACkB;CAClB,QAAQ,IAAI,OAAO;CACnB,MAAM,IAAI,OAAO;CACjB,KAAK,KAAK,OAAO;CACjB,KAAK,MAAM,YAAY,QAAQ,eAAe;EAC5C,IAAI,aAAa,QACf,OAAO,CAAC,GAAG,MAAM,QAAQ,CAAC,CAAC,KAAK,MAAM,EAAE,OAAO,IAAI;EAErD,IAAI,CAAC,QAAQ,IAAI,QAAQ,GAAG;GAC1B,MAAM,QAAQ,IAAI,OAAO,SAAS,OAAO,MAAM,UAAU,MAAM;GAC/D,IAAI,OAAO,OAAO;EACpB;CACF;CACA,MAAM,OAAO,OAAO;CACpB,KAAK,IAAI;CACT,OAAO;AACT"}
@@ -1,4 +1,5 @@
1
- import { EntityDbMetadata } from "./EntityDbMetadata";
1
+ import { EntityDbMetadata } from "./EntityDbMetadata.cjs";
2
+ //#region src/sortForeignKeys.d.ts
2
3
  /**
3
4
  * Sorts entities by non-deferred foreign key order.
4
5
  *
@@ -25,8 +26,10 @@ import { EntityDbMetadata } from "./EntityDbMetadata";
25
26
  * two arrays of all soft-cycle (nullable, fixup-able) and hard-cycle (not-nullable, blocking)
26
27
  * keys.
27
28
  */
28
- export declare function sortByNonDeferredForeignKeys(entities: EntityDbMetadata[]): {
29
- nullableCycles: string[];
30
- notNullCycles: string[];
29
+ declare function sortByNonDeferredForeignKeys(entities: EntityDbMetadata[]): {
30
+ nullableCycles: string[];
31
+ notNullCycles: string[];
31
32
  };
32
- //# sourceMappingURL=sortForeignKeys.d.ts.map
33
+ //#endregion
34
+ export { sortByNonDeferredForeignKeys };
35
+ //# sourceMappingURL=sortForeignKeys.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sortForeignKeys.d.cts","names":[],"sources":["../src/sortForeignKeys.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4BgB,6BAA6B,UAAU;EACrD;EACA"}
@@ -0,0 +1,35 @@
1
+ import { EntityDbMetadata } from "./EntityDbMetadata.mjs";
2
+ //#region src/sortForeignKeys.d.ts
3
+ /**
4
+ * Sorts entities by non-deferred foreign key order.
5
+ *
6
+ * Ideally databases/schemas will support/enable deferred FKs, which let us insert/delete rows
7
+ * in any arbitrary order, and the FK checks will not be applied until txn commit.
8
+ *
9
+ * However, if not enabled/support, we have to worry about two things:
10
+ *
11
+ * 1. Inserting "parents" before their children
12
+ * - And if the parent has a circular reference to not-yet-inserted cycle
13
+ * 2. Deleting "children" before their parents
14
+ * - Again if the parent has a circular reference to the child
15
+ *
16
+ * For both of these, we can just look at the FK ordering to "put the parent first",
17
+ * but run into two problems:
18
+ *
19
+ * - If there is a cycle for not-null FKs, that breaks both INSERTs and DELETEs, so we
20
+ * must warn the user about these to fix.
21
+ * - If there is a cycle with nullable FKs, we can work around that by using NULL as a
22
+ * transient/dummy value, for the initial insert, do the 2nd insert, and then "fixup" the
23
+ * first insert with a UPDATE to the actual column value.
24
+ *
25
+ * Given ^, we set the `entity.nonDeferredFkOrder` of each entity, and then also return
26
+ * two arrays of all soft-cycle (nullable, fixup-able) and hard-cycle (not-nullable, blocking)
27
+ * keys.
28
+ */
29
+ declare function sortByNonDeferredForeignKeys(entities: EntityDbMetadata[]): {
30
+ nullableCycles: string[];
31
+ notNullCycles: string[];
32
+ };
33
+ //#endregion
34
+ export { sortByNonDeferredForeignKeys };
35
+ //# sourceMappingURL=sortForeignKeys.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sortForeignKeys.d.mts","names":[],"sources":["../src/sortForeignKeys.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4BgB,6BAA6B,UAAU;EACrD;EACA"}
@@ -1,127 +1,98 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sortByNonDeferredForeignKeys = sortByNonDeferredForeignKeys;
1
+ import "./EntityDbMetadata.js";
2
+ //#region src/sortForeignKeys.ts
4
3
  /**
5
- * Sorts entities by non-deferred foreign key order.
6
- *
7
- * Ideally databases/schemas will support/enable deferred FKs, which let us insert/delete rows
8
- * in any arbitrary order, and the FK checks will not be applied until txn commit.
9
- *
10
- * However, if not enabled/support, we have to worry about two things:
11
- *
12
- * 1. Inserting "parents" before their children
13
- * - And if the parent has a circular reference to not-yet-inserted cycle
14
- * 2. Deleting "children" before their parents
15
- * - Again if the parent has a circular reference to the child
16
- *
17
- * For both of these, we can just look at the FK ordering to "put the parent first",
18
- * but run into two problems:
19
- *
20
- * - If there is a cycle for not-null FKs, that breaks both INSERTs and DELETEs, so we
21
- * must warn the user about these to fix.
22
- * - If there is a cycle with nullable FKs, we can work around that by using NULL as a
23
- * transient/dummy value, for the initial insert, do the 2nd insert, and then "fixup" the
24
- * first insert with a UPDATE to the actual column value.
25
- *
26
- * Given ^, we set the `entity.nonDeferredFkOrder` of each entity, and then also return
27
- * two arrays of all soft-cycle (nullable, fixup-able) and hard-cycle (not-nullable, blocking)
28
- * keys.
29
- */
4
+ * Sorts entities by non-deferred foreign key order.
5
+ *
6
+ * Ideally databases/schemas will support/enable deferred FKs, which let us insert/delete rows
7
+ * in any arbitrary order, and the FK checks will not be applied until txn commit.
8
+ *
9
+ * However, if not enabled/support, we have to worry about two things:
10
+ *
11
+ * 1. Inserting "parents" before their children
12
+ * - And if the parent has a circular reference to not-yet-inserted cycle
13
+ * 2. Deleting "children" before their parents
14
+ * - Again if the parent has a circular reference to the child
15
+ *
16
+ * For both of these, we can just look at the FK ordering to "put the parent first",
17
+ * but run into two problems:
18
+ *
19
+ * - If there is a cycle for not-null FKs, that breaks both INSERTs and DELETEs, so we
20
+ * must warn the user about these to fix.
21
+ * - If there is a cycle with nullable FKs, we can work around that by using NULL as a
22
+ * transient/dummy value, for the initial insert, do the 2nd insert, and then "fixup" the
23
+ * first insert with a UPDATE to the actual column value.
24
+ *
25
+ * Given ^, we set the `entity.nonDeferredFkOrder` of each entity, and then also return
26
+ * two arrays of all soft-cycle (nullable, fixup-able) and hard-cycle (not-nullable, blocking)
27
+ * keys.
28
+ */
30
29
  function sortByNonDeferredForeignKeys(entities) {
31
- // Kahn's algorithm, O(V + E)
32
- const graph = Object.fromEntries(entities.map((e) => [
33
- e.name,
34
- {
35
- entity: e,
36
- upstreamFks: new Set(),
37
- downstreamFks: new Set(),
38
- },
39
- ]));
40
- // Add all not-null deps first, as they are most important, cannot be fixed up.
41
- // - Failures here are fatal-ish
42
- // Then add nullable deps next, as they can be fixed-up
43
- const nullableCycles = [];
44
- const notNullCycles = [];
45
- // If we see `books.author_id`, mark `author.inDegree++`
46
- entities.forEach((entity) => {
47
- entity.nonDeferredFks
48
- .filter((m2o) => m2o.notNull)
49
- .forEach((m2o) => {
50
- const added = addDependency(graph, entity, m2o);
51
- if (Array.isArray(added))
52
- notNullCycles.push(added.join(" -> "));
53
- });
54
- });
55
- // Do it again for nullable
56
- entities.forEach((entity) => {
57
- entity.nonDeferredFks
58
- .filter((m2o) => !m2o.notNull)
59
- .forEach((m2o) => {
60
- const added = addDependency(graph, entity, m2o);
61
- if (Array.isArray(added))
62
- nullableCycles.push(added.join(" -> "));
63
- });
64
- });
65
- // Topological Sort
66
- // Enqueue entities with 0 out-degree (reverse Kahn), i.e. `authors`, they'll be at the top of the tree
67
- let queue = Object.values(graph).filter((n) => n.upstreamFks.size === 0);
68
- let level = 1;
69
- while (queue.length > 0) {
70
- // console.log(`Queue: ${queue.map((n) => n.entity.name)}`);
71
- const nextLevel = [];
72
- for (const current of queue) {
73
- current.entity.nonDeferredFkOrder = level;
74
- current.downstreamFks.forEach((node) => {
75
- if (node.upstreamFks.delete(current) && node.upstreamFks.size === 0) {
76
- nextLevel.push(node);
77
- }
78
- });
79
- }
80
- queue = nextLevel;
81
- level++;
82
- }
83
- // Anything left with a -1 value means there is a cycle
84
- // Use a marker value for "cyclic"
85
- entities.filter((e) => e.nonDeferredFkOrder === -1).forEach((e) => (e.nonDeferredFkOrder = 100_000));
86
- return { nullableCycles, notNullCycles: notNullCycles };
30
+ const graph = Object.fromEntries(entities.map((e) => [e.name, {
31
+ entity: e,
32
+ upstreamFks: /* @__PURE__ */ new Set(),
33
+ downstreamFks: /* @__PURE__ */ new Set()
34
+ }]));
35
+ const nullableCycles = [];
36
+ const notNullCycles = [];
37
+ entities.forEach((entity) => {
38
+ entity.nonDeferredFks.filter((m2o) => m2o.notNull).forEach((m2o) => {
39
+ const added = addDependency(graph, entity, m2o);
40
+ if (Array.isArray(added)) notNullCycles.push(added.join(" -> "));
41
+ });
42
+ });
43
+ entities.forEach((entity) => {
44
+ entity.nonDeferredFks.filter((m2o) => !m2o.notNull).forEach((m2o) => {
45
+ const added = addDependency(graph, entity, m2o);
46
+ if (Array.isArray(added)) nullableCycles.push(added.join(" -> "));
47
+ });
48
+ });
49
+ let queue = Object.values(graph).filter((n) => n.upstreamFks.size === 0);
50
+ let level = 1;
51
+ while (queue.length > 0) {
52
+ const nextLevel = [];
53
+ for (const current of queue) {
54
+ current.entity.nonDeferredFkOrder = level;
55
+ current.downstreamFks.forEach((node) => {
56
+ if (node.upstreamFks.delete(current) && node.upstreamFks.size === 0) nextLevel.push(node);
57
+ });
58
+ }
59
+ queue = nextLevel;
60
+ level++;
61
+ }
62
+ entities.filter((e) => e.nonDeferredFkOrder === -1).forEach((e) => e.nonDeferredFkOrder = 1e5);
63
+ return {
64
+ nullableCycles,
65
+ notNullCycles
66
+ };
87
67
  }
88
68
  function addDependency(graph, entity, m2o) {
89
- const from = graph[entity.name]; // i.e. books
90
- const to = graph[m2o.otherEntity.name]; // i.e. authors
91
- const cycle = willCreateCycle(graph, from, to);
92
- if (cycle) {
93
- // console.log(`Skipped ${entity.name}.${m2o.columnName} -> ${m2o.otherEntity.name}`);
94
- return cycle;
95
- }
96
- // console.log(`Added ${entity.name}.${m2o.columnName} -> ${m2o.otherEntity.name}`);
97
- from.upstreamFks.add(to);
98
- to.downstreamFks.add(from);
99
- return true;
69
+ const from = graph[entity.name];
70
+ const to = graph[m2o.otherEntity.name];
71
+ const cycle = willCreateCycle(graph, from, to);
72
+ if (cycle) return cycle;
73
+ from.upstreamFks.add(to);
74
+ to.downstreamFks.add(from);
75
+ return true;
100
76
  }
101
77
  function willCreateCycle(graph, from, to) {
102
- const visited = new Set();
103
- const stack = new Set();
104
- const path = [];
105
- // If `from=books[.author_id]` pointing at `to=authors`, we want to do `to.downstreamFks.add(from)`,
106
- // but first make sure that none of from's dowstreams are to, because if so it would make a cycle.
107
- return dfs(graph, visited, stack, path, from, to);
78
+ return dfs(graph, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set(), [], from, to);
108
79
  }
109
80
  function dfs(graph, visited, stack, path, current, target) {
110
- visited.add(current);
111
- stack.add(current);
112
- path.push(current);
113
- for (const neighbor of current.downstreamFks) {
114
- if (neighbor === target) {
115
- return [...path, neighbor].map((n) => n.entity.name);
116
- }
117
- if (!visited.has(neighbor)) {
118
- const cycle = dfs(graph, visited, stack, path, neighbor, target);
119
- if (cycle)
120
- return cycle;
121
- }
122
- }
123
- stack.delete(current);
124
- path.pop();
125
- return false;
81
+ visited.add(current);
82
+ stack.add(current);
83
+ path.push(current);
84
+ for (const neighbor of current.downstreamFks) {
85
+ if (neighbor === target) return [...path, neighbor].map((n) => n.entity.name);
86
+ if (!visited.has(neighbor)) {
87
+ const cycle = dfs(graph, visited, stack, path, neighbor, target);
88
+ if (cycle) return cycle;
89
+ }
90
+ }
91
+ stack.delete(current);
92
+ path.pop();
93
+ return false;
126
94
  }
95
+ //#endregion
96
+ export { sortByNonDeferredForeignKeys };
97
+
127
98
  //# sourceMappingURL=sortForeignKeys.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sortForeignKeys.js","sourceRoot":"","sources":["../src/sortForeignKeys.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sortForeignKeys.js","names":[],"sources":["../src/sortForeignKeys.ts"],"sourcesContent":["import { type EntityDbMetadata, type ManyToOneField, type PolymorphicFieldComponent } from \"./EntityDbMetadata.ts\";\n\n/**\n * Sorts entities by non-deferred foreign key order.\n *\n * Ideally databases/schemas will support/enable deferred FKs, which let us insert/delete rows\n * in any arbitrary order, and the FK checks will not be applied until txn commit.\n *\n * However, if not enabled/support, we have to worry about two things:\n *\n * 1. Inserting \"parents\" before their children\n * - And if the parent has a circular reference to not-yet-inserted cycle\n * 2. Deleting \"children\" before their parents\n * - Again if the parent has a circular reference to the child\n *\n * For both of these, we can just look at the FK ordering to \"put the parent first\",\n * but run into two problems:\n *\n * - If there is a cycle for not-null FKs, that breaks both INSERTs and DELETEs, so we\n * must warn the user about these to fix.\n * - If there is a cycle with nullable FKs, we can work around that by using NULL as a\n * transient/dummy value, for the initial insert, do the 2nd insert, and then \"fixup\" the\n * first insert with a UPDATE to the actual column value.\n *\n * Given ^, we set the `entity.nonDeferredFkOrder` of each entity, and then also return\n * two arrays of all soft-cycle (nullable, fixup-able) and hard-cycle (not-nullable, blocking)\n * keys.\n */\nexport function sortByNonDeferredForeignKeys(entities: EntityDbMetadata[]): {\n nullableCycles: string[];\n notNullCycles: string[];\n} {\n // Kahn's algorithm, O(V + E)\n\n const graph: Record<string, Node> = Object.fromEntries(\n entities.map((e) => [\n e.name,\n {\n entity: e,\n upstreamFks: new Set(),\n downstreamFks: new Set(),\n },\n ]),\n );\n\n // Add all not-null deps first, as they are most important, cannot be fixed up.\n // - Failures here are fatal-ish\n // Then add nullable deps next, as they can be fixed-up\n\n const nullableCycles: string[] = [];\n const notNullCycles: string[] = [];\n\n // If we see `books.author_id`, mark `author.inDegree++`\n entities.forEach((entity) => {\n entity.nonDeferredFks\n .filter((m2o) => m2o.notNull)\n .forEach((m2o) => {\n const added = addDependency(graph, entity, m2o);\n if (Array.isArray(added)) notNullCycles.push(added.join(\" -> \"));\n });\n });\n\n // Do it again for nullable\n entities.forEach((entity) => {\n entity.nonDeferredFks\n .filter((m2o) => !m2o.notNull)\n .forEach((m2o) => {\n const added = addDependency(graph, entity, m2o);\n if (Array.isArray(added)) nullableCycles.push(added.join(\" -> \"));\n });\n });\n\n // Topological Sort\n // Enqueue entities with 0 out-degree (reverse Kahn), i.e. `authors`, they'll be at the top of the tree\n let queue = Object.values(graph).filter((n) => n.upstreamFks.size === 0);\n let level = 1;\n while (queue.length > 0) {\n // console.log(`Queue: ${queue.map((n) => n.entity.name)}`);\n const nextLevel: Node[] = [];\n for (const current of queue) {\n current.entity.nonDeferredFkOrder = level;\n current.downstreamFks.forEach((node) => {\n if (node.upstreamFks.delete(current) && node.upstreamFks.size === 0) {\n nextLevel.push(node);\n }\n });\n }\n queue = nextLevel;\n level++;\n }\n\n // Anything left with a -1 value means there is a cycle\n // Use a marker value for \"cyclic\"\n entities.filter((e) => e.nonDeferredFkOrder === -1).forEach((e) => (e.nonDeferredFkOrder = 100_000));\n\n return { nullableCycles, notNullCycles: notNullCycles };\n}\n\ntype Node = {\n entity: EntityDbMetadata;\n upstreamFks: Set<Node>;\n downstreamFks: Set<Node>;\n};\n\nfunction addDependency(\n graph: Record<string, Node>,\n entity: EntityDbMetadata,\n m2o: ManyToOneField | PolymorphicFieldComponent,\n): true | string[] {\n const from = graph[entity.name]; // i.e. books\n const to = graph[m2o.otherEntity.name]; // i.e. authors\n const cycle = willCreateCycle(graph, from, to);\n if (cycle) {\n // console.log(`Skipped ${entity.name}.${m2o.columnName} -> ${m2o.otherEntity.name}`);\n return cycle;\n }\n // console.log(`Added ${entity.name}.${m2o.columnName} -> ${m2o.otherEntity.name}`);\n from.upstreamFks.add(to);\n to.downstreamFks.add(from);\n return true;\n}\n\nfunction willCreateCycle(graph: Record<string, Node>, from: Node, to: Node): false | string[] {\n const visited: Set<Node> = new Set();\n const stack: Set<Node> = new Set();\n const path: Node[] = [];\n // If `from=books[.author_id]` pointing at `to=authors`, we want to do `to.downstreamFks.add(from)`,\n // but first make sure that none of from's dowstreams are to, because if so it would make a cycle.\n return dfs(graph, visited, stack, path, from, to);\n}\n\nfunction dfs(\n graph: Record<string, Node>,\n visited: Set<Node>,\n stack: Set<Node>,\n path: Node[],\n current: Node,\n target: Node,\n): false | string[] {\n visited.add(current);\n stack.add(current);\n path.push(current);\n for (const neighbor of current.downstreamFks) {\n if (neighbor === target) {\n return [...path, neighbor].map((n) => n.entity.name);\n }\n if (!visited.has(neighbor)) {\n const cycle = dfs(graph, visited, stack, path, neighbor, target);\n if (cycle) return cycle;\n }\n }\n stack.delete(current);\n path.pop();\n return false;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,SAAgB,6BAA6B,UAG3C;CAGA,MAAM,QAA8B,OAAO,YACzC,SAAS,KAAK,MAAM,CAClB,EAAE,MACF;EACE,QAAQ;EACR,6BAAa,IAAI,IAAI;EACrB,+BAAe,IAAI,IAAI;CACzB,CACF,CAAC,CACH;CAMA,MAAM,iBAA2B,CAAC;CAClC,MAAM,gBAA0B,CAAC;CAGjC,SAAS,SAAS,WAAW;EAC3B,OAAO,eACJ,QAAQ,QAAQ,IAAI,OAAO,CAAC,CAC5B,SAAS,QAAQ;GAChB,MAAM,QAAQ,cAAc,OAAO,QAAQ,GAAG;GAC9C,IAAI,MAAM,QAAQ,KAAK,GAAG,cAAc,KAAK,MAAM,KAAK,MAAM,CAAC;EACjE,CAAC;CACL,CAAC;CAGD,SAAS,SAAS,WAAW;EAC3B,OAAO,eACJ,QAAQ,QAAQ,CAAC,IAAI,OAAO,CAAC,CAC7B,SAAS,QAAQ;GAChB,MAAM,QAAQ,cAAc,OAAO,QAAQ,GAAG;GAC9C,IAAI,MAAM,QAAQ,KAAK,GAAG,eAAe,KAAK,MAAM,KAAK,MAAM,CAAC;EAClE,CAAC;CACL,CAAC;CAID,IAAI,QAAQ,OAAO,OAAO,KAAK,CAAC,CAAC,QAAQ,MAAM,EAAE,YAAY,SAAS,CAAC;CACvE,IAAI,QAAQ;CACZ,OAAO,MAAM,SAAS,GAAG;EAEvB,MAAM,YAAoB,CAAC;EAC3B,KAAK,MAAM,WAAW,OAAO;GAC3B,QAAQ,OAAO,qBAAqB;GACpC,QAAQ,cAAc,SAAS,SAAS;IACtC,IAAI,KAAK,YAAY,OAAO,OAAO,KAAK,KAAK,YAAY,SAAS,GAChE,UAAU,KAAK,IAAI;GAEvB,CAAC;EACH;EACA,QAAQ;EACR;CACF;CAIA,SAAS,QAAQ,MAAM,EAAE,uBAAuB,EAAE,CAAC,CAAC,SAAS,MAAO,EAAE,qBAAqB,GAAQ;CAEnG,OAAO;EAAE;EAA+B;CAAc;AACxD;AAQA,SAAS,cACP,OACA,QACA,KACiB;CACjB,MAAM,OAAO,MAAM,OAAO;CAC1B,MAAM,KAAK,MAAM,IAAI,YAAY;CACjC,MAAM,QAAQ,gBAAgB,OAAO,MAAM,EAAE;CAC7C,IAAI,OAEF,OAAO;CAGT,KAAK,YAAY,IAAI,EAAE;CACvB,GAAG,cAAc,IAAI,IAAI;CACzB,OAAO;AACT;AAEA,SAAS,gBAAgB,OAA6B,MAAY,IAA4B;CAM5F,OAAO,IAAI,uBAAO,IALa,IAKP,mBAAG,IAJE,IAIE,GAAG,CAAG,GAAG,MAAM,EAAE;AAClD;AAEA,SAAS,IACP,OACA,SACA,OACA,MACA,SACA,QACkB;CAClB,QAAQ,IAAI,OAAO;CACnB,MAAM,IAAI,OAAO;CACjB,KAAK,KAAK,OAAO;CACjB,KAAK,MAAM,YAAY,QAAQ,eAAe;EAC5C,IAAI,aAAa,QACf,OAAO,CAAC,GAAG,MAAM,QAAQ,CAAC,CAAC,KAAK,MAAM,EAAE,OAAO,IAAI;EAErD,IAAI,CAAC,QAAQ,IAAI,QAAQ,GAAG;GAC1B,MAAM,QAAQ,IAAI,OAAO,SAAS,OAAO,MAAM,UAAU,MAAM;GAC/D,IAAI,OAAO,OAAO;EACpB;CACF;CACA,MAAM,OAAO,OAAO;CACpB,KAAK,IAAI;CACT,OAAO;AACT"}