sonamu 0.0.41 → 0.1.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 (219) hide show
  1. package/.pnp.cjs +1968 -956
  2. package/.pnp.loader.mjs +1816 -54
  3. package/.yarnrc.yml +1 -1
  4. package/dist/api/caster.d.ts +2 -4
  5. package/dist/api/caster.d.ts.map +1 -1
  6. package/dist/api/code-converters.d.ts +3 -3
  7. package/dist/api/code-converters.d.ts.map +1 -1
  8. package/dist/api/code-converters.js +5 -15
  9. package/dist/api/code-converters.js.map +1 -1
  10. package/dist/api/context.d.ts +1 -1
  11. package/dist/api/context.d.ts.map +1 -1
  12. package/dist/api/decorators.d.ts +3 -3
  13. package/dist/api/decorators.d.ts.map +1 -1
  14. package/dist/api/sonamu.d.ts +3 -3
  15. package/dist/api/sonamu.d.ts.map +1 -1
  16. package/dist/api/sonamu.js +6 -6
  17. package/dist/api/sonamu.js.map +1 -1
  18. package/dist/bin/cli.js +240 -26
  19. package/dist/bin/cli.js.map +1 -1
  20. package/dist/database/db.d.ts +2 -2
  21. package/dist/database/db.d.ts.map +1 -1
  22. package/dist/database/db.js +1 -1
  23. package/dist/database/db.js.map +1 -1
  24. package/dist/database/upsert-builder.d.ts +2 -2
  25. package/dist/database/upsert-builder.d.ts.map +1 -1
  26. package/dist/database/upsert-builder.js +10 -8
  27. package/dist/database/upsert-builder.js.map +1 -1
  28. package/dist/entity/entity-manager.d.ts +29 -0
  29. package/dist/entity/entity-manager.d.ts.map +1 -0
  30. package/dist/entity/entity-manager.js +128 -0
  31. package/dist/entity/entity-manager.js.map +1 -0
  32. package/dist/entity/entity-utils.d.ts +61 -0
  33. package/dist/entity/entity-utils.d.ts.map +1 -0
  34. package/dist/entity/entity-utils.js +121 -0
  35. package/dist/entity/entity-utils.js.map +1 -0
  36. package/dist/entity/entity.d.ts +49 -0
  37. package/dist/entity/entity.d.ts.map +1 -0
  38. package/dist/entity/entity.js +504 -0
  39. package/dist/entity/entity.js.map +1 -0
  40. package/dist/entity/migrator.d.ts +143 -0
  41. package/dist/entity/migrator.d.ts.map +1 -0
  42. package/dist/entity/migrator.js +1385 -0
  43. package/dist/entity/migrator.js.map +1 -0
  44. package/dist/entity/smd-utils.d.ts +61 -0
  45. package/dist/entity/smd-utils.d.ts.map +1 -0
  46. package/dist/entity/smd-utils.js +121 -0
  47. package/dist/entity/smd-utils.js.map +1 -0
  48. package/dist/index.d.ts +3 -3
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +3 -3
  51. package/dist/index.js.map +1 -1
  52. package/dist/smd/entity-manager.d.ts +28 -0
  53. package/dist/smd/entity-manager.d.ts.map +1 -0
  54. package/dist/smd/entity-manager.js +119 -0
  55. package/dist/smd/entity-manager.js.map +1 -0
  56. package/dist/smd/entity.d.ts +40 -0
  57. package/dist/smd/entity.d.ts.map +1 -0
  58. package/dist/smd/entity.js +430 -0
  59. package/dist/smd/entity.js.map +1 -0
  60. package/dist/smd/migrator.d.ts +2 -2
  61. package/dist/smd/migrator.d.ts.map +1 -1
  62. package/dist/smd/migrator.js +5 -5
  63. package/dist/smd/migrator.js.map +1 -1
  64. package/dist/smd/smd-manager.d.ts +3 -3
  65. package/dist/smd/smd-manager.d.ts.map +1 -1
  66. package/dist/smd/smd-manager.js +2 -2
  67. package/dist/smd/smd-manager.js.map +1 -1
  68. package/dist/smd/smd-utils.d.ts +4 -4
  69. package/dist/smd/smd-utils.d.ts.map +1 -1
  70. package/dist/smd/smd-utils.js.map +1 -1
  71. package/dist/smd/smd.d.ts +5 -6
  72. package/dist/smd/smd.d.ts.map +1 -1
  73. package/dist/smd/smd.js +3 -3
  74. package/dist/smd/smd.js.map +1 -1
  75. package/dist/syncer/syncer.d.ts +15 -11
  76. package/dist/syncer/syncer.d.ts.map +1 -1
  77. package/dist/syncer/syncer.js +134 -74
  78. package/dist/syncer/syncer.js.map +1 -1
  79. package/dist/templates/base-template.d.ts +2 -2
  80. package/dist/templates/base-template.d.ts.map +1 -1
  81. package/dist/templates/entity.template.d.ts +17 -0
  82. package/dist/templates/entity.template.d.ts.map +1 -0
  83. package/dist/templates/entity.template.js +46 -0
  84. package/dist/templates/entity.template.js.map +1 -0
  85. package/dist/templates/generated.template.d.ts +11 -7
  86. package/dist/templates/generated.template.d.ts.map +1 -1
  87. package/dist/templates/generated.template.js +72 -43
  88. package/dist/templates/generated.template.js.map +1 -1
  89. package/dist/templates/generated_http.template.d.ts +3 -3
  90. package/dist/templates/generated_http.template.d.ts.map +1 -1
  91. package/dist/templates/generated_http.template.js +3 -3
  92. package/dist/templates/generated_http.template.js.map +1 -1
  93. package/dist/templates/init_enums.template.d.ts +2 -2
  94. package/dist/templates/init_enums.template.d.ts.map +1 -1
  95. package/dist/templates/init_enums.template.js +2 -2
  96. package/dist/templates/init_enums.template.js.map +1 -1
  97. package/dist/templates/init_generated.template.d.ts +3 -3
  98. package/dist/templates/init_generated.template.d.ts.map +1 -1
  99. package/dist/templates/init_generated.template.js +13 -14
  100. package/dist/templates/init_generated.template.js.map +1 -1
  101. package/dist/templates/init_types.template.d.ts +3 -3
  102. package/dist/templates/init_types.template.d.ts.map +1 -1
  103. package/dist/templates/init_types.template.js +10 -10
  104. package/dist/templates/init_types.template.js.map +1 -1
  105. package/dist/templates/model.template.d.ts +3 -3
  106. package/dist/templates/model.template.d.ts.map +1 -1
  107. package/dist/templates/model.template.js +28 -28
  108. package/dist/templates/model.template.js.map +1 -1
  109. package/dist/templates/model_test.template.d.ts +3 -3
  110. package/dist/templates/model_test.template.d.ts.map +1 -1
  111. package/dist/templates/model_test.template.js +4 -4
  112. package/dist/templates/model_test.template.js.map +1 -1
  113. package/dist/templates/service.template.d.ts +3 -3
  114. package/dist/templates/service.template.d.ts.map +1 -1
  115. package/dist/templates/service.template.js +3 -3
  116. package/dist/templates/service.template.js.map +1 -1
  117. package/dist/templates/smd.template.d.ts +2 -2
  118. package/dist/templates/smd.template.d.ts.map +1 -1
  119. package/dist/templates/smd.template.js +2 -2
  120. package/dist/templates/smd.template.js.map +1 -1
  121. package/dist/templates/view_enums_buttonset.template.d.ts +3 -3
  122. package/dist/templates/view_enums_buttonset.template.d.ts.map +1 -1
  123. package/dist/templates/view_enums_buttonset.template.js +4 -4
  124. package/dist/templates/view_enums_buttonset.template.js.map +1 -1
  125. package/dist/templates/view_enums_dropdown.template.d.ts +3 -3
  126. package/dist/templates/view_enums_dropdown.template.d.ts.map +1 -1
  127. package/dist/templates/view_enums_dropdown.template.js +3 -3
  128. package/dist/templates/view_enums_dropdown.template.js.map +1 -1
  129. package/dist/templates/view_enums_select.template.d.ts +3 -3
  130. package/dist/templates/view_enums_select.template.d.ts.map +1 -1
  131. package/dist/templates/view_enums_select.template.js +3 -3
  132. package/dist/templates/view_enums_select.template.js.map +1 -1
  133. package/dist/templates/view_form.template.d.ts +25 -29
  134. package/dist/templates/view_form.template.d.ts.map +1 -1
  135. package/dist/templates/view_form.template.js +19 -19
  136. package/dist/templates/view_form.template.js.map +1 -1
  137. package/dist/templates/view_id_all_select.template.d.ts +3 -3
  138. package/dist/templates/view_id_all_select.template.d.ts.map +1 -1
  139. package/dist/templates/view_id_all_select.template.js +4 -4
  140. package/dist/templates/view_id_all_select.template.js.map +1 -1
  141. package/dist/templates/view_id_async_select.template.d.ts +3 -3
  142. package/dist/templates/view_id_async_select.template.d.ts.map +1 -1
  143. package/dist/templates/view_id_async_select.template.js +6 -6
  144. package/dist/templates/view_id_async_select.template.js.map +1 -1
  145. package/dist/templates/view_list.template.d.ts +30 -34
  146. package/dist/templates/view_list.template.d.ts.map +1 -1
  147. package/dist/templates/view_list.template.js +40 -40
  148. package/dist/templates/view_list.template.js.map +1 -1
  149. package/dist/templates/view_list_columns.template.d.ts +3 -3
  150. package/dist/templates/view_list_columns.template.d.ts.map +1 -1
  151. package/dist/templates/view_list_columns.template.js +3 -3
  152. package/dist/templates/view_list_columns.template.js.map +1 -1
  153. package/dist/templates/view_search_input.template.d.ts +3 -3
  154. package/dist/templates/view_search_input.template.d.ts.map +1 -1
  155. package/dist/templates/view_search_input.template.js +3 -3
  156. package/dist/templates/view_search_input.template.js.map +1 -1
  157. package/dist/testing/fixture-manager.d.ts +2 -3
  158. package/dist/testing/fixture-manager.d.ts.map +1 -1
  159. package/dist/testing/fixture-manager.js +21 -42
  160. package/dist/testing/fixture-manager.js.map +1 -1
  161. package/dist/types/smd.types.d.ts +741 -0
  162. package/dist/types/smd.types.d.ts.map +1 -0
  163. package/dist/types/smd.types.js +292 -0
  164. package/dist/types/smd.types.js.map +1 -0
  165. package/dist/types/types.d.ts +185 -190
  166. package/dist/types/types.d.ts.map +1 -1
  167. package/dist/types/types.js +22 -30
  168. package/dist/types/types.js.map +1 -1
  169. package/dist/ui/index.d.ts +4 -0
  170. package/dist/ui/index.d.ts.map +1 -0
  171. package/dist/ui/index.js +14 -0
  172. package/dist/ui/index.js.map +1 -0
  173. package/dist/ui/main.d.ts +4 -0
  174. package/dist/ui/main.d.ts.map +1 -0
  175. package/dist/ui/main.js +15 -0
  176. package/dist/ui/main.js.map +1 -0
  177. package/dist/utils/model.d.ts +2 -2
  178. package/dist/utils/model.d.ts.map +1 -1
  179. package/dist/utils/utils.d.ts +1 -0
  180. package/dist/utils/utils.d.ts.map +1 -1
  181. package/dist/utils/utils.js +6 -2
  182. package/dist/utils/utils.js.map +1 -1
  183. package/package.json +11 -8
  184. package/src/api/code-converters.ts +9 -17
  185. package/src/api/sonamu.ts +10 -6
  186. package/src/bin/cli.ts +247 -26
  187. package/src/database/upsert-builder.ts +2 -2
  188. package/src/entity/entity-manager.ts +150 -0
  189. package/src/{smd/smd-utils.ts → entity/entity-utils.ts} +4 -7
  190. package/src/entity/entity.ts +666 -0
  191. package/src/{smd → entity}/migrator.ts +426 -106
  192. package/src/index.ts +3 -3
  193. package/src/smd/smd-manager.ts +3 -13
  194. package/src/smd/smd.ts +13 -10
  195. package/src/syncer/syncer.ts +125 -73
  196. package/src/templates/base-template.ts +2 -2
  197. package/src/templates/entity.template.ts +50 -0
  198. package/src/templates/generated.template.ts +93 -57
  199. package/src/templates/generated_http.template.ts +4 -4
  200. package/src/templates/init_types.template.ts +11 -11
  201. package/src/templates/model.template.ts +29 -29
  202. package/src/templates/model_test.template.ts +5 -5
  203. package/src/templates/service.template.ts +4 -4
  204. package/src/templates/view_enums_buttonset.template.ts +5 -5
  205. package/src/templates/view_enums_dropdown.template.ts +4 -4
  206. package/src/templates/view_enums_select.template.ts +8 -4
  207. package/src/templates/view_form.template.ts +21 -21
  208. package/src/templates/view_id_all_select.template.ts +5 -5
  209. package/src/templates/view_id_async_select.template.ts +9 -7
  210. package/src/templates/view_list.template.ts +54 -44
  211. package/src/templates/view_list_columns.template.ts +4 -4
  212. package/src/templates/view_search_input.template.ts +4 -4
  213. package/src/testing/fixture-manager.ts +19 -60
  214. package/src/types/types.ts +59 -41
  215. package/src/utils/utils.ts +4 -0
  216. package/tsconfig.json +4 -1
  217. package/src/templates/init_enums.template.ts +0 -71
  218. package/src/templates/init_generated.template.ts +0 -51
  219. package/src/templates/smd.template.ts +0 -53
