sonamu 0.0.8 → 0.0.9

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 (67) hide show
  1. package/dist/api/index.d.ts +1 -1
  2. package/dist/api/index.d.ts.map +1 -1
  3. package/dist/api/index.js +1 -1
  4. package/dist/api/index.js.map +1 -1
  5. package/dist/api/init.d.ts +35 -5
  6. package/dist/api/init.d.ts.map +1 -1
  7. package/dist/api/init.js +142 -79
  8. package/dist/api/init.js.map +1 -1
  9. package/dist/api/sonamu.d.ts +42 -0
  10. package/dist/api/sonamu.d.ts.map +1 -0
  11. package/dist/api/sonamu.js +175 -0
  12. package/dist/api/sonamu.js.map +1 -0
  13. package/dist/bin/cli.js +6 -19
  14. package/dist/bin/cli.js.map +1 -1
  15. package/dist/database/db.d.ts +1 -3
  16. package/dist/database/db.d.ts.map +1 -1
  17. package/dist/database/db.js +12 -23
  18. package/dist/database/db.js.map +1 -1
  19. package/dist/index.d.ts +1 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +1 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/smd/migrator.d.ts +0 -5
  24. package/dist/smd/migrator.d.ts.map +1 -1
  25. package/dist/smd/migrator.js +18 -19
  26. package/dist/smd/migrator.js.map +1 -1
  27. package/dist/smd/smd-manager.d.ts.map +1 -1
  28. package/dist/smd/smd-manager.js +2 -3
  29. package/dist/smd/smd-manager.js.map +1 -1
  30. package/dist/smd/smd.d.ts.map +1 -1
  31. package/dist/smd/smd.js +3 -4
  32. package/dist/smd/smd.js.map +1 -1
  33. package/dist/syncer/syncer.d.ts +8 -12
  34. package/dist/syncer/syncer.d.ts.map +1 -1
  35. package/dist/syncer/syncer.js +43 -43
  36. package/dist/syncer/syncer.js.map +1 -1
  37. package/dist/templates/generated_http.template.js +2 -2
  38. package/dist/templates/generated_http.template.js.map +1 -1
  39. package/dist/templates/service.template.d.ts +1 -1
  40. package/dist/templates/service.template.d.ts.map +1 -1
  41. package/dist/templates/service.template.js +3 -2
  42. package/dist/templates/service.template.js.map +1 -1
  43. package/dist/templates/view_form.template.d.ts +2 -2
  44. package/dist/templates/view_list.template.d.ts +2 -2
  45. package/dist/testing/fixture-manager.d.ts +6 -7
  46. package/dist/testing/fixture-manager.d.ts.map +1 -1
  47. package/dist/testing/fixture-manager.js +35 -42
  48. package/dist/testing/fixture-manager.js.map +1 -1
  49. package/dist/utils/utils.d.ts +1 -0
  50. package/dist/utils/utils.d.ts.map +1 -1
  51. package/dist/utils/utils.js +10 -3
  52. package/dist/utils/utils.js.map +1 -1
  53. package/package.json +1 -1
  54. package/src/api/index.ts +1 -1
  55. package/src/api/sonamu.ts +212 -0
  56. package/src/bin/cli.ts +6 -23
  57. package/src/database/db.ts +15 -27
  58. package/src/index.ts +1 -1
  59. package/src/smd/migrator.ts +18 -31
  60. package/src/smd/smd-manager.ts +3 -4
  61. package/src/smd/smd.ts +7 -8
  62. package/src/syncer/syncer.ts +49 -68
  63. package/src/templates/generated_http.template.ts +2 -2
  64. package/src/templates/service.template.ts +6 -5
  65. package/src/testing/fixture-manager.ts +44 -54
  66. package/src/utils/utils.ts +6 -1
  67. package/src/api/init.ts +0 -129
@@ -10,6 +10,7 @@ import {
10
10
  } from "../api/code-converters";
11
11
  import { ExtendedApi } from "../api/decorators";
12
12
  import { Template } from "./base-template";
13
+ import { Sonamu } from "../api/sonamu";
13
14
 
