sonamu 0.0.8 → 0.0.10
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.
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +1 -1
- package/dist/api/index.js.map +1 -1
- package/dist/api/init.d.ts +35 -5
- package/dist/api/init.d.ts.map +1 -1
- package/dist/api/init.js +142 -79
- package/dist/api/init.js.map +1 -1
- package/dist/api/sonamu.d.ts +42 -0
- package/dist/api/sonamu.d.ts.map +1 -0
- package/dist/api/sonamu.js +175 -0
- package/dist/api/sonamu.js.map +1 -0
- package/dist/bin/cli.js +6 -21
- package/dist/bin/cli.js.map +1 -1
- package/dist/database/db.d.ts +1 -3
- package/dist/database/db.d.ts.map +1 -1
- package/dist/database/db.js +12 -23
- package/dist/database/db.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/smd/migrator.d.ts +0 -5
- package/dist/smd/migrator.d.ts.map +1 -1
- package/dist/smd/migrator.js +18 -19
- package/dist/smd/migrator.js.map +1 -1
- package/dist/smd/smd-manager.d.ts.map +1 -1
- package/dist/smd/smd-manager.js +2 -3
- package/dist/smd/smd-manager.js.map +1 -1
- package/dist/smd/smd.d.ts.map +1 -1
- package/dist/smd/smd.js +3 -4
- package/dist/smd/smd.js.map +1 -1
- package/dist/syncer/syncer.d.ts +8 -12
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +46 -43
- package/dist/syncer/syncer.js.map +1 -1
- package/dist/templates/generated_http.template.js +2 -2
- package/dist/templates/generated_http.template.js.map +1 -1
- package/dist/templates/service.template.d.ts +1 -1
- package/dist/templates/service.template.d.ts.map +1 -1
- package/dist/templates/service.template.js +3 -2
- package/dist/templates/service.template.js.map +1 -1
- package/dist/templates/view_form.template.d.ts +2 -2
- package/dist/templates/view_list.template.d.ts +2 -2
- package/dist/testing/fixture-manager.d.ts +6 -7
- package/dist/testing/fixture-manager.d.ts.map +1 -1
- package/dist/testing/fixture-manager.js +35 -42
- package/dist/testing/fixture-manager.js.map +1 -1
- package/dist/utils/utils.d.ts +1 -0
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +10 -3
- package/dist/utils/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/api/index.ts +1 -1
- package/src/api/sonamu.ts +212 -0
- package/src/bin/cli.ts +6 -26
- package/src/database/db.ts +15 -27
- package/src/index.ts +1 -1
- package/src/smd/migrator.ts +18 -31
- package/src/smd/smd-manager.ts +3 -4
- package/src/smd/smd.ts +7 -8
- package/src/syncer/syncer.ts +58 -68
- package/src/templates/generated_http.template.ts +2 -2
- package/src/templates/service.template.ts +6 -5
- package/src/testing/fixture-manager.ts +44 -54
- package/src/utils/utils.ts +6 -1
- 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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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 = `${
|
|
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
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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
|
-
(
|
|
81
|
+
(Sonamu.dbConfig.test.connection as Knex.ConnectionConfig).database
|
|
87
82
|
}.${tableName}
|
|
88
83
|
SELECT * FROM ${
|
|
89
|
-
(
|
|
90
|
-
.
|
|
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
|
|
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 = (
|
|
233
|
+
const fixtureDatabase = (Sonamu.dbConfig.fixture_remote.connection as any)
|
|
240
234
|
.database;
|
|
241
|
-
const realDatabase = (
|
|
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
|
-
|
|
290
|
-
|
|
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
|
}
|
package/src/utils/utils.ts
CHANGED
|
@@ -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).
|
|
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
|
-
}
|