sonamu 0.6.0 → 0.7.1

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 (406) 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 +2 -1
  39. package/dist/api/caster.d.ts.map +1 -1
  40. package/dist/api/caster.js +6 -1
  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 +178 -409
  44. package/dist/api/config.d.ts +27 -13
  45. package/dist/api/config.d.ts.map +1 -1
  46. package/dist/api/config.js +19 -26
  47. package/dist/api/context.d.ts +4 -3
  48. package/dist/api/context.d.ts.map +1 -1
  49. package/dist/api/context.js +1 -1
  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 +111 -18
  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 +3 -3
  56. package/dist/api/sonamu.d.ts +7 -7
  57. package/dist/api/sonamu.d.ts.map +1 -1
  58. package/dist/api/sonamu.js +83 -51
  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 +5 -1
  63. package/dist/bin/build-config.d.ts.map +1 -1
  64. package/dist/bin/build-config.js +5 -2
  65. package/dist/bin/cli.js +165 -64
  66. package/dist/bin/loader-register.d.ts +2 -0
  67. package/dist/bin/loader-register.d.ts.map +1 -0
  68. package/dist/bin/loader-register.js +34 -0
  69. package/dist/database/_batch_update.d.ts +5 -3
  70. package/dist/database/_batch_update.d.ts.map +1 -1
  71. package/dist/database/_batch_update.js +30 -13
  72. package/dist/database/base-model.d.ts +96 -10
  73. package/dist/database/base-model.d.ts.map +1 -1
  74. package/dist/database/base-model.js +232 -89
  75. package/dist/database/base-model.types.d.ts +93 -0
  76. package/dist/database/base-model.types.d.ts.map +1 -0
  77. package/dist/database/base-model.types.js +10 -0
  78. package/dist/database/code-generator.d.ts +1 -1
  79. package/dist/database/code-generator.d.ts.map +1 -1
  80. package/dist/database/code-generator.js +11 -10
  81. package/dist/database/db.d.ts +5 -6
  82. package/dist/database/db.d.ts.map +1 -1
  83. package/dist/database/db.js +22 -25
  84. package/dist/database/puri-subset.test-d.js +81 -0
  85. package/dist/database/puri-subset.types.d.ts +123 -0
  86. package/dist/database/puri-subset.types.d.ts.map +1 -0
  87. package/dist/database/puri-subset.types.js +16 -0
  88. package/dist/database/puri-wrapper.d.ts +13 -11
  89. package/dist/database/puri-wrapper.d.ts.map +1 -1
  90. package/dist/database/puri-wrapper.js +2 -2
  91. package/dist/database/puri.d.ts +25 -14
  92. package/dist/database/puri.d.ts.map +1 -1
  93. package/dist/database/puri.js +83 -21
  94. package/dist/database/puri.types.d.ts +21 -7
  95. package/dist/database/puri.types.d.ts.map +1 -1
  96. package/dist/database/puri.types.js +4 -1
  97. package/dist/database/transaction-context.d.ts +1 -1
  98. package/dist/database/transaction-context.d.ts.map +1 -1
  99. package/dist/database/transaction-context.js +1 -1
  100. package/dist/database/upsert-builder.d.ts +9 -3
  101. package/dist/database/upsert-builder.d.ts.map +1 -1
  102. package/dist/database/upsert-builder.js +227 -78
  103. package/dist/entity/entity-manager.d.ts +165 -2
  104. package/dist/entity/entity-manager.d.ts.map +1 -1
  105. package/dist/entity/entity-manager.js +26 -10
  106. package/dist/entity/entity.d.ts +5 -3
  107. package/dist/entity/entity.d.ts.map +1 -1
  108. package/dist/entity/entity.js +153 -54
  109. package/dist/exceptions/error-handler.d.ts +1 -1
  110. package/dist/exceptions/error-handler.d.ts.map +1 -1
  111. package/dist/exceptions/error-handler.js +1 -1
  112. package/dist/exceptions/so-exceptions.d.ts +1 -1
  113. package/dist/exceptions/so-exceptions.d.ts.map +1 -1
  114. package/dist/exceptions/so-exceptions.js +1 -1
  115. package/dist/file-storage/driver.d.ts +1 -1
  116. package/dist/file-storage/driver.d.ts.map +1 -1
  117. package/dist/file-storage/driver.js +1 -1
  118. package/dist/file-storage/file-storage.js +2 -2
  119. package/dist/index.d.ts +18 -11
  120. package/dist/index.d.ts.map +1 -1
  121. package/dist/index.js +19 -13
  122. package/dist/migration/code-generation.d.ts +1 -1
  123. package/dist/migration/code-generation.d.ts.map +1 -1
  124. package/dist/migration/code-generation.js +123 -67
  125. package/dist/migration/migration-set.d.ts +2 -10
  126. package/dist/migration/migration-set.d.ts.map +1 -1
  127. package/dist/migration/migration-set.js +67 -218
  128. package/dist/migration/migrator.d.ts +24 -73
  129. package/dist/migration/migrator.d.ts.map +1 -1
  130. package/dist/migration/migrator.js +121 -301
  131. package/dist/migration/postgresql-schema-reader.d.ts +51 -0
  132. package/dist/migration/postgresql-schema-reader.d.ts.map +1 -0
  133. package/dist/migration/postgresql-schema-reader.js +245 -0
  134. package/dist/migration/types.d.ts +6 -38
  135. package/dist/migration/types.d.ts.map +1 -1
  136. package/dist/migration/types.js +1 -1
  137. package/dist/naite/messaging-types.d.ts +43 -0
  138. package/dist/naite/messaging-types.d.ts.map +1 -0
  139. package/dist/naite/messaging-types.js +7 -0
  140. package/dist/naite/naite-reporter.d.ts +41 -0
  141. package/dist/naite/naite-reporter.d.ts.map +1 -0
  142. package/dist/naite/naite-reporter.js +102 -0
  143. package/dist/naite/naite.d.ts +91 -8
  144. package/dist/naite/naite.d.ts.map +1 -1
  145. package/dist/naite/naite.js +285 -41
  146. package/dist/stream/sse.d.ts +2 -2
  147. package/dist/stream/sse.d.ts.map +1 -1
  148. package/dist/stream/sse.js +1 -1
  149. package/dist/syncer/api-parser.d.ts +3 -13
  150. package/dist/syncer/api-parser.d.ts.map +1 -1
  151. package/dist/syncer/api-parser.js +67 -56
  152. package/dist/syncer/checksum.d.ts +2 -2
  153. package/dist/syncer/checksum.d.ts.map +1 -1
  154. package/dist/syncer/checksum.js +11 -11
  155. package/dist/syncer/code-generator.d.ts +3 -3
  156. package/dist/syncer/code-generator.d.ts.map +1 -1
  157. package/dist/syncer/code-generator.js +37 -17
  158. package/dist/syncer/entity-operations.d.ts +2 -2
  159. package/dist/syncer/entity-operations.d.ts.map +1 -1
  160. package/dist/syncer/entity-operations.js +9 -8
  161. package/dist/syncer/file-patterns.d.ts +1 -1
  162. package/dist/syncer/file-patterns.d.ts.map +1 -1
  163. package/dist/syncer/file-patterns.js +1 -1
  164. package/dist/syncer/index.d.ts +4 -4
  165. package/dist/syncer/index.d.ts.map +1 -1
  166. package/dist/syncer/index.js +5 -5
  167. package/dist/syncer/module-loader.d.ts +4 -4
  168. package/dist/syncer/module-loader.d.ts.map +1 -1
  169. package/dist/syncer/module-loader.js +17 -12
  170. package/dist/syncer/syncer.d.ts +31 -24
  171. package/dist/syncer/syncer.d.ts.map +1 -1
  172. package/dist/syncer/syncer.js +92 -45
  173. package/dist/template/entity-converter.d.ts +1 -1
  174. package/dist/template/entity-converter.d.ts.map +1 -1
  175. package/dist/template/entity-converter.js +15 -8
  176. package/dist/template/helpers.d.ts +2 -2
  177. package/dist/template/helpers.d.ts.map +1 -1
  178. package/dist/template/helpers.js +3 -3
  179. package/dist/template/implementations/entity.template.d.ts +2 -2
  180. package/dist/template/implementations/entity.template.d.ts.map +1 -1
  181. package/dist/template/implementations/entity.template.js +4 -5
  182. package/dist/template/implementations/generated.template.d.ts +2 -3
  183. package/dist/template/implementations/generated.template.d.ts.map +1 -1
  184. package/dist/template/implementations/generated.template.js +46 -29
  185. package/dist/template/implementations/generated_http.template.d.ts +2 -3
  186. package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
  187. package/dist/template/implementations/generated_http.template.js +9 -9
  188. package/dist/template/implementations/generated_sso.template.d.ts +3 -4
  189. package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
  190. package/dist/template/implementations/generated_sso.template.js +54 -25
  191. package/dist/template/implementations/init_types.template.d.ts +2 -2
  192. package/dist/template/implementations/init_types.template.d.ts.map +1 -1
  193. package/dist/template/implementations/init_types.template.js +2 -2
  194. package/dist/template/implementations/model.template.d.ts +2 -2
  195. package/dist/template/implementations/model.template.d.ts.map +1 -1
  196. package/dist/template/implementations/model.template.js +47 -37
  197. package/dist/template/implementations/model_test.template.d.ts +2 -2
  198. package/dist/template/implementations/model_test.template.d.ts.map +1 -1
  199. package/dist/template/implementations/model_test.template.js +2 -2
  200. package/dist/template/implementations/service.template.d.ts +4 -4
  201. package/dist/template/implementations/service.template.d.ts.map +1 -1
  202. package/dist/template/implementations/service.template.js +24 -16
  203. package/dist/template/implementations/view_enums_buttonset.template.d.ts +2 -2
  204. package/dist/template/implementations/view_enums_buttonset.template.d.ts.map +1 -1
  205. package/dist/template/implementations/view_enums_buttonset.template.js +1 -1
  206. package/dist/template/implementations/view_enums_dropdown.template.d.ts +2 -2
  207. package/dist/template/implementations/view_enums_dropdown.template.d.ts.map +1 -1
  208. package/dist/template/implementations/view_enums_dropdown.template.js +2 -2
  209. package/dist/template/implementations/view_enums_select.template.d.ts +2 -2
  210. package/dist/template/implementations/view_enums_select.template.d.ts.map +1 -1
  211. package/dist/template/implementations/view_enums_select.template.js +2 -2
  212. package/dist/template/implementations/view_form.template.d.ts +2 -2
  213. package/dist/template/implementations/view_form.template.d.ts.map +1 -1
  214. package/dist/template/implementations/view_form.template.js +4 -4
  215. package/dist/template/implementations/view_id_all_select.template.d.ts +2 -2
  216. package/dist/template/implementations/view_id_all_select.template.d.ts.map +1 -1
  217. package/dist/template/implementations/view_id_all_select.template.js +1 -1
  218. package/dist/template/implementations/view_id_async_select.template.d.ts +2 -2
  219. package/dist/template/implementations/view_id_async_select.template.d.ts.map +1 -1
  220. package/dist/template/implementations/view_id_async_select.template.js +1 -1
  221. package/dist/template/implementations/view_list.template.d.ts +2 -2
  222. package/dist/template/implementations/view_list.template.d.ts.map +1 -1
  223. package/dist/template/implementations/view_list.template.js +29 -19
  224. package/dist/template/implementations/view_list_columns.template.d.ts +3 -3
  225. package/dist/template/implementations/view_list_columns.template.d.ts.map +1 -1
  226. package/dist/template/implementations/view_list_columns.template.js +1 -1
  227. package/dist/template/implementations/view_search_input.template.d.ts +2 -2
  228. package/dist/template/implementations/view_search_input.template.d.ts.map +1 -1
  229. package/dist/template/implementations/view_search_input.template.js +1 -1
  230. package/dist/template/index.d.ts +4 -2
  231. package/dist/template/index.d.ts.map +1 -1
  232. package/dist/template/index.js +5 -3
  233. package/dist/template/template-manager.d.ts +56 -0
  234. package/dist/template/template-manager.d.ts.map +1 -0
  235. package/dist/template/template-manager.js +125 -0
  236. package/dist/template/template-types.d.ts +16 -0
  237. package/dist/template/template-types.d.ts.map +1 -0
  238. package/dist/template/template-types.js +7 -0
  239. package/dist/template/template.d.ts +12 -2
  240. package/dist/template/template.d.ts.map +1 -1
  241. package/dist/template/template.js +19 -6
  242. package/dist/template/zod-converter.d.ts +40 -7
  243. package/dist/template/zod-converter.d.ts.map +1 -1
  244. package/dist/template/zod-converter.js +386 -58
  245. package/dist/testing/_relation-graph.d.ts +1 -1
  246. package/dist/testing/_relation-graph.d.ts.map +1 -1
  247. package/dist/testing/_relation-graph.js +12 -3
  248. package/dist/testing/fixture-manager.d.ts +42 -11
  249. package/dist/testing/fixture-manager.d.ts.map +1 -1
  250. package/dist/testing/fixture-manager.js +338 -236
  251. package/dist/types/types.d.ts +709 -104
  252. package/dist/types/types.d.ts.map +1 -1
  253. package/dist/types/types.js +309 -52
  254. package/dist/typings/knex.d.js +2 -2
  255. package/dist/utils/async-utils.d.ts.map +1 -1
  256. package/dist/utils/async-utils.js +3 -3
  257. package/dist/utils/console-util.js +1 -1
  258. package/dist/utils/controller.d.ts +1 -0
  259. package/dist/utils/controller.d.ts.map +1 -1
  260. package/dist/utils/controller.js +4 -1
  261. package/dist/utils/esm-utils.d.ts +0 -6
  262. package/dist/utils/esm-utils.d.ts.map +1 -1
  263. package/dist/utils/esm-utils.js +2 -9
  264. package/dist/utils/formatter.d.ts +3 -0
  265. package/dist/utils/formatter.d.ts.map +1 -0
  266. package/dist/utils/formatter.js +110 -0
  267. package/dist/utils/fs-utils.d.ts +1 -1
  268. package/dist/utils/fs-utils.d.ts.map +1 -1
  269. package/dist/utils/fs-utils.js +1 -1
  270. package/dist/utils/lodash-able.d.ts.map +1 -1
  271. package/dist/utils/lodash-able.js +1 -1
  272. package/dist/utils/object-utils.d.ts +44 -0
  273. package/dist/utils/object-utils.d.ts.map +1 -0
  274. package/dist/utils/object-utils.js +191 -0
  275. package/dist/utils/path-utils.d.ts +1 -1
  276. package/dist/utils/path-utils.d.ts.map +1 -1
  277. package/dist/utils/path-utils.js +3 -3
  278. package/dist/utils/process-utils.js +1 -1
  279. package/dist/utils/sql-parser.d.ts +5 -1
  280. package/dist/utils/sql-parser.d.ts.map +1 -1
  281. package/dist/utils/sql-parser.js +14 -3
  282. package/dist/utils/type-utils.d.ts +23 -0
  283. package/dist/utils/type-utils.d.ts.map +1 -0
  284. package/dist/utils/type-utils.js +45 -0
  285. package/dist/utils/utils.d.ts +7 -1
  286. package/dist/utils/utils.d.ts.map +1 -1
  287. package/dist/utils/utils.js +44 -5
  288. package/dist/utils/zod-error.d.ts +1 -1
  289. package/dist/utils/zod-error.d.ts.map +1 -1
  290. package/dist/utils/zod-error.js +1 -1
  291. package/package.json +55 -30
  292. package/src/ai/agents/agent.ts +87 -0
  293. package/src/ai/agents/index.ts +2 -0
  294. package/src/ai/agents/types.ts +47 -0
  295. package/src/ai/index.ts +1 -0
  296. package/src/ai/providers/rtzr/api.ts +37 -0
  297. package/src/ai/providers/rtzr/error.ts +34 -0
  298. package/src/ai/providers/rtzr/index.ts +4 -0
  299. package/src/ai/providers/rtzr/model.ts +201 -0
  300. package/src/ai/providers/rtzr/options.ts +49 -0
  301. package/src/ai/providers/rtzr/provider.ts +91 -0
  302. package/src/ai/providers/rtzr/utils.ts +127 -0
  303. package/src/api/base-frame.ts +4 -2
  304. package/src/api/caster.ts +17 -23
  305. package/src/api/code-converters.ts +176 -533
  306. package/src/api/config.ts +39 -56
  307. package/src/api/context.ts +7 -18
  308. package/src/api/decorators.ts +175 -46
  309. package/src/api/index.ts +2 -2
  310. package/src/api/sonamu.ts +133 -124
  311. package/src/api/validator.ts +83 -0
  312. package/src/bin/build-config.ts +7 -1
  313. package/src/bin/cli.ts +192 -110
  314. package/src/bin/loader-register.ts +38 -0
  315. package/src/database/_batch_update.ts +46 -31
  316. package/src/database/base-model.ts +390 -182
  317. package/src/database/base-model.types.ts +155 -0
  318. package/src/database/code-generator.ts +13 -32
  319. package/src/database/db.ts +36 -50
  320. package/src/database/puri-subset.test-d.ts +471 -0
  321. package/src/database/puri-subset.types.ts +195 -0
  322. package/src/database/puri-wrapper.ts +58 -67
  323. package/src/database/puri.ts +182 -126
  324. package/src/database/puri.types.ts +64 -31
  325. package/src/database/transaction-context.ts +1 -1
  326. package/src/database/upsert-builder.ts +261 -132
  327. package/src/entity/entity-manager.ts +36 -28
  328. package/src/entity/entity.ts +330 -249
  329. package/src/exceptions/error-handler.ts +3 -3
  330. package/src/exceptions/so-exceptions.ts +11 -11
  331. package/src/file-storage/driver.ts +5 -5
  332. package/src/file-storage/file-storage.ts +2 -2
  333. package/src/index.ts +18 -12
  334. package/src/migration/code-generation.ts +185 -172
  335. package/src/migration/migration-set.ts +80 -293
  336. package/src/migration/migrator.ts +182 -425
  337. package/src/migration/mysql-schema-reader.ts.txt +272 -0
  338. package/src/migration/postgresql-schema-reader.ts +310 -0
  339. package/src/migration/types.ts +6 -39
  340. package/src/naite/messaging-types.ts +51 -0
  341. package/src/naite/naite-reporter.ts +128 -0
  342. package/src/naite/naite.ts +378 -33
  343. package/src/shared/web.shared.ts.txt +20 -24
  344. package/src/stream/sse.ts +5 -5
  345. package/src/syncer/api-parser.ts +52 -69
  346. package/src/syncer/checksum.ts +25 -37
  347. package/src/syncer/code-generator.ts +58 -62
  348. package/src/syncer/entity-operations.ts +12 -15
  349. package/src/syncer/file-patterns.ts +2 -2
  350. package/src/syncer/index.ts +4 -4
  351. package/src/syncer/module-loader.ts +28 -25
  352. package/src/syncer/syncer.ts +155 -162
  353. package/src/template/entity-converter.ts +18 -27
  354. package/src/template/helpers.ts +8 -11
  355. package/src/template/implementations/entity.template.ts +6 -6
  356. package/src/template/implementations/generated.template.ts +99 -99
  357. package/src/template/implementations/generated_http.template.ts +21 -54
  358. package/src/template/implementations/generated_sso.template.ts +78 -65
  359. package/src/template/implementations/init_types.template.ts +4 -6
  360. package/src/template/implementations/model.template.ts +47 -38
  361. package/src/template/implementations/model_test.template.ts +3 -3
  362. package/src/template/implementations/service.template.ts +56 -80
  363. package/src/template/implementations/view_enums_buttonset.template.ts +2 -2
  364. package/src/template/implementations/view_enums_dropdown.template.ts +4 -4
  365. package/src/template/implementations/view_enums_select.template.ts +3 -3
  366. package/src/template/implementations/view_form.template.ts +34 -75
  367. package/src/template/implementations/view_id_all_select.template.ts +2 -2
  368. package/src/template/implementations/view_id_async_select.template.ts +9 -23
  369. package/src/template/implementations/view_list.template.ts +54 -95
  370. package/src/template/implementations/view_list_columns.template.ts +4 -10
  371. package/src/template/implementations/view_search_input.template.ts +2 -2
  372. package/src/template/index.ts +4 -2
  373. package/src/template/template-manager.ts +166 -0
  374. package/src/template/template-types.ts +16 -0
  375. package/src/template/template.ts +29 -10
  376. package/src/template/zod-converter.ts +459 -101
  377. package/src/testing/_relation-graph.ts +18 -11
  378. package/src/testing/fixture-manager.ts +468 -362
  379. package/src/types/types.ts +516 -248
  380. package/src/typings/knex.d.ts +7 -9
  381. package/src/utils/async-utils.ts +8 -12
  382. package/src/utils/console-util.ts +1 -1
  383. package/src/utils/controller.ts +3 -0
  384. package/src/utils/esm-utils.ts +8 -18
  385. package/src/utils/formatter.ts +109 -0
  386. package/src/utils/fs-utils.ts +1 -1
  387. package/src/utils/lodash-able.ts +1 -4
  388. package/src/utils/object-utils.ts +217 -0
  389. package/src/utils/path-utils.ts +3 -6
  390. package/src/utils/process-utils.ts +1 -1
  391. package/src/utils/sql-parser.ts +23 -5
  392. package/src/utils/type-utils.ts +83 -0
  393. package/src/utils/utils.ts +58 -9
  394. package/src/utils/zod-error.ts +3 -3
  395. package/dist/bin/cli-wrapper.d.ts +0 -3
  396. package/dist/bin/cli-wrapper.d.ts.map +0 -1
  397. package/dist/bin/cli-wrapper.js +0 -72
  398. package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts +0 -2
  399. package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts.map +0 -1
  400. package/dist/database/knex-plugins/knex-on-duplicate-update.js +0 -39
  401. package/dist/entity/entity-utils.d.ts +0 -61
  402. package/dist/entity/entity-utils.d.ts.map +0 -1
  403. package/dist/entity/entity-utils.js +0 -210
  404. package/src/bin/cli-wrapper.ts +0 -82
  405. package/src/database/knex-plugins/knex-on-duplicate-update.ts +0 -45
  406. package/src/entity/entity-utils.ts +0 -291