14
15
  export class Template__service extends Template {
15
16
  constructor() {
@@ -44,10 +45,10 @@ export class Template__service extends Template {
44
45
  };
45
46
  }
46
47
 
47
- getTypeSource(
48
- apis: ExtendedApi[],
49
- apiPrefix: string = "/api"
50
- ): { lines: string[]; importKeys: string[] } {
48
+ getTypeSource(apis: ExtendedApi[]): {
49
+ lines: string[];
50
+ importKeys: string[];
51
+ } {
51
52
  const importKeys: string[] = [];
52
53
 
53
54
  // 제네릭에서 선언한 타입, importKeys에서 제외 필요
@@ -95,7 +96,7 @@ export class Template__service extends Template {
95
96
  client === "swr" ? 0 : 1
96
97
  )
97
98
  .map((client) => {
98
- const apiBaseUrl = `${apiPrefix}${api.path}`;
99
+ const apiBaseUrl = `${Sonamu.config.route.prefix}${api.path}`;
99
100
  switch (client) {
100
101
  case "axios":
101
102
  return this.renderAxios(
@@ -2,8 +2,8 @@ import chalk from "chalk";
2
2
  import { execSync } from "child_process";
3
3
  import knex, { Knex } from "knex";
4
4
  import { uniq } from "lodash";
5
+ import { Sonamu } from "../api";
5
6
  import { BaseModel } from "../database/base-model";
6
- import { DB, SonamuDBConfig } from "../database/db";
7
7
  import { SMDManager } from "../smd/smd-manager";
8
8
  import {
9
9
  isBelongsToOneRelationProp,
@@ -11,17 +11,29 @@ import {
11
11
  } from "../types/types";
12
12
 
13
13
  export class FixtureManager {
14
- private config?: {
15
- tdb: Knex;
16
- fdb: Knex;
17
- knexfile: SonamuDBConfig;
18
- };
14
+ private _tdb: Knex | null = null;
15
+ set tdb(tdb: Knex) {
16
+ this._tdb = tdb;
17
+ }
18
+ get tdb(): Knex {
19
+ return this._tdb!;
20
+ }
21
+
22
+ private _fdb: Knex | null = null;
23
+ set fdb(fdb: Knex) {
24
+ this._fdb = fdb;
25
+ }
26
+ get fdb(): Knex {
27
+ return this._fdb!;
28
+ }
19
29
 
20
30
  constructor(public usingTables?: string[]) {
31
+ this.tdb = knex(Sonamu.dbConfig.test);
32
+ this.fdb = knex(Sonamu.dbConfig.fixture_local);
33
+
21
34
  if (process.env.NODE_ENV === "test") {
22
35
  beforeAll(async () => {
23
- await this.init();
24
- await SMDManager.autoload(true);
36
+ await Sonamu.init();
25
37
  });
26
38
 
27
39
  beforeEach(async () => {
@@ -35,32 +47,11 @@ export class FixtureManager {
35
47
  }
36
48
  }
37
49
 
38
- async init(): Promise<{
39
- tdb: Knex;
40
- fdb: Knex;
41
- knexfile: SonamuDBConfig;
42
- }> {
43
- if (this.config) {
44
- return this.config;
45
- }
46
-
47
- const knexfile = await DB.readKnexfile();
48
- this.config = {
49
- knexfile,
50
- tdb: knex(knexfile.test),
51
- fdb: knex(knexfile.fixture_local),
52
- };
53
- return this.config;
54
- }
55
-
56
50
  async cleanAndSeed() {
57
- const { tdb, fdb, knexfile } = await this.init();
58
- // console.time("FIXTURE-CleanAndSeed");
59
-
60
51
  let tableNames: string[] = [];
61
52
 
62
53
  if (this.usingTables === undefined) {
63
- const [tables] = await tdb.raw(
54
+ const [tables] = await this.tdb.raw(
64
55
  "SHOW TABLE STATUS WHERE Engine IS NOT NULL"
65
56
  );
66
57
  tableNames = tables.map((tableInfo: any) => tableInfo["Name"]);
@@ -68,31 +59,37 @@ export class FixtureManager {
68
59
  tableNames = this.usingTables;
69
60
  }
70
61
 
71
- await tdb.raw(`SET FOREIGN_KEY_CHECKS = 0`);
62
+ await this.tdb.raw(`SET FOREIGN_KEY_CHECKS = 0`);
72
63
  for await (let tableName of tableNames) {
73
64
  if (tableName == "migrations") {
74
65
  continue;
75
66
  }
76
67
 
77
- const [[fdbChecksumRow]] = await fdb.raw(`CHECKSUM TABLE ${tableName}`);
68
+ const [[fdbChecksumRow]] = await this.fdb.raw(
69
+ `CHECKSUM TABLE ${tableName}`
70
+ );
78
71
  const fdbChecksum = fdbChecksumRow["Checksum"];
79
72
 
80
- const [[tdbChecksumRow]] = await tdb.raw(`CHECKSUM TABLE ${tableName}`);
73
+ const [[tdbChecksumRow]] = await this.tdb.raw(
74
+ `CHECKSUM TABLE ${tableName}`
75
+ );
81
76
  const tdbChecksum = tdbChecksumRow["Checksum"];
82
77
 
83
78
  if (fdbChecksum !== tdbChecksum) {
84
- await tdb(tableName).truncate();
79
+ await this.tdb(tableName).truncate();
85
80
  const rawQuery = `INSERT INTO ${
86
- (knexfile.test.connection as Knex.ConnectionConfig).database
81
+ (Sonamu.dbConfig.test.connection as Knex.ConnectionConfig).database
87
82
  }.${tableName}
88
83
  SELECT * FROM ${
89
- (knexfile.fixture_local.connection as Knex.ConnectionConfig)
90
- .database
84
+ (
85
+ Sonamu.dbConfig.fixture_local
86
+ .connection as Knex.ConnectionConfig
87
+ ).database
91
88
  }.${tableName}`;
92
- await tdb.raw(rawQuery);
89
+ await this.tdb.raw(rawQuery);
93
90
  }
94
91
  }
95
- await tdb.raw(`SET FOREIGN_KEY_CHECKS = 1`);
92
+ await this.tdb.raw(`SET FOREIGN_KEY_CHECKS = 1`);
96
93
 
97
94
  // console.timeEnd("FIXTURE-CleanAndSeed");
98
95
  }
@@ -147,10 +144,9 @@ export class FixtureManager {
147
144
  }
148
145
 
149
146
  async sync() {
150
- const { fdb, knexfile } = await this.init();
151
- const frdb = knex(knexfile.fixture_remote);
147
+ const frdb = knex(Sonamu.dbConfig.fixture_remote);
152
148
 
153
- const [tables] = await fdb.raw(
149
+ const [tables] = await this.fdb.raw(
154
150
  "SHOW TABLE STATUS WHERE Engine IS NOT NULL"
155
151
  );
156
152
  const tableNames: string[] = tables.map(
@@ -165,10 +161,10 @@ export class FixtureManager {
165
161
  }
166
162
 
167
163
  const remoteChecksum = await this.getChecksum(frdb, tableName);
168
- const localChecksum = await this.getChecksum(fdb, tableName);
164
+ const localChecksum = await this.getChecksum(this.fdb, tableName);
169
165
 
170
166
  if (remoteChecksum !== localChecksum) {
171
- await fdb.transaction(async (transaction) => {
167
+ await this.fdb.transaction(async (transaction) => {
172
168
  await transaction.raw(`SET FOREIGN_KEY_CHECKS = 0`);
173
169
  await transaction(tableName).truncate();
174
170
 
@@ -223,8 +219,6 @@ export class FixtureManager {
223
219
  field: string,
224
220
  id: number
225
221
  ): Promise<string[]> {
226
- const { knexfile } = await this.init();
227
-
228
222
  console.log({ smdId, field, id });
229
223
  const smd = SMDManager.get(smdId);
230
224
  const wdb = BaseModel.getDB("w");
@@ -236,9 +230,9 @@ export class FixtureManager {
236
230
  }
237
231
 
238
232
  // 픽스쳐DB, 실DB
239
- const fixtureDatabase = (knexfile.fixture_remote.connection as any)
233
+ const fixtureDatabase = (Sonamu.dbConfig.fixture_remote.connection as any)
240
234
  .database;
241
- const realDatabase = (knexfile.production_master.connection as any)
235
+ const realDatabase = (Sonamu.dbConfig.production_master.connection as any)
242
236
  .database;
243
237
 
244
238
  const selfQuery = `INSERT IGNORE INTO \`${fixtureDatabase}\`.\`${smd.table}\` (SELECT * FROM \`${realDatabase}\`.\`${smd.table}\` WHERE \`id\` = ${id})`;
@@ -286,11 +280,7 @@ export class FixtureManager {
286
280
  }
287
281
 
288
282
  async destory() {
289
- if (!this.config) {
290
- return;
291
- }
292
- const { tdb, fdb } = await this.init();
293
- await tdb.destroy();
294
- await fdb.destroy();
283
+ await this.tdb.destroy();
284
+ await this.fdb.destroy();
295
285
  }
296
286
  }
@@ -28,6 +28,11 @@ export async function importMultiple(
28
28
  );
29
29
  }
30
30
  export async function findAppRootPath() {
31
+ const apiRootPath = await findApiRootPath();
32
+ return apiRootPath.split(path.sep).slice(0, -1).join(path.sep);
33
+ }
34
+
35
+ export async function findApiRootPath() {
31
36
  if (require.main === undefined) {
32
37
  throw new Error("Cannot find AppRoot using Sonamu");
33
38
  }
@@ -37,7 +42,7 @@ export async function findAppRootPath() {
37
42
  }
38
43
  do {
39
44
  if (existsSync(path.join(dir, "/package.json"))) {
40
- return dir.split(path.sep).slice(0, -1).join(path.sep);
45
+ return dir.split(path.sep).join(path.sep);
41
46
  }
42
47
  dir = dir.split(path.sep).slice(0, -1).join(path.sep);
43
48
  } while (dir.split(path.sep).length > 1);
package/src/api/init.ts DELETED
@@ -1,129 +0,0 @@
1
- import chalk from "chalk";
2
- import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
3
- import { IncomingMessage, Server, ServerResponse } from "http";
4
- import { ZodError } from "zod";
5
- import { getZodObjectFromApi } from "./code-converters";
6
- import { Context } from "./context";
7
- import { BadRequestException } from "../exceptions/so-exceptions";
8
- import { SMDManager } from "../smd/smd-manager";
9
- import { fastifyCaster } from "../api/caster";
10
- import { ApiParamType } from "../types/types";
11
- import { Syncer } from "../syncer/syncer";
12
- import { isLocal } from "../utils/controller";
13
- import { DB } from "../database/db";
14
- import { BaseModel } from "../database/base-model";
15
- import { findAppRootPath } from "../utils/utils";
16
-
17
- export type SonamuInitConfig = {
18
- prefix: string;
19
- syncTargets: string[];
20
- contextProvider: (
21
- defaultContext: Pick<Context, "headers" | "reply">,
22
- request: FastifyRequest,
23
- reply: FastifyReply
24
- ) => Context;
25
- };
26
- export async function init(
27
- server: FastifyInstance<Server, IncomingMessage, ServerResponse>,
28
- config: SonamuInitConfig
29
- ) {
30
- // 전체 라우팅 리스트
31
- server.get(
32
- `${config.prefix}/routes`,
33
- async (_request, _reply): Promise<any> => {
34
- return apis;
35
- }
36
- );
37
-
38
- // Healthcheck API
39
- server.get(
40
- `${config.prefix}/healthcheck`,
41
- async (_request, _reply): Promise<string> => {
42
- return "ok";
43
- }
44
- );
45
-
46
- // Syncer
47
- const appRootPath = await findAppRootPath();
48
- const syncer = Syncer.getInstance({
49
- appRootPath: appRootPath,
50
- targets: config.syncTargets,
51
- });
52
-
53
- // DB 설정파일 확인
54
- await DB.readKnexfile();
55
- console.log(chalk.green("DB Config Loaded!"));
56
-
57
- // Autoload: SMD / Models / Types / APIs
58
- console.time(chalk.cyan("autoload&sync:"));
59
- await SMDManager.autoload();
60
- const importedModels = await syncer.autoloadModels(appRootPath);
61
- const references = await syncer.autoloadTypes(appRootPath);
62
- const apis = await syncer.autoloadApis(appRootPath);
63
- if (isLocal()) {
64
- await syncer.sync();
65
- }
66
- console.timeEnd(chalk.cyan("autoload&sync:"));
67
-
68
- // API 라우팅 등록
69
- apis.map((api) => {
70
- // model
71
- if (importedModels[api.modelName] === undefined) {
72
- throw new Error(`정의되지 않은 모델에 접근 ${api.modelName}`);
73
- }
74
- const model = importedModels[api.modelName];
75
-
76
- // 파라미터 정보로 zod 스키마 빌드
77
- const ReqType = getZodObjectFromApi(api, references);
78
-
79
- // route
80
- server.route({
81
- method: api.options.httpMethod!,
82
- url: config.prefix + api.path,
83
- handler: async (request, reply): Promise<unknown> => {
84
- const which = api.options.httpMethod === "GET" ? "query" : "body";
85
- let reqBody: {
86
- [key: string]: unknown;
87
- };
88
- try {
89
- reqBody = fastifyCaster(ReqType).parse(request[which] ?? {});
90
- } catch (e) {
91
- if (e instanceof ZodError) {
92
- // TODO: BadRequest 에러 핸들링 (ZodError issues를 humanize하여 출력하는 로직 필요)
93
- throw new BadRequestException(
94
- `${(e as ZodError).issues[0].message}`,
95
- e.errors
96
- );
97
- } else {
98
- throw e;
99
- }
100
- }
101
-
102
- const result = await (model as any)[api.methodName].apply(
103
- model,
104
- api.parameters.map((param) => {
105
- // Context 인젝션
106
- if (ApiParamType.isContext(param.type)) {
107
- return config.contextProvider(
108
- {
109
- headers: request.headers,
110
- reply,
111
- },
112
- request,
113
- reply
114
- );
115
- } else {
116
- return reqBody[param.name];
117
- }
118
- })
119
- );
120
- reply.type(api.options.contentType ?? "application/json");
121
- return result;
122
- },
123
- }); // END server.route
124
- });
125
- }
126
-
127
- export async function destroy(): Promise<void> {
128
- await BaseModel.destroy();
129
- }