sonamu 0.5.7 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (529) hide show
  1. package/.swcrc.project-default +18 -0
  2. package/bin/cli.js +24 -0
  3. package/dist/ai/agents/agent.d.ts +11 -0
  4. package/dist/ai/agents/agent.d.ts.map +1 -0
  5. package/dist/ai/agents/agent.js +65 -0
  6. package/dist/ai/agents/index.d.ts +3 -0
  7. package/dist/ai/agents/index.d.ts.map +1 -0
  8. package/dist/ai/agents/index.js +4 -0
  9. package/dist/ai/agents/types.d.ts +43 -0
  10. package/dist/ai/agents/types.d.ts.map +1 -0
  11. package/dist/ai/agents/types.js +3 -0
  12. package/dist/ai/index.d.ts +2 -0
  13. package/dist/ai/index.d.ts.map +1 -0
  14. package/dist/ai/index.js +3 -0
  15. package/dist/ai/providers/rtzr/api.d.ts +22 -0
  16. package/dist/ai/providers/rtzr/api.d.ts.map +1 -0
  17. package/dist/ai/providers/rtzr/api.js +28 -0
  18. package/dist/ai/providers/rtzr/error.d.ts +18 -0
  19. package/dist/ai/providers/rtzr/error.d.ts.map +1 -0
  20. package/dist/ai/providers/rtzr/error.js +29 -0
  21. package/dist/ai/providers/rtzr/index.d.ts +5 -0
  22. package/dist/ai/providers/rtzr/index.d.ts.map +1 -0
  23. package/dist/ai/providers/rtzr/index.js +6 -0
  24. package/dist/ai/providers/rtzr/model.d.ts +52 -0
  25. package/dist/ai/providers/rtzr/model.d.ts.map +1 -0
  26. package/dist/ai/providers/rtzr/model.js +137 -0
  27. package/dist/ai/providers/rtzr/options.d.ts +7 -0
  28. package/dist/ai/providers/rtzr/options.d.ts.map +1 -0
  29. package/dist/ai/providers/rtzr/options.js +47 -0
  30. package/dist/ai/providers/rtzr/provider.d.ts +18 -0
  31. package/dist/ai/providers/rtzr/provider.d.ts.map +1 -0
  32. package/dist/ai/providers/rtzr/provider.js +54 -0
  33. package/dist/ai/providers/rtzr/utils.d.ts +19 -0
  34. package/dist/ai/providers/rtzr/utils.d.ts.map +1 -0
  35. package/dist/ai/providers/rtzr/utils.js +88 -0
  36. package/dist/api/base-frame.d.ts +2 -2
  37. package/dist/api/base-frame.d.ts.map +1 -1
  38. package/dist/api/base-frame.js +13 -2
  39. package/dist/api/caster.d.ts.map +1 -1
  40. package/dist/api/caster.js +71 -2
  41. package/dist/api/code-converters.d.ts +58 -14
  42. package/dist/api/code-converters.d.ts.map +1 -1
  43. package/dist/api/code-converters.js +258 -2
  44. package/dist/api/config.d.ts +90 -0
  45. package/dist/api/config.d.ts.map +1 -0
  46. package/dist/api/config.js +25 -0
  47. package/dist/api/context.d.ts +4 -2
  48. package/dist/api/context.d.ts.map +1 -1
  49. package/dist/api/context.js +3 -2
  50. package/dist/api/decorators.d.ts +20 -6
  51. package/dist/api/decorators.d.ts.map +1 -1
  52. package/dist/api/decorators.js +235 -2
  53. package/dist/api/index.d.ts +2 -2
  54. package/dist/api/index.d.ts.map +1 -1
  55. package/dist/api/index.js +9 -2
  56. package/dist/api/sonamu.d.ts +10 -24
  57. package/dist/api/sonamu.d.ts.map +1 -1
  58. package/dist/api/sonamu.js +514 -2
  59. package/dist/api/validator.d.ts +6 -0
  60. package/dist/api/validator.d.ts.map +1 -0
  61. package/dist/api/validator.js +81 -0
  62. package/dist/bin/build-config.d.ts +6 -1
  63. package/dist/bin/build-config.d.ts.map +1 -1
  64. package/dist/bin/build-config.js +15 -2
  65. package/dist/bin/cli.js +519 -2
  66. package/dist/bin/hot-hook-register.d.ts +11 -0
  67. package/dist/bin/hot-hook-register.d.ts.map +1 -0
  68. package/dist/bin/hot-hook-register.js +21 -0
  69. package/dist/bin/loader-register.d.ts +2 -0
  70. package/dist/bin/loader-register.d.ts.map +1 -0
  71. package/dist/bin/loader-register.js +34 -0
  72. package/dist/database/_batch_update.d.ts +5 -3
  73. package/dist/database/_batch_update.d.ts.map +1 -1
  74. package/dist/database/_batch_update.js +95 -2
  75. package/dist/database/base-model.d.ts +96 -10
  76. package/dist/database/base-model.d.ts.map +1 -1
  77. package/dist/database/base-model.js +390 -2
  78. package/dist/database/base-model.types.d.ts +93 -0
  79. package/dist/database/base-model.types.d.ts.map +1 -0
  80. package/dist/database/base-model.types.js +10 -0
  81. package/dist/database/code-generator.d.ts +1 -1
  82. package/dist/database/code-generator.d.ts.map +1 -1
  83. package/dist/database/code-generator.js +54 -2
  84. package/dist/database/db.d.ts +6 -21
  85. package/dist/database/db.d.ts.map +1 -1
  86. package/dist/database/db.js +129 -2
  87. package/dist/database/puri-subset.test-d.js +81 -0
  88. package/dist/database/puri-subset.types.d.ts +123 -0
  89. package/dist/database/puri-subset.types.d.ts.map +1 -0
  90. package/dist/database/puri-subset.types.js +16 -0
  91. package/dist/database/puri-wrapper.d.ts +13 -11
  92. package/dist/database/puri-wrapper.d.ts.map +1 -1
  93. package/dist/database/puri-wrapper.js +109 -2
  94. package/dist/database/puri.d.ts +41 -23
  95. package/dist/database/puri.d.ts.map +1 -1
  96. package/dist/database/puri.js +601 -2
  97. package/dist/database/puri.types.d.ts +25 -6
  98. package/dist/database/puri.types.d.ts.map +1 -1
  99. package/dist/database/puri.types.js +6 -2
  100. package/dist/database/transaction-context.d.ts +1 -1
  101. package/dist/database/transaction-context.d.ts.map +1 -1
  102. package/dist/database/transaction-context.js +14 -2
  103. package/dist/database/upsert-builder.d.ts +9 -3
  104. package/dist/database/upsert-builder.d.ts.map +1 -1
  105. package/dist/database/upsert-builder.js +365 -2
  106. package/dist/entity/entity-manager.d.ts +167 -2
  107. package/dist/entity/entity-manager.d.ts.map +1 -1
  108. package/dist/entity/entity-manager.js +130 -2
  109. package/dist/entity/entity.d.ts +5 -3
  110. package/dist/entity/entity.d.ts.map +1 -1
  111. package/dist/entity/entity.js +750 -2
  112. package/dist/exceptions/error-handler.d.ts +1 -1
  113. package/dist/exceptions/error-handler.d.ts.map +1 -1
  114. package/dist/exceptions/error-handler.js +29 -2
  115. package/dist/exceptions/so-exceptions.d.ts +1 -1
  116. package/dist/exceptions/so-exceptions.d.ts.map +1 -1
  117. package/dist/exceptions/so-exceptions.js +85 -2
  118. package/dist/file-storage/driver.d.ts +1 -1
  119. package/dist/file-storage/driver.d.ts.map +1 -1
  120. package/dist/file-storage/driver.js +79 -2
  121. package/dist/file-storage/file-storage.js +75 -2
  122. package/dist/index.d.ts +18 -9
  123. package/dist/index.d.ts.map +1 -1
  124. package/dist/index.js +34 -2
  125. package/dist/migration/code-generation.d.ts +1 -1
  126. package/dist/migration/code-generation.d.ts.map +1 -1
  127. package/dist/migration/code-generation.js +614 -2
  128. package/dist/migration/migration-set.d.ts +2 -10
  129. package/dist/migration/migration-set.d.ts.map +1 -1
  130. package/dist/migration/migration-set.js +213 -2
  131. package/dist/migration/migrator.d.ts +24 -82
  132. package/dist/migration/migrator.d.ts.map +1 -1
  133. package/dist/migration/migrator.js +330 -2
  134. package/dist/migration/postgresql-schema-reader.d.ts +51 -0
  135. package/dist/migration/postgresql-schema-reader.d.ts.map +1 -0
  136. package/dist/migration/postgresql-schema-reader.js +245 -0
  137. package/dist/migration/types.d.ts +6 -38
  138. package/dist/migration/types.d.ts.map +1 -1
  139. package/dist/migration/types.js +3 -2
  140. package/dist/naite/messaging-types.d.ts +43 -0
  141. package/dist/naite/messaging-types.d.ts.map +1 -0
  142. package/dist/naite/messaging-types.js +7 -0
  143. package/dist/naite/naite-reporter.d.ts +41 -0
  144. package/dist/naite/naite-reporter.d.ts.map +1 -0
  145. package/dist/naite/naite-reporter.js +102 -0
  146. package/dist/naite/naite.d.ts +95 -0
  147. package/dist/naite/naite.d.ts.map +1 -0
  148. package/dist/naite/naite.js +316 -0
  149. package/dist/stream/index.js +3 -2
  150. package/dist/stream/sse.d.ts +2 -2
  151. package/dist/stream/sse.d.ts.map +1 -1
  152. package/dist/stream/sse.js +38 -2
  153. package/dist/syncer/api-parser.d.ts +10 -0
  154. package/dist/syncer/api-parser.d.ts.map +1 -0
  155. package/dist/syncer/api-parser.js +240 -0
  156. package/dist/syncer/checksum.d.ts +21 -0
  157. package/dist/syncer/checksum.d.ts.map +1 -0
  158. package/dist/syncer/checksum.js +98 -0
  159. package/dist/syncer/code-generator.d.ts +20 -0
  160. package/dist/syncer/code-generator.d.ts.map +1 -0
  161. package/dist/syncer/code-generator.js +161 -0
  162. package/dist/syncer/entity-operations.d.ts +17 -0
  163. package/dist/syncer/entity-operations.d.ts.map +1 -0
  164. package/dist/syncer/entity-operations.js +59 -0
  165. package/dist/syncer/file-patterns.d.ts +29 -0
  166. package/dist/syncer/file-patterns.d.ts.map +1 -0
  167. package/dist/syncer/file-patterns.js +38 -0
  168. package/dist/syncer/index.d.ts +6 -0
  169. package/dist/syncer/index.d.ts.map +1 -1
  170. package/dist/syncer/index.js +9 -2
  171. package/dist/syncer/module-loader.d.ts +35 -0
  172. package/dist/syncer/module-loader.d.ts.map +1 -0
  173. package/dist/syncer/module-loader.js +87 -0
  174. package/dist/syncer/syncer.d.ts +98 -106
  175. package/dist/syncer/syncer.d.ts.map +1 -1
  176. package/dist/syncer/syncer.js +422 -2
  177. package/dist/template/entity-converter.d.ts +14 -0
  178. package/dist/template/entity-converter.d.ts.map +1 -0
  179. package/dist/template/entity-converter.js +108 -0
  180. package/dist/template/helpers.d.ts +23 -0
  181. package/dist/template/helpers.d.ts.map +1 -0
  182. package/dist/template/helpers.js +64 -0
  183. package/dist/{templates → template/implementations}/entity.template.d.ts +3 -3
  184. package/dist/template/implementations/entity.template.d.ts.map +1 -0
  185. package/dist/template/implementations/entity.template.js +86 -0
  186. package/dist/{templates → template/implementations}/generated.template.d.ts +3 -4
  187. package/dist/template/implementations/generated.template.d.ts.map +1 -0
  188. package/dist/template/implementations/generated.template.js +249 -0
  189. package/dist/{templates → template/implementations}/generated_http.template.d.ts +3 -4
  190. package/dist/template/implementations/generated_http.template.d.ts.map +1 -0
  191. package/dist/template/implementations/generated_http.template.js +131 -0
  192. package/dist/{templates → template/implementations}/generated_sso.template.d.ts +4 -5
  193. package/dist/template/implementations/generated_sso.template.d.ts.map +1 -0
  194. package/dist/template/implementations/generated_sso.template.js +134 -0
  195. package/dist/{templates → template/implementations}/init_types.template.d.ts +3 -3
  196. package/dist/template/implementations/init_types.template.d.ts.map +1 -0
  197. package/dist/template/implementations/init_types.template.js +38 -0
  198. package/dist/template/implementations/model.template.d.ts +17 -0
  199. package/dist/template/implementations/model.template.d.ts.map +1 -0
  200. package/dist/template/implementations/model.template.js +181 -0
  201. package/dist/{templates → template/implementations}/model_test.template.d.ts +3 -3
  202. package/dist/template/implementations/model_test.template.d.ts.map +1 -0
  203. package/dist/template/implementations/model_test.template.js +35 -0
  204. package/dist/{templates → template/implementations}/service.template.d.ts +6 -6
  205. package/dist/template/implementations/service.template.d.ts.map +1 -0
  206. package/dist/template/implementations/service.template.js +201 -0
  207. package/dist/{templates → template/implementations}/view_enums_buttonset.template.d.ts +3 -3
  208. package/dist/template/implementations/view_enums_buttonset.template.d.ts.map +1 -0
  209. package/dist/template/implementations/view_enums_buttonset.template.js +31 -0
  210. package/dist/{templates → template/implementations}/view_enums_dropdown.template.d.ts +3 -4
  211. package/dist/template/implementations/view_enums_dropdown.template.d.ts.map +1 -0
  212. package/dist/template/implementations/view_enums_dropdown.template.js +50 -0
  213. package/dist/{templates → template/implementations}/view_enums_select.template.d.ts +3 -3
  214. package/dist/template/implementations/view_enums_select.template.d.ts.map +1 -0
  215. package/dist/template/implementations/view_enums_select.template.js +55 -0
  216. package/dist/{templates → template/implementations}/view_form.template.d.ts +5 -5
  217. package/dist/template/implementations/view_form.template.d.ts.map +1 -0
  218. package/dist/template/implementations/view_form.template.js +337 -0
  219. package/dist/{templates → template/implementations}/view_id_all_select.template.d.ts +3 -3
  220. package/dist/template/implementations/view_id_all_select.template.d.ts.map +1 -0
  221. package/dist/template/implementations/view_id_all_select.template.js +31 -0
  222. package/dist/{templates → template/implementations}/view_id_async_select.template.d.ts +3 -3
  223. package/dist/template/implementations/view_id_async_select.template.d.ts.map +1 -0
  224. package/dist/template/implementations/view_id_async_select.template.js +105 -0
  225. package/dist/{templates → template/implementations}/view_list.template.d.ts +5 -13
  226. package/dist/template/implementations/view_list.template.d.ts.map +1 -0
  227. package/dist/template/implementations/view_list.template.js +475 -0
  228. package/dist/template/implementations/view_list_columns.template.d.ts +17 -0
  229. package/dist/template/implementations/view_list_columns.template.d.ts.map +1 -0
  230. package/dist/template/implementations/view_list_columns.template.js +49 -0
  231. package/dist/{templates → template/implementations}/view_search_input.template.d.ts +3 -3
  232. package/dist/template/implementations/view_search_input.template.d.ts.map +1 -0
  233. package/dist/template/implementations/view_search_input.template.js +64 -0
  234. package/dist/template/index.d.ts +7 -0
  235. package/dist/template/index.d.ts.map +1 -0
  236. package/dist/template/index.js +8 -0
  237. package/dist/template/template-manager.d.ts +56 -0
  238. package/dist/template/template-manager.d.ts.map +1 -0
  239. package/dist/template/template-manager.js +125 -0
  240. package/dist/template/template-types.d.ts +16 -0
  241. package/dist/template/template-types.d.ts.map +1 -0
  242. package/dist/template/template-types.js +7 -0
  243. package/dist/template/template.d.ts +49 -0
  244. package/dist/template/template.d.ts.map +1 -0
  245. package/dist/template/template.js +60 -0
  246. package/dist/template/zod-converter.d.ts +51 -0
  247. package/dist/template/zod-converter.d.ts.map +1 -0
  248. package/dist/template/zod-converter.js +449 -0
  249. package/dist/testing/_relation-graph.d.ts +1 -1
  250. package/dist/testing/_relation-graph.d.ts.map +1 -1
  251. package/dist/testing/_relation-graph.js +89 -2
  252. package/dist/testing/fixture-manager.d.ts +42 -11
  253. package/dist/testing/fixture-manager.d.ts.map +1 -1
  254. package/dist/testing/fixture-manager.js +623 -2
  255. package/dist/types/types.d.ts +747 -143
  256. package/dist/types/types.d.ts.map +1 -1
  257. package/dist/types/types.js +546 -2
  258. package/dist/typings/knex.d.js +3 -2
  259. package/dist/utils/async-utils.d.ts +7 -0
  260. package/dist/utils/async-utils.d.ts.map +1 -1
  261. package/dist/utils/async-utils.js +57 -2
  262. package/dist/utils/console-util.d.ts +2 -0
  263. package/dist/utils/console-util.d.ts.map +1 -0
  264. package/dist/utils/console-util.js +6 -0
  265. package/dist/utils/controller.d.ts +1 -0
  266. package/dist/utils/controller.d.ts.map +1 -1
  267. package/dist/utils/controller.js +29 -2
  268. package/dist/utils/esm-utils.d.ts +39 -0
  269. package/dist/utils/esm-utils.d.ts.map +1 -0
  270. package/dist/utils/esm-utils.js +49 -0
  271. package/dist/utils/formatter.d.ts +3 -0
  272. package/dist/utils/formatter.d.ts.map +1 -0
  273. package/dist/utils/formatter.js +110 -0
  274. package/dist/utils/fs-utils.d.ts +1 -1
  275. package/dist/utils/fs-utils.d.ts.map +1 -1
  276. package/dist/utils/fs-utils.js +17 -2
  277. package/dist/utils/lodash-able.d.ts.map +1 -1
  278. package/dist/utils/lodash-able.js +6 -2
  279. package/dist/utils/model.js +22 -2
  280. package/dist/utils/object-utils.d.ts +44 -0
  281. package/dist/utils/object-utils.d.ts.map +1 -0
  282. package/dist/utils/object-utils.js +191 -0
  283. package/dist/utils/path-utils.d.ts +89 -0
  284. package/dist/utils/path-utils.d.ts.map +1 -0
  285. package/dist/utils/path-utils.js +60 -0
  286. package/dist/utils/process-utils.d.ts +13 -0
  287. package/dist/utils/process-utils.d.ts.map +1 -0
  288. package/dist/utils/process-utils.js +36 -0
  289. package/dist/utils/sql-parser.d.ts +5 -1
  290. package/dist/utils/sql-parser.d.ts.map +1 -1
  291. package/dist/utils/sql-parser.js +46 -2
  292. package/dist/utils/type-utils.d.ts +23 -0
  293. package/dist/utils/type-utils.d.ts.map +1 -0
  294. package/dist/utils/type-utils.js +45 -0
  295. package/dist/utils/utils.d.ts +10 -7
  296. package/dist/utils/utils.d.ts.map +1 -1
  297. package/dist/utils/utils.js +72 -2
  298. package/dist/utils/zod-error.d.ts +1 -1
  299. package/dist/utils/zod-error.d.ts.map +1 -1
  300. package/dist/utils/zod-error.js +19 -2
  301. package/package.json +65 -27
  302. package/src/ai/agents/agent.ts +87 -0
  303. package/src/ai/agents/index.ts +2 -0
  304. package/src/ai/agents/types.ts +47 -0
  305. package/src/ai/index.ts +1 -0
  306. package/src/ai/providers/rtzr/api.ts +37 -0
  307. package/src/ai/providers/rtzr/error.ts +34 -0
  308. package/src/ai/providers/rtzr/index.ts +4 -0
  309. package/src/ai/providers/rtzr/model.ts +201 -0
  310. package/src/ai/providers/rtzr/options.ts +49 -0
  311. package/src/ai/providers/rtzr/provider.ts +91 -0
  312. package/src/ai/providers/rtzr/utils.ts +127 -0
  313. package/src/api/base-frame.ts +4 -2
  314. package/src/api/caster.ts +17 -23
  315. package/src/api/code-converters.ts +178 -535
  316. package/src/api/config.ts +125 -0
  317. package/src/api/context.ts +7 -17
  318. package/src/api/decorators.ts +176 -46
  319. package/src/api/index.ts +2 -2
  320. package/src/api/sonamu.ts +190 -167
  321. package/src/api/validator.ts +83 -0
  322. package/src/bin/build-config.ts +8 -1
  323. package/src/bin/cli.ts +258 -124
  324. package/src/bin/hot-hook-register.ts +22 -0
  325. package/src/bin/loader-register.ts +38 -0
  326. package/src/database/_batch_update.ts +46 -31
  327. package/src/database/base-model.ts +390 -182
  328. package/src/database/base-model.types.ts +155 -0
  329. package/src/database/code-generator.ts +13 -32
  330. package/src/database/db.ts +40 -96
  331. package/src/database/puri-subset.test-d.ts +471 -0
  332. package/src/database/puri-subset.types.ts +195 -0
  333. package/src/database/puri-wrapper.ts +58 -67
  334. package/src/database/puri.ts +229 -148
  335. package/src/database/puri.types.ts +76 -30
  336. package/src/database/transaction-context.ts +1 -1
  337. package/src/database/upsert-builder.ts +262 -132
  338. package/src/entity/entity-manager.ts +48 -36
  339. package/src/entity/entity.ts +330 -248
  340. package/src/exceptions/error-handler.ts +3 -3
  341. package/src/exceptions/so-exceptions.ts +11 -11
  342. package/src/file-storage/driver.ts +5 -5
  343. package/src/file-storage/file-storage.ts +2 -2
  344. package/src/index.ts +18 -10
  345. package/src/migration/code-generation.ts +185 -172
  346. package/src/migration/migration-set.ts +80 -293
  347. package/src/migration/migrator.ts +199 -571
  348. package/src/migration/mysql-schema-reader.ts.txt +272 -0
  349. package/src/migration/postgresql-schema-reader.ts +310 -0
  350. package/src/migration/types.ts +6 -39
  351. package/src/naite/messaging-types.ts +51 -0
  352. package/src/naite/naite-reporter.ts +128 -0
  353. package/src/naite/naite.ts +415 -0
  354. package/src/shared/web.shared.ts.txt +20 -24
  355. package/src/stream/sse.ts +5 -5
  356. package/src/syncer/api-parser.ts +282 -0
  357. package/src/syncer/checksum.ts +140 -0
  358. package/src/syncer/code-generator.ts +198 -0
  359. package/src/syncer/entity-operations.ts +65 -0
  360. package/src/syncer/file-patterns.ts +56 -0
  361. package/src/syncer/index.ts +6 -0
  362. package/src/syncer/module-loader.ts +128 -0
  363. package/src/syncer/syncer.ts +389 -1453
  364. package/src/template/entity-converter.ts +114 -0
  365. package/src/template/helpers.ts +81 -0
  366. package/src/{templates → template/implementations}/entity.template.ts +7 -7
  367. package/src/{templates → template/implementations}/generated.template.ts +101 -101
  368. package/src/{templates → template/implementations}/generated_http.template.ts +27 -57
  369. package/src/template/implementations/generated_sso.template.ts +151 -0
  370. package/src/{templates → template/implementations}/init_types.template.ts +5 -7
  371. package/src/{templates → template/implementations}/model.template.ts +52 -43
  372. package/src/{templates → template/implementations}/model_test.template.ts +5 -5
  373. package/src/{templates → template/implementations}/service.template.ts +66 -82
  374. package/src/{templates → template/implementations}/view_enums_buttonset.template.ts +3 -3
  375. package/src/{templates → template/implementations}/view_enums_dropdown.template.ts +4 -20
  376. package/src/{templates → template/implementations}/view_enums_select.template.ts +4 -4
  377. package/src/{templates → template/implementations}/view_form.template.ts +40 -83
  378. package/src/{templates → template/implementations}/view_id_all_select.template.ts +3 -3
  379. package/src/{templates → template/implementations}/view_id_async_select.template.ts +10 -24
  380. package/src/{templates → template/implementations}/view_list.template.ts +60 -152
  381. package/src/{templates → template/implementations}/view_list_columns.template.ts +5 -11
  382. package/src/{templates → template/implementations}/view_search_input.template.ts +3 -3
  383. package/src/template/index.ts +6 -0
  384. package/src/template/template-manager.ts +166 -0
  385. package/src/template/template-types.ts +16 -0
  386. package/src/template/template.ts +105 -0
  387. package/src/template/zod-converter.ts +525 -0
  388. package/src/testing/_relation-graph.ts +18 -11
  389. package/src/testing/fixture-manager.ts +472 -359
  390. package/src/types/types.ts +553 -308
  391. package/src/typings/knex.d.ts +7 -9
  392. package/src/utils/async-utils.ts +23 -10
  393. package/src/utils/console-util.ts +4 -0
  394. package/src/utils/controller.ts +3 -0
  395. package/src/utils/esm-utils.ts +59 -0
  396. package/src/utils/formatter.ts +109 -0
  397. package/src/utils/fs-utils.ts +1 -1
  398. package/src/utils/lodash-able.ts +1 -4
  399. package/src/utils/object-utils.ts +217 -0
  400. package/src/utils/path-utils.ts +99 -0
  401. package/src/utils/process-utils.ts +46 -0
  402. package/src/utils/sql-parser.ts +23 -5
  403. package/src/utils/type-utils.ts +83 -0
  404. package/src/utils/utils.ts +66 -43
  405. package/src/utils/zod-error.ts +3 -4
  406. package/dist/api/base-frame.js.map +0 -1
  407. package/dist/api/caster.js.map +0 -1
  408. package/dist/api/code-converters.js.map +0 -1
  409. package/dist/api/context.js.map +0 -1
  410. package/dist/api/decorators.js.map +0 -1
  411. package/dist/api/index.js.map +0 -1
  412. package/dist/api/sonamu.js.map +0 -1
  413. package/dist/bin/build-config.js.map +0 -1
  414. package/dist/bin/cli-wrapper.d.ts +0 -3
  415. package/dist/bin/cli-wrapper.d.ts.map +0 -1
  416. package/dist/bin/cli-wrapper.js +0 -3
  417. package/dist/bin/cli-wrapper.js.map +0 -1
  418. package/dist/bin/cli.js.map +0 -1
  419. package/dist/database/_batch_update.js.map +0 -1
  420. package/dist/database/base-model.js.map +0 -1
  421. package/dist/database/code-generator.js.map +0 -1
  422. package/dist/database/db.js.map +0 -1
  423. package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts +0 -2
  424. package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts.map +0 -1
  425. package/dist/database/knex-plugins/knex-on-duplicate-update.js +0 -2
  426. package/dist/database/knex-plugins/knex-on-duplicate-update.js.map +0 -1
  427. package/dist/database/puri-wrapper.js.map +0 -1
  428. package/dist/database/puri.js.map +0 -1
  429. package/dist/database/puri.types.js.map +0 -1
  430. package/dist/database/transaction-context.js.map +0 -1
  431. package/dist/database/upsert-builder.js.map +0 -1
  432. package/dist/entity/entity-manager.js.map +0 -1
  433. package/dist/entity/entity-utils.d.ts +0 -61
  434. package/dist/entity/entity-utils.d.ts.map +0 -1
  435. package/dist/entity/entity-utils.js +0 -2
  436. package/dist/entity/entity-utils.js.map +0 -1
  437. package/dist/entity/entity.js.map +0 -1
  438. package/dist/exceptions/error-handler.js.map +0 -1
  439. package/dist/exceptions/so-exceptions.js.map +0 -1
  440. package/dist/file-storage/driver.js.map +0 -1
  441. package/dist/file-storage/file-storage.js.map +0 -1
  442. package/dist/index.js.map +0 -1
  443. package/dist/migration/code-generation.js.map +0 -1
  444. package/dist/migration/migration-set.js.map +0 -1
  445. package/dist/migration/migrator.js.map +0 -1
  446. package/dist/migration/types.js.map +0 -1
  447. package/dist/stream/index.js.map +0 -1
  448. package/dist/stream/sse.js.map +0 -1
  449. package/dist/syncer/index.js.map +0 -1
  450. package/dist/syncer/syncer.js.map +0 -1
  451. package/dist/templates/base-template.d.ts +0 -13
  452. package/dist/templates/base-template.d.ts.map +0 -1
  453. package/dist/templates/base-template.js +0 -2
  454. package/dist/templates/base-template.js.map +0 -1
  455. package/dist/templates/entity.template.d.ts.map +0 -1
  456. package/dist/templates/entity.template.js +0 -2
  457. package/dist/templates/entity.template.js.map +0 -1
  458. package/dist/templates/generated.template.d.ts.map +0 -1
  459. package/dist/templates/generated.template.js +0 -2
  460. package/dist/templates/generated.template.js.map +0 -1
  461. package/dist/templates/generated_http.template.d.ts.map +0 -1
  462. package/dist/templates/generated_http.template.js +0 -2
  463. package/dist/templates/generated_http.template.js.map +0 -1
  464. package/dist/templates/generated_sso.template.d.ts.map +0 -1
  465. package/dist/templates/generated_sso.template.js +0 -2
  466. package/dist/templates/generated_sso.template.js.map +0 -1
  467. package/dist/templates/index.d.ts +0 -2
  468. package/dist/templates/index.d.ts.map +0 -1
  469. package/dist/templates/index.js +0 -2
  470. package/dist/templates/index.js.map +0 -1
  471. package/dist/templates/init_types.template.d.ts.map +0 -1
  472. package/dist/templates/init_types.template.js +0 -2
  473. package/dist/templates/init_types.template.js.map +0 -1
  474. package/dist/templates/model.template.d.ts +0 -17
  475. package/dist/templates/model.template.d.ts.map +0 -1
  476. package/dist/templates/model.template.js +0 -2
  477. package/dist/templates/model.template.js.map +0 -1
  478. package/dist/templates/model_test.template.d.ts.map +0 -1
  479. package/dist/templates/model_test.template.js +0 -2
  480. package/dist/templates/model_test.template.js.map +0 -1
  481. package/dist/templates/service.template.d.ts.map +0 -1
  482. package/dist/templates/service.template.js +0 -2
  483. package/dist/templates/service.template.js.map +0 -1
  484. package/dist/templates/view_enums_buttonset.template.d.ts.map +0 -1
  485. package/dist/templates/view_enums_buttonset.template.js +0 -2
  486. package/dist/templates/view_enums_buttonset.template.js.map +0 -1
  487. package/dist/templates/view_enums_dropdown.template.d.ts.map +0 -1
  488. package/dist/templates/view_enums_dropdown.template.js +0 -2
  489. package/dist/templates/view_enums_dropdown.template.js.map +0 -1
  490. package/dist/templates/view_enums_select.template.d.ts.map +0 -1
  491. package/dist/templates/view_enums_select.template.js +0 -2
  492. package/dist/templates/view_enums_select.template.js.map +0 -1
  493. package/dist/templates/view_form.template.d.ts.map +0 -1
  494. package/dist/templates/view_form.template.js +0 -2
  495. package/dist/templates/view_form.template.js.map +0 -1
  496. package/dist/templates/view_id_all_select.template.d.ts.map +0 -1
  497. package/dist/templates/view_id_all_select.template.js +0 -2
  498. package/dist/templates/view_id_all_select.template.js.map +0 -1
  499. package/dist/templates/view_id_async_select.template.d.ts.map +0 -1
  500. package/dist/templates/view_id_async_select.template.js +0 -2
  501. package/dist/templates/view_id_async_select.template.js.map +0 -1
  502. package/dist/templates/view_list.template.d.ts.map +0 -1
  503. package/dist/templates/view_list.template.js +0 -2
  504. package/dist/templates/view_list.template.js.map +0 -1
  505. package/dist/templates/view_list_columns.template.d.ts +0 -17
  506. package/dist/templates/view_list_columns.template.d.ts.map +0 -1
  507. package/dist/templates/view_list_columns.template.js +0 -2
  508. package/dist/templates/view_list_columns.template.js.map +0 -1
  509. package/dist/templates/view_search_input.template.d.ts.map +0 -1
  510. package/dist/templates/view_search_input.template.js +0 -2
  511. package/dist/templates/view_search_input.template.js.map +0 -1
  512. package/dist/testing/_relation-graph.js.map +0 -1
  513. package/dist/testing/fixture-manager.js.map +0 -1
  514. package/dist/types/types.js.map +0 -1
  515. package/dist/typings/knex.d.js.map +0 -1
  516. package/dist/utils/async-utils.js.map +0 -1
  517. package/dist/utils/controller.js.map +0 -1
  518. package/dist/utils/fs-utils.js.map +0 -1
  519. package/dist/utils/lodash-able.js.map +0 -1
  520. package/dist/utils/model.js.map +0 -1
  521. package/dist/utils/sql-parser.js.map +0 -1
  522. package/dist/utils/utils.js.map +0 -1
  523. package/dist/utils/zod-error.js.map +0 -1
  524. package/src/bin/cli-wrapper.ts +0 -75
  525. package/src/database/knex-plugins/knex-on-duplicate-update.ts +0 -45
  526. package/src/entity/entity-utils.ts +0 -291
  527. package/src/templates/base-template.ts +0 -19
  528. package/src/templates/generated_sso.template.ts +0 -138
  529. package/src/templates/index.ts +0 -1
