sonamu 0.0.7 → 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.
- package/.pnp.cjs +13 -0
- 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 +152 -67
- 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.js +2 -2
- package/dist/smd/smd-manager.js.map +1 -1
- package/dist/smd/smd.d.ts.map +1 -1
- package/dist/smd/smd.js +4 -5
- 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 +43 -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/init_enums.template.js +1 -1
- package/dist/templates/init_generated.template.d.ts.map +1 -1
- package/dist/templates/init_generated.template.js +8 -1
- package/dist/templates/init_generated.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/smd.template.js +2 -2
- package/dist/templates/smd.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 -41
- 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 +13 -3
- package/dist/utils/utils.js.map +1 -1
- package/package.json +8 -4
- package/src/api/index.ts +1 -1
- package/src/api/sonamu.ts +212 -0
- package/src/bin/cli.ts +159 -70
- 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 -3
- package/src/smd/smd.ts +10 -9
- package/src/syncer/syncer.ts +49 -68
- package/src/templates/generated_http.template.ts +2 -2
- package/src/templates/init_enums.template.ts +1 -1
- package/src/templates/init_generated.template.ts +8 -1
- package/src/templates/service.template.ts +6 -5
- package/src/templates/smd.template.ts +2 -2
- package/src/testing/fixture-manager.ts +44 -53
- package/src/utils/utils.ts +9 -1
- package/src/api/init.ts +0 -129
package/src/syncer/syncer.ts
CHANGED
|
@@ -82,12 +82,8 @@ import { Template__view_enums_buttonset } from "../templates/view_enums_buttonse
|
|
|
82
82
|
import { Template__view_search_input } from "../templates/view_search_input.template";
|
|
83
83
|
import { Template__view_list_columns } from "../templates/view_list_columns.template";
|
|
84
84
|
import { Template__generated_http } from "../templates/generated_http.template";
|
|
85
|
+
import { Sonamu } from "../api/sonamu";
|
|
85
86
|
|
|
86
|
-
type SyncerConfig = {
|
|
87
|
-
appRootPath: string;
|
|
88
|
-
checksumsPath: string;
|
|
89
|
-
targets: string[];
|
|
90
|
-
};
|
|
91
87
|
type FileType = "model" | "types" | "enums" | "smd" | "generated";
|
|
92
88
|
type GlobPattern = {
|
|
93
89
|
[key in FileType]: string;
|
|
@@ -112,15 +108,6 @@ export type RenderedTemplate = {
|
|
|
112
108
|
};
|
|
113
109
|
|
|
114
110
|
export class Syncer {
|
|
115
|
-
private static instance: Syncer;
|
|
116
|
-
public static getInstance(config?: Partial<SyncerConfig>) {
|
|
117
|
-
if (this.instance && config !== undefined) {
|
|
118
|
-
throw new Error("Syncer has already configured.");
|
|
119
|
-
}
|
|
120
|
-
return this.instance ?? (this.instance = new this(config));
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
config: SyncerConfig;
|
|
124
111
|
apis: {
|
|
125
112
|
typeParameters: ApiParamType.TypeParam[];
|
|
126
113
|
parameters: ApiParam[];
|
|
@@ -131,22 +118,19 @@ export class Syncer {
|
|
|
131
118
|
options: ApiDecoratorOptions;
|
|
132
119
|
}[] = [];
|
|
133
120
|
types: { [typeName: string]: z.ZodObject<any> } = {};
|
|
121
|
+
models: { [modelName: string]: unknown } = {};
|
|
134
122
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
config?.appRootPath ?? path.resolve(__dirname, "../../");
|
|
138
|
-
this.config = {
|
|
139
|
-
appRootPath,
|
|
140
|
-
checksumsPath: `${appRootPath}/api/.tf-checksum`,
|
|
141
|
-
targets: ["web"],
|
|
142
|
-
...config,
|
|
143
|
-
};
|
|
123
|
+
get checksumsPath(): string {
|
|
124
|
+
return path.join(Sonamu.apiRootPath, "/.tf-checksum");
|
|
144
125
|
}
|
|
126
|
+
public constructor() {}
|
|
145
127
|
|
|
146
128
|
async sync(): Promise<void> {
|
|
129
|
+
const { targets } = Sonamu.config.sync;
|
|
130
|
+
|
|
147
131
|
// 트리거와 무관하게 shared 분배
|
|
148
132
|
await Promise.all(
|
|
149
|
-
|
|
133
|
+
targets.map(async (target) => {
|
|
150
134
|
const srcCodePath = path
|
|
151
135
|
.join(__dirname, `../shared/${target}.shared.ts.txt`)
|
|
152
136
|
.replace("/dist/", "/src/");
|
|
@@ -155,7 +139,7 @@ export class Syncer {
|
|
|
155
139
|
}
|
|
156
140
|
|
|
157
141
|
const dstCodePath = path.join(
|
|
158
|
-
|
|
142
|
+
Sonamu.appRootPath,
|
|
159
143
|
target,
|
|
160
144
|
"src/services/sonamu.shared.ts"
|
|
161
145
|
);
|
|
@@ -233,16 +217,14 @@ export class Syncer {
|
|
|
233
217
|
// 트리거: model
|
|
234
218
|
if (diffTypes.includes("model")) {
|
|
235
219
|
const smdIds = this.getSMDIdFromPath(diffGroups["model"]);
|
|
236
|
-
|
|
237
220
|
console.log("// 액션: 서비스 생성");
|
|
238
221
|
await this.actionGenerateServices(smdIds);
|
|
239
|
-
|
|
240
222
|
console.log("// 액션: HTTP파일 생성");
|
|
241
223
|
await this.actionGenerateHttps(smdIds);
|
|
242
224
|
}
|
|
243
225
|
|
|
244
226
|
// 저장
|
|
245
|
-
await this.saveChecksums(
|
|
227
|
+
await this.saveChecksums(await this.getCurrentChecksums());
|
|
246
228
|
}
|
|
247
229
|
|
|
248
230
|
getSMDIdFromPath(filePaths: string[]): string[] {
|
|
@@ -328,13 +310,16 @@ export class Syncer {
|
|
|
328
310
|
}
|
|
329
311
|
|
|
330
312
|
async actionSyncFilesToTargets(tsPaths: string[]): Promise<string[]> {
|
|
313
|
+
const { targets } = Sonamu.config.sync;
|
|
314
|
+
const { dir: apiDir } = Sonamu.config.api;
|
|
315
|
+
|
|
331
316
|
return (
|
|
332
317
|
await Promise.all(
|
|
333
|
-
|
|
318
|
+
targets.map(async (target) =>
|
|
334
319
|
Promise.all(
|
|
335
320
|
tsPaths.map(async (src) => {
|
|
336
321
|
const dst = src
|
|
337
|
-
.replace(
|
|
322
|
+
.replace(`/${apiDir}/`, `/${target}/`)
|
|
338
323
|
.replace("/application/", "/services/");
|
|
339
324
|
const dir = dirname(dst);
|
|
340
325
|
if (!existsSync(dir)) {
|
|
@@ -352,13 +337,12 @@ export class Syncer {
|
|
|
352
337
|
async getCurrentChecksums(): Promise<PathAndChecksum[]> {
|
|
353
338
|
const PatternGroup: GlobPattern = {
|
|
354
339
|
/* TS 체크 */
|
|
355
|
-
types:
|
|
356
|
-
enums:
|
|
357
|
-
generated:
|
|
358
|
-
this.config.appRootPath + "/api/src/application/**/*.generated.ts",
|
|
340
|
+
types: Sonamu.apiRootPath + "/src/application/**/*.types.ts",
|
|
341
|
+
enums: Sonamu.apiRootPath + "/src/application/**/*.enums.ts",
|
|
342
|
+
generated: Sonamu.apiRootPath + "/src/application/**/*.generated.ts",
|
|
359
343
|
/* compiled-JS 체크 */
|
|
360
|
-
model:
|
|
361
|
-
smd:
|
|
344
|
+
model: Sonamu.apiRootPath + "/dist/application/**/*.model.js",
|
|
345
|
+
smd: Sonamu.apiRootPath + "/dist/application/**/*.smd.js",
|
|
362
346
|
};
|
|
363
347
|
|
|
364
348
|
const filePaths = (
|
|
@@ -386,19 +370,19 @@ export class Syncer {
|
|
|
386
370
|
}
|
|
387
371
|
|
|
388
372
|
async getPreviousChecksums(): Promise<PathAndChecksum[]> {
|
|
389
|
-
if (existsSync(this.
|
|
373
|
+
if (existsSync(this.checksumsPath) === false) {
|
|
390
374
|
return [];
|
|
391
375
|
}
|
|
392
376
|
|
|
393
377
|
const previousChecksums = (await readJSON(
|
|
394
|
-
this.
|
|
378
|
+
this.checksumsPath
|
|
395
379
|
)) as PathAndChecksum[];
|
|
396
380
|
return previousChecksums;
|
|
397
381
|
}
|
|
398
382
|
|
|
399
383
|
async saveChecksums(checksums: PathAndChecksum[]): Promise<void> {
|
|
400
|
-
await writeJSON(this.
|
|
401
|
-
console.debug("checksum saved", this.
|
|
384
|
+
await writeJSON(this.checksumsPath, checksums);
|
|
385
|
+
console.debug("checksum saved", this.checksumsPath);
|
|
402
386
|
}
|
|
403
387
|
|
|
404
388
|
async getChecksumOfFile(filePath: string): Promise<string> {
|
|
@@ -671,10 +655,10 @@ export class Syncer {
|
|
|
671
655
|
return printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);
|
|
672
656
|
}
|
|
673
657
|
|
|
674
|
-
async autoloadApis(
|
|
658
|
+
async autoloadApis() {
|
|
675
659
|
const pathPattern = path.join(
|
|
676
|
-
|
|
677
|
-
"
|
|
660
|
+
Sonamu.apiRootPath,
|
|
661
|
+
"/src/application/**/*.model.ts"
|
|
678
662
|
);
|
|
679
663
|
// console.debug(chalk.yellow(`autoload:APIs @ ${pathPattern}`));
|
|
680
664
|
|
|
@@ -686,12 +670,10 @@ export class Syncer {
|
|
|
686
670
|
return this.apis;
|
|
687
671
|
}
|
|
688
672
|
|
|
689
|
-
async autoloadModels(
|
|
690
|
-
basePath: string
|
|
691
|
-
): Promise<{ [modelName: string]: unknown }> {
|
|
673
|
+
async autoloadModels(): Promise<{ [modelName: string]: unknown }> {
|
|
692
674
|
const pathPattern = path.join(
|
|
693
|
-
|
|
694
|
-
"
|
|
675
|
+
Sonamu.apiRootPath,
|
|
676
|
+
"dist/application/**/*.model.js"
|
|
695
677
|
);
|
|
696
678
|
// console.debug(chalk.yellow(`autoload:models @ ${pathPattern}`));
|
|
697
679
|
|
|
@@ -700,22 +682,21 @@ export class Syncer {
|
|
|
700
682
|
const functions = modules
|
|
701
683
|
.map(({ imported }) => Object.entries(imported))
|
|
702
684
|
.flat();
|
|
703
|
-
|
|
685
|
+
this.models = Object.fromEntries(
|
|
704
686
|
functions.filter(([name]) => name.endsWith("Model"))
|
|
705
687
|
);
|
|
688
|
+
return this.models;
|
|
706
689
|
}
|
|
707
690
|
|
|
708
|
-
async autoloadTypes(
|
|
709
|
-
basePath: string
|
|
710
|
-
): Promise<{ [typeName: string]: z.ZodObject<any> }> {
|
|
691
|
+
async autoloadTypes(): Promise<{ [typeName: string]: z.ZodObject<any> }> {
|
|
711
692
|
if (Object.keys(this.types).length > 0) {
|
|
712
693
|
return this.types;
|
|
713
694
|
}
|
|
714
695
|
|
|
715
696
|
const pathPatterns = [
|
|
716
|
-
path.join(
|
|
717
|
-
path.join(
|
|
718
|
-
path.join(
|
|
697
|
+
path.join(Sonamu.apiRootPath, "/dist/application/**/*.types.js"),
|
|
698
|
+
path.join(Sonamu.apiRootPath, "/dist/application/**/*.enums.js"),
|
|
699
|
+
path.join(Sonamu.apiRootPath, "/dist/application/**/*.generated.js"),
|
|
719
700
|
];
|
|
720
701
|
// console.debug(chalk.magenta(`autoload:types @ ${pathPatterns.join("\n")}`));
|
|
721
702
|
|
|
@@ -784,9 +765,9 @@ export class Syncer {
|
|
|
784
765
|
if (key === "service" || key === "generated_http") {
|
|
785
766
|
// service 필요 정보 (API 리스트)
|
|
786
767
|
const smd = SMDManager.get(options.smdId);
|
|
787
|
-
const modelTsPath = `${path.
|
|
788
|
-
|
|
789
|
-
"
|
|
768
|
+
const modelTsPath = `${path.join(
|
|
769
|
+
Sonamu.apiRootPath,
|
|
770
|
+
"/src/application"
|
|
790
771
|
)}/${smd.names.fs}/${smd.names.fs}.model.ts`;
|
|
791
772
|
extra = [await this.readApisFromFile(modelTsPath)];
|
|
792
773
|
} else if (key === "view_list" || key === "model") {
|
|
@@ -890,8 +871,8 @@ export class Syncer {
|
|
|
890
871
|
}
|
|
891
872
|
|
|
892
873
|
async writeCodeToPath(pathAndCode: PathAndCode): Promise<string[]> {
|
|
893
|
-
const {
|
|
894
|
-
const filePath = `${appRootPath}/${pathAndCode.path}`;
|
|
874
|
+
const { targets } = Sonamu.config.sync;
|
|
875
|
+
const filePath = `${Sonamu.appRootPath}/${pathAndCode.path}`;
|
|
895
876
|
|
|
896
877
|
const dstFilePaths = uniq(
|
|
897
878
|
targets.map((target) => filePath.replace("/:target/", `/${target}/`))
|
|
@@ -949,8 +930,8 @@ export class Syncer {
|
|
|
949
930
|
} else {
|
|
950
931
|
filteredPathAndCodes = pathAndCodes.filter((pathAndCode, index) => {
|
|
951
932
|
if (index === 0) {
|
|
952
|
-
const {
|
|
953
|
-
const filePath = `${appRootPath}/${pathAndCode.path}`;
|
|
933
|
+
const { targets } = Sonamu.config.sync;
|
|
934
|
+
const filePath = `${Sonamu.appRootPath}/${pathAndCode.path}`;
|
|
954
935
|
const dstFilePaths = targets.map((target) =>
|
|
955
936
|
filePath.replace("/:target/", `/${target}/`)
|
|
956
937
|
);
|
|
@@ -991,21 +972,22 @@ export class Syncer {
|
|
|
991
972
|
enumsKeys.map((componentId) => {
|
|
992
973
|
const { target, path: p } = tpl.getTargetAndPath(names, componentId);
|
|
993
974
|
result[`${key}__${componentId}`] = existsSync(
|
|
994
|
-
path.join(
|
|
975
|
+
path.join(Sonamu.appRootPath, target, p)
|
|
995
976
|
);
|
|
996
977
|
});
|
|
997
978
|
return result;
|
|
998
979
|
}
|
|
999
980
|
|
|
1000
981
|
const { target, path: p } = tpl.getTargetAndPath(names);
|
|
982
|
+
const { targets } = Sonamu.config.sync;
|
|
1001
983
|
if (target.includes(":target")) {
|
|
1002
|
-
|
|
984
|
+
targets.map((t) => {
|
|
1003
985
|
result[`${key}__${t}`] = existsSync(
|
|
1004
|
-
path.join(
|
|
986
|
+
path.join(Sonamu.appRootPath, target.replace(":target", t), p)
|
|
1005
987
|
);
|
|
1006
988
|
});
|
|
1007
989
|
} else {
|
|
1008
|
-
result[key] = existsSync(path.join(
|
|
990
|
+
result[key] = existsSync(path.join(Sonamu.appRootPath, target, p));
|
|
1009
991
|
}
|
|
1010
992
|
|
|
1011
993
|
return result;
|
|
@@ -1015,8 +997,7 @@ export class Syncer {
|
|
|
1015
997
|
async getZodTypeById(zodTypeId: string): Promise<z.ZodTypeAny> {
|
|
1016
998
|
const modulePath = SMDManager.getModulePath(zodTypeId);
|
|
1017
999
|
const moduleAbsPath = path.join(
|
|
1018
|
-
|
|
1019
|
-
"api",
|
|
1000
|
+
Sonamu.apiRootPath,
|
|
1020
1001
|
"dist",
|
|
1021
1002
|
"application",
|
|
1022
1003
|
modulePath + ".js"
|
|
@@ -7,7 +7,7 @@ import { ExtendedApi } from "../api/decorators";
|
|
|
7
7
|
import { Template } from "./base-template";
|
|
8
8
|
import prettier from "prettier";
|
|
9
9
|
import { DateTime } from "luxon";
|
|
10
|
-
import {
|
|
10
|
+
import { Sonamu } from "../api/sonamu";
|
|
11
11
|
|
|
12
12
|
export class Template__generated_http extends Template {
|
|
13
13
|
constructor() {
|
|
@@ -23,7 +23,7 @@ export class Template__generated_http extends Template {
|
|
|
23
23
|
|
|
24
24
|
render({ smdId }: TemplateOptions["generated"], apis: ExtendedApi[]) {
|
|
25
25
|
const names = SMDManager.getNamesFromId(smdId);
|
|
26
|
-
const references =
|
|
26
|
+
const references = Sonamu.syncer.types;
|
|
27
27
|
|
|
28
28
|
const lines = apis.map((api) => {
|
|
29
29
|
const reqObject = this.resolveApiParams(api, references);
|
|
@@ -31,7 +31,7 @@ export class Template__init_enums extends Template {
|
|
|
31
31
|
...this.getTargetAndPath(names),
|
|
32
32
|
body: `
|
|
33
33
|
import { z } from "zod";
|
|
34
|
-
import { EnumsLabelKo } from "
|
|
34
|
+
import { EnumsLabelKo } from "sonamu";
|
|
35
35
|
|
|
36
36
|
${Object.entries(record)
|
|
37
37
|
.map(
|
|
@@ -33,10 +33,17 @@ export const ${smdId}BaseListParams = z.object({
|
|
|
33
33
|
keyword: z.string(),
|
|
34
34
|
orderBy: ${smdId}OrderBy,
|
|
35
35
|
withoutCount: z.boolean(),
|
|
36
|
-
});
|
|
36
|
+
}).partial();
|
|
37
37
|
export type ${smdId}BaseListParams = z.infer<typeof ${smdId}BaseListParams>;
|
|
38
38
|
|
|
39
|
+
export type ${smdId}SubsetKey = never;
|
|
40
|
+
export type ${smdId}SubsetMapping = {};
|
|
41
|
+
/* BEGIN- Server-side Only */
|
|
42
|
+
import { SubsetQuery } from "sonamu";
|
|
43
|
+
export const ${names.camel}SubsetQueries: { [key in ${smdId}SubsetKey]: SubsetQuery } = {};
|
|
44
|
+
|
|
39
45
|
export type ${smdId}FieldExpr = string;
|
|
46
|
+
/* END- Server-side Only */
|
|
40
47
|
`.trim(),
|
|
41
48
|
importKeys: [],
|
|
42
49
|
};
|
|
@@ -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(
|
|
@@ -21,14 +21,14 @@ export class Template__smd extends Template {
|
|
|
21
21
|
return {
|
|
22
22
|
...this.getTargetAndPath(names),
|
|
23
23
|
body: `
|
|
24
|
-
import { p,
|
|
24
|
+
import { p, SMDInput } from "sonamu";
|
|
25
25
|
import { ${smdId}FieldExpr } from "./${names.fs}.generated";
|
|
26
26
|
|
|
27
27
|
/*
|
|
28
28
|
${smdId} SMD
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
export const ${names.camel}
|
|
31
|
+
export const ${names.camel}SmdInput: SMDInput<${smdId}FieldExpr> = {
|
|
32
32
|
id: "${smdId}",
|
|
33
33
|
title: "${title ?? smdId}",
|
|
34
34
|
props: [
|
|
@@ -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,16 +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
|
|
36
|
+
await Sonamu.init();
|
|
24
37
|
});
|
|
25
38
|
|
|
26
39
|
beforeEach(async () => {
|
|
@@ -34,32 +47,11 @@ export class FixtureManager {
|
|
|
34
47
|
}
|
|
35
48
|
}
|
|
36
49
|
|
|
37
|
-
async init(): Promise<{
|
|
38
|
-
tdb: Knex;
|
|
39
|
-
fdb: Knex;
|
|
40
|
-
knexfile: SonamuDBConfig;
|
|
41
|
-
}> {
|
|
42
|
-
if (this.config) {
|
|
43
|
-
return this.config;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const knexfile = await DB.readKnexfile();
|
|
47
|
-
this.config = {
|
|
48
|
-
knexfile,
|
|
49
|
-
tdb: knex(knexfile.test),
|
|
50
|
-
fdb: knex(knexfile.fixture_local),
|
|
51
|
-
};
|
|
52
|
-
return this.config;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
50
|
async cleanAndSeed() {
|
|
56
|
-
const { tdb, fdb, knexfile } = await this.init();
|
|
57
|
-
// console.time("FIXTURE-CleanAndSeed");
|
|
58
|
-
|
|
59
51
|
let tableNames: string[] = [];
|
|
60
52
|
|
|
61
53
|
if (this.usingTables === undefined) {
|
|
62
|
-
const [tables] = await tdb.raw(
|
|
54
|
+
const [tables] = await this.tdb.raw(
|
|
63
55
|
"SHOW TABLE STATUS WHERE Engine IS NOT NULL"
|
|
64
56
|
);
|
|
65
57
|
tableNames = tables.map((tableInfo: any) => tableInfo["Name"]);
|
|
@@ -67,31 +59,37 @@ export class FixtureManager {
|
|
|
67
59
|
tableNames = this.usingTables;
|
|
68
60
|
}
|
|
69
61
|
|
|
70
|
-
await tdb.raw(`SET FOREIGN_KEY_CHECKS = 0`);
|
|
62
|
+
await this.tdb.raw(`SET FOREIGN_KEY_CHECKS = 0`);
|
|
71
63
|
for await (let tableName of tableNames) {
|
|
72
64
|
if (tableName == "migrations") {
|
|
73
65
|
continue;
|
|
74
66
|
}
|
|
75
67
|
|
|
76
|
-
const [[fdbChecksumRow]] = await fdb.raw(
|
|
68
|
+
const [[fdbChecksumRow]] = await this.fdb.raw(
|
|
69
|
+
`CHECKSUM TABLE ${tableName}`
|
|
70
|
+
);
|
|
77
71
|
const fdbChecksum = fdbChecksumRow["Checksum"];
|
|
78
72
|
|
|
79
|
-
const [[tdbChecksumRow]] = await tdb.raw(
|
|
73
|
+
const [[tdbChecksumRow]] = await this.tdb.raw(
|
|
74
|
+
`CHECKSUM TABLE ${tableName}`
|
|
75
|
+
);
|
|
80
76
|
const tdbChecksum = tdbChecksumRow["Checksum"];
|
|
81
77
|
|
|
82
78
|
if (fdbChecksum !== tdbChecksum) {
|
|
83
|
-
await tdb(tableName).truncate();
|
|
79
|
+
await this.tdb(tableName).truncate();
|
|
84
80
|
const rawQuery = `INSERT INTO ${
|
|
85
|
-
(
|
|
81
|
+
(Sonamu.dbConfig.test.connection as Knex.ConnectionConfig).database
|
|
86
82
|
}.${tableName}
|
|
87
83
|
SELECT * FROM ${
|
|
88
|
-
(
|
|
89
|
-
.
|
|
84
|
+
(
|
|
85
|
+
Sonamu.dbConfig.fixture_local
|
|
86
|
+
.connection as Knex.ConnectionConfig
|
|
87
|
+
).database
|
|
90
88
|
}.${tableName}`;
|
|
91
|
-
await tdb.raw(rawQuery);
|
|
89
|
+
await this.tdb.raw(rawQuery);
|
|
92
90
|
}
|
|
93
91
|
}
|
|
94
|
-
await tdb.raw(`SET FOREIGN_KEY_CHECKS = 1`);
|
|
92
|
+
await this.tdb.raw(`SET FOREIGN_KEY_CHECKS = 1`);
|
|
95
93
|
|
|
96
94
|
// console.timeEnd("FIXTURE-CleanAndSeed");
|
|
97
95
|
}
|
|
@@ -146,10 +144,9 @@ export class FixtureManager {
|
|
|
146
144
|
}
|
|
147
145
|
|
|
148
146
|
async sync() {
|
|
149
|
-
const
|
|
150
|
-
const frdb = knex(knexfile.fixture_remote);
|
|
147
|
+
const frdb = knex(Sonamu.dbConfig.fixture_remote);
|
|
151
148
|
|
|
152
|
-
const [tables] = await fdb.raw(
|
|
149
|
+
const [tables] = await this.fdb.raw(
|
|
153
150
|
"SHOW TABLE STATUS WHERE Engine IS NOT NULL"
|
|
154
151
|
);
|
|
155
152
|
const tableNames: string[] = tables.map(
|
|
@@ -164,10 +161,10 @@ export class FixtureManager {
|
|
|
164
161
|
}
|
|
165
162
|
|
|
166
163
|
const remoteChecksum = await this.getChecksum(frdb, tableName);
|
|
167
|
-
const localChecksum = await this.getChecksum(fdb, tableName);
|
|
164
|
+
const localChecksum = await this.getChecksum(this.fdb, tableName);
|
|
168
165
|
|
|
169
166
|
if (remoteChecksum !== localChecksum) {
|
|
170
|
-
await fdb.transaction(async (transaction) => {
|
|
167
|
+
await this.fdb.transaction(async (transaction) => {
|
|
171
168
|
await transaction.raw(`SET FOREIGN_KEY_CHECKS = 0`);
|
|
172
169
|
await transaction(tableName).truncate();
|
|
173
170
|
|
|
@@ -222,8 +219,6 @@ export class FixtureManager {
|
|
|
222
219
|
field: string,
|
|
223
220
|
id: number
|
|
224
221
|
): Promise<string[]> {
|
|
225
|
-
const { knexfile } = await this.init();
|
|
226
|
-
|
|
227
222
|
console.log({ smdId, field, id });
|
|
228
223
|
const smd = SMDManager.get(smdId);
|
|
229
224
|
const wdb = BaseModel.getDB("w");
|
|
@@ -235,9 +230,9 @@ export class FixtureManager {
|
|
|
235
230
|
}
|
|
236
231
|
|
|
237
232
|
// 픽스쳐DB, 실DB
|
|
238
|
-
const fixtureDatabase = (
|
|
233
|
+
const fixtureDatabase = (Sonamu.dbConfig.fixture_remote.connection as any)
|
|
239
234
|
.database;
|
|
240
|
-
const realDatabase = (
|
|
235
|
+
const realDatabase = (Sonamu.dbConfig.production_master.connection as any)
|
|
241
236
|
.database;
|
|
242
237
|
|
|
243
238
|
const selfQuery = `INSERT IGNORE INTO \`${fixtureDatabase}\`.\`${smd.table}\` (SELECT * FROM \`${realDatabase}\`.\`${smd.table}\` WHERE \`id\` = ${id})`;
|
|
@@ -285,11 +280,7 @@ export class FixtureManager {
|
|
|
285
280
|
}
|
|
286
281
|
|
|
287
282
|
async destory() {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}
|
|
291
|
-
const { tdb, fdb } = await this.init();
|
|
292
|
-
await tdb.destroy();
|
|
293
|
-
await fdb.destroy();
|
|
283
|
+
await this.tdb.destroy();
|
|
284
|
+
await this.fdb.destroy();
|
|
294
285
|
}
|
|
295
286
|
}
|
package/src/utils/utils.ts
CHANGED
|
@@ -28,13 +28,21 @@ 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
|
}
|
|
34
39
|
let dir = path.dirname(require.main.path);
|
|
40
|
+
if (dir.includes("/.yarn/")) {
|
|
41
|
+
dir = dir.split("/.yarn/")[0];
|
|
42
|
+
}
|
|
35
43
|
do {
|
|
36
44
|
if (existsSync(path.join(dir, "/package.json"))) {
|
|
37
|
-
return dir.split(path.sep).
|
|
45
|
+
return dir.split(path.sep).join(path.sep);
|
|
38
46
|
}
|
|
39
47
|
dir = dir.split(path.sep).slice(0, -1).join(path.sep);
|
|
40
48
|
} while (dir.split(path.sep).length > 1);
|