package/src/bin/cli.ts CHANGED
@@ -1,26 +1,29 @@
1
1
  import chalk from "chalk";
2
2
  import dotenv from "dotenv";
3
+
3
4
  dotenv.config();
4
5
 
5
- import path from "path";
6
- import { fileURLToPath } from "url";
7
- import { tsicli } from "tsicli";
8
6
  import { execSync, spawn } from "child_process";
9
- import { mkdir, readdir, writeFile } from "fs/promises";
10
- import { exists } from "../utils/fs-utils";
7
+ import { mkdir, readdir, rm, writeFile } from "fs/promises";
8
+ import knex, { type Knex } from "knex";
9
+ import { createRequire } from "module";
10
+ import path from "path";
11
11
  import process from "process";
12
+ import { tsicli } from "tsicli";
12
13
  import { Sonamu } from "../api";
13
- import knex, { Knex } from "knex";
14
+ import type { SonamuDBConfig } from "../database/db";
14
15
  import { EntityManager } from "../entity/entity-manager";
15
16
  import { Migrator } from "../migration/migrator";
16
17
  import { FixtureManager } from "../testing/fixture-manager";
18
+ import { exists } from "../utils/fs-utils";
17
19
  import { findApiRootPath } from "../utils/utils";
20
+ import { BUILD_DIR, SWC_BUILD_COMMAND, TSC_TYPE_CHECK_COMMAND } from "./build-config";
18
21
 