@@ -1,2 +1,330 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"Migrator",{enumerable:true,get:function(){return Migrator}});var _lodash=/*#__PURE__*/_interop_require_default(require("lodash"));var _knex=/*#__PURE__*/_interop_require_default(require("knex"));var _chalk=/*#__PURE__*/_interop_require_default(require("chalk"));var _luxon=require("luxon");var _promises=require("fs/promises");var _fsutils=require("../utils/fs-utils");var _prompts=/*#__PURE__*/_interop_require_default(require("prompts"));var _child_process=require("child_process");var _path=/*#__PURE__*/_interop_require_default(require("path"));var _entitymanager=require("../entity/entity-manager");var _api=require("../api");var _soexceptions=require("../exceptions/so-exceptions");var _codegeneration=require("./code-generation");var _migrationset=require("./migration-set");function _array_like_to_array(arr,len){if(len==null||len>arr.length)len=arr.length;for(var i=0,arr2=new Array(len);i<len;i++)arr2[i]=arr[i];return arr2}function _array_with_holes(arr){if(Array.isArray(arr))return arr}function _array_without_holes(arr){if(Array.isArray(arr))return _array_like_to_array(arr)}function asyncGeneratorStep(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg);var value=info.value}catch(error){reject(error);return}if(info.done){resolve(value)}else{Promise.resolve(value).then(_next,_throw)}}function _async_to_generator(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"throw",err)}_next(undefined)})}}function _class_call_check(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function")}}function _defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if("value"in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor)}}function _create_class(Constructor,protoProps,staticProps){if(protoProps)_defineProperties(Constructor.prototype,protoProps);if(staticProps)_defineProperties(Constructor,staticProps);return Constructor}function _define_property(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}function _interop_require_default(obj){return obj&&obj.__esModule?obj:{default:obj}}function _iterable_to_array(iter){if(typeof Symbol!=="undefined"&&iter[Symbol.iterator]!=null||iter["@@iterator"]!=null)return Array.from(iter)}function _iterable_to_array_limit(arr,i){var _i=arr==null?null:typeof Symbol!=="undefined"&&arr[Symbol.iterator]||arr["@@iterator"];if(_i==null)return;var _arr=[];var _n=true;var _d=false;var _s,_e;try{for(_i=_i.call(arr);!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break}}catch(err){_d=true;_e=err}finally{try{if(!_n&&_i["return"]!=null)_i["return"]()}finally{if(_d)throw _e}}return _arr}function _non_iterable_rest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _non_iterable_spread(){throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _object_spread(target){for(var i=1;i<arguments.length;i++){var source=arguments[i]!=null?arguments[i]:{};var ownKeys=Object.keys(source);if(typeof Object.getOwnPropertySymbols==="function"){ownKeys=ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym){return Object.getOwnPropertyDescriptor(source,sym).enumerable}))}ownKeys.forEach(function(key){_define_property(target,key,source[key])})}return target}function ownKeys(object,enumerableOnly){var keys=Object.keys(object);if(Object.getOwnPropertySymbols){var symbols=Object.getOwnPropertySymbols(object);if(enumerableOnly){symbols=symbols.filter(function(sym){return Object.getOwnPropertyDescriptor(object,sym).enumerable})}keys.push.apply(keys,symbols)}return keys}function _object_spread_props(target,source){source=source!=null?source:{};if(Object.getOwnPropertyDescriptors){Object.defineProperties(target,Object.getOwnPropertyDescriptors(source))}else{ownKeys(Object(source)).forEach(function(key){Object.defineProperty(target,key,Object.getOwnPropertyDescriptor(source,key))})}return target}function _sliced_to_array(arr,i){return _array_with_holes(arr)||_iterable_to_array_limit(arr,i)||_unsupported_iterable_to_array(arr,i)||_non_iterable_rest()}function _to_consumable_array(arr){return _array_without_holes(arr)||_iterable_to_array(arr)||_unsupported_iterable_to_array(arr)||_non_iterable_spread()}function _unsupported_iterable_to_array(o,minLen){if(!o)return;if(typeof o==="string")return _array_like_to_array(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);if(n==="Object"&&o.constructor)n=o.constructor.name;if(n==="Map"||n==="Set")return Array.from(n);if(n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _array_like_to_array(o,minLen)}function _ts_generator(thisArg,body){var f,y,t,_={label:0,sent:function(){if(t[0]&1)throw t[1];return t[1]},trys:[],ops:[]},g=Object.create((typeof Iterator==="function"?Iterator:Object).prototype);return g.next=verb(0),g["throw"]=verb(1),g["return"]=verb(2),typeof Symbol==="function"&&(g[Symbol.iterator]=function(){return this}),g;function verb(n){return function(v){return step([n,v])}}function step(op){if(f)throw new TypeError("Generator is already executing.");while(g&&(g=0,op[0]&&(_=0)),_)try{if(f=1,y&&(t=op[0]&2?y["return"]:op[0]?y["throw"]||((t=y["return"])&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;if(y=0,t)op=[op[0]&2,t.value];switch(op[0]){case 0:case 1:t=op;break;case 4:_.label++;return{value:op[1],done:false};case 5:_.label++;y=op[1];op=[0];continue;case 7:op=_.ops.pop();_.trys.pop();continue;default:if(!(t=_.trys,t=t.length>0&&t[t.length-1])&&(op[0]===6||op[0]===2)){_=0;continue}if(op[0]===3&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(op[0]===6&&_.label<t[1]){_.label=t[1];t=op;break}if(t&&_.label<t[2]){_.label=t[2];_.ops.push(op);break}if(t[2])_.ops.pop();_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e];y=0}finally{f=t=0}if(op[0]&5)throw op[1];return{value:op[0]?op[1]:void 0,done:true}}}var Migrator=/*#__PURE__*/function(){"use strict";function Migrator(options){_class_call_check(this,Migrator);_define_property(this,"options",void 0);_define_property(this,"targets",void 0);this.options=options;var dbConfig=_api.Sonamu.dbConfig;if(this.options.mode==="dev"){var devDB=(0,_knex.default)(dbConfig.development_master);var testDB=(0,_knex.default)(dbConfig.test);var fixtureLocalDB=(0,_knex.default)(dbConfig.fixture_local);var applyDBs=[devDB,testDB,fixtureLocalDB];if(dbConfig.fixture_local.connection.host!==dbConfig.fixture_remote.connection.host||dbConfig.fixture_local.connection.database!==dbConfig.fixture_remote.connection.database){var fixtureRemoteDB=(0,_knex.default)(dbConfig.fixture_remote);applyDBs.push(fixtureRemoteDB)}this.targets={compare:devDB,pending:devDB,shadow:testDB,apply:applyDBs}}else if(this.options.mode==="deploy"){var productionDB=(0,_knex.default)(dbConfig.production_master);var testDB1=(0,_knex.default)(dbConfig.test);this.targets={pending:productionDB,shadow:testDB1,apply:[productionDB]}}else{throw new Error("잘못된 모드 ".concat(this.options.mode," 입력"))}}_create_class(Migrator,[{key:"getMigrationCodes",value:function getMigrationCodes(){return _async_to_generator(function(){var srcMigrationsDir,distMigrationsDir,srcMigrations,distMigrations,normal,onlyTs,onlyJs;return _ts_generator(this,function(_state){switch(_state.label){case 0:srcMigrationsDir="".concat(_api.Sonamu.apiRootPath,"/src/migrations");distMigrationsDir="".concat(_api.Sonamu.apiRootPath,"/dist/migrations");return[4,(0,_fsutils.exists)(srcMigrationsDir)];case 1:if(!!_state.sent())return[3,3];return[4,(0,_promises.mkdir)(srcMigrationsDir,{recursive:true})];case 2:_state.sent();_state.label=3;case 3:return[4,(0,_fsutils.exists)(distMigrationsDir)];case 4:if(!!_state.sent())return[3,6];return[4,(0,_promises.mkdir)(distMigrationsDir,{recursive:true})];case 5:_state.sent();_state.label=6;case 6:return[4,(0,_promises.readdir)(srcMigrationsDir)];case 7:srcMigrations=_state.sent().filter(function(f){return f.endsWith(".ts")}).map(function(f){return f.split(".")[0]});return[4,(0,_promises.readdir)(distMigrationsDir)];case 8:distMigrations=_state.sent().filter(function(f){return f.endsWith(".js")}).map(function(f){return f.split(".")[0]});normal=_lodash.default.intersection(srcMigrations,distMigrations).map(function(filename){return{name:filename,path:_path.default.join(srcMigrationsDir,filename)+".ts"}}).sort(function(a,b){return a>b?1:-1});onlyTs=_lodash.default.difference(srcMigrations,distMigrations).map(function(filename){return{name:filename,path:_path.default.join(srcMigrationsDir,filename)+".ts"}});onlyJs=_lodash.default.difference(distMigrations,srcMigrations).map(function(filename){return{name:filename,path:_path.default.join(distMigrationsDir,filename)+".js"}});return[2,{normal:normal,onlyTs:onlyTs,onlyJs:onlyJs}]}})})()}},{key:"getStatus",value:function getStatus(){return _async_to_generator(function(){var _this,_ref,normal,onlyTs,onlyJs,connKeys,statuses,preparedCodes;return _ts_generator(this,function(_state){switch(_state.label){case 0:_this=this;return[4,this.getMigrationCodes()];case 1:_ref=_state.sent(),normal=_ref.normal,onlyTs=_ref.onlyTs,onlyJs=_ref.onlyJs;if(onlyTs.length>0){console.debug({onlyTs:onlyTs});throw new _soexceptions.ServiceUnavailableException("There are un-compiled TS migration files.\nPlease compile them first. You might want to run a development server with HMR.\n\n".concat(onlyTs.map(function(f){return f.name}).join("\n")))}if(!(onlyJs.length>0))return[3,3];console.debug({onlyJs:onlyJs});return[4,Promise.all(onlyJs.map(function(f){return _async_to_generator(function(){return _ts_generator(this,function(_state){(0,_child_process.execSync)("rm -f ".concat(f.path.replace("/src/","/dist/").replace(".ts",".js")));return[2]})})()}))];case 2:_state.sent();_state.label=3;case 3:connKeys=Object.keys(_api.Sonamu.dbConfig).filter(function(key){return key.endsWith("_slave")===false});return[4,Promise.all(connKeys.map(function(connKey){return _async_to_generator(function(){var knexOptions,tConn,status,pending,currentVersion,connection,_connection_user;return _ts_generator(this,function(_state){switch(_state.label){case 0:knexOptions=_api.Sonamu.dbConfig[connKey];tConn=(0,_knex.default)(knexOptions);return[4,function(){return _async_to_generator(function(){var err;return _ts_generator(this,function(_state){switch(_state.label){case 0:_state.trys.push([0,2,,3]);return[4,tConn.migrate.status()];case 1:return[2,_state.sent()];case 2:err=_state.sent();console.warn(_chalk.default.yellow("".concat(connKey,"의 마이그레이션 상태를 가져오는 데에 실패하였습니다. 데이터베이스가 올바르게 구성되지 않은 것 같습니다. 확인하시고 다시 시도해주세요.\n시도한 연결 설정:\n").concat(JSON.stringify(knexOptions.connection,null,2),"\n발생한 에러:\n").concat(err,"\n")));return[2,"error"];case 3:return[2]}})})()}()];case 1:status=_state.sent();return[4,function(){return _async_to_generator(function(){var _ref,fdList,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:_state.trys.push([0,2,,3]);return[4,tConn.migrate.list()];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),2]),fdList=_ref[1];return[2,fdList.map(function(fd){return fd.file.replace(".js","")})];case 2:err=_state.sent();return[2,[]];case 3:return[2]}})})()}()];case 2:pending=_state.sent();return[4,function(){return _async_to_generator(function(){var err;return _ts_generator(this,function(_state){switch(_state.label){case 0:_state.trys.push([0,2,,3]);return[4,tConn.migrate.currentVersion()];case 1:return[2,_state.sent()];case 2:err=_state.sent();return[2,"error"];case 3:return[2]}})})()}()];case 3:currentVersion=_state.sent();connection=knexOptions.connection;return[4,tConn.destroy()];case 4:_state.sent();return[2,{name:connKey.replace("_master",""),connKey:connKey,connString:"mysql2://".concat((_connection_user=connection.user)!==null&&_connection_user!==void 0?_connection_user:"","@").concat(connection.host,":").concat(connection.port,"/").concat(connection.database),currentVersion:currentVersion,status:status,pending:pending}]}})})()}))];case 4:statuses=_state.sent();return[4,function(){return _async_to_generator(function(){var status0conn,compareDBconn,genCodes;return _ts_generator(this,function(_state){switch(_state.label){case 0:status0conn=statuses.find(function(status){return status.status===0});if(status0conn===undefined){return[2,[]]}compareDBconn=(0,_knex.default)(_api.Sonamu.dbConfig[status0conn.connKey]);return[4,this.compareMigrations(compareDBconn)];case 1:genCodes=_state.sent();return[4,compareDBconn.destroy()];case 2:_state.sent();return[2,genCodes]}})}).call(_this)}()];case 5:preparedCodes=_state.sent();return[2,{conns:statuses,codes:normal,preparedCodes:preparedCodes}]}})}).call(this)}},{key:"runAction",value:function runAction(action,targets){return _async_to_generator(function(){var configs,conns,result;return _ts_generator(this,function(_state){switch(_state.label){case 0:configs=_lodash.default.uniqBy(targets.map(function(target){return{connKey:target,options:_api.Sonamu.dbConfig[target]}}).filter(function(c){return c.options!==undefined}),function(param){var options=param.options;var _options_connection_port;return"".concat(options.connection.host,":").concat((_options_connection_port=options.connection.port)!==null&&_options_connection_port!==void 0?_options_connection_port:3306,"/").concat(options.connection.database)});return[4,Promise.all(configs.map(function(config){return _async_to_generator(function(){return _ts_generator(this,function(_state){return[2,{connKey:config.connKey,knex:(0,_knex.default)(config.options)}]})})()}))];case 1:conns=_state.sent();return[4,function(){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(action){case"apply":return[2,Promise.all(conns.map(function(param){var connKey=param.connKey,knex=param.knex;return _async_to_generator(function(){var _ref,batchNo,applied;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,knex.migrate.latest()];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),2]),batchNo=_ref[0],applied=_ref[1];return[2,{connKey:connKey,batchNo:batchNo,applied:applied}]}})})()}))];case"rollback":return[2,Promise.all(conns.map(function(param){var connKey=param.connKey,knex=param.knex;return _async_to_generator(function(){var _ref,batchNo,applied;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,knex.migrate.rollback()];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),2]),batchNo=_ref[0],applied=_ref[1];return[2,{connKey:connKey,batchNo:batchNo,applied:applied}]}})})()}))]}return[2]})})()}()];case 2:result=_state.sent();return[4,Promise.all(conns.map(function(param){var knex=param.knex;return knex.destroy()}))];case 3:_state.sent();return[2,result]}})})()}},{key:"delCodes",value:function delCodes(codeNames){return _async_to_generator(function(){var conns,delFiles,res;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.getStatus()];case 1:conns=_state.sent().conns;if(conns.some(function(conn){return codeNames.some(function(codeName){return conn.pending.includes(codeName)===false})})){throw new Error("You cannot delete a migration file if there is already applied.")}delFiles=codeNames.map(function(codeName){return["".concat(_api.Sonamu.apiRootPath,"/src/migrations/").concat(codeName,".ts"),"".concat(_api.Sonamu.apiRootPath,"/dist/migrations/").concat(codeName,".js")]}).flat();return[4,Promise.all(delFiles.map(function(delFile){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,(0,_fsutils.exists)(delFile)];case 1:if(!_state.sent())return[3,3];console.log(_chalk.default.red("DELETE: ".concat(delFile)));return[4,(0,_promises.unlink)(delFile)];case 2:_state.sent();return[2,delFiles.includes(".ts")?1:0];case 3:return[2,0]}})})()}))];case 2:res=_state.sent();return[2,_lodash.default.sum(res)]}})}).call(this)}},{key:"generatePreparedCodes",value:function generatePreparedCodes(){return _async_to_generator(function(){var preparedCodes,migrationsDir,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_iterator,_step,_step_value,index,pcode,dateTag,filePath,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.getStatus()];case 1:preparedCodes=_state.sent().preparedCodes;if(preparedCodes.length===0){console.log(_chalk.default.green("\n현재 모두 싱크된 상태입니다."));return[2,0]}migrationsDir="".concat(_api.Sonamu.apiRootPath,"/src/migrations");_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=2;case 2:_state.trys.push([2,7,8,9]);_iterator=preparedCodes.entries()[Symbol.iterator]();_state.label=3;case 3:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,6];_step_value=_sliced_to_array(_step.value,2),index=_step_value[0],pcode=_step_value[1];if(!pcode.formatted)return[3,5];dateTag=_luxon.DateTime.local().plus({seconds:index}).toFormat("yyyyMMddHHmmss");filePath="".concat(migrationsDir,"/").concat(dateTag,"_").concat(pcode.title,".ts");return[4,(0,_promises.writeFile)(filePath,pcode.formatted)];case 4:_state.sent();console.log(_chalk.default.green("MIGRTAION CREATED ".concat(filePath)));_state.label=5;case 5:_iteratorNormalCompletion=true;return[3,3];case 6:return[3,9];case 7:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,9];case 8:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 9:return[2,preparedCodes.length]}})}).call(this)}},{key:"clearPendingList",value:function clearPendingList(){return _async_to_generator(function(){var _ref,pendingList,migrationsDir,delList,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_iterator,_step,p,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.targets.pending.migrate.list()];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),2]),pendingList=_ref[1];migrationsDir="".concat(_api.Sonamu.apiRootPath,"/src/migrations");delList=pendingList.map(function(df){return _path.default.join(migrationsDir,df.file).replace(".js",".ts")});_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=2;case 2:_state.trys.push([2,8,9,10]);_iterator=delList[Symbol.iterator]();_state.label=3;case 3:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,7];p=_step.value;return[4,(0,_fsutils.exists)(p)];case 4:if(!_state.sent())return[3,6];return[4,(0,_promises.unlink)(p)];case 5:_state.sent();_state.label=6;case 6:_iteratorNormalCompletion=true;return[3,3];case 7:return[3,10];case 8:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,10];case 9:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 10:return[4,this.cleanUpDist(true)];case 11:_state.sent();return[2]}})}).call(this)}},{key:"check",value:function check(){return _async_to_generator(function(){var codes;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.compareMigrations(this.targets.compare)];case 1:codes=_state.sent();if(codes.length===0){console.log(_chalk.default.green("\n현재 모두 싱크된 상태입니다."));return[2]}console.table(codes,["type","title"]);console.log(codes[0]);return[2]}})}).call(this)}},{key:"run",value:function run(){return _async_to_generator(function(){var _ref,pendingList,answer,codes,answer1,migrationsDir,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_iterator,_step,_step_value,index,code,dateTag,filePath,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.targets.pending.migrate.list()];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),2]),pendingList=_ref[1];if(!(pendingList.length>0))return[3,5];console.log(_chalk.default.red("pending 된 마이그레이션이 존재합니다."),pendingList.map(function(pending){return pending.file}));return[4,(0,_prompts.default)({type:"confirm",name:"value",message:"Shadow DB 테스트를 진행하시겠습니까?",initial:true})];case 2:answer=_state.sent();if(answer.value===false){return[2]}console.time(_chalk.default.blue("Migrator - runShadowTest"));return[4,this.runShadowTest()];case 3:_state.sent();console.timeEnd(_chalk.default.blue("Migrator - runShadowTest"));return[4,Promise.all(this.targets.apply.map(function(applyDb){return _async_to_generator(function(){var label,_ref;return _ts_generator(this,function(_state){switch(_state.label){case 0:label=_chalk.default.green("APPLIED ".concat(applyDb.client.connectionSettings.host," ").concat(applyDb.client.database()));console.time(label);return[4,applyDb.migrate.latest()];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]);console.timeEnd(label);return[2]}})})()}))];case 4:_state.sent();_state.label=5;case 5:return[4,this.compareMigrations(this.targets.compare)];case 6:codes=_state.sent();if(codes.length===0){console.log(_chalk.default.green("\n현재 모두 싱크된 상태입니다."));return[2]}console.table(codes,["type","title"]);return[4,(0,_prompts.default)({type:"confirm",name:"value",message:"마이그레이션 코드를 생성하시겠습니까?",initial:false})];case 7:answer1=_state.sent();if(answer1.value===false){return[2]}migrationsDir="".concat(_api.Sonamu.apiRootPath,"/src/migrations");_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=8;case 8:_state.trys.push([8,13,14,15]);_iterator=codes.entries()[Symbol.iterator]();_state.label=9;case 9:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,12];_step_value=_sliced_to_array(_step.value,2),index=_step_value[0],code=_step_value[1];if(!code.formatted)return[3,11];dateTag=_luxon.DateTime.local().plus({seconds:index}).toFormat("yyyyMMddHHmmss");filePath="".concat(migrationsDir,"/").concat(dateTag,"_").concat(code.title,".ts");return[4,(0,_promises.writeFile)(filePath,code.formatted)];case 10:_state.sent();console.log(_chalk.default.green("MIGRTAION CREATED ".concat(filePath)));_state.label=11;case 11:_iteratorNormalCompletion=true;return[3,9];case 12:return[3,15];case 13:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,15];case 14:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 15:return[2]}})}).call(this)}},{key:"rollback",value:function rollback(){return _async_to_generator(function(){var rollbackAllResult;return _ts_generator(this,function(_state){switch(_state.label){case 0:console.time(_chalk.default.red("rollback:"));return[4,Promise.all(this.targets.apply.map(function(db){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,db.migrate.forceFreeMigrationsLock()];case 1:_state.sent();return[2,db.migrate.rollback(undefined,false)]}})})()}))];case 1:rollbackAllResult=_state.sent();console.dir({rollbackAllResult:rollbackAllResult},{depth:null});console.timeEnd(_chalk.default.red("rollback:"));return[2]}})}).call(this)}},{key:"cleanUpDist",value:function cleanUpDist(){var force=arguments.length>0&&arguments[0]!==void 0?arguments[0]:false;return _async_to_generator(function(){var files,_tmp,diffOnSrc,diffOnDist,answer,filesToRm,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_iterator,_step,filePath,err;function getFilesUnder(dir){return _async_to_generator(function(){var migrationPath;return _ts_generator(this,function(_state){switch(_state.label){case 0:migrationPath=_path.default.join(_api.Sonamu.apiRootPath,dir,"migrations");return[4,(0,_fsutils.exists)(migrationPath)];case 1:if(!!_state.sent())return[3,3];return[4,(0,_promises.mkdir)(migrationPath,{recursive:true})];case 2:_state.sent();_state.label=3;case 3:return[4,(0,_promises.readdir)(migrationPath)];case 4:return[2,_state.sent().filter(function(filename){return filename.startsWith(".")===false})]}})})()}return _ts_generator(this,function(_state){switch(_state.label){case 0:_tmp={};return[4,getFilesUnder("src")];case 1:_tmp.src=_state.sent();return[4,getFilesUnder("dist")];case 2:files=(_tmp.dist=_state.sent(),_tmp);diffOnSrc=_lodash.default.differenceBy(files.src,files.dist,function(filename){return filename.split(".")[0]});if(diffOnSrc.length>0){throw new Error("컴파일 되지 않은 파일이 있습니다.\n"+diffOnSrc.join("\n"))}diffOnDist=_lodash.default.differenceBy(files.dist,files.src,function(filename){return filename.split(".")[0]});if(!(diffOnDist.length>0))return[3,13];console.log(_chalk.default.red("원본 ts파일을 찾을 수 없는 js파일이 있습니다."));console.log(diffOnDist);if(!!force)return[3,4];return[4,(0,_prompts.default)({type:"confirm",name:"value",message:"삭제를 진행하시겠습니까?",initial:true})];case 3:answer=_state.sent();if(answer.value===false){return[2]}_state.label=4;case 4:filesToRm=diffOnDist.map(function(filename){return _path.default.join(_api.Sonamu.apiRootPath,"dist","migrations",filename)});_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=5;case 5:_state.trys.push([5,10,11,12]);_iterator=filesToRm[Symbol.iterator]();_state.label=6;case 6:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,9];filePath=_step.value;return[4,(0,_promises.unlink)(filePath)];case 7:_state.sent();_state.label=8;case 8:_iteratorNormalCompletion=true;return[3,6];case 9:return[3,12];case 10:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,12];case 11:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 12:console.log(_chalk.default.green("".concat(filesToRm.length,"건 삭제되었습니다!")));_state.label=13;case 13:return[2]}})})()}},{key:"runShadowTest",value:function runShadowTest(){return _async_to_generator(function(){var tdb,tdbConn,shadowDatabase,tmpSqlPath,_tdbConn_port,_tdbConn_port1,sdb,_ref,batchNo,applied,e;return _ts_generator(this,function(_state){switch(_state.label){case 0:tdb=(0,_knex.default)(_api.Sonamu.dbConfig.test);tdbConn=_api.Sonamu.dbConfig.test.connection;shadowDatabase=tdbConn.database+"__migration_shadow";tmpSqlPath="/tmp/".concat(shadowDatabase,".sql");console.log(_chalk.default.magenta("".concat(tdbConn.database,"의 데이터 ").concat(tmpSqlPath,"로 덤프")));(0,_child_process.execSync)("mysqldump -h".concat(tdbConn.host," -P").concat((_tdbConn_port=tdbConn.port)!==null&&_tdbConn_port!==void 0?_tdbConn_port:3306," -u").concat(tdbConn.user," -p'").concat(tdbConn.password,"' ").concat(tdbConn.database," --single-transaction --no-create-db --triggers > ").concat(tmpSqlPath,";"));(0,_child_process.execSync)("sed -i'' -e 's/`".concat(tdbConn.database,"`/`").concat(shadowDatabase,"`/g' ").concat(tmpSqlPath,";"));console.log(_chalk.default.magenta("".concat(shadowDatabase," 리셋")));return[4,tdb.raw("DROP DATABASE IF EXISTS `".concat(shadowDatabase,"`;"))];case 1:_state.sent();return[4,tdb.raw("CREATE DATABASE `".concat(shadowDatabase,"`;"))];case 2:_state.sent();console.log(_chalk.default.magenta("".concat(shadowDatabase," 데이터베이스 생성")));(0,_child_process.execSync)("mysql -h".concat(tdbConn.host," -P").concat((_tdbConn_port1=tdbConn.port)!==null&&_tdbConn_port1!==void 0?_tdbConn_port1:3306," -u").concat(tdbConn.user," -p'").concat(tdbConn.password,"' ").concat(shadowDatabase," < ").concat(tmpSqlPath,";"));sdb=(0,_knex.default)(_object_spread_props(_object_spread({},_api.Sonamu.dbConfig.test),{connection:_object_spread_props(_object_spread({},tdbConn),{database:shadowDatabase,password:tdbConn.password})}));_state.label=3;case 3:_state.trys.push([3,6,7,9]);return[4,sdb.migrate.latest()];case 4:_ref=_sliced_to_array.apply(void 0,[_state.sent(),2]),batchNo=_ref[0],applied=_ref[1];console.log(_chalk.default.green("Shadow DB 테스트에 성공했습니다!"),{batchNo:batchNo,applied:applied});console.log(_chalk.default.magenta("".concat(shadowDatabase," 삭제")));return[4,tdb.raw("DROP DATABASE IF EXISTS `".concat(shadowDatabase,"`;"))];case 5:_state.sent();return[2,[{connKey:"shadow",batchNo:batchNo,applied:applied}]];case 6:e=_state.sent();console.error(e);throw new _soexceptions.ServiceUnavailableException("Shadow DB 테스트 진행 중 에러");case 7:return[4,tdb.destroy()];case 8:_state.sent();return[7];case 9:return[2]}})})()}},{key:"resetAll",value:function resetAll(){return _async_to_generator(function(){var answer,rollbackAllResult,migrationsDir;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,(0,_prompts.default)({type:"confirm",name:"value",message:"모든 DB를 롤백하고 전체 마이그레이션 파일을 삭제하시겠습니까?",initial:false})];case 1:answer=_state.sent();if(answer.value===false){return[2]}console.time(_chalk.default.red("rollback-all:"));return[4,Promise.all(this.targets.apply.map(function(db){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,db.migrate.forceFreeMigrationsLock()];case 1:_state.sent();return[2,db.migrate.rollback(undefined,true)]}})})()}))];case 2:rollbackAllResult=_state.sent();console.log({rollbackAllResult:rollbackAllResult});console.timeEnd(_chalk.default.red("rollback-all:"));migrationsDir="".concat(_api.Sonamu.apiRootPath,"/src/migrations");console.time(_chalk.default.red("delete migration files"));(0,_child_process.execSync)("rm -f ".concat(migrationsDir,"/*"));(0,_child_process.execSync)("rm -f ".concat(migrationsDir.replace("/src/","/dist/"),"/*"));console.timeEnd(_chalk.default.red("delete migration files"));return[2]}})}).call(this)}},{key:"compareMigrations",value:function compareMigrations(compareDB){return _async_to_generator(function(){var entityIds,entitySetsWithJoinTable,joinTablesWithDup,joinTables,entitySets,codes;return _ts_generator(this,function(_state){switch(_state.label){case 0:entityIds=_entitymanager.EntityManager.getAllIds();entitySetsWithJoinTable=entityIds.filter(function(entityId){return _entitymanager.EntityManager.get(entityId).props.length>0}).map(function(entityId){return(0,_migrationset.getMigrationSetFromEntity)(_entitymanager.EntityManager.get(entityId))});joinTablesWithDup=entitySetsWithJoinTable.map(function(entitySet){return entitySet.joinTables}).flat();joinTables=Object.values(_lodash.default.groupBy(joinTablesWithDup,function(jt){return jt.table})).map(function(tables){if(tables.length===1){return tables[0]}return _object_spread_props(_object_spread({},tables[0]),{indexes:_lodash.default.uniqBy(tables.flatMap(function(t){return t.indexes}),function(index){return[index.type].concat(_to_consumable_array(index.columns.sort())).join("-")})})});entitySets=_to_consumable_array(entitySetsWithJoinTable).concat(_to_consumable_array(joinTables));return[4,Promise.all(entitySets.map(function(entitySet){return _async_to_generator(function(){var dbSet;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,(0,_migrationset.getMigrationSetFromDB)(compareDB,entitySet.table)];case 1:dbSet=_state.sent();if(!(dbSet===null))return[3,3];return[4,(0,_codegeneration.generateCreateCode)(entitySet)];case 2:return[2,_state.sent()];case 3:return[4,(0,_codegeneration.generateAlterCode)(entitySet,dbSet)];case 4:return[2,_state.sent()];case 5:return[2]}})})()}))];case 1:codes=_state.sent().flat();codes.sort(function(codeA,codeB){if(codeA.type==="foreign"&&codeB.type=="normal"){return 1}else if(codeA.type==="normal"&&codeB.type==="foreign"){return-1}else{return 0}});return[2,codes]}})})()}},{key:"destroy",value:function destroy(){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,Promise.all(this.targets.apply.map(function(db){return db.destroy()}))];case 1:_state.sent();return[2]}})}).call(this)}}]);return Migrator}();
2
- //# sourceMappingURL=migrator.js.map
1
+ import assert from "assert";
2
+ import chalk from "chalk";
3
+ import { mkdir, readdir, unlink, writeFile } from "node:fs/promises";
4
+ import knex from "knex";
5
+ import path from "path";
6
+ import { group, sum, unique } from "radashi";
7
+ import { Sonamu } from "../api/index.js";
8
+ import { DB } from "../database/db.js";
9
+ import { EntityManager } from "../entity/entity-manager.js";
10
+ import { ServiceUnavailableException } from "../exceptions/so-exceptions.js";
11
+ import { Naite } from "../naite/naite.js";
12
+ import { isTest } from "../utils/controller.js";
13
+ import { exists } from "../utils/fs-utils.js";
14
+ import { generateAlterCode, generateCreateCode } from "./code-generation.js";
15
+ import { getMigrationSetFromEntity } from "./migration-set.js";
16
+ import { PostgreSQLSchemaReader } from "./postgresql-schema-reader.js";
17
+ export class Migrator {
18
+ async getMigrationCodes() {
19
+ const srcMigrationsDir = path.join(Sonamu.apiRootPath, "src", "migrations"); // 이건 환경에 관계없이 항상 src에서 찾아야 해요.
20
+ if (!await exists(srcMigrationsDir)) {
21
+ await mkdir(srcMigrationsDir, {
22
+ recursive: true
23
+ });
24
+ }
25
+ const codes = (await readdir(srcMigrationsDir)).filter((f)=>f.endsWith(".ts")).map((f)=>({
26
+ name: f.replace(".ts", ""),
27
+ path: path.join(srcMigrationsDir, f)
28
+ })).sort((a, b)=>a.name < b.name ? 1 : -1); // 이름 내림차순 정렬(최신순)
29
+ Naite.t("migrator:getMigrationCodes:results", codes);
30
+ return codes;
31
+ }
32
+ /**
33
+ * 타겟별 마이그레이션 상태와 코드 생성/준비 상태를 구해옵니다.
34
+ * 실제로 DB에 접근도 하고 마이그레이션 코드 파일도 확인하고,
35
+ * 필요하다면 적용할 수 있는 코드를 생성까지 해옵니다.
36
+ *
37
+ * CLI와 Sonamu UI에서 사용됩니다.
38
+ *
39
+ * @returns
40
+ */ async getStatus() {
41
+ const codes = await this.getMigrationCodes();
42
+ Naite.t("migrator:getStatus:codes", codes);
43
+ const connKeys = Object.keys(Sonamu.dbConfig).filter((key)=>key.endsWith("_slave") === false);
44
+ let migrationStatusError;
45
+ const statuses = await Promise.all(connKeys.map(async (connKey)=>{
46
+ const knexOptions = Sonamu.dbConfig[connKey];
47
+ const tConn = knex(knexOptions);
48
+ const status = await (async ()=>{
49
+ try {
50
+ return await tConn.migrate.status();
51
+ } catch (err) {
52
+ console.warn(chalk.yellow(`${connKey}의 마이그레이션 상태를 가져오는 데에 실패하였습니다. 데이터베이스가 올바르게 구성되지 않은 것 같습니다. 확인하시고 다시 시도해주세요.\n시도한 연결 설정:\n${JSON.stringify(knexOptions.connection, null, 2)}\n발생한 에러:\n${err}\n`));
53
+ migrationStatusError = err instanceof Error ? err.message : String(err);
54
+ return "error";
55
+ }
56
+ })();
57
+ const pending = await (async ()=>{
58
+ try {
59
+ const [, fdList] = await tConn.migrate.list();
60
+ return fdList.map((fd)=>fd.file.replace(".ts", ""));
61
+ } catch (err) {
62
+ migrationStatusError = err instanceof Error ? err.message : String(err);
63
+ return [];
64
+ }
65
+ })();
66
+ const currentVersion = await (async ()=>{
67
+ try {
68
+ return await tConn.migrate.currentVersion();
69
+ } catch (_err) {
70
+ migrationStatusError = _err instanceof Error ? _err.message : String(_err);
71
+ return "error";
72
+ }
73
+ })();
74
+ Naite.t("migrator:getStatus:status", status);
75
+ const connection = knexOptions.connection;
76
+ await tConn.destroy();
77
+ return {
78
+ name: connKey.replace("_master", ""),
79
+ connKey,
80
+ connString: `pg://${connection.user ?? ""}@${connection.host}:${connection.port}/${connection.database}`,
81
+ currentVersion,
82
+ status: status,
83
+ pending
84
+ };
85
+ }));
86
+ Naite.t("migrator:getStatus:conns", statuses);
87
+ const preparedCodes = await (async ()=>{
88
+ const status0conn = statuses.find((status)=>status.status === 0);
89
+ if (status0conn === undefined) {
90
+ console.warn(chalk.yellow(`While trying to prepare migration codes, we found that there is no database to compare migrations. We need at least one database where every migration is applied(status === 0). You might want to apply your existing migrations to one of the databases.`));
91
+ return [];
92
+ }
93
+ const compareDBconn = knex(Sonamu.dbConfig[status0conn.connKey]);
94
+ const genCodes = await this.compareMigrations(compareDBconn);
95
+ await compareDBconn.destroy();
96
+ return genCodes;
97
+ })();
98
+ Naite.t("migrator:getStatus:preparedCodes", preparedCodes);
99
+ return {
100
+ conns: statuses,
101
+ codes,
102
+ preparedCodes,
103
+ error: migrationStatusError
104
+ };
105
+ }
106
+ /**
107
+ * 마이그레이션을 적용하거나 롤백합니다.
108
+ * Sonamu UI에서 마이그레이션 작업을 수행할 때 사용됩니다.
109
+ *
110
+ * CLI와 Sonamu UI에서 사용됩니다.
111
+ *
112
+ * @param action 작업 유형 (apply/rollback)
113
+ * @param targets 작업 대상 DB 설정 키 (keyof SonamuDBConfig)
114
+ * @returns 작업 결과
115
+ */ async runAction(action, targets) {
116
+ Naite.t("migrator:runAction:action", action);
117
+ Naite.t("migrator:runAction:targets", targets);
118
+ // get uniq knex configs
119
+ const configs = unique(targets.map((target)=>({
120
+ connKey: target,
121
+ options: Sonamu.dbConfig[target]
122
+ })).filter((c)=>c.options !== undefined), ({ options })=>`${options.connection.host}:${options.connection.port ?? 5432}/${options.connection.database}`);
123
+ // get connections
124
+ const conns = await Promise.all(configs.map(async (config)=>({
125
+ connKey: config.connKey,
126
+ knex: knex(config.options)
127
+ })));
128
+ // action
129
+ const result = await (async ()=>{
130
+ switch(action){
131
+ case "apply":
132
+ return Promise.all(conns.map(async ({ connKey, knex })=>{
133
+ const [batchNo, applied] = await knex.migrate.latest();
134
+ return {
135
+ connKey,
136
+ batchNo,
137
+ applied
138
+ };
139
+ }));
140
+ case "rollback":
141
+ return Promise.all(conns.map(async ({ connKey, knex })=>{
142
+ const [batchNo, applied] = await knex.migrate.rollback();
143
+ return {
144
+ connKey,
145
+ batchNo,
146
+ applied
147
+ };
148
+ }));
149
+ }
150
+ })();
151
+ // destroy
152
+ await Promise.all(conns.map(({ knex })=>{
153
+ return knex.destroy();
154
+ }));
155
+ Naite.t("migrator:runAction:result", result);
156
+ return result;
157
+ }
158
+ /**
159
+ * 삭제 가능한 마이그레이션 코드 파일을 검증합니다.
160
+ *
161
+ * @param conns 마이그레이션 상태 배열
162
+ * @param codeNames 삭제할 마이그레이션 코드 파일 이름 배열
163
+ * @returns 삭제 가능 여부 및 적용된 마이그레이션 코드 파일 이름
164
+ */ validateDeletable(conns, codeNames) {
165
+ const appliedCodes = codeNames.filter((codeName)=>conns.some((conn)=>conn.pending.includes(codeName) === false));
166
+ return {
167
+ canDelete: appliedCodes.length === 0,
168
+ appliedCodes
169
+ };
170
+ }
171
+ /**
172
+ * 마이그레이션 코드 파일을 삭제합니다.
173
+ *
174
+ * Sonamu UI에서 사용됩니다.
175
+ *
176
+ * @param codeNames 삭제할 마이그레이션 코드 파일 이름 배열
177
+ * @returns 삭제된 마이그레이션 코드 파일 개수
178
+ */ async delCodes(codeNames) {
179
+ const { conns } = await this.getStatus();
180
+ const { canDelete, appliedCodes } = this.validateDeletable(conns, codeNames);
181
+ if (!canDelete) {
182
+ throw new Error(`You cannot delete a migration file if there is already applied. Applied codes: ${appliedCodes.join(", ")}`);
183
+ }
184
+ return sum(await Promise.all(codeNames.map(async (codeName)=>{
185
+ const filePath = `${Sonamu.apiRootPath}/src/migrations/${codeName}.ts`;
186
+ if (await exists(filePath)) {
187
+ await unlink(filePath);
188
+ return 1;
189
+ }
190
+ return 0;
191
+ })));
192
+ }
193
+ genDateTag(index, baseDate = new Date()) {
194
+ const date = new Date(baseDate.getTime() + index * 1000);
195
+ const pad = (num, size = 2)=>num.toString().padStart(size, "0");
196
+ return date.getFullYear().toString() + pad(date.getMonth() + 1) + pad(date.getDate()) + pad(date.getHours()) + pad(date.getMinutes()) + pad(date.getSeconds());
197
+ }
198
+ /**
199
+ * 마이그레이션 코드 파일을 생성합니다.
200
+ *
201
+ * Sonamu UI에서 사용됩니다.
202
+ *
203
+ * @returns 생성된 마이그레이션 코드 파일 개수
204
+ */ async generatePreparedCodes() {
205
+ const { preparedCodes } = await this.getStatus();
206
+ Naite.t("migrator:generatePreparedCodes:preparedCodes", preparedCodes);
207
+ if (preparedCodes.length === 0) {
208
+ console.log(chalk.green("\n현재 모두 싱크된 상태입니다."));
209
+ return 0;
210
+ }
211
+ // 실제 코드 생성
212
+ const migrationsDir = `${Sonamu.apiRootPath}/src/migrations`;
213
+ for (const [index, pcode] of preparedCodes.entries()){
214
+ if (pcode.formatted) {
215
+ const dateTag = this.genDateTag(index);
216
+ const filePath = `${migrationsDir}/${dateTag}_${pcode.title}.ts`;
217
+ await writeFile(filePath, pcode.formatted);
218
+ !isTest() && console.log(chalk.green(`MIGRTAION CREATED ${filePath}`));
219
+ }
220
+ }
221
+ return preparedCodes.length;
222
+ }
223
+ async compareMigrations(compareDB) {
224
+ // Entity 순회하여 싱크
225
+ const entityIds = EntityManager.getAllIds();
226
+ // 조인테이블 포함하여 Entity에서 MigrationSet 추출
227
+ const entitySetsWithJoinTable = entityIds.filter((entityId)=>EntityManager.get(entityId).props.length > 0).map((entityId)=>getMigrationSetFromEntity(EntityManager.get(entityId)));
228
+ // 조인테이블만 추출
229
+ const joinTablesWithDup = entitySetsWithJoinTable.flatMap((entitySet)=>entitySet.joinTables);
230
+ // 중복 제거 (중복인 경우 indexes를 병합)
231
+ const joinTables = Object.values(group(joinTablesWithDup, (jt)=>jt.table)).map((tables)=>{
232
+ assert(tables !== undefined, "tables is undefined");
233
+ if (tables.length === 1) {
234
+ return tables[0];
235
+ }
236
+ return {
237
+ ...tables[0],
238
+ indexes: unique(tables.flatMap((t)=>t.indexes), (index)=>[
239
+ index.type,
240
+ ...index.columns.sort()
241
+ ].join("-"))
242
+ };
243
+ });
244
+ // 조인테이블 포함하여 MigrationSet 배열
245
+ const entitySets = [
246
+ ...entitySetsWithJoinTable,
247
+ ...joinTables
248
+ ];
249
+ const codes = (await Promise.all(entitySets.map(async (entitySet)=>{
250
+ const dbSet = await PostgreSQLSchemaReader.getMigrationSetFromDB(compareDB, entitySet.table);
251
+ Naite.t(`migrator:compareMigrations:entitySet:${entitySet.table}`, entitySet);
252
+ Naite.t(`migrator:compareMigrations:dbSet:${entitySet.table}`, dbSet);
253
+ if (dbSet === null) {
254
+ // 기존 테이블 없음, 새로 테이블 생성
255
+ return await generateCreateCode(entitySet);
256
+ } else {
257
+ // 기존 테이블 존재하는 케이스
258
+ return await generateAlterCode(entitySet, dbSet);
259
+ }
260
+ }))).flat();
261
+ // normal 타입이 앞으로, foreign이 뒤로
262
+ codes.sort((codeA, codeB)=>{
263
+ if (codeA.type === "foreign" && codeB.type === "normal") {
264
+ return 1;
265
+ } else if (codeA.type === "normal" && codeB.type === "foreign") {
266
+ return -1;
267
+ } else {
268
+ return 0;
269
+ }
270
+ });
271
+ return codes;
272
+ }
273
+ /**
274
+ * Shadow DB 테스트를 진행합니다.
275
+ *
276
+ * Sonamu UI에서 사용됩니다.
277
+ *
278
+ * @returns Shadow DB 테스트 결과
279
+ */ async runShadowTest() {
280
+ const tdbConn = Sonamu.dbConfig.test.connection;
281
+ const shadowDatabase = `${tdbConn.database}__migration_shadow`;
282
+ // 테스트 상황에서는 트랜잭션을 초기화하고, 새 데이터베이스 커넥션을 가져와야 함
283
+ if (isTest()) {
284
+ await DB.clearTestTransaction();
285
+ await DB.destroy();
286
+ }
287
+ // 기존 Shadow DB 삭제 후 Shadow DB 생성
288
+ const tdb = knex(Sonamu.dbConfig.test);
289
+ !isTest() && console.log(chalk.magenta(`${shadowDatabase} 삭제`));
290
+ await tdb.raw(`DROP DATABASE IF EXISTS ${shadowDatabase}`);
291
+ await tdb.raw(`CREATE DATABASE ${shadowDatabase} TEMPLATE ${tdbConn.database}`);
292
+ // Shadow DB에 연결
293
+ const sdb = knex({
294
+ ...Sonamu.dbConfig.test,
295
+ connection: {
296
+ ...tdbConn,
297
+ database: shadowDatabase,
298
+ password: tdbConn.password
299
+ }
300
+ });
301
+ // shadow DB 테스트 진행
302
+ try {
303
+ const [batchNo, applied] = await sdb.migrate.latest();
304
+ !isTest() && console.log(chalk.green("Shadow DB 테스트에 성공했습니다!"), {
305
+ batchNo,
306
+ applied
307
+ });
308
+ return [
309
+ {
310
+ connKey: "shadow",
311
+ batchNo,
312
+ applied
313
+ }
314
+ ];
315
+ } catch (e) {
316
+ console.error(e);
317
+ throw new ServiceUnavailableException("Shadow DB 테스트 진행 중 에러");
318
+ } finally{
319
+ // Shadow DB 연결 종료
320
+ await sdb.destroy();
321
+ // Shadow DB 삭제
322
+ !isTest() && console.log(chalk.magenta(`${shadowDatabase} 삭제`));
323
+ await tdb.raw(`DROP DATABASE IF EXISTS ${shadowDatabase}`);
324
+ // Test DB 연결 종료
325
+ await tdb.destroy();
326
+ }
327
+ }
328
+ }
329
+
330
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWdyYXRpb24vbWlncmF0b3IudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQgY2hhbGsgZnJvbSBcImNoYWxrXCI7XG5pbXBvcnQgeyBta2RpciwgcmVhZGRpciwgdW5saW5rLCB3cml0ZUZpbGUgfSBmcm9tIFwiZnMvcHJvbWlzZXNcIjtcbmltcG9ydCBrbmV4LCB7IHR5cGUgS25leCB9IGZyb20gXCJrbmV4XCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgZ3JvdXAsIHN1bSwgdW5pcXVlIH0gZnJvbSBcInJhZGFzaGlcIjtcbmltcG9ydCB7IFNvbmFtdSB9IGZyb20gXCIuLi9hcGlcIjtcbmltcG9ydCB7IERCLCB0eXBlIFNvbmFtdURCQ29uZmlnIH0gZnJvbSBcIi4uL2RhdGFiYXNlL2RiXCI7XG5pbXBvcnQgeyBFbnRpdHlNYW5hZ2VyIH0gZnJvbSBcIi4uL2VudGl0eS9lbnRpdHktbWFuYWdlclwiO1xuaW1wb3J0IHsgU2VydmljZVVuYXZhaWxhYmxlRXhjZXB0aW9uIH0gZnJvbSBcIi4uL2V4Y2VwdGlvbnMvc28tZXhjZXB0aW9uc1wiO1xuaW1wb3J0IHsgTmFpdGUgfSBmcm9tIFwiLi4vbmFpdGUvbmFpdGVcIjtcbmltcG9ydCB0eXBlIHsgR2VuTWlncmF0aW9uQ29kZSwgTWlncmF0aW9uU2V0IH0gZnJvbSBcIi4uL3R5cGVzL3R5cGVzXCI7XG5pbXBvcnQgeyBpc1Rlc3QgfSBmcm9tIFwiLi4vdXRpbHMvY29udHJvbGxlclwiO1xuaW1wb3J0IHsgZXhpc3RzIH0gZnJvbSBcIi4uL3V0aWxzL2ZzLXV0aWxzXCI7XG5pbXBvcnQgeyBnZW5lcmF0ZUFsdGVyQ29kZSwgZ2VuZXJhdGVDcmVhdGVDb2RlIH0gZnJvbSBcIi4vY29kZS1nZW5lcmF0aW9uXCI7XG5pbXBvcnQgeyBnZXRNaWdyYXRpb25TZXRGcm9tRW50aXR5IH0gZnJvbSBcIi4vbWlncmF0aW9uLXNldFwiO1xuaW1wb3J0IHsgUG9zdGdyZVNRTFNjaGVtYVJlYWRlciB9IGZyb20gXCIuL3Bvc3RncmVzcWwtc2NoZW1hLXJlYWRlclwiO1xuaW1wb3J0IHR5cGUgeyBDb25uU3RyaW5nLCBNaWdyYXRpb25Db2RlLCBNaWdyYXRpb25TdGF0dXMgfSBmcm9tIFwiLi90eXBlc1wiO1xuXG5leHBvcnQgdHlwZSBNaWdyYXRpb25SZXN1bHQgPSB7XG4gIGNvbm5LZXk6IHN0cmluZztcbiAgYmF0Y2hObzogbnVtYmVyO1xuICBhcHBsaWVkOiBzdHJpbmdbXTtcbn1bXTtcblxuZXhwb3J0IGNsYXNzIE1pZ3JhdG9yIHtcbiAgcHJpdmF0ZSBhc3luYyBnZXRNaWdyYXRpb25Db2RlcygpOiBQcm9taXNlPE1pZ3JhdGlvbkNvZGVbXT4ge1xuICAgIGNvbnN0IHNyY01pZ3JhdGlvbnNEaXIgPSBwYXRoLmpvaW4oU29uYW11LmFwaVJvb3RQYXRoLCBcInNyY1wiLCBcIm1pZ3JhdGlvbnNcIik7IC8vIOydtOqxtCDtmZjqsr3sl5Ag6rSA6rOE7JeG7J20IO2VreyDgSBzcmPsl5DshJwg7LC+7JWE7JW8IO2VtOyalC5cblxuICAgIGlmICghKGF3YWl0IGV4aXN0cyhzcmNNaWdyYXRpb25zRGlyKSkpIHtcbiAgICAgIGF3YWl0IG1rZGlyKHNyY01pZ3JhdGlvbnNEaXIsIHtcbiAgICAgICAgcmVjdXJzaXZlOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgY29uc3QgY29kZXMgPSAoYXdhaXQgcmVhZGRpcihzcmNNaWdyYXRpb25zRGlyKSlcbiAgICAgIC5maWx0ZXIoKGYpID0+IGYuZW5kc1dpdGgoXCIudHNcIikpXG4gICAgICAubWFwKChmKSA9PiAoe1xuICAgICAgICBuYW1lOiBmLnJlcGxhY2UoXCIudHNcIiwgXCJcIiksXG4gICAgICAgIHBhdGg6IHBhdGguam9pbihzcmNNaWdyYXRpb25zRGlyLCBmKSxcbiAgICAgIH0pKVxuICAgICAgLnNvcnQoKGEsIGIpID0+IChhLm5hbWUgPCBiLm5hbWUgPyAxIDogLTEpKTsgLy8g7J2066aEIOuCtOumvOywqOyInCDsoJXroKwo7LWc7Iug7IicKVxuXG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOmdldE1pZ3JhdGlvbkNvZGVzOnJlc3VsdHNcIiwgY29kZXMpO1xuICAgIHJldHVybiBjb2RlcztcbiAgfVxuXG4gIC8qKlxuICAgKiDtg4Dqsp/rs4Qg66eI7J206re466CI7J207IWYIOyDge2DnOyZgCDsvZTrk5wg7IOd7ISxL+ykgOu5hCDsg4Htg5zrpbwg6rWs7ZW07Ji164uI64ukLlxuICAgKiDsi6TsoJzroZwgRELsl5Ag7KCR6re864+EIO2VmOqzoCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvOuPhCDtmZXsnbjtlZjqs6AsXG4gICAqIO2VhOyalO2VmOuLpOuptCDsoIHsmqntlaAg7IiYIOyeiOuKlCDsvZTrk5zrpbwg7IOd7ISx6rmM7KeAIO2VtOyYteuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JmAIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEByZXR1cm5zXG4gICAqL1xuICBhc3luYyBnZXRTdGF0dXMoKTogUHJvbWlzZTxNaWdyYXRpb25TdGF0dXM+IHtcbiAgICBjb25zdCBjb2RlcyA9IGF3YWl0IHRoaXMuZ2V0TWlncmF0aW9uQ29kZXMoKTtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0U3RhdHVzOmNvZGVzXCIsIGNvZGVzKTtcblxuICAgIGNvbnN0IGNvbm5LZXlzID0gT2JqZWN0LmtleXMoU29uYW11LmRiQ29uZmlnKS5maWx0ZXIoXG4gICAgICAoa2V5KSA9PiBrZXkuZW5kc1dpdGgoXCJfc2xhdmVcIikgPT09IGZhbHNlLFxuICAgICkgYXMgKGtleW9mIHR5cGVvZiBTb25hbXUuZGJDb25maWcpW107XG5cbiAgICBsZXQgbWlncmF0aW9uU3RhdHVzRXJyb3I6IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICAgIGNvbnN0IHN0YXR1c2VzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBjb25uS2V5cy5tYXAoYXN5bmMgKGNvbm5LZXkpID0+IHtcbiAgICAgICAgY29uc3Qga25leE9wdGlvbnMgPSBTb25hbXUuZGJDb25maWdbY29ubktleV07XG4gICAgICAgIGNvbnN0IHRDb25uID0ga25leChrbmV4T3B0aW9ucyk7XG5cbiAgICAgICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgKGFzeW5jICgpID0+IHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHRDb25uLm1pZ3JhdGUuc3RhdHVzKCk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICAgICAgICBgJHtjb25uS2V5feydmCDrp4jsnbTqt7jroIjsnbTshZgg7IOB7YOc66W8IOqwgOyguOyYpOuKlCDrjbDsl5Ag7Iuk7Yyo7ZWY7JiA7Iq164uI64ukLiDrjbDsnbTthLDrsqDsnbTsiqTqsIAg7Jis67CU66W06rKMIOq1rOyEseuQmOyngCDslYrsnYAg6rKDIOqwmeyKteuLiOuLpC4g7ZmV7J247ZWY7Iuc6rOgIOuLpOyLnCDsi5zrj4TtlbTso7zshLjsmpQuXFxu7Iuc64+E7ZWcIOyXsOqysCDshKTsoJU6XFxuJHtKU09OLnN0cmluZ2lmeShrbmV4T3B0aW9ucy5jb25uZWN0aW9uLCBudWxsLCAyKX1cXG7rsJzsg53tlZwg7JeQ65+sOlxcbiR7ZXJyfVxcbmAsXG4gICAgICAgICAgICAgICksXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgbWlncmF0aW9uU3RhdHVzRXJyb3IgPSBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogU3RyaW5nKGVycik7XG4gICAgICAgICAgICByZXR1cm4gXCJlcnJvclwiO1xuICAgICAgICAgIH1cbiAgICAgICAgfSkoKTtcbiAgICAgICAgY29uc3QgcGVuZGluZzogc3RyaW5nW10gPSBhd2FpdCAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBbLCBmZExpc3RdID0gYXdhaXQgdENvbm4ubWlncmF0ZS5saXN0KCk7XG4gICAgICAgICAgICByZXR1cm4gZmRMaXN0Lm1hcCgoZmQ6IHsgZmlsZTogc3RyaW5nIH0pID0+IGZkLmZpbGUucmVwbGFjZShcIi50c1wiLCBcIlwiKSk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBtaWdyYXRpb25TdGF0dXNFcnJvciA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKTtcbiAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pKCk7XG4gICAgICAgIGNvbnN0IGN1cnJlbnRWZXJzaW9uID0gYXdhaXQgKGFzeW5jICgpID0+IHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHRDb25uLm1pZ3JhdGUuY3VycmVudFZlcnNpb24oKTtcbiAgICAgICAgICB9IGNhdGNoIChfZXJyKSB7XG4gICAgICAgICAgICBtaWdyYXRpb25TdGF0dXNFcnJvciA9IF9lcnIgaW5zdGFuY2VvZiBFcnJvciA/IF9lcnIubWVzc2FnZSA6IFN0cmluZyhfZXJyKTtcbiAgICAgICAgICAgIHJldHVybiBcImVycm9yXCI7XG4gICAgICAgICAgfVxuICAgICAgICB9KSgpO1xuICAgICAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0U3RhdHVzOnN0YXR1c1wiLCBzdGF0dXMpO1xuXG4gICAgICAgIGNvbnN0IGNvbm5lY3Rpb24gPSBrbmV4T3B0aW9ucy5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnO1xuXG4gICAgICAgIGF3YWl0IHRDb25uLmRlc3Ryb3koKTtcblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIG5hbWU6IGNvbm5LZXkucmVwbGFjZShcIl9tYXN0ZXJcIiwgXCJcIiksXG4gICAgICAgICAgY29ubktleSxcbiAgICAgICAgICBjb25uU3RyaW5nOiBgcGc6Ly8ke2Nvbm5lY3Rpb24udXNlciA/PyBcIlwifUAke2Nvbm5lY3Rpb24uaG9zdH06JHtcbiAgICAgICAgICAgIGNvbm5lY3Rpb24ucG9ydFxuICAgICAgICAgIH0vJHtjb25uZWN0aW9uLmRhdGFiYXNlfWAgYXMgQ29ublN0cmluZyxcbiAgICAgICAgICBjdXJyZW50VmVyc2lvbixcbiAgICAgICAgICBzdGF0dXM6IHN0YXR1cyBhcyBudW1iZXIgfCBcImVycm9yXCIsXG4gICAgICAgICAgcGVuZGluZyxcbiAgICAgICAgfTtcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0U3RhdHVzOmNvbm5zXCIsIHN0YXR1c2VzKTtcblxuICAgIGNvbnN0IHByZXBhcmVkQ29kZXM6IEdlbk1pZ3JhdGlvbkNvZGVbXSA9IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBzdGF0dXMwY29ubiA9IHN0YXR1c2VzLmZpbmQoKHN0YXR1cykgPT4gc3RhdHVzLnN0YXR1cyA9PT0gMCk7XG4gICAgICBpZiAoc3RhdHVzMGNvbm4gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgY2hhbGsueWVsbG93KFxuICAgICAgICAgICAgYFdoaWxlIHRyeWluZyB0byBwcmVwYXJlIG1pZ3JhdGlvbiBjb2Rlcywgd2UgZm91bmQgdGhhdCB0aGVyZSBpcyBubyBkYXRhYmFzZSB0byBjb21wYXJlIG1pZ3JhdGlvbnMuIFdlIG5lZWQgYXQgbGVhc3Qgb25lIGRhdGFiYXNlIHdoZXJlIGV2ZXJ5IG1pZ3JhdGlvbiBpcyBhcHBsaWVkKHN0YXR1cyA9PT0gMCkuIFlvdSBtaWdodCB3YW50IHRvIGFwcGx5IHlvdXIgZXhpc3RpbmcgbWlncmF0aW9ucyB0byBvbmUgb2YgdGhlIGRhdGFiYXNlcy5gLFxuICAgICAgICAgICksXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgY29tcGFyZURCY29ubiA9IGtuZXgoU29uYW11LmRiQ29uZmlnW3N0YXR1czBjb25uLmNvbm5LZXldKTtcbiAgICAgIGNvbnN0IGdlbkNvZGVzID0gYXdhaXQgdGhpcy5jb21wYXJlTWlncmF0aW9ucyhjb21wYXJlREJjb25uKTtcblxuICAgICAgYXdhaXQgY29tcGFyZURCY29ubi5kZXN0cm95KCk7XG5cbiAgICAgIHJldHVybiBnZW5Db2RlcztcbiAgICB9KSgpO1xuXG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOmdldFN0YXR1czpwcmVwYXJlZENvZGVzXCIsIHByZXBhcmVkQ29kZXMpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGNvbm5zOiBzdGF0dXNlcyxcbiAgICAgIGNvZGVzLFxuICAgICAgcHJlcGFyZWRDb2RlcyxcbiAgICAgIGVycm9yOiBtaWdyYXRpb25TdGF0dXNFcnJvcixcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIOuniOydtOq3uOugiOydtOyFmOydhCDsoIHsmqntlZjqsbDrgpgg66Gk67Cx7ZWp64uI64ukLlxuICAgKiBTb25hbXUgVUnsl5DshJwg66eI7J206re466CI7J207IWYIOyekeyXheydhCDsiJjtlontlaAg65WMIOyCrOyaqeuQqeuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JmAIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEBwYXJhbSBhY3Rpb24g7J6R7JeFIOycoO2YlSAoYXBwbHkvcm9sbGJhY2spXG4gICAqIEBwYXJhbSB0YXJnZXRzIOyekeyXhSDrjIDsg4EgREIg7ISk7KCVIO2CpCAoa2V5b2YgU29uYW11REJDb25maWcpXG4gICAqIEByZXR1cm5zIOyekeyXhSDqsrDqs7xcbiAgICovXG4gIGFzeW5jIHJ1bkFjdGlvbihcbiAgICBhY3Rpb246IFwiYXBwbHlcIiB8IFwicm9sbGJhY2tcIixcbiAgICB0YXJnZXRzOiAoa2V5b2YgU29uYW11REJDb25maWcpW10sXG4gICk6IFByb21pc2U8TWlncmF0aW9uUmVzdWx0PiB7XG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOnJ1bkFjdGlvbjphY3Rpb25cIiwgYWN0aW9uKTtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6cnVuQWN0aW9uOnRhcmdldHNcIiwgdGFyZ2V0cyk7XG5cbiAgICAvLyBnZXQgdW5pcSBrbmV4IGNvbmZpZ3NcbiAgICBjb25zdCBjb25maWdzID0gdW5pcXVlKFxuICAgICAgdGFyZ2V0c1xuICAgICAgICAubWFwKCh0YXJnZXQpID0+ICh7XG4gICAgICAgICAgY29ubktleTogdGFyZ2V0LFxuICAgICAgICAgIG9wdGlvbnM6IFNvbmFtdS5kYkNvbmZpZ1t0YXJnZXQgYXMga2V5b2YgdHlwZW9mIFNvbmFtdS5kYkNvbmZpZ10sXG4gICAgICAgIH0pKVxuICAgICAgICAuZmlsdGVyKChjKSA9PiBjLm9wdGlvbnMgIT09IHVuZGVmaW5lZCksXG4gICAgICAoeyBvcHRpb25zIH0pID0+XG4gICAgICAgIGAkeyhvcHRpb25zLmNvbm5lY3Rpb24gYXMgS25leC5QZ0Nvbm5lY3Rpb25Db25maWcpLmhvc3R9OiR7XG4gICAgICAgICAgKG9wdGlvbnMuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZykucG9ydCA/PyA1NDMyXG4gICAgICAgIH0vJHsob3B0aW9ucy5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnKS5kYXRhYmFzZX1gLFxuICAgICk7XG5cbiAgICAvLyBnZXQgY29ubmVjdGlvbnNcbiAgICBjb25zdCBjb25ucyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgY29uZmlncy5tYXAoYXN5bmMgKGNvbmZpZykgPT4gKHtcbiAgICAgICAgY29ubktleTogY29uZmlnLmNvbm5LZXksXG4gICAgICAgIGtuZXg6IGtuZXgoY29uZmlnLm9wdGlvbnMpLFxuICAgICAgfSkpLFxuICAgICk7XG5cbiAgICAvLyBhY3Rpb25cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCAoYXN5bmMgKCkgPT4ge1xuICAgICAgc3dpdGNoIChhY3Rpb24pIHtcbiAgICAgICAgY2FzZSBcImFwcGx5XCI6XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UuYWxsKFxuICAgICAgICAgICAgY29ubnMubWFwKGFzeW5jICh7IGNvbm5LZXksIGtuZXggfSkgPT4ge1xuICAgICAgICAgICAgICBjb25zdCBbYmF0Y2hObywgYXBwbGllZF0gPSBhd2FpdCBrbmV4Lm1pZ3JhdGUubGF0ZXN0KCk7XG4gICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgY29ubktleSxcbiAgICAgICAgICAgICAgICBiYXRjaE5vLFxuICAgICAgICAgICAgICAgIGFwcGxpZWQsIC8vIOydtOuyiCBsYXRlc3Qg7Zi47Lac66GcIOyduO2VtCBcInVwXCLsnbQg7KCB7Jqp65CcIOuniOydtOq3uOugiOydtOyFmCDsnbTrpoQoZS5nLiBcIjIwMjUxMTI0MjMzNTU3X2NyZWF0ZV9fY29tcGFuaWVzLnRzXCIp65Ok7J2YIOuwsOyXtOyeheuLiOuLpC4g7LC46rOgOiBodHRwczovL2dpdGh1Yi5jb20va25leC9rbmV4L2Jsb2IvMDFiMTc3YzQ4NWQ2OTZmMWI3Mjg1OGRlZTcyOGJhMTQzYzRmYWQ3Ni9saWIvbWlncmF0aW9ucy9taWdyYXRlL01pZ3JhdG9yLmpzI0w1NjBcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICk7XG4gICAgICAgIGNhc2UgXCJyb2xsYmFja1wiOlxuICAgICAgICAgIHJldHVybiBQcm9taXNlLmFsbChcbiAgICAgICAgICAgIGNvbm5zLm1hcChhc3luYyAoeyBjb25uS2V5LCBrbmV4IH0pID0+IHtcbiAgICAgICAgICAgICAgY29uc3QgW2JhdGNoTm8sIGFwcGxpZWRdID0gYXdhaXQga25leC5taWdyYXRlLnJvbGxiYWNrKCk7XG4gICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgY29ubktleSxcbiAgICAgICAgICAgICAgICBiYXRjaE5vLFxuICAgICAgICAgICAgICAgIGFwcGxpZWQsIC8vIOydtOuyiCByb2xsYmFjayDtmLjstpzroZwg7J247ZW0IFwiZG93blwi7J20IOyggeyaqeuQnCg966Gk67Cx65CcKSDrp4jsnbTqt7jroIjsnbTshZgg7J2066aEKGUuZy4gXCIyMDI1MTEyNDIzMzU1N19jcmVhdGVfX2NvbXBhbmllcy50c1wiKeuTpOydmCDrsLDsl7TsnoXri4jri6QuIOywuOqzoDogaHR0cHM6Ly9naXRodWIuY29tL2tuZXgva25leC9ibG9iLzAxYjE3N2M0ODVkNjk2ZjFiNzI4NThkZWU3MjhiYTE0M2M0ZmFkNzYvbGliL21pZ3JhdGlvbnMvbWlncmF0ZS9NaWdyYXRvci5qcyNMNjExXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApO1xuICAgICAgfVxuICAgIH0pKCk7XG5cbiAgICAvLyBkZXN0cm95XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBjb25ucy5tYXAoKHsga25leCB9KSA9PiB7XG4gICAgICAgIHJldHVybiBrbmV4LmRlc3Ryb3koKTtcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICBOYWl0ZS50KFwibWlncmF0b3I6cnVuQWN0aW9uOnJlc3VsdFwiLCByZXN1bHQpO1xuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiDsgq3soJwg6rCA64ql7ZWcIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J287J2EIOqygOymne2VqeuLiOuLpC5cbiAgICpcbiAgICogQHBhcmFtIGNvbm5zIOuniOydtOq3uOugiOydtOyFmCDsg4Htg5wg67Cw7Je0XG4gICAqIEBwYXJhbSBjb2RlTmFtZXMg7IKt7KCc7ZWgIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J28IOydtOumhCDrsLDsl7RcbiAgICogQHJldHVybnMg7IKt7KCcIOqwgOuKpSDsl6zrtoAg67CPIOyggeyaqeuQnCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDsnbTrpoRcbiAgICovXG4gIHZhbGlkYXRlRGVsZXRhYmxlKGNvbm5zOiBNaWdyYXRpb25TdGF0dXNbXCJjb25uc1wiXSwgY29kZU5hbWVzOiBzdHJpbmdbXSkge1xuICAgIGNvbnN0IGFwcGxpZWRDb2RlcyA9IGNvZGVOYW1lcy5maWx0ZXIoKGNvZGVOYW1lKSA9PlxuICAgICAgY29ubnMuc29tZSgoY29ubikgPT4gY29ubi5wZW5kaW5nLmluY2x1ZGVzKGNvZGVOYW1lKSA9PT0gZmFsc2UpLFxuICAgICk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgY2FuRGVsZXRlOiBhcHBsaWVkQ29kZXMubGVuZ3RoID09PSAwLFxuICAgICAgYXBwbGllZENvZGVzLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICog66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbzsnYQg7IKt7KCc7ZWp64uI64ukLlxuICAgKlxuICAgKiBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcGFyYW0gY29kZU5hbWVzIOyCreygnO2VoCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDsnbTrpoQg67Cw7Je0XG4gICAqIEByZXR1cm5zIOyCreygnOuQnCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDqsJzsiJhcbiAgICovXG4gIGFzeW5jIGRlbENvZGVzKGNvZGVOYW1lczogc3RyaW5nW10pOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHsgY29ubnMgfSA9IGF3YWl0IHRoaXMuZ2V0U3RhdHVzKCk7XG4gICAgY29uc3QgeyBjYW5EZWxldGUsIGFwcGxpZWRDb2RlcyB9ID0gdGhpcy52YWxpZGF0ZURlbGV0YWJsZShjb25ucywgY29kZU5hbWVzKTtcbiAgICBpZiAoIWNhbkRlbGV0ZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgWW91IGNhbm5vdCBkZWxldGUgYSBtaWdyYXRpb24gZmlsZSBpZiB0aGVyZSBpcyBhbHJlYWR5IGFwcGxpZWQuIEFwcGxpZWQgY29kZXM6ICR7YXBwbGllZENvZGVzLmpvaW4oXCIsIFwiKX1gLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc3VtKFxuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIGNvZGVOYW1lcy5tYXAoYXN5bmMgKGNvZGVOYW1lKSA9PiB7XG4gICAgICAgICAgY29uc3QgZmlsZVBhdGggPSBgJHtTb25hbXUuYXBpUm9vdFBhdGh9L3NyYy9taWdyYXRpb25zLyR7Y29kZU5hbWV9LnRzYDtcbiAgICAgICAgICBpZiAoYXdhaXQgZXhpc3RzKGZpbGVQYXRoKSkge1xuICAgICAgICAgICAgYXdhaXQgdW5saW5rKGZpbGVQYXRoKTtcbiAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgfSksXG4gICAgICApLFxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGdlbkRhdGVUYWcoaW5kZXg6IG51bWJlciwgYmFzZURhdGU6IERhdGUgPSBuZXcgRGF0ZSgpKTogc3RyaW5nIHtcbiAgICBjb25zdCBkYXRlID0gbmV3IERhdGUoYmFzZURhdGUuZ2V0VGltZSgpICsgaW5kZXggKiAxMDAwKTtcbiAgICBjb25zdCBwYWQgPSAobnVtOiBudW1iZXIsIHNpemU6IG51bWJlciA9IDIpID0+IG51bS50b1N0cmluZygpLnBhZFN0YXJ0KHNpemUsIFwiMFwiKTtcbiAgICByZXR1cm4gKFxuICAgICAgZGF0ZS5nZXRGdWxsWWVhcigpLnRvU3RyaW5nKCkgK1xuICAgICAgcGFkKGRhdGUuZ2V0TW9udGgoKSArIDEpICtcbiAgICAgIHBhZChkYXRlLmdldERhdGUoKSkgK1xuICAgICAgcGFkKGRhdGUuZ2V0SG91cnMoKSkgK1xuICAgICAgcGFkKGRhdGUuZ2V0TWludXRlcygpKSArXG4gICAgICBwYWQoZGF0ZS5nZXRTZWNvbmRzKCkpXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvOydhCDsg53shLHtlanri4jri6QuXG4gICAqXG4gICAqIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEByZXR1cm5zIOyDneyEseuQnCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDqsJzsiJhcbiAgICovXG4gIGFzeW5jIGdlbmVyYXRlUHJlcGFyZWRDb2RlcygpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHsgcHJlcGFyZWRDb2RlcyB9ID0gYXdhaXQgdGhpcy5nZXRTdGF0dXMoKTtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2VuZXJhdGVQcmVwYXJlZENvZGVzOnByZXBhcmVkQ29kZXNcIiwgcHJlcGFyZWRDb2Rlcyk7XG4gICAgaWYgKHByZXBhcmVkQ29kZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihcIlxcbu2YhOyerCDrqqjrkZAg7Iux7YGs65CcIOyDge2DnOyeheuLiOuLpC5cIikpO1xuICAgICAgcmV0dXJuIDA7XG4gICAgfVxuXG4gICAgLy8g7Iuk7KCcIOy9lOuTnCDsg53shLFcbiAgICBjb25zdCBtaWdyYXRpb25zRGlyID0gYCR7U29uYW11LmFwaVJvb3RQYXRofS9zcmMvbWlncmF0aW9uc2A7XG5cbiAgICBmb3IgKGNvbnN0IFtpbmRleCwgcGNvZGVdIG9mIHByZXBhcmVkQ29kZXMuZW50cmllcygpKSB7XG4gICAgICBpZiAocGNvZGUuZm9ybWF0dGVkKSB7XG4gICAgICAgIGNvbnN0IGRhdGVUYWcgPSB0aGlzLmdlbkRhdGVUYWcoaW5kZXgpO1xuICAgICAgICBjb25zdCBmaWxlUGF0aCA9IGAke21pZ3JhdGlvbnNEaXJ9LyR7ZGF0ZVRhZ31fJHtwY29kZS50aXRsZX0udHNgO1xuICAgICAgICBhd2FpdCB3cml0ZUZpbGUoZmlsZVBhdGgsIHBjb2RlLmZvcm1hdHRlZCk7XG4gICAgICAgICFpc1Rlc3QoKSAmJiBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihgTUlHUlRBSU9OIENSRUFURUQgJHtmaWxlUGF0aH1gKSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHByZXBhcmVkQ29kZXMubGVuZ3RoO1xuICB9XG5cbiAgYXN5bmMgY29tcGFyZU1pZ3JhdGlvbnMoY29tcGFyZURCOiBLbmV4KTogUHJvbWlzZTxHZW5NaWdyYXRpb25Db2RlW10+IHtcbiAgICAvLyBFbnRpdHkg7Iic7ZqM7ZWY7JesIOyLse2BrFxuICAgIGNvbnN0IGVudGl0eUlkcyA9IEVudGl0eU1hbmFnZXIuZ2V0QWxsSWRzKCk7XG5cbiAgICAvLyDsobDsnbjthYzsnbTruJQg7Y+s7ZWo7ZWY7JesIEVudGl0eeyXkOyEnCBNaWdyYXRpb25TZXQg7LaU7LacXG4gICAgY29uc3QgZW50aXR5U2V0c1dpdGhKb2luVGFibGUgPSBlbnRpdHlJZHNcbiAgICAgIC5maWx0ZXIoKGVudGl0eUlkKSA9PiBFbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlJZCkucHJvcHMubGVuZ3RoID4gMClcbiAgICAgIC5tYXAoKGVudGl0eUlkKSA9PiBnZXRNaWdyYXRpb25TZXRGcm9tRW50aXR5KEVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eUlkKSkpO1xuXG4gICAgLy8g7KGw7J247YWM7J2067iU66eMIOy2lOy2nFxuICAgIGNvbnN0IGpvaW5UYWJsZXNXaXRoRHVwID0gZW50aXR5U2V0c1dpdGhKb2luVGFibGUuZmxhdE1hcCgoZW50aXR5U2V0KSA9PiBlbnRpdHlTZXQuam9pblRhYmxlcyk7XG4gICAgLy8g7KSR67O1IOygnOqxsCAo7KSR67O17J24IOqyveyasCBpbmRleGVz66W8IOuzke2VqSlcbiAgICBjb25zdCBqb2luVGFibGVzID0gT2JqZWN0LnZhbHVlcyhncm91cChqb2luVGFibGVzV2l0aER1cCwgKGp0KSA9PiBqdC50YWJsZSkpLm1hcCgodGFibGVzKSA9PiB7XG4gICAgICBhc3NlcnQodGFibGVzICE9PSB1bmRlZmluZWQsIFwidGFibGVzIGlzIHVuZGVmaW5lZFwiKTtcbiAgICAgIGlmICh0YWJsZXMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgIHJldHVybiB0YWJsZXNbMF07XG4gICAgICB9XG4gICAgICByZXR1cm4ge1xuICAgICAgICAuLi50YWJsZXNbMF0sXG4gICAgICAgIGluZGV4ZXM6IHVuaXF1ZShcbiAgICAgICAgICB0YWJsZXMuZmxhdE1hcCgodCkgPT4gdC5pbmRleGVzKSxcbiAgICAgICAgICAoaW5kZXgpID0+IFtpbmRleC50eXBlLCAuLi5pbmRleC5jb2x1bW5zLnNvcnQoKV0uam9pbihcIi1cIiksXG4gICAgICAgICksXG4gICAgICB9O1xuICAgIH0pO1xuXG4gICAgLy8g7KGw7J247YWM7J2067iUIO2PrO2VqO2VmOyXrCBNaWdyYXRpb25TZXQg67Cw7Je0XG4gICAgY29uc3QgZW50aXR5U2V0czogTWlncmF0aW9uU2V0W10gPSBbLi4uZW50aXR5U2V0c1dpdGhKb2luVGFibGUsIC4uLmpvaW5UYWJsZXNdO1xuXG4gICAgY29uc3QgY29kZXM6IEdlbk1pZ3JhdGlvbkNvZGVbXSA9IChcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBlbnRpdHlTZXRzLm1hcChhc3luYyAoZW50aXR5U2V0KSA9PiB7XG4gICAgICAgICAgY29uc3QgZGJTZXQgPSBhd2FpdCBQb3N0Z3JlU1FMU2NoZW1hUmVhZGVyLmdldE1pZ3JhdGlvblNldEZyb21EQihcbiAgICAgICAgICAgIGNvbXBhcmVEQixcbiAgICAgICAgICAgIGVudGl0eVNldC50YWJsZSxcbiAgICAgICAgICApO1xuICAgICAgICAgIE5haXRlLnQoYG1pZ3JhdG9yOmNvbXBhcmVNaWdyYXRpb25zOmVudGl0eVNldDoke2VudGl0eVNldC50YWJsZX1gLCBlbnRpdHlTZXQpO1xuICAgICAgICAgIE5haXRlLnQoYG1pZ3JhdG9yOmNvbXBhcmVNaWdyYXRpb25zOmRiU2V0OiR7ZW50aXR5U2V0LnRhYmxlfWAsIGRiU2V0KTtcblxuICAgICAgICAgIGlmIChkYlNldCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgLy8g6riw7KG0IO2FjOydtOu4lCDsl4bsnYwsIOyDiOuhnCDthYzsnbTruJQg7IOd7ISxXG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZ2VuZXJhdGVDcmVhdGVDb2RlKGVudGl0eVNldCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIOq4sOyhtCDthYzsnbTruJQg7KG07J6s7ZWY64qUIOy8gOydtOyKpFxuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IGdlbmVyYXRlQWx0ZXJDb2RlKGVudGl0eVNldCwgZGJTZXQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSksXG4gICAgICApXG4gICAgKS5mbGF0KCk7XG5cbiAgICAvLyBub3JtYWwg7YOA7J6F7J20IOyVnuycvOuhnCwgZm9yZWlnbuydtCDrkqTroZxcbiAgICBjb2Rlcy5zb3J0KChjb2RlQSwgY29kZUIpID0+IHtcbiAgICAgIGlmIChjb2RlQS50eXBlID09PSBcImZvcmVpZ25cIiAmJiBjb2RlQi50eXBlID09PSBcIm5vcm1hbFwiKSB7XG4gICAgICAgIHJldHVybiAxO1xuICAgICAgfSBlbHNlIGlmIChjb2RlQS50eXBlID09PSBcIm5vcm1hbFwiICYmIGNvZGVCLnR5cGUgPT09IFwiZm9yZWlnblwiKSB7XG4gICAgICAgIHJldHVybiAtMTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGNvZGVzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNoYWRvdyBEQiDthYzsiqTtirjrpbwg7KeE7ZaJ7ZWp64uI64ukLlxuICAgKlxuICAgKiBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcmV0dXJucyBTaGFkb3cgREIg7YWM7Iqk7Yq4IOqysOqzvFxuICAgKi9cbiAgYXN5bmMgcnVuU2hhZG93VGVzdCgpOiBQcm9taXNlPE1pZ3JhdGlvblJlc3VsdD4ge1xuICAgIGNvbnN0IHRkYkNvbm4gPSBTb25hbXUuZGJDb25maWcudGVzdC5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnO1xuICAgIGNvbnN0IHNoYWRvd0RhdGFiYXNlID0gYCR7dGRiQ29ubi5kYXRhYmFzZX1fX21pZ3JhdGlvbl9zaGFkb3dgO1xuXG4gICAgLy8g7YWM7Iqk7Yq4IOyDge2ZqeyXkOyEnOuKlCDtirjrnpzsnq3shZjsnYQg7LSI6riw7ZmU7ZWY6rOgLCDsg4gg642w7J207YSw67Kg7J207IqkIOy7pOuEpeyFmOydhCDqsIDsoLjsmYDslbwg7ZWoXG4gICAgaWYgKGlzVGVzdCgpKSB7XG4gICAgICBhd2FpdCBEQi5jbGVhclRlc3RUcmFuc2FjdGlvbigpO1xuICAgICAgYXdhaXQgREIuZGVzdHJveSgpO1xuICAgIH1cblxuICAgIC8vIOq4sOyhtCBTaGFkb3cgREIg7IKt7KCcIO2bhCBTaGFkb3cgREIg7IOd7ISxXG4gICAgY29uc3QgdGRiID0ga25leChTb25hbXUuZGJDb25maWcudGVzdCk7XG4gICAgIWlzVGVzdCgpICYmIGNvbnNvbGUubG9nKGNoYWxrLm1hZ2VudGEoYCR7c2hhZG93RGF0YWJhc2V9IOyCreygnGApKTtcbiAgICBhd2FpdCB0ZGIucmF3KGBEUk9QIERBVEFCQVNFIElGIEVYSVNUUyAke3NoYWRvd0RhdGFiYXNlfWApO1xuICAgIGF3YWl0IHRkYi5yYXcoYENSRUFURSBEQVRBQkFTRSAke3NoYWRvd0RhdGFiYXNlfSBURU1QTEFURSAke3RkYkNvbm4uZGF0YWJhc2V9YCk7XG5cbiAgICAvLyBTaGFkb3cgRELsl5Ag7Jew6rKwXG4gICAgY29uc3Qgc2RiID0ga25leCh7XG4gICAgICAuLi5Tb25hbXUuZGJDb25maWcudGVzdCxcbiAgICAgIGNvbm5lY3Rpb246IHtcbiAgICAgICAgLi4udGRiQ29ubixcbiAgICAgICAgZGF0YWJhc2U6IHNoYWRvd0RhdGFiYXNlLFxuICAgICAgICBwYXNzd29yZDogdGRiQ29ubi5wYXNzd29yZCxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICAvLyBzaGFkb3cgREIg7YWM7Iqk7Yq4IOynhO2WiVxuICAgIHRyeSB7XG4gICAgICBjb25zdCBbYmF0Y2hObywgYXBwbGllZF0gPSBhd2FpdCBzZGIubWlncmF0ZS5sYXRlc3QoKTtcbiAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihcIlNoYWRvdyBEQiDthYzsiqTtirjsl5Ag7ISx6rO17ZaI7Iq164uI64ukIVwiKSwge1xuICAgICAgICAgIGJhdGNoTm8sXG4gICAgICAgICAgYXBwbGllZCxcbiAgICAgICAgfSk7XG5cbiAgICAgIHJldHVybiBbXG4gICAgICAgIHtcbiAgICAgICAgICBjb25uS2V5OiBcInNoYWRvd1wiLFxuICAgICAgICAgIGJhdGNoTm8sXG4gICAgICAgICAgYXBwbGllZCxcbiAgICAgICAgfSxcbiAgICAgIF07XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgY29uc29sZS5lcnJvcihlKTtcbiAgICAgIHRocm93IG5ldyBTZXJ2aWNlVW5hdmFpbGFibGVFeGNlcHRpb24oXCJTaGFkb3cgREIg7YWM7Iqk7Yq4IOynhO2WiSDspJEg7JeQ65+sXCIpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICAvLyBTaGFkb3cgREIg7Jew6rKwIOyiheujjFxuICAgICAgYXdhaXQgc2RiLmRlc3Ryb3koKTtcblxuICAgICAgLy8gU2hhZG93IERCIOyCreygnFxuICAgICAgIWlzVGVzdCgpICYmIGNvbnNvbGUubG9nKGNoYWxrLm1hZ2VudGEoYCR7c2hhZG93RGF0YWJhc2V9IOyCreygnGApKTtcbiAgICAgIGF3YWl0IHRkYi5yYXcoYERST1AgREFUQUJBU0UgSUYgRVhJU1RTICR7c2hhZG93RGF0YWJhc2V9YCk7XG5cbiAgICAgIC8vIFRlc3QgREIg7Jew6rKwIOyiheujjFxuICAgICAgYXdhaXQgdGRiLmRlc3Ryb3koKTtcbiAgICB9XG4gIH1cbn1cbiJdLCJuYW1lcyI6WyJhc3NlcnQiLCJjaGFsayIsIm1rZGlyIiwicmVhZGRpciIsInVubGluayIsIndyaXRlRmlsZSIsImtuZXgiLCJwYXRoIiwiZ3JvdXAiLCJzdW0iLCJ1bmlxdWUiLCJTb25hbXUiLCJEQiIsIkVudGl0eU1hbmFnZXIiLCJTZXJ2aWNlVW5hdmFpbGFibGVFeGNlcHRpb24iLCJOYWl0ZSIsImlzVGVzdCIsImV4aXN0cyIsImdlbmVyYXRlQWx0ZXJDb2RlIiwiZ2VuZXJhdGVDcmVhdGVDb2RlIiwiZ2V0TWlncmF0aW9uU2V0RnJvbUVudGl0eSIsIlBvc3RncmVTUUxTY2hlbWFSZWFkZXIiLCJNaWdyYXRvciIsImdldE1pZ3JhdGlvbkNvZGVzIiwic3JjTWlncmF0aW9uc0RpciIsImpvaW4iLCJhcGlSb290UGF0aCIsInJlY3Vyc2l2ZSIsImNvZGVzIiwiZmlsdGVyIiwiZiIsImVuZHNXaXRoIiwibWFwIiwibmFtZSIsInJlcGxhY2UiLCJzb3J0IiwiYSIsImIiLCJ0IiwiZ2V0U3RhdHVzIiwiY29ubktleXMiLCJPYmplY3QiLCJrZXlzIiwiZGJDb25maWciLCJrZXkiLCJtaWdyYXRpb25TdGF0dXNFcnJvciIsInN0YXR1c2VzIiwiUHJvbWlzZSIsImFsbCIsImNvbm5LZXkiLCJrbmV4T3B0aW9ucyIsInRDb25uIiwic3RhdHVzIiwibWlncmF0ZSIsImVyciIsImNvbnNvbGUiLCJ3YXJuIiwieWVsbG93IiwiSlNPTiIsInN0cmluZ2lmeSIsImNvbm5lY3Rpb24iLCJFcnJvciIsIm1lc3NhZ2UiLCJTdHJpbmciLCJwZW5kaW5nIiwiZmRMaXN0IiwibGlzdCIsImZkIiwiZmlsZSIsImN1cnJlbnRWZXJzaW9uIiwiX2VyciIsImRlc3Ryb3kiLCJjb25uU3RyaW5nIiwidXNlciIsImhvc3QiLCJwb3J0IiwiZGF0YWJhc2UiLCJwcmVwYXJlZENvZGVzIiwic3RhdHVzMGNvbm4iLCJmaW5kIiwidW5kZWZpbmVkIiwiY29tcGFyZURCY29ubiIsImdlbkNvZGVzIiwiY29tcGFyZU1pZ3JhdGlvbnMiLCJjb25ucyIsImVycm9yIiwicnVuQWN0aW9uIiwiYWN0aW9uIiwidGFyZ2V0cyIsImNvbmZpZ3MiLCJ0YXJnZXQiLCJvcHRpb25zIiwiYyIsImNvbmZpZyIsInJlc3VsdCIsImJhdGNoTm8iLCJhcHBsaWVkIiwibGF0ZXN0Iiwicm9sbGJhY2siLCJ2YWxpZGF0ZURlbGV0YWJsZSIsImNvZGVOYW1lcyIsImFwcGxpZWRDb2RlcyIsImNvZGVOYW1lIiwic29tZSIsImNvbm4iLCJpbmNsdWRlcyIsImNhbkRlbGV0ZSIsImxlbmd0aCIsImRlbENvZGVzIiwiZmlsZVBhdGgiLCJnZW5EYXRlVGFnIiwiaW5kZXgiLCJiYXNlRGF0ZSIsIkRhdGUiLCJkYXRlIiwiZ2V0VGltZSIsInBhZCIsIm51bSIsInNpemUiLCJ0b1N0cmluZyIsInBhZFN0YXJ0IiwiZ2V0RnVsbFllYXIiLCJnZXRNb250aCIsImdldERhdGUiLCJnZXRIb3VycyIsImdldE1pbnV0ZXMiLCJnZXRTZWNvbmRzIiwiZ2VuZXJhdGVQcmVwYXJlZENvZGVzIiwibG9nIiwiZ3JlZW4iLCJtaWdyYXRpb25zRGlyIiwicGNvZGUiLCJlbnRyaWVzIiwiZm9ybWF0dGVkIiwiZGF0ZVRhZyIsInRpdGxlIiwiY29tcGFyZURCIiwiZW50aXR5SWRzIiwiZ2V0QWxsSWRzIiwiZW50aXR5U2V0c1dpdGhKb2luVGFibGUiLCJlbnRpdHlJZCIsImdldCIsInByb3BzIiwiam9pblRhYmxlc1dpdGhEdXAiLCJmbGF0TWFwIiwiZW50aXR5U2V0Iiwiam9pblRhYmxlcyIsInZhbHVlcyIsImp0IiwidGFibGUiLCJ0YWJsZXMiLCJpbmRleGVzIiwidHlwZSIsImNvbHVtbnMiLCJlbnRpdHlTZXRzIiwiZGJTZXQiLCJnZXRNaWdyYXRpb25TZXRGcm9tREIiLCJmbGF0IiwiY29kZUEiLCJjb2RlQiIsInJ1blNoYWRvd1Rlc3QiLCJ0ZGJDb25uIiwidGVzdCIsInNoYWRvd0RhdGFiYXNlIiwiY2xlYXJUZXN0VHJhbnNhY3Rpb24iLCJ0ZGIiLCJtYWdlbnRhIiwicmF3Iiwic2RiIiwicGFzc3dvcmQiLCJlIl0sIm1hcHBpbmdzIjoiQUFBQSxPQUFPQSxZQUFZLFNBQVM7QUFDNUIsT0FBT0MsV0FBVyxRQUFRO0FBQzFCLFNBQVND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
@@ -0,0 +1,51 @@
1
+ import type { Knex } from "knex";
2
+ import type { MigrationColumn, MigrationSet } from "../types/types";
3
+ export type PgColumn = {
4
+ column_name: string;
5
+ data_type: string;
6
+ udt_name: string;
7
+ character_maximum_length: number | null;
8
+ numeric_precision: number | null;
9
+ numeric_scale: number | null;
10
+ is_nullable: string;
11
+ column_default: string | null;
12
+ };
13
+ type PgIndex = {
14
+ index_name: string;
15
+ column_name: string;
16
+ is_unique: boolean;
17
+ is_primary: boolean;
18
+ index_type: string;
19
+ };
20
+ type PgForeign = {
21
+ constraint_name: string;
22
+ column_name: string;
23
+ foreign_table_name: string;
24
+ foreign_column_name: string;
25
+ update_rule: string;
26
+ delete_rule: string;
27
+ };
28
+ declare class PostgreSQLSchemaReaderClass {
29
+ /**
30
+ * DB에서 테이블 정보를 읽어서 MigrationSet을 만들어옵니다.
31
+ * @param compareDB Knex 인스턴스
32
+ * @param table 테이블 이름
33
+ * @returns MigrationSet 객체
34
+ */
35
+ getMigrationSetFromDB(compareDB: Knex, table: string): Promise<MigrationSet | null>;
36
+ /**
37
+ * PostgreSQL의 constraint action을 Knex 형식으로 변환
38
+ */
39
+ private mapConstraintAction;
40
+ /**
41
+ * 기존 테이블 읽어서 cols, indexes, foreigns 반환
42
+ */
43
+ readTable(compareDB: Knex, tableName: string): Promise<[PgColumn[], PgIndex[], PgForeign[]]>;
44
+ /**
45
+ * PostgreSQL 컬럼 타입을 분석하여 MigrationColumn 객체로 변환합니다.
46
+ */
47
+ resolveDBColType(dbColumn: PgColumn): Pick<MigrationColumn, "type" | "length" | "precision" | "scale" | "numberType">;
48
+ }
49
+ export declare const PostgreSQLSchemaReader: PostgreSQLSchemaReaderClass;
50
+ export {};
51
+ //# sourceMappingURL=postgresql-schema-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgresql-schema-reader.d.ts","sourceRoot":"","sources":["../../src/migration/postgresql-schema-reader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,KAAK,EACV,eAAe,EAGf,YAAY,EAEb,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,QAAQ,GAAG;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC;AAEF,KAAK,OAAO,GAAG;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,KAAK,SAAS,GAAG;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,cAAM,2BAA2B;IAC/B;;;;;OAKG;IACG,qBAAqB,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAuFzF;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAW3B;;OAEG;IACG,SAAS,CACb,SAAS,EAAE,IAAI,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAkEhD;;OAEG;IACH,gBAAgB,CACd,QAAQ,EAAE,QAAQ,GACjB,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,GAAG,YAAY,CAAC;CAmFnF;AAED,eAAO,MAAM,sBAAsB,6BAAoC,CAAC"}