package/src/bin/cli.ts CHANGED
@@ -7,13 +7,24 @@ dotenv.config();
7
7
 
8
8
  import path from "path";
9
9
  import { BaseModel } from "../database/base-model";
10
- import { SMDManager } from "../smd/smd-manager";
11
- import { Migrator } from "../smd/migrator";
10
+ import { EntityManager } from "../entity/entity-manager";
11
+ import { Migrator } from "../entity/migrator";
12
12
  import { FixtureManager } from "../testing/fixture-manager";
13
13
  import { tsicli } from "tsicli";
14
14
  import { execSync } from "child_process";
15
- import { existsSync, mkdirSync, readdirSync, writeFileSync } from "fs";
15
+ import {
16
+ existsSync,
17
+ mkdirSync,
18
+ readdirSync,
19
+ unlinkSync,
20
+ writeFileSync,
21
+ } from "fs";
16
22
  import { Sonamu } from "../api";
23
+ import knex, { Knex } from "knex";
24
+ import { camelize } from "inflection";
25
+ import prettier from "prettier";
26
+ import { SMDManager } from "../smd/smd-manager";
27
+ import process from "process";
17
28
 
18
29
  let migrator: Migrator;
19
30
 
@@ -22,20 +33,21 @@ async function bootstrap() {
22
33
 
23
34
  await tsicli(process.argv, {
24
35
  types: {
25
- "#smdId": {
36
+ "#entityId": {
26
37
  type: "autocomplete",
27
- name: "#smdId",
28
- message: "Please input #smdId",
29
- choices: SMDManager.getAllParentIds().map((smdId) => ({
30
- title: smdId,
31
- value: smdId,
38
+ name: "#entityId",
39
+ message: "Please input #entityId",
40
+ choices: EntityManager.getAllParentIds().map((entityId) => ({
41
+ title: entityId,
42
+ value: entityId,
32
43
  })),
33
44
  },
34
45
  "#recordIds": "number[]",
35
46
  "#name": "string",
36
47
  },
37
48
  args: [
38
- ["fixture", "import", "#smdId", "#recordIds"],
49
+ ["fixture", "init"],
50
+ ["fixture", "import", "#entityId", "#recordIds"],
39
51
  ["fixture", "sync"],
40
52
  ["migrate", "run"],
41
53
  ["migrate", "check"],
@@ -43,11 +55,13 @@ async function bootstrap() {
43
55
  ["migrate", "reset"],
44
56
  ["migrate", "clear"],
45
57
  ["stub", "practice", "#name"],
46
- ["stub", "smd", "#name"],
47
- ["scaffold", "model", "#smdId"],
48
- ["scaffold", "model_test", "#smdId"],
49
- ["scaffold", "view_list", "#smdId"],
50
- ["scaffold", "view_form", "#smdId"],
58
+ ["stub", "entity", "#name"],
59
+ ["scaffold", "model", "#entityId"],
60
+ ["scaffold", "model_test", "#entityId"],
61
+ ["scaffold", "view_list", "#entityId"],
62
+ ["scaffold", "view_form", "#entityId"],
63
+ ["ui"],
64
+ ["smd_migration"],
51
65
  ],
52
66
  runners: {
53
67
  migrate_run,
@@ -55,14 +69,17 @@ async function bootstrap() {
55
69
  migrate_rollback,
56
70
  migrate_clear,
57
71
  migrate_reset,
72
+ fixture_init,
58
73
  fixture_import,
59
74
  fixture_sync,
60
75
  stub_practice,
61
- stub_smd,
76
+ stub_entity,
62
77
  scaffold_model,
63
78
  scaffold_model_test,
79
+ ui,
64
80
  // scaffold_view_list,
65
81
  // scaffold_view_form,
82
+ smd_migration,
66
83
  },
67
84
  });
68
85
  }
@@ -120,10 +137,84 @@ async function migrate_reset() {
120
137
  await migrator.resetAll();
121
138
  }
122
139
 
123
- async function fixture_import(smdId: string, recordIds: number[]) {
140
+ async function fixture_init() {
141
+ const srcConfig = Sonamu.dbConfig.development_master;
142
+ const targets = [
143
+ {
144
+ label: "(REMOTE) Fixture DB",
145
+ config: Sonamu.dbConfig.fixture_remote,
146
+ },
147
+ {
148
+ label: "(LOCAL) Fixture DB",
149
+ config: Sonamu.dbConfig.fixture_local,
150
+ toSkip: (() => {
151
+ const remoteConn = Sonamu.dbConfig.fixture_remote
152
+ .connection as Knex.ConnectionConfig;
153
+ const localConn = Sonamu.dbConfig.fixture_local
154
+ .connection as Knex.ConnectionConfig;
155
+ return (
156
+ remoteConn.host === localConn.host &&
157
+ remoteConn.database === localConn.database
158
+ );
159
+ })(),
160
+ },
161
+ {
162
+ label: "(LOCAL) Testing DB",
163
+ config: Sonamu.dbConfig.test,
164
+ },
165
+ ] as {
166
+ label: string;
167
+ config: Knex.Config;
168
+ toSkip?: boolean;
169
+ }[];
170
+
171
+ // 1. 기준DB 스키마를 덤프
172
+ console.log("DUMP...");
173
+ const dumpFilename = `/tmp/sonamu-fixture-init-${Date.now()}.sql`;
174
+ const srcConn = srcConfig.connection as Knex.ConnectionConfig;
175
+ execSync(
176
+ `mysqldump -h${srcConn.host} -u${srcConn.user} -p${srcConn.password} --single-transaction -d --no-create-db --triggers ${srcConn.database} > ${dumpFilename}`
177
+ );
178
+
179
+ // 2. 대상DB 각각에 대하여 존재여부 확인 후 붓기
180
+ for await (const { label, config, toSkip } of targets) {
181
+ const conn = config.connection as Knex.ConnectionConfig;
182
+
183
+ if (toSkip === true) {
184
+ console.log(chalk.red(`${label}: Skipped!`));
185
+ continue;
186
+ }
187
+
188
+ const db = knex({
189
+ ...config,
190
+ connection: {
191
+ ...((config.connection ?? {}) as Knex.ConnectionConfig),
192
+ database: undefined,
193
+ },
194
+ });
195
+ const [[row]] = await db.raw(`SHOW DATABASES LIKE "${conn.database}"`);
196
+ if (row) {
197
+ console.log(
198
+ chalk.yellow(`${label}: Database "${conn.database} Already exists`)
199
+ );
200
+ await db.destroy();
201
+ continue;
202
+ }
203
+
204
+ console.log(`SYNC to ${label}...`);
205
+ const mysqlCmd = `mysql -h${conn.host} -u${conn.user} -p${conn.password}`;
206
+ execSync(`${mysqlCmd} -e 'DROP DATABASE IF EXISTS ${conn.database}'`);
207
+ execSync(`${mysqlCmd} -e 'CREATE DATABASE ${conn.database}'`);
208
+ execSync(`${mysqlCmd} ${conn.database} < ${dumpFilename}`);
209
+
210
+ await db.destroy();
211
+ }
212
+ }
213
+
214
+ async function fixture_import(entityId: string, recordIds: number[]) {
124
215
  await setupFixtureManager();
125
216
 
126
- await FixtureManager.importFixture(smdId, recordIds);
217
+ await FixtureManager.importFixture(entityId, recordIds);
127
218
  await FixtureManager.sync();
128
219
  }
129
220
 
@@ -188,20 +279,150 @@ async function stub_practice(name: string) {
188
279
  execSync(`echo "${runCode}" | pbcopy`);
189
280
  }
190
281
 
191
- async function stub_smd(name: string) {
192
- await Sonamu.syncer.generateTemplate("smd", {
193
- smdId: name,
194
- });
282
+ async function stub_entity(entityId: string) {
283
+ await Sonamu.syncer.createEntity(entityId);
195
284
  }
196
285
 
197
- async function scaffold_model(smdId: string) {
286
+ async function scaffold_model(entityId: string) {
198
287
  await Sonamu.syncer.generateTemplate("model", {
199
- smdId,
288
+ entityId,
200
289
  });
201
290
  }
202
291
 
203
- async function scaffold_model_test(smdId: string) {
292
+ async function scaffold_model_test(entityId: string) {
204
293
  await Sonamu.syncer.generateTemplate("model_test", {
205
- smdId,
294
+ entityId,
206
295
  });
207
296
  }
297
+
298
+ async function ui() {
299
+ try {
300
+ const sonamuUI: {
301
+ startServers: (appRootPath: string) => void;
302
+ } = await import("@sonamu-kit/ui" as string);
303
+ sonamuUI.startServers(Sonamu.appRootPath);
304
+ } catch (e: unknown) {
305
+ if (e instanceof Error && e.message.includes("isn't declared")) {
306
+ console.log(`You need to install ${chalk.blue(`@sonamu-kit/ui`)} first.`);
307
+ return;
308
+ }
309
+ throw e;
310
+ }
311
+ }
312
+
313
+ async function smd_migration() {
314
+ await SMDManager.autoload();
315
+ const smdIds = SMDManager.getAllIds();
316
+
317
+ function enumLabelsToEntityEnums(
318
+ entityId: string,
319
+ enumLabels: {
320
+ [enumName: string]: { [name: string]: { ko: string } };
321
+ }
322
+ ): { [enumName: string]: { [name: string]: string } } {
323
+ return Object.fromEntries(
324
+ Object.entries(enumLabels).map(([enumLabelName, enumLabel]) => {
325
+ const enumName =
326
+ entityId + camelize(enumLabelName.toLowerCase(), false);
327
+ return [
328
+ enumName,
329
+ Object.fromEntries(
330
+ Object.entries(enumLabel).map(([name, { ko }]) => [name, ko])
331
+ ),
332
+ ];
333
+ })
334
+ );
335
+ }
336
+ for await (const smdId of smdIds) {
337
+ const smd = SMDManager.get(smdId);
338
+ const entityJson = {
339
+ id: smd.id,
340
+ ...(smd.parentId ? { parentId: smd.parentId } : {}),
341
+ title: smd.title,
342
+ props: smd.props,
343
+ indexes: smd.indexes,
344
+ subsets: smd.subsets,
345
+ enums: enumLabelsToEntityEnums(smd.id, smd.enumLabels),
346
+ };
347
+
348
+ const parentNames = SMDManager.getNamesFromId(smd.parentId ?? smd.id);
349
+ const names = SMDManager.getNamesFromId(smd.id);
350
+ const dstPath = path.join(
351
+ Sonamu.apiRootPath,
352
+ "src",
353
+ "application",
354
+ parentNames.fs,
355
+ `${names.fs}.entity.json`
356
+ );
357
+
358
+ const formatted = prettier.format(JSON.stringify(entityJson), {
359
+ parser: "json",
360
+ });
361
+ writeFileSync(dstPath, formatted);
362
+ console.log(chalk.blue(`CREATED: ${dstPath}`));
363
+
364
+ // smd.ts, enums.ts, genereated.ts 삭제 (트랜스파일 된 js파일도 삭제)
365
+ const srcSmdPath = path.join(
366
+ Sonamu.apiRootPath,
367
+ "src",
368
+ "application",
369
+ parentNames.fs,
370
+ `${names.fs}.smd.ts`
371
+ );
372
+ const dstSmdPath = srcSmdPath
373
+ .replace("/src/", "/dist/")
374
+ .replace(/\.ts$/, ".js");
375
+ const srcEnumsPath = path.join(
376
+ Sonamu.apiRootPath,
377
+ "src",
378
+ "application",
379
+ parentNames.fs,
380
+ `${names.fs}.enums.ts`
381
+ );
382
+ const dstEnumsPath = srcEnumsPath
383
+ .replace("/src/", "/dist/")
384
+ .replace(/\.ts$/, ".js");
385
+ const srcGeneratedPath = path.join(
386
+ Sonamu.apiRootPath,
387
+ "src",
388
+ "application",
389
+ parentNames.fs,
390
+ `${names.fs}.generated.ts`
391
+ );
392
+ const dstGeneratedPath = srcGeneratedPath
393
+ .replace("/src/", "/dist/")
394
+ .replace(/\.ts$/, ".js");
395
+
396
+ [
397
+ srcSmdPath,
398
+ dstSmdPath,
399
+ srcEnumsPath,
400
+ dstEnumsPath,
401
+ ...Sonamu.config.sync.targets.map((target) =>
402
+ srcEnumsPath
403
+ .replace(Sonamu.apiRootPath, path.join(Sonamu.appRootPath, target))
404
+ .replace("/src/application/", "/src/services/")
405
+ ),
406
+ srcGeneratedPath,
407
+ dstGeneratedPath,
408
+ ].map((p) => {
409
+ if (existsSync(p) === false) {
410
+ console.log(chalk.yellow(`NOT FOUND: ${p}`));
411
+ return;
412
+ }
413
+ unlinkSync(p);
414
+ console.log(chalk.red(`DELETED: ${p}`));
415
+ });
416
+ }
417
+
418
+ // Entity로 reload
419
+ console.log("Entity로 다시 로드합니다.");
420
+ EntityManager.isAutoloaded = false;
421
+ await EntityManager.autoload();
422
+
423
+ // Entity를 통해 generated.ts 재생성
424
+ const entityIds = EntityManager.getAllParentIds();
425
+ for await (const entityId of entityIds) {
426
+ await Sonamu.syncer.generateTemplate("generated", { entityId });
427
+ }
428
+ }
@@ -1,7 +1,7 @@
1
1
  import { v4 as uuidv4 } from "uuid";
2
2
  import _, { chunk, defaults, groupBy } from "lodash";
3
3
  import { Knex } from "knex";
4
- import { SMDManager } from "../smd/smd-manager";
4
+ import { EntityManager } from "../entity/entity-manager";
5
5
 
6
6
  type TableData = {
7
7
  references: Set<string>;
@@ -34,7 +34,7 @@ export class UpsertBuilder {
34
34
  if (table === undefined) {
35
35
  const tableSpec = (() => {
36
36
  try {
37
- return SMDManager.getTableSpec(tableName);
37
+ return EntityManager.getTableSpec(tableName);
38
38
  } catch {
39
39
  return null;
40
40
  }
@@ -0,0 +1,150 @@
1
+ import chalk from "chalk";
2
+ import { glob } from "glob";
3
+ import { dasherize, underscore, pluralize, camelize } from "inflection";
4
+ import _ from "lodash";
5
+ import path from "path";
6
+ import { Entity } from "./entity";
7
+ import { EntityJson } from "../types/types";
8
+ import { Sonamu } from "../api/sonamu";
9
+ import { readFileSync } from "fs";
10
+
11
+ export type EntityNamesRecord = Record<
12
+ | "fs"
13
+ | "fsPlural"
14
+ | "camel"
15
+ | "camelPlural"
16
+ | "capital"
17
+ | "capitalPlural"
18
+ | "upper"
19
+ | "constant",
20
+ string
21
+ >;
22
+ type TableSpec = {
23
+ name: string;
24
+ uniqueColumns: string[];
25
+ };
26
+ class EntityManagerClass {
27
+ private entities: Map<string, Entity> = new Map();
28
+ public modulePaths: Map<string, string> = new Map();
29
+ private tableSpecs: Map<string, TableSpec> = new Map();
30
+ public isAutoloaded: boolean = false;
31
+
32
+ // 경로 전달받아 모든 entity.json 파일 로드
33
+ async autoload(doSilent: boolean = false) {
34
+ if (this.isAutoloaded) {
35
+ return;
36
+ }
37
+ const pathPattern = path.join(
38
+ Sonamu.apiRootPath,
39
+ "/src/application/**/*.entity.json"
40
+ );
41
+ !doSilent && console.log(chalk.yellow(`autoload ${pathPattern}`));
42
+
43
+ return new Promise((resolve) => {
44
+ glob(path.resolve(pathPattern!), (_err, files) => {
45
+ Promise.all(
46
+ files.map(async (file) => {
47
+ this.register(JSON.parse(readFileSync(file).toString()));
48
+ })
49
+ ).then(() => {
50
+ resolve("ok");
51
+ this.isAutoloaded = true;
52
+ });
53
+ });
54
+ });
55
+ }
56
+
57
+ async reload(doSilent: boolean = false) {
58
+ this.entities.clear();
59
+ this.modulePaths.clear();
60
+ this.tableSpecs.clear();
61
+ this.isAutoloaded = false;
62
+
63
+ return this.autoload(doSilent);
64
+ }
65
+
66
+ register(json: EntityJson): void {
67
+ const entity = new Entity(json);
68
+ this.entities.set(json.id, entity);
69
+ }
70
+
71
+ get(entityId: string): Entity {
72
+ const entity = this.entities.get(entityId);
73
+ if (entity === undefined) {
74
+ throw new Error(`존재하지 않는 Entity 요청 ${entityId}`);
75
+ }
76
+
77
+ return entity;
78
+ }
79
+
80
+ exists(entityId: string): boolean {
81
+ const entity = this.entities.get(entityId);
82
+ return entity !== undefined;
83
+ }
84
+
85
+ getAllIds(): string[] {
86
+ return Array.from(EntityManager.entities.keys());
87
+ }
88
+
89
+ getAllParentIds(): string[] {
90
+ return this.getAllIds().filter((entityId) => {
91
+ const entity = this.get(entityId);
92
+ return entity.parentId === undefined;
93
+ });
94
+ }
95
+
96
+ getChildrenIds(parentId: string): string[] {
97
+ return this.getAllIds().filter((entityId) => {
98
+ const entity = this.get(entityId);
99
+ return entity.parentId === parentId;
100
+ });
101
+ }
102
+
103
+ setModulePath(key: string, modulePath: string): void {
104
+ // console.debug(chalk.cyan(`setModulePath :: ${key} :: ${modulePath}`));
105
+ this.modulePaths.set(key, modulePath);
106
+ }
107
+
108
+ getModulePath(key: string): string {
109
+ const modulePath = this.modulePaths.get(key);
110
+ if (modulePath === undefined) {
111
+ throw new Error(`존재하지 않는 모듈 패스 요청 ${key}`);
112
+ }
113
+
114
+ return modulePath;
115
+ }
116
+
117
+ setTableSpec(tableSpec: TableSpec) {
118
+ this.tableSpecs.set(tableSpec.name, tableSpec);
119
+ }
120
+
121
+ getTableSpec(key: string): TableSpec {
122
+ const tableSpec = this.tableSpecs.get(key);
123
+ if (tableSpec === undefined) {
124
+ throw new Error(`존재하지 않는 테이블 스펙 요청 ${key}`);
125
+ }
126
+
127
+ return tableSpec;
128
+ }
129
+
130
+ getNamesFromId(entityId: string): EntityNamesRecord {
131
+ // entityId가 단복수 동형 단어인 경우 List 붙여서 생성
132
+ const pluralized =
133
+ pluralize(entityId) === entityId
134
+ ? `${entityId}List`
135
+ : pluralize(entityId);
136
+
137
+ return {
138
+ fs: dasherize(underscore(entityId)).toLowerCase(),
139
+ fsPlural: dasherize(underscore(pluralized)).toLowerCase(),
140
+ camel: camelize(entityId, true),
141
+ camelPlural: camelize(pluralized, true),
142
+ capital: entityId,
143
+ capitalPlural: pluralized,
144
+ upper: entityId.toUpperCase(),
145
+ constant: underscore(entityId).toUpperCase(),
146
+ };
147
+ }
148
+ }
149
+
150
+ export const EntityManager = new EntityManagerClass();
@@ -15,7 +15,7 @@ import {
15
15
  JsonProp,
16
16
  ManyToManyRelationProp,
17
17
  OneToOneRelationProp,
18
- SMDIndex,
18
+ EntityIndex,
19
19
  StringProp,
20
20
  TextProp,
21
21
  TimeProp,
@@ -212,10 +212,7 @@ function enums(
212
212
  }
213
213
  function virtual(
214
214
  name: string,
215
- option: Omit<
216
- VirtualProp,
217
- "name" | "type" | "index" | "unique" | "dbDefault" | "toFilter"
218
- >
215
+ option: Omit<VirtualProp, "name" | "type" | "dbDefault" | "toFilter">
219
216
  ): VirtualProp {
220
217
  return {
221
218
  name,
@@ -276,14 +273,14 @@ export const i = {
276
273
  unique,
277
274
  };
278
275
 
279
- function index(columns: string | string[]): SMDIndex {
276
+ function index(columns: string | string[]): EntityIndex {
280
277
  return {
281
278
  type: "index",
282
279
  columns: asArray(columns),
283
280
  };
284
281
  }
285
282
 
286
- function unique(columns: string | string[]): SMDIndex {
283
+ function unique(columns: string | string[]): EntityIndex {
287
284
  return {
288
285
  type: "unique",
289
286
  columns: asArray(columns),