19
22
  let migrator: Migrator;
20
23
 
21
24
  async function bootstrap() {
22
- // dev 명령어가 아닌 경우에만 Sonamu 초기화
23
- if (process.argv[2] !== "dev") {
25
+ const notToInit = ["dev", "build", "start"].includes(process.argv[2] ?? "");
26
+ if (!notToInit) {
24
27
  await Sonamu.init(false, false);
25
28
  }
26
29
 
@@ -55,16 +58,14 @@ async function bootstrap() {
55
58
  ["scaffold", "view_list", "#entityId"],
56
59
  ["scaffold", "view_form", "#entityId"],
57
60
  ["ui"],
61
+ ["sync"],
58
62
  ["dev"],
63
+ ["build"],
59
64
  ["start"],
60
65
  ],
61
66
  runners: {
62
- migrate_run,
63
- migrate_check,
64
- migrate_rollback,
65
- migrate_clear,
66
- migrate_reset,
67
67
  migrate_status,
68
+ migrate_run,
68
69
  fixture_init,
69
70
  fixture_import,
70
71
  fixture_sync,
@@ -75,32 +76,66 @@ async function bootstrap() {
75
76
  ui,
76
77
  // scaffold_view_list,
77
78
  // scaffold_view_form,
79
+ sync,
78
80
  dev,
81
+ build,
79
82
  start,
80
83
  },
81
84
  });
82
85
  }
86
+
83
87
  bootstrap().finally(async () => {
84
- if (migrator) {
85
- await migrator.destroy();
86
- }
87
88
  await FixtureManager.destroy();
88
89
  });
89
90
 
91
+ /**
92
+ * pnpm sync 하면 실행되는 함수입니다.
93
+ * 프로젝트를 싱크합니다.
94
+ */
95
+ async function sync() {
96
+ await Sonamu.syncer.sync();
97
+ }
98
+
99
+ /**
100
+ * pnpm dev 하면 실행되는 함수입니다.
101
+ * 프로젝트에 대해 HMR 지원하는 개발 서버를 띄워줍니다.
102
+ *
103
+ * TypeScript를 바로 실행할 수 있도록 @sonamu-kit/loader를,
104
+ * HMR을 지원하기 위해 @sonamu-kit/hot-hook을 import하며,
105
+ * 소스맵 지원을 위해 --enable-source-maps 플래그를 포함하여 실행합니다.
106
+ *
107
+ * 이때 @sonamu-kit/loader와 @sonamu-kit/hot-hook는 sonamu가 자체적으로 가지고 있는 dependency입니다.
108
+ * 또한 실행에 사용하는 @sonamu-kit/hot-runner도 마찬가지로 sonamu가 자체적으로 가지고 있는 dependency입니다.
109
+ * 따라서 사용자 프로젝트에서는 이 세 패키지를 직접 설치할 필요가 없습니다.
110
+ *
111
+ * Sonamu.init 없이 호출될 것을 상정하여 구현되었습니다.
112
+ */
90
113
  async function dev() {
91
114
  const apiRoot = findApiRootPath();
92
- const entryPoint = 'src/index.ts';
115
+ const entryPoint = "src/index.ts";
93
116
 
94
- console.log(chalk.yellow.bold('🚀 Starting Sonamu dev server...\n'));
117
+ console.log(chalk.yellow.bold("🚀 Starting Sonamu dev server...\n"));
118
+
119
+ // 이 sonamu 패키지가 dependencies로 가지고 있는 @sonamu-kit/hot-runner의 bin/run.js를 사용합니다.
120
+ // 이 경로(/bin/run.js)는 @sonamu-kit/hot-runner의 package.json의 bin 필드에 명시되어 있는 그것과 같습니다.
121
+ const hotRunnerBinPath = createRequire(import.meta.url).resolve(
122
+ "@sonamu-kit/hot-runner/bin/run.js",
123
+ );
95
124
 
96
125
  const serverProcess = spawn(
97
- "hot-runner",
126
+ process.execPath, // node
98
127
  [
99
- "--clear-screen=false",
100
- "--node-args=--import=@sonamu-kit/loader",
101
- "--node-args=--import=sonamu/hot-hook-register",
102
- "--node-args=--enable-source-maps",
103
- entryPoint,
128
+ hotRunnerBinPath, // 이렇게 해서 hot-runner를 실행하구요
129
+ "--clear-screen=false", // 이하 hot-runner에게 넘겨줄 인자들입니다.
130
+ "--node-args=--import=sonamu/loader-register", // TypeScript 서포트를 위한 로더,
131
+ "--node-args=--import=sonamu/hot-hook-register", // HMR을 지원하기 위한 hot-hook,
132
+ "--node-args=--enable-source-maps", // 그리고 소스맵 지원을 위한 플래그입니다.
133
+ "--on-key=r:restart:Restart server", // r 누르면 서버 재시작하게 해줘요.
134
+ `--on-key=f:shell(rm ${path.join(apiRoot, "sonamu.lock")}):restart:Force restart`, // f 누르면 sonamu.lock 파일을 지우고 서버 재시작하게 해줘요.
135
+
136
+ "--on-key=enter:shell(echo hi):Key binding test", // enter를 key로 쓸 수 있음을 보이기 위한 테스트입니다.
137
+ "--on-key=ctrl+f ctrl+f:shell(git pull && pnpm install && pnpm --filter sonamu build && echo 'Sonamu is now up-to-date!'):restart:Pull & install & build & restart", // modifier와의 조합, 그리고 두 개의 chord를 사용할 수 있음을 보이기 위한 테스트입니다.
138
+ entryPoint, // 마지막으로 실제 실행할 스크립트의 경로를 넘겨줍니다.
104
139
  ],
105
140
  {
106
141
  cwd: apiRoot,
@@ -108,23 +143,23 @@ async function dev() {
108
143
  env: {
109
144
  ...process.env,
110
145
  NODE_ENV: "development",
111
- HOT: "yes",
112
- API_ROOT_PATH: apiRoot,
146
+ HOT: "yes", // 얘가 있어야 HMR이 활성화됩니다.
147
+ API_ROOT_PATH: apiRoot, // 이 경로가 hot-hook의 루트 디렉토리가 됩니다.
113
148
  },
114
- }
149
+ },
115
150
  );
116
151
 
117
152
  // 종료 처리
118
153
  const cleanup = () => {
119
- console.log(chalk.yellow('\n\n👋 Shutting down...'));
120
- serverProcess.kill('SIGTERM');
154
+ console.log(chalk.yellow("\n\n👋 Shutting down..."));
155
+ serverProcess.kill("SIGTERM");
121
156
  process.exit(0);
122
157
  };
123
158
 
124
- process.on('SIGINT', cleanup);
125
- process.on('SIGTERM', cleanup);
159
+ process.on("SIGINT", cleanup);
160
+ process.on("SIGTERM", cleanup);
126
161
 
127
- serverProcess.on('exit', (code) => {
162
+ serverProcess.on("exit", (code) => {
128
163
  if (code !== 0) {
129
164
  console.error(chalk.red(`❌ Server exited with code ${code}`));
130
165
  process.exit(code || 1);
@@ -132,25 +167,112 @@ async function dev() {
132
167
  });
133
168
  }
134
169
 
170
+ /**
171
+ * pnpm build 하면 실행되는 함수입니다.
172
+ * 프로젝트를 빌드합니다.
173
+ *
174
+ * 빌드에 필요한 .swcrc는 프로젝트 루트에서 찾고, 없으면 sonamu가 관리하는 .swcrc.project-default를 사용합니다.
175
+ * sonamu.config.ts는 src에 들어있지 않기 때문에 SWC_BUILD_COMMAND로 빌드되지 않습니다.
176
+ * 따라서 따로 빌드해줍니다.
177
+ *
178
+ * Sonamu.init 없이 호출될 것을 상정하여 구현되었습니다.
179
+ */
180
+ async function build() {
181
+ const apiRoot = findApiRootPath();
182
+
183
+ // 출력 디렉토리를 제거합니다.
184
+ try {
185
+ console.log(chalk.blue("Removing build directory..."));
186
+ if (await exists(BUILD_DIR)) {
187
+ await rm(BUILD_DIR, { recursive: true, force: true });
188
+ }
189
+ } catch (error) {
190
+ console.error(chalk.red("Remove build directory failed."), error);
191
+ process.exit(1);
192
+ }
193
+
194
+ // .swcrc 파일을 지정합니다.
195
+ let swcFilePath = ".swcrc";
196
+ try {
197
+ if (await exists(swcFilePath)) {
198
+ // 사용자 프로젝트에 .swcrc가 있으면 우선으로 사용합니다.
199
+ console.log(chalk.blue("Using .swcrc from project root..."));
200
+ } else {
201
+ // 아니라면 sonamu가 관리하는 .swcrc.project-default를 가져다 씁니다.
202
+ console.log(chalk.blue("Using default .swcrc from sonamu package..."));
203
+ swcFilePath = path.join(import.meta.dirname, "..", "..", ".swcrc.project-default");
204
+ }
205
+ } catch (error) {
206
+ console.error(chalk.red("Setting up swc config file failed."), error);
207
+ process.exit(1);
208
+ }
209
+
210
+ // 소스 디렉토리를 빌드합니다.
211
+ try {
212
+ console.log(chalk.blue("Building with swc..."));
213
+ execSync(SWC_BUILD_COMMAND(swcFilePath), { cwd: apiRoot, stdio: "inherit" });
214
+ } catch (error) {
215
+ console.error(chalk.red("Build failed."), error);
216
+ process.exit(1);
217
+ }
218
+
219
+ // sonamu.config.ts만 따로 빌드합니다.
220
+ // 이 친구는 src에 들어있지 않기 때문에 SWC_BUILD_COMMAND로 빌드되지 않습니다.
221
+ // 따라서 따로 빌드해줍니다.
222
+ try {
223
+ const configPath = path.join(apiRoot, "sonamu.config.ts");
224
+ if (await exists(configPath)) {
225
+ console.log(chalk.blue("Building sonamu.config.ts..."));
226
+ execSync(`swc ${configPath} -o ${BUILD_DIR}/sonamu.config.js`, {
227
+ cwd: apiRoot,
228
+ stdio: "inherit",
229
+ });
230
+ }
231
+ } catch (error) {
232
+ console.error(chalk.red("Building sonamu.config.ts failed."), error);
233
+ process.exit(1);
234
+ }
235
+
236
+ // 마지막에는 타입 체크를 해요.
237
+ try {
238
+ console.log(chalk.blue("Checking types with tsc..."));
239
+ execSync(TSC_TYPE_CHECK_COMMAND, {
240
+ cwd: apiRoot,
241
+ stdio: "inherit",
242
+ });
243
+ } catch (error) {
244
+ console.error(chalk.red("Type check failed."), error);
245
+ process.exit(1);
246
+ }
247
+ }
248
+
249
+ /**
250
+ * pnpm start 하면 실행되는 함수입니다.
251
+ * 빌드된 프로젝트를 실행합니다.
252
+ *
253
+ * 빌드된 결과물(dist 디렉토리의 index.js 엔트리포인트)이 없다면 실행을 중단합니다.
254
+ * 소스맵 지원과 dotenv 지원을 포함하여 실행합니다.
255
+ *
256
+ * Sonamu.init 없이 호출될 것을 상정하여 구현되었습니다.
257
+ */
135
258
  async function start() {
136
- const entryPoint = 'dist/index.js';
259
+ const apiRoot = findApiRootPath();
260
+ const entryPoint = "dist/index.js";
137
261
 
138
262
  if (!(await exists(entryPoint))) {
139
- console.log(
140
- chalk.red(`${entryPoint} not found. Please build your project first.`)
141
- );
263
+ console.log(chalk.red(`${entryPoint} not found. Please build your project first.`));
142
264
  console.log(chalk.blue("Run: yarn sonamu build"));
143
265
  return;
144
266
  }
145
267
 
146
268
  const { spawn } = await import("child_process");
147
269
  const serverProcess = spawn(
148
- "node",
270
+ process.execPath,
149
271
  ["--enable-source-maps", "-r", "dotenv/config", entryPoint],
150
272
  {
151
- cwd: Sonamu.apiRootPath,
273
+ cwd: apiRoot,
152
274
  stdio: "inherit",
153
- }
275
+ },
154
276
  );
155
277
 
156
278
  process.on("SIGINT", () => {
@@ -161,9 +283,7 @@ async function start() {
161
283
 
162
284
  async function setupMigrator() {
163
285
  // migrator
164
- migrator = new Migrator({
165
- mode: "dev",
166
- });
286
+ migrator = new Migrator();
167
287
  }
168
288
 
169
289
  async function setupFixtureManager() {
@@ -173,13 +293,10 @@ async function setupFixtureManager() {
173
293
  async function migrate_run() {
174
294
  await setupMigrator();
175
295
 
176
- await migrator.run();
177
- }
178
-
179
- async function migrate_check() {
180
- await setupMigrator();
181
-
182
- await migrator.check();
296
+ await migrator.runAction(
297
+ "apply",
298
+ Object.keys(Sonamu.dbConfig) as (keyof SonamuDBConfig)[] /*싹 다!*/,
299
+ );
183
300
  }
184
301
 
185
302
  async function migrate_status() {
@@ -190,24 +307,6 @@ async function migrate_status() {
190
307
  console.log(status);
191
308
  }
192
309
 
193
- async function migrate_rollback() {
194
- await setupMigrator();
195
-
196
- await migrator.rollback();
197
- }
198
-
199
- async function migrate_clear() {
200
- await setupMigrator();
201
-
202
- await migrator.clearPendingList();
203
- }
204
-
205
- async function migrate_reset() {
206
- await setupMigrator();
207
-
208
- await migrator.resetAll();
209
- }
210
-
211
310
  async function fixture_init() {
212
311
  const srcConfig = Sonamu.dbConfig.development_master;
213
312
  const targets = [
@@ -215,23 +314,14 @@ async function fixture_init() {
215
314
  label: "(REMOTE) Fixture DB",
216
315
  config: Sonamu.dbConfig.fixture_remote,
217
316
  },
218
- {
219
- label: "(LOCAL) Fixture DB",
220
- config: Sonamu.dbConfig.fixture_local,
221
- toSkip: (() => {
222
- const remoteConn = Sonamu.dbConfig.fixture_remote
223
- .connection as Knex.ConnectionConfig;
224
- const localConn = Sonamu.dbConfig.fixture_local
225
- .connection as Knex.ConnectionConfig;
226
- return (
227
- remoteConn.host === localConn.host &&
228
- remoteConn.database === localConn.database
229
- );
230
- })(),
231
- },
232
317
  {
233
318
  label: "(LOCAL) Testing DB",
234
319
  config: Sonamu.dbConfig.test,
320
+ toSkip: (() => {
321
+ const remoteConn = Sonamu.dbConfig.fixture_remote.connection as Knex.ConnectionConfig;
322
+ const localConn = Sonamu.dbConfig.test.connection as Knex.ConnectionConfig;
323
+ return remoteConn.host === localConn.host && remoteConn.database === localConn.database;
324
+ })(),
235
325
  },
236
326
  ] as {
237
327
  label: string;
@@ -245,16 +335,16 @@ async function fixture_init() {
245
335
  const srcConn = srcConfig.connection as Knex.ConnectionConfig;
246
336
  const migrationsDump = `/tmp/sonamu-fixture-init-migrations-${Date.now()}.sql`;
247
337
  execSync(
248
- `mysqldump -h${srcConn.host} -u${srcConn.user} -p${srcConn.password} --single-transaction -d --no-create-db --triggers ${srcConn.database} > ${dumpFilename}`
338
+ `mysqldump -h${srcConn.host} -u${srcConn.user} -p${srcConn.password} --single-transaction -d --no-create-db --triggers ${srcConn.database} > ${dumpFilename}`,
249
339
  );
250
340
  const _db = knex(srcConfig);
251
341
  const [[migrations]] = await _db.raw(
252
342
  "SELECT COUNT(*) as count FROM information_schema.tables WHERE table_schema = ? AND table_name = 'knex_migrations'",
253
- [srcConn.database]
343
+ [srcConn.database],
254
344
  );
255
345
  if (migrations.count > 0) {
256
346
  execSync(
257
- `mysqldump -h${srcConn.host} -u${srcConn.user} -p${srcConn.password} --single-transaction --no-create-db --triggers ${srcConn.database} knex_migrations knex_migrations_lock > ${migrationsDump}`
347
+ `mysqldump -h${srcConn.host} -u${srcConn.user} -p${srcConn.password} --single-transaction --no-create-db --triggers ${srcConn.database} knex_migrations knex_migrations_lock > ${migrationsDump}`,
258
348
  );
259
349
  }
260
350
 
@@ -276,9 +366,7 @@ async function fixture_init() {
276
366
  });
277
367
  const [[row]] = await db.raw(`SHOW DATABASES LIKE "${conn.database}"`);
278
368
  if (row) {
279
- console.log(
280
- chalk.yellow(`${label}: Database "${conn.database}" Already exists`)
281
- );
369
+ console.log(chalk.yellow(`${label}: Database "${conn.database}" Already exists`));
282
370
  await db.destroy();
283
371
  continue;
284
372
  }
@@ -321,11 +409,9 @@ async function stub_practice(name: string) {
321
409
  }
322
410
 
323
411
  const filteredSeqs = fileNames
324
- .filter(
325
- (fileName) => fileName.startsWith("p") && fileName.endsWith(".ts")
326
- )
412
+ .filter((fileName) => fileName.startsWith("p") && fileName.endsWith(".ts"))
327
413
  .map((fileName) => {
328
- const [, seqNo] = fileName.match(/^p([0-9]+)\-/) ?? ["0", "0"];
414
+ const [, seqNo] = fileName.match(/^p([0-9]+)-/) ?? ["0", "0"];
329
415
  return parseInt(seqNo);
330
416
  })
331
417
  .sort((a, b) => b - a);
@@ -358,14 +444,14 @@ async function stub_practice(name: string) {
358
444
 
359
445
  const runCode = `yarn node -r dotenv/config --enable-source-maps dist/practices/${fileName.replace(
360
446
  ".ts",
361
- ".js"
447
+ ".js",
362
448
  )}`;
363
449
  console.log(`${chalk.blue(runCode)} copied to clipboard.`);
364
450
  execSync(`echo "${runCode}" | pbcopy`);
365
451
  }
366
452
 
367
453
  async function stub_entity(entityId: string) {
368
- await Sonamu.syncer.createEntity({ entityId });
454
+ await Sonamu.syncer.createEntity({ entityId, title: entityId });
369
455
  }
370
456
 
371
457
  async function scaffold_model(entityId: string) {
@@ -382,18 +468,15 @@ async function scaffold_model_test(entityId: string) {
382
468
 
383
469
  async function ui() {
384
470
  try {
385
- // @sonamu-kit/ui run-ui.ts 스크립트 경로 찾기
386
- const uiModulePath = await import.meta.resolve("@sonamu-kit/ui");
387
- const uiNodePath = path.join(
388
- path.dirname(fileURLToPath(uiModulePath)),
389
- "run-ui.js"
390
- );
471
+ // 사용자 프로젝트의 패키지들 중에서 @sonamu-kit/ui 찾습니다.
472
+ // 이를 위해서 createRequire를 사용하여 프로젝트 경로 기준으로 resolve합니다.
473
+ const projectRequire = createRequire(path.join(Sonamu.apiRootPath, "package.json"));
474
+ const uiPackagePath = projectRequire.resolve("@sonamu-kit/ui"); // 없으면 여기서 터져요(MODULE_NOT_FOUND)
475
+ const uiNodePath = path.join(path.dirname(uiPackagePath), "run-ui.js");
391
476
 
392
477
  if (!(await exists(uiNodePath))) {
393
478
  console.log(
394
- chalk.red(
395
- `UI runner script not found at ${uiNodePath}. Please rebuild @sonamu-kit/ui.`
396
- )
479
+ chalk.red(`UI runner script not found at ${uiNodePath}. Please rebuild @sonamu-kit/ui.`),
397
480
  );
398
481
  return;
399
482
  }
@@ -402,8 +485,10 @@ async function ui() {
402
485
  const uiProcess = spawn(
403
486
  process.execPath,
404
487
  [
405
- "--import", "@sonamu-kit/loader",
406
- "--import", "sonamu/hot-hook-register",
488
+ "--import",
489
+ "sonamu/loader-register",
490
+ "--import",
491
+ "sonamu/hot-hook-register",
407
492
  "--enable-source-maps",
408
493
  "--no-warnings",
409
494
  uiNodePath,
@@ -413,12 +498,11 @@ async function ui() {
413
498
  env: {
414
499
  ...process.env,
415
500
  HOT: "yes",
416
- PROJECT_NAME:
417
- Sonamu.config.projectName ?? path.basename(Sonamu.apiRootPath),
501
+ PROJECT_NAME: Sonamu.config.projectName ?? path.basename(Sonamu.apiRootPath),
418
502
  API_ROOT_PATH: Sonamu.apiRootPath,
419
503
  UI_PORT: (Sonamu.config.ui?.port ?? 57000).toString(),
420
504
  },
421
- }
505
+ },
422
506
  );
423
507
 
424
508
  // 종료 처리
@@ -439,9 +523,7 @@ async function ui() {
439
523
  });
440
524
  } catch (e: unknown) {
441
525
  if (e instanceof Error && e.message.includes("isn't declared")) {
442
- console.log(
443
- `You need to install ${chalk.blue(`@sonamu-kit/ui`)} first.`
444
- );
526
+ console.log(`You need to install ${chalk.blue(`@sonamu-kit/ui`)} first.`);
445
527
  return;
446
528
  }
447
529
  throw e;
@@ -0,0 +1,38 @@
1
+ import { register } from "node:module";
2
+ import * as path from "node:path";
3
+ import { exists } from "../utils/fs-utils.js";
4
+ import { findApiRootPath } from "../utils/utils.js";
5
+
6
+ /**
7
+ * @sonamu-kit/loader/loader를 등록하는 스크립트입니다.
8
+ * 이 스크립트는 sonamu cli로 dev 실행할 때 --import로 실행됩니다.
9
+ */
10
+ async function setupSwcConfig() {
11
+ try {
12
+ const apiRoot = findApiRootPath();
13
+
14
+ // 프로젝트 루트에서 .swcrc 찾기
15
+ const projectSwcrcPath = path.join(apiRoot, ".swcrc");
16
+ if (await exists(projectSwcrcPath)) {
17
+ // 사용자 프로젝트에 .swcrc가 있으면 우선으로 사용합니다.
18
+ process.env.SWCRC_PATH = projectSwcrcPath;
19
+ return;
20
+ }
21
+
22
+ // 아니라면 sonamu가 관리하는 .swcrc.project-default를 가져다 씁니다.
23
+ const sonamuSwcrcPath = path.join(import.meta.dirname, "..", "..", ".swcrc.project-default");
24
+ if (await exists(sonamuSwcrcPath)) {
25
+ process.env.SWCRC_PATH = sonamuSwcrcPath;
26
+ return;
27
+ }
28
+ } catch {
29
+ // 환경 변수 설정 실패는 무시 (loader가 기본 설정 사용)
30
+ }
31
+ }
32
+
33
+ // swc 설정 파일 경로를 환경 변수로 설정
34
+ await setupSwcConfig();
35
+
36
+ register("@sonamu-kit/loader/loader", {
37
+ parentURL: import.meta.url,
38
+ });
@@ -3,11 +3,12 @@
3
3
  https://github.com/knex/knex/issues/5716
4
4
  */
5
5
 
6
- import { Knex } from "knex";
6
+ import type { Knex } from "knex";
7
7
 
8
+ type ColumnValue = string | number | boolean | null;
8
9
  export type RowWithId<Id extends string> = {
9
- [key in Id]: any;
10
- } & Record<string, any>;
10
+ [key in Id]: ColumnValue;
11
+ } & Record<string, ColumnValue>;
11
12
 
12
13
  /**
13
14
  * Batch update rows in a table. Technically its a patch since it only updates the specified columns. Any omitted columns will not be affected
@@ -24,17 +25,14 @@ export async function batchUpdate<Id extends string>(
24
25
  ids: Id[],
25
26
  rows: RowWithId<Id>[],
26
27
  chunkSize = 50,
27
- trx: Knex.Transaction | null = null
28
+ trx: Knex.Transaction | null = null,
28
29
  ) {
29
30
  const chunks: RowWithId<Id>[][] = [];
30
31
  for (let i = 0; i < rows.length; i += chunkSize) {
31
32
  chunks.push(rows.slice(i, i + chunkSize));
32
33
  }
33
34
 
34
- const executeUpdate = async (
35
- chunk: RowWithId<Id>[],
36
- transaction: Knex.Transaction
37
- ) => {
35
+ const executeUpdate = async (chunk: RowWithId<Id>[], transaction: Knex.Transaction) => {
38
36
  const sql = generateBatchUpdateSQL(knex, tableName, chunk, ids);
39
37
  return knex.raw(sql).transacting(transaction);
40
38
  };
@@ -59,7 +57,7 @@ export async function batchUpdate<Id extends string>(
59
57
  * [ { a: 1, b: 2 }, { a: 3, c: 4 } ] => Set([ "a", "b", "c" ])
60
58
  * @param data
61
59
  */
62
- function generateKeySetFromData(data: Record<string, any>[]) {
60
+ function generateKeySetFromData(data: Record<string, ColumnValue>[]) {
63
61
  const keySet: Set<string> = new Set();
64
62
  for (const row of data) {
65
63
  for (const key of Object.keys(row)) {
@@ -72,50 +70,67 @@ function generateKeySetFromData(data: Record<string, any>[]) {
72
70
  function generateBatchUpdateSQL<Id extends string>(
73
71
  db: Knex,
74
72
  tableName: string,
75
- data: Record<string, any>[],
76
- identifiers: Id[]
73
+ data: Record<string, ColumnValue>[],
74
+ identifiers: Id[],
77
75
  ) {
78
76
  const keySet = generateKeySetFromData(data);
79
- const bindings = [];
77
+ const allBindings: (string | number | boolean | null)[] = [];
80
78
 
81
79
  const invalidIdentifiers = identifiers.filter((id) => !keySet.has(id));
82
80
  if (invalidIdentifiers.length > 0) {
83
81
  throw new Error(
84
- `Invalid identifiers: ${invalidIdentifiers.join(", ")}. Identifiers must exist in the data`
82
+ `Invalid identifiers: ${invalidIdentifiers.join(", ")}. Identifiers must exist in the data`,
85
83
  );
86
84
  }
87
85
 
88
- const cases = [];
86
+ const cases: string[] = [];
87
+
89
88
  for (const key of keySet) {
90
89
  if (identifiers.includes(key as Id)) continue;
91
90
 
92
- const rows = [];
91
+ const caseBindings: (string | number | boolean | null)[] = [];
92
+ const whenClauses: string[] = [];
93
+
93
94
  for (const row of data) {
94
- if (Object.hasOwnProperty.call(row, key)) {
95
- const whereClause = identifiers
96
- .map((id) => `\`${id}\` = ?`)
97
- .join(" AND ");
98
- rows.push(`WHEN (${whereClause}) THEN ?`);
99
- bindings.push(...identifiers.map((i) => row[i]), row[key]);
95
+ if (Object.hasOwn(row, key)) {
96
+ const whereParts = identifiers.map(() => `?? = ?`).join(" AND ");
97
+ whenClauses.push(`WHEN (${whereParts}) THEN ?`);
98
+
99
+ // identifier 이름과 값들을 추가
100
+ for (const id of identifiers) {
101
+ caseBindings.push(id, row[id]);
102
+ }
103
+ // THEN 값 추가
104
+ caseBindings.push(row[key]);
100
105
  }
101
106
  }
102
107
 
103
- const whenThen = rows.join(" ");
104
- cases.push(`\`${key}\` = CASE ${whenThen} ELSE \`${key}\` END`);
108
+ const whenThen = whenClauses.join(" ");
109
+ cases.push(`?? = CASE ${whenThen} ELSE ?? END`);
110
+
111
+ // 컬럼명 2개 추가 (SET의 컬럼명, ELSE의 컬럼명)
112
+ allBindings.push(key);
113
+ allBindings.push(...caseBindings);
114
+ allBindings.push(key);
105
115
  }
106
116
 
107
117
  const whereInClauses = identifiers
108
- .map((col) => `${col} IN (${data.map(() => "?").join(", ")})`)
118
+ .map((_col) => `?? IN (${data.map(() => "?").join(", ")})`)
109
119
  .join(" AND ");
110
120
 
111
- const whereInBindings = identifiers.flatMap((col) =>
112
- data.map((row) => row[col])
113
- );
121
+ const whereInBindings: (string | number | boolean | null)[] = [];
122
+ for (const col of identifiers) {
123
+ whereInBindings.push(col);
124
+ for (const row of data) {
125
+ whereInBindings.push(row[col]);
126
+ }
127
+ }
114
128
 
115
- const sql = db.raw(
116
- `UPDATE \`${tableName}\` SET ${cases.join(", ")} WHERE ${whereInClauses}`,
117
- [...bindings, ...whereInBindings]
118
- );
129
+ const sql = db.raw(`UPDATE ?? SET ${cases.join(", ")} WHERE ${whereInClauses}`, [
130
+ tableName,
131
+ ...allBindings,
132
+ ...whereInBindings,
133
+ ]);
119
134
 
120
135
  return sql.toQuery();
121
136
  }