sonamu 0.2.31 → 0.2.33
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 +11 -10
- package/.vscode/settings.json +1 -1
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +3 -0
- package/dist/api/sonamu.js.map +1 -1
- package/dist/bin/cli.js +7 -4
- package/dist/bin/cli.js.map +1 -1
- package/dist/database/_batch_update.d.ts +15 -0
- package/dist/database/_batch_update.d.ts.map +1 -0
- package/dist/database/_batch_update.js +89 -0
- package/dist/database/_batch_update.js.map +1 -0
- package/dist/database/base-model.d.ts +2 -1
- package/dist/database/base-model.d.ts.map +1 -1
- package/dist/database/base-model.js +45 -31
- package/dist/database/base-model.js.map +1 -1
- package/dist/database/upsert-builder.d.ts.map +1 -1
- package/dist/database/upsert-builder.js +11 -54
- package/dist/database/upsert-builder.js.map +1 -1
- package/dist/entity/entity.js +1 -1
- package/dist/entity/entity.js.map +1 -1
- package/dist/entity/migrator.d.ts +4 -4
- package/dist/entity/migrator.d.ts.map +1 -1
- package/dist/entity/migrator.js +213 -205
- package/dist/entity/migrator.js.map +1 -1
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +26 -26
- package/dist/syncer/syncer.js.map +1 -1
- package/dist/templates/base-template.d.ts +1 -1
- package/dist/templates/base-template.d.ts.map +1 -1
- package/dist/templates/generated_http.template.d.ts +2 -2
- package/dist/templates/generated_http.template.d.ts.map +1 -1
- package/dist/templates/generated_http.template.js +49 -38
- package/dist/templates/generated_http.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/package.json +3 -3
- package/src/api/sonamu.ts +4 -0
- package/src/bin/cli.ts +11 -6
- package/src/database/_batch_update.ts +106 -0
- package/src/database/base-model.ts +66 -42
- package/src/database/upsert-builder.ts +16 -12
- package/src/entity/entity.ts +1 -1
- package/src/entity/migrator.ts +106 -103
- package/src/syncer/syncer.ts +58 -58
- package/src/templates/base-template.ts +1 -1
- package/src/templates/generated_http.template.ts +37 -35
package/src/entity/migrator.ts
CHANGED
|
@@ -429,7 +429,7 @@ export class Migrator {
|
|
|
429
429
|
{
|
|
430
430
|
file: string;
|
|
431
431
|
directory: string;
|
|
432
|
-
}[]
|
|
432
|
+
}[],
|
|
433
433
|
];
|
|
434
434
|
const migrationsDir = `${Sonamu.apiRootPath}/src/migrations`;
|
|
435
435
|
const delList = pendingList.map((df) => {
|
|
@@ -752,50 +752,50 @@ export class Migrator {
|
|
|
752
752
|
if (dbSet === null) {
|
|
753
753
|
// 기존 테이블 없음, 새로 테이블 생성
|
|
754
754
|
return [
|
|
755
|
-
this.generateCreateCode_ColumnAndIndexes(
|
|
755
|
+
await this.generateCreateCode_ColumnAndIndexes(
|
|
756
756
|
entitySet.table,
|
|
757
757
|
entitySet.columns,
|
|
758
758
|
entitySet.indexes
|
|
759
759
|
),
|
|
760
|
-
...this.generateCreateCode_Foreign(
|
|
760
|
+
...(await this.generateCreateCode_Foreign(
|
|
761
761
|
entitySet.table,
|
|
762
762
|
entitySet.foreigns
|
|
763
|
-
),
|
|
763
|
+
)),
|
|
764
764
|
];
|
|
765
765
|
}
|
|
766
766
|
|
|
767
767
|
// 기존 테이블 존재하는 케이스
|
|
768
|
-
const alterCodes: (GenMigrationCode | GenMigrationCode[] | null)[] =
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
768
|
+
const alterCodes: (GenMigrationCode | GenMigrationCode[] | null)[] =
|
|
769
|
+
await Promise.all(
|
|
770
|
+
(["columnsAndIndexes", "foreigns"] as const).map((key) => {
|
|
771
|
+
// 배열 원소의 순서가 달라서 불일치가 발생하는걸 방지하기 위해 각 항목별로 정렬 처리 후 비교
|
|
772
|
+
if (key === "columnsAndIndexes") {
|
|
773
|
+
const replaceColumnDefaultTo = (col: MigrationColumn) => {
|
|
774
|
+
// float인 경우 기본값을 0으로 지정하는 경우 "0.00"으로 변환되는 케이스 대응
|
|
775
|
+
if (
|
|
776
|
+
col.type === "float" &&
|
|
777
|
+
col.defaultTo &&
|
|
778
|
+
col.defaultTo.includes('"') === false
|
|
779
|
+
) {
|
|
780
|
+
col.defaultTo = `"${Number(col.defaultTo).toFixed(
|
|
781
|
+
col.scale ?? 2
|
|
782
|
+
)}"`;
|
|
783
|
+
}
|
|
784
|
+
// string인 경우 기본값이 빈 스트링인 경우 대응
|
|
785
|
+
if (col.type === "string" && col.defaultTo === "") {
|
|
786
|
+
col.defaultTo = '""';
|
|
787
|
+
}
|
|
788
|
+
return col;
|
|
789
|
+
};
|
|
790
|
+
const entityColumns = sortBy(
|
|
791
|
+
entitySet.columns,
|
|
792
|
+
(a) => a.name
|
|
793
|
+
).map(replaceColumnDefaultTo);
|
|
794
|
+
const dbColumns = sortBy(dbSet.columns, (a) => a.name).map(
|
|
795
|
+
replaceColumnDefaultTo
|
|
796
|
+
);
|
|
797
|
+
|
|
798
|
+
/* 디버깅용 코드, 특정 컬럼에서 불일치 발생할 때 확인
|
|
799
799
|
const entityColumn = entitySet.columns.find(
|
|
800
800
|
(col) => col.name === "price_krw"
|
|
801
801
|
);
|
|
@@ -805,63 +805,66 @@ export class Migrator {
|
|
|
805
805
|
console.debug({ entityColumn, dbColumn });
|
|
806
806
|
*/
|
|
807
807
|
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
808
|
+
const entityIndexes = sortBy(entitySet.indexes, (a) =>
|
|
809
|
+
[
|
|
810
|
+
a.type,
|
|
811
|
+
...a.columns.sort((c1, c2) => (c1 > c2 ? 1 : -1)),
|
|
812
|
+
].join("-")
|
|
813
|
+
);
|
|
814
|
+
const dbIndexes = sortBy(dbSet.indexes, (a) =>
|
|
815
|
+
[
|
|
816
|
+
a.type,
|
|
817
|
+
...a.columns.sort((c1, c2) => (c1 > c2 ? 1 : -1)),
|
|
818
|
+
].join("-")
|
|
819
|
+
);
|
|
820
|
+
|
|
821
|
+
const isEqualColumns = equal(entityColumns, dbColumns);
|
|
822
|
+
const isEqualIndexes = equal(entityIndexes, dbIndexes);
|
|
823
|
+
if (isEqualColumns && isEqualIndexes) {
|
|
824
|
+
return null;
|
|
825
|
+
} else {
|
|
826
|
+
// this.showMigrationSet("MD", entitySet);
|
|
827
|
+
// this.showMigrationSet("DB", dbSet);
|
|
828
|
+
return this.generateAlterCode_ColumnAndIndexes(
|
|
829
|
+
entitySet.table,
|
|
830
|
+
entityColumns,
|
|
831
|
+
entityIndexes,
|
|
832
|
+
dbColumns,
|
|
833
|
+
dbIndexes
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
} else {
|
|
837
|
+
const replaceNoActionOnMySQL = (f: MigrationForeign) => {
|
|
838
|
+
// MySQL에서 RESTRICT와 NO ACTION은 동일함
|
|
839
|
+
const { onDelete, onUpdate } = f;
|
|
840
|
+
return {
|
|
841
|
+
...f,
|
|
842
|
+
onUpdate:
|
|
843
|
+
onUpdate === "RESTRICT" ? "NO ACTION" : onUpdate,
|
|
844
|
+
onDelete:
|
|
845
|
+
onDelete === "RESTRICT" ? "NO ACTION" : onDelete,
|
|
846
|
+
};
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
const entityForeigns = sortBy(entitySet.foreigns, (a) =>
|
|
850
|
+
[a.to, ...a.columns].join("-")
|
|
851
|
+
).map((f) => replaceNoActionOnMySQL(f));
|
|
852
|
+
const dbForeigns = sortBy(dbSet.foreigns, (a) =>
|
|
853
|
+
[a.to, ...a.columns].join("-")
|
|
854
|
+
).map((f) => replaceNoActionOnMySQL(f));
|
|
855
|
+
|
|
856
|
+
if (equal(entityForeigns, dbForeigns) === false) {
|
|
857
|
+
// console.dir({ entityForeigns, dbForeigns }, { depth: null });
|
|
858
|
+
return this.generateAlterCode_Foreigns(
|
|
859
|
+
entitySet.table,
|
|
860
|
+
entityForeigns,
|
|
861
|
+
dbForeigns
|
|
862
|
+
);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
824
865
|
return null;
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
// this.showMigrationSet("DB", dbSet);
|
|
828
|
-
return this.generateAlterCode_ColumnAndIndexes(
|
|
829
|
-
entitySet.table,
|
|
830
|
-
entityColumns,
|
|
831
|
-
entityIndexes,
|
|
832
|
-
dbColumns,
|
|
833
|
-
dbIndexes
|
|
834
|
-
);
|
|
835
|
-
}
|
|
836
|
-
} else {
|
|
837
|
-
const replaceNoActionOnMySQL = (f: MigrationForeign) => {
|
|
838
|
-
// MySQL에서 RESTRICT와 NO ACTION은 동일함
|
|
839
|
-
const { onDelete, onUpdate } = f;
|
|
840
|
-
return {
|
|
841
|
-
...f,
|
|
842
|
-
onUpdate: onUpdate === "RESTRICT" ? "NO ACTION" : onUpdate,
|
|
843
|
-
onDelete: onDelete === "RESTRICT" ? "NO ACTION" : onDelete,
|
|
844
|
-
};
|
|
845
|
-
};
|
|
846
|
-
|
|
847
|
-
const entityForeigns = sortBy(entitySet.foreigns, (a) =>
|
|
848
|
-
[a.to, ...a.columns].join("-")
|
|
849
|
-
).map((f) => replaceNoActionOnMySQL(f));
|
|
850
|
-
const dbForeigns = sortBy(dbSet.foreigns, (a) =>
|
|
851
|
-
[a.to, ...a.columns].join("-")
|
|
852
|
-
).map((f) => replaceNoActionOnMySQL(f));
|
|
853
|
-
|
|
854
|
-
if (equal(entityForeigns, dbForeigns) === false) {
|
|
855
|
-
// console.dir({ entityForeigns, dbForeigns }, { depth: null });
|
|
856
|
-
return this.generateAlterCode_Foreigns(
|
|
857
|
-
entitySet.table,
|
|
858
|
-
entityForeigns,
|
|
859
|
-
dbForeigns
|
|
860
|
-
);
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
return null;
|
|
864
|
-
});
|
|
866
|
+
})
|
|
867
|
+
);
|
|
865
868
|
if (alterCodes.every((alterCode) => alterCode === null)) {
|
|
866
869
|
return null;
|
|
867
870
|
} else {
|
|
@@ -1398,11 +1401,11 @@ export class Migrator {
|
|
|
1398
1401
|
/*
|
|
1399
1402
|
테이블 생성하는 케이스 - 컬럼/인덱스 생성
|
|
1400
1403
|
*/
|
|
1401
|
-
generateCreateCode_ColumnAndIndexes(
|
|
1404
|
+
async generateCreateCode_ColumnAndIndexes(
|
|
1402
1405
|
table: string,
|
|
1403
1406
|
columns: MigrationColumn[],
|
|
1404
1407
|
indexes: MigrationIndex[]
|
|
1405
|
-
): GenMigrationCode {
|
|
1408
|
+
): Promise<GenMigrationCode> {
|
|
1406
1409
|
// 컬럼, 인덱스 처리
|
|
1407
1410
|
const lines: string[] = [
|
|
1408
1411
|
'import { Knex } from "knex";',
|
|
@@ -1425,7 +1428,7 @@ export class Migrator {
|
|
|
1425
1428
|
table,
|
|
1426
1429
|
type: "normal",
|
|
1427
1430
|
title: `create__${table}`,
|
|
1428
|
-
formatted: prettier.format(lines.join("\n"), {
|
|
1431
|
+
formatted: await prettier.format(lines.join("\n"), {
|
|
1429
1432
|
parser: "typescript",
|
|
1430
1433
|
}),
|
|
1431
1434
|
};
|
|
@@ -1433,10 +1436,10 @@ export class Migrator {
|
|
|
1433
1436
|
/*
|
|
1434
1437
|
테이블 생성하는 케이스 - FK 생성
|
|
1435
1438
|
*/
|
|
1436
|
-
generateCreateCode_Foreign(
|
|
1439
|
+
async generateCreateCode_Foreign(
|
|
1437
1440
|
table: string,
|
|
1438
1441
|
foreigns: MigrationForeign[]
|
|
1439
|
-
): GenMigrationCode[] {
|
|
1442
|
+
): Promise<GenMigrationCode[]> {
|
|
1440
1443
|
if (foreigns.length === 0) {
|
|
1441
1444
|
return [];
|
|
1442
1445
|
}
|
|
@@ -1473,7 +1476,7 @@ export class Migrator {
|
|
|
1473
1476
|
table,
|
|
1474
1477
|
type: "foreign",
|
|
1475
1478
|
title: `foreign__${table}__${foreignKeysString}`,
|
|
1476
|
-
formatted: prettier.format(lines.join("\n"), {
|
|
1479
|
+
formatted: await prettier.format(lines.join("\n"), {
|
|
1477
1480
|
parser: "typescript",
|
|
1478
1481
|
}),
|
|
1479
1482
|
},
|
|
@@ -1550,13 +1553,13 @@ export class Migrator {
|
|
|
1550
1553
|
}
|
|
1551
1554
|
}
|
|
1552
1555
|
|
|
1553
|
-
generateAlterCode_ColumnAndIndexes(
|
|
1556
|
+
async generateAlterCode_ColumnAndIndexes(
|
|
1554
1557
|
table: string,
|
|
1555
1558
|
entityColumns: MigrationColumn[],
|
|
1556
1559
|
entityIndexes: MigrationIndex[],
|
|
1557
1560
|
dbColumns: MigrationColumn[],
|
|
1558
1561
|
dbIndexes: MigrationIndex[]
|
|
1559
|
-
): GenMigrationCode[] {
|
|
1562
|
+
): Promise<GenMigrationCode[]> {
|
|
1560
1563
|
/*
|
|
1561
1564
|
세부 비교 후 다른점 찾아서 코드 생성
|
|
1562
1565
|
|
|
@@ -1615,7 +1618,7 @@ export class Migrator {
|
|
|
1615
1618
|
"}",
|
|
1616
1619
|
];
|
|
1617
1620
|
|
|
1618
|
-
const formatted = prettier.format(lines.join("\n"), {
|
|
1621
|
+
const formatted = await prettier.format(lines.join("\n"), {
|
|
1619
1622
|
parser: "typescript",
|
|
1620
1623
|
});
|
|
1621
1624
|
|
|
@@ -1853,11 +1856,11 @@ export class Migrator {
|
|
|
1853
1856
|
return linesTo;
|
|
1854
1857
|
}
|
|
1855
1858
|
|
|
1856
|
-
generateAlterCode_Foreigns(
|
|
1859
|
+
async generateAlterCode_Foreigns(
|
|
1857
1860
|
table: string,
|
|
1858
1861
|
entityForeigns: MigrationForeign[],
|
|
1859
1862
|
dbForeigns: MigrationForeign[]
|
|
1860
|
-
): GenMigrationCode[] {
|
|
1863
|
+
): Promise<GenMigrationCode[]> {
|
|
1861
1864
|
// console.log({ entityForeigns, dbForeigns });
|
|
1862
1865
|
|
|
1863
1866
|
const getKey = (mf: MigrationForeign): string => {
|
|
@@ -1913,7 +1916,7 @@ export class Migrator {
|
|
|
1913
1916
|
"}",
|
|
1914
1917
|
];
|
|
1915
1918
|
|
|
1916
|
-
const formatted = prettier.format(lines.join("\n"), {
|
|
1919
|
+
const formatted = await prettier.format(lines.join("\n"), {
|
|
1917
1920
|
parser: "typescript",
|
|
1918
1921
|
});
|
|
1919
1922
|
|
package/src/syncer/syncer.ts
CHANGED
|
@@ -121,7 +121,7 @@ export class Syncer {
|
|
|
121
121
|
models: { [modelName: string]: unknown } = {};
|
|
122
122
|
|
|
123
123
|
get checksumsPath(): string {
|
|
124
|
-
return path.join(Sonamu.apiRootPath, "/.
|
|
124
|
+
return path.join(Sonamu.apiRootPath, "/.so-checksum");
|
|
125
125
|
}
|
|
126
126
|
public constructor() {}
|
|
127
127
|
|
|
@@ -705,7 +705,12 @@ export class Syncer {
|
|
|
705
705
|
);
|
|
706
706
|
// console.debug(chalk.yellow(`autoload:models @ ${pathPattern}`));
|
|
707
707
|
|
|
708
|
-
const filePaths = await globAsync(pathPattern)
|
|
708
|
+
const filePaths = (await globAsync(pathPattern)).filter((path) => {
|
|
709
|
+
// src 디렉터리 내에 있는 해당 파일이 존재할 경우에만 로드
|
|
710
|
+
// 삭제된 파일이지만 dist에 남아있는 경우 BaseSchema undefined 에러 방지
|
|
711
|
+
const srcPath = path.replace("/dist/", "/src/").replace(".js", ".ts");
|
|
712
|
+
return existsSync(srcPath);
|
|
713
|
+
});
|
|
709
714
|
const modules = await importMultiple(filePaths);
|
|
710
715
|
const functions = modules
|
|
711
716
|
.map(({ imported }) => Object.entries(imported))
|
|
@@ -731,7 +736,14 @@ export class Syncer {
|
|
|
731
736
|
|
|
732
737
|
const filePaths = (
|
|
733
738
|
await Promise.all(pathPatterns.map((pattern) => globAsync(pattern)))
|
|
734
|
-
)
|
|
739
|
+
)
|
|
740
|
+
.flat()
|
|
741
|
+
.filter((path) => {
|
|
742
|
+
// src 디렉터리 내에 있는 해당 파일이 존재할 경우에만 로드
|
|
743
|
+
// 삭제된 파일이지만 dist에 남아있는 경우 BaseSchema undefined 에러 방지
|
|
744
|
+
const srcPath = path.replace("/dist/", "/src/").replace(".js", ".ts");
|
|
745
|
+
return existsSync(srcPath);
|
|
746
|
+
});
|
|
735
747
|
const modules = await importMultiple(filePaths, doRefresh);
|
|
736
748
|
const functions = modules
|
|
737
749
|
.map(({ imported }) => Object.entries(imported))
|
|
@@ -822,7 +834,7 @@ export class Syncer {
|
|
|
822
834
|
}
|
|
823
835
|
}
|
|
824
836
|
|
|
825
|
-
const rendered = template.render(options, ...extra);
|
|
837
|
+
const rendered = await template.render(options, ...extra);
|
|
826
838
|
const resolved = await this.resolveRenderedTemplate(key, rendered);
|
|
827
839
|
|
|
828
840
|
let preTemplateResolved: PathAndCode[] = [];
|
|
@@ -896,7 +908,7 @@ export class Syncer {
|
|
|
896
908
|
if (key === "generated_http") {
|
|
897
909
|
return [header, body].join("\n\n");
|
|
898
910
|
} else {
|
|
899
|
-
return
|
|
911
|
+
return prettier.format([header, body].join("\n\n"), {
|
|
900
912
|
parser: key === "entity" ? "json" : "typescript",
|
|
901
913
|
});
|
|
902
914
|
}
|
|
@@ -954,32 +966,17 @@ export class Syncer {
|
|
|
954
966
|
)
|
|
955
967
|
).flat();
|
|
956
968
|
|
|
957
|
-
/*
|
|
958
|
-
overwrite가 true일 때
|
|
959
|
-
- 생각하지 않고 그냥 다 덮어씀
|
|
960
|
-
overwrite가 false일 때
|
|
961
|
-
- 옵션1 (현재구현): 그냥 파일 하나라도 있으면 코드 생성 안함
|
|
962
|
-
- 옵션2 : 있는 파일은 전부 그대로 두고 없는 파일만 싹 생성함
|
|
963
|
-
- 옵션3 : 메인 파일만 그대로 두고, 파생 파일은 전부 생성함 => 이게 맞지 않나?
|
|
964
|
-
*/
|
|
965
|
-
|
|
966
969
|
const filteredPathAndCodes: PathAndCode[] = (() => {
|
|
967
970
|
if (generateOptions.overwrite === true) {
|
|
968
971
|
return pathAndCodes;
|
|
969
972
|
} else {
|
|
970
|
-
return pathAndCodes.filter((pathAndCode
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
return dstFilePaths.every(
|
|
978
|
-
(dstPath) => existsSync(dstPath) === false
|
|
979
|
-
);
|
|
980
|
-
} else {
|
|
981
|
-
return true;
|
|
982
|
-
}
|
|
973
|
+
return pathAndCodes.filter((pathAndCode) => {
|
|
974
|
+
const { targets } = Sonamu.config.sync;
|
|
975
|
+
const filePath = `${Sonamu.appRootPath}/${pathAndCode.path}`;
|
|
976
|
+
const dstFilePaths = targets.map((target) =>
|
|
977
|
+
filePath.replace("/:target/", `/${target}/`)
|
|
978
|
+
);
|
|
979
|
+
return dstFilePaths.every((dstPath) => existsSync(dstPath) === false);
|
|
983
980
|
});
|
|
984
981
|
}
|
|
985
982
|
})();
|
|
@@ -1026,32 +1023,38 @@ export class Syncer {
|
|
|
1026
1023
|
(name) => name !== names.constant
|
|
1027
1024
|
);
|
|
1028
1025
|
|
|
1029
|
-
return keys.reduce(
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1026
|
+
return keys.reduce(
|
|
1027
|
+
(result, key) => {
|
|
1028
|
+
const tpl = this.getTemplate(key);
|
|
1029
|
+
if (key.startsWith("view_enums")) {
|
|
1030
|
+
enumsKeys.map((componentId) => {
|
|
1031
|
+
const { target, path: p } = tpl.getTargetAndPath(
|
|
1032
|
+
names,
|
|
1033
|
+
componentId
|
|
1034
|
+
);
|
|
1035
|
+
result[`${key}__${componentId}`] = existsSync(
|
|
1036
|
+
path.join(Sonamu.appRootPath, target, p)
|
|
1037
|
+
);
|
|
1038
|
+
});
|
|
1039
|
+
return result;
|
|
1040
|
+
}
|
|
1040
1041
|
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1042
|
+
const { target, path: p } = tpl.getTargetAndPath(names);
|
|
1043
|
+
const { targets } = Sonamu.config.sync;
|
|
1044
|
+
if (target.includes(":target")) {
|
|
1045
|
+
targets.map((t) => {
|
|
1046
|
+
result[`${key}__${t}`] = existsSync(
|
|
1047
|
+
path.join(Sonamu.appRootPath, target.replace(":target", t), p)
|
|
1048
|
+
);
|
|
1049
|
+
});
|
|
1050
|
+
} else {
|
|
1051
|
+
result[key] = existsSync(path.join(Sonamu.appRootPath, target, p));
|
|
1052
|
+
}
|
|
1052
1053
|
|
|
1053
|
-
|
|
1054
|
-
|
|
1054
|
+
return result;
|
|
1055
|
+
},
|
|
1056
|
+
{} as Record<`${TemplateKey}${string}`, boolean>
|
|
1057
|
+
);
|
|
1055
1058
|
}
|
|
1056
1059
|
|
|
1057
1060
|
async getZodTypeById(zodTypeId: string): Promise<z.ZodTypeAny> {
|
|
@@ -1096,9 +1099,8 @@ export class Syncer {
|
|
|
1096
1099
|
const obj = await propNode.children.reduce(
|
|
1097
1100
|
async (promise, childPropNode) => {
|
|
1098
1101
|
const result = await promise;
|
|
1099
|
-
result[childPropNode.prop!.name] =
|
|
1100
|
-
childPropNode
|
|
1101
|
-
);
|
|
1102
|
+
result[childPropNode.prop!.name] =
|
|
1103
|
+
await this.propNodeToZodType(childPropNode);
|
|
1102
1104
|
return result;
|
|
1103
1105
|
},
|
|
1104
1106
|
{} as any
|
|
@@ -1332,10 +1334,8 @@ export class Syncer {
|
|
|
1332
1334
|
table?: string,
|
|
1333
1335
|
title?: string
|
|
1334
1336
|
) {
|
|
1335
|
-
if (
|
|
1336
|
-
throw new BadRequestException(
|
|
1337
|
-
"entityId는 자바스크립트 변수명 규칙을 따라야 합니다."
|
|
1338
|
-
);
|
|
1337
|
+
if (!/^[A-Z][a-zA-Z0-9]*$/.test(entityId)) {
|
|
1338
|
+
throw new BadRequestException("entityId는 CamelCase 형식이어야 합니다.");
|
|
1339
1339
|
}
|
|
1340
1340
|
|
|
1341
1341
|
await this.generateTemplate("entity", {
|
|
@@ -7,7 +7,7 @@ export abstract class Template {
|
|
|
7
7
|
public abstract render(
|
|
8
8
|
options: TemplateOptions[TemplateKey],
|
|
9
9
|
...extra: unknown[]
|
|
10
|
-
): RenderedTemplate
|
|
10
|
+
): RenderedTemplate | Promise<RenderedTemplate>;
|
|
11
11
|
|
|
12
12
|
public abstract getTargetAndPath(
|
|
13
13
|
names?: EntityNamesRecord,
|
|
@@ -21,7 +21,7 @@ export class Template__generated_http extends Template {
|
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
render({}: TemplateOptions["generated_http"]) {
|
|
24
|
+
async render({}: TemplateOptions["generated_http"]) {
|
|
25
25
|
const {
|
|
26
26
|
syncer: { types, apis },
|
|
27
27
|
config: {
|
|
@@ -29,42 +29,44 @@ export class Template__generated_http extends Template {
|
|
|
29
29
|
},
|
|
30
30
|
} = Sonamu;
|
|
31
31
|
|
|
32
|
-
const lines =
|
|
33
|
-
|
|
32
|
+
const lines = await Promise.all(
|
|
33
|
+
apis.map(async (api) => {
|
|
34
|
+
const reqObject = this.resolveApiParams(api, types);
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
36
|
+
const dataLines = await (async () => {
|
|
37
|
+
if ((api.options.httpMethod ?? "GET") === "GET") {
|
|
38
|
+
return {
|
|
39
|
+
querystring: [
|
|
40
|
+
qs
|
|
41
|
+
.stringify(reqObject, { encode: false })
|
|
42
|
+
.split("&")
|
|
43
|
+
.join("\n\t&"),
|
|
44
|
+
],
|
|
45
|
+
body: [],
|
|
46
|
+
};
|
|
47
|
+
} else {
|
|
48
|
+
return {
|
|
49
|
+
querystring: [],
|
|
50
|
+
body: [
|
|
51
|
+
"",
|
|
52
|
+
await prettier.format(JSON.stringify(reqObject), {
|
|
53
|
+
parser: "json",
|
|
54
|
+
}),
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
})();
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
return [
|
|
61
|
+
[
|
|
62
|
+
`${api.options.httpMethod ?? "GET"} {{baseUrl}}${prefix}${api.path}`,
|
|
63
|
+
...dataLines.querystring,
|
|
64
|
+
].join("\n\t?"),
|
|
65
|
+
`Content-Type: ${api.options.contentType ?? "application/json"}`,
|
|
66
|
+
...dataLines.body,
|
|
67
|
+
].join("\n");
|
|
68
|
+
})
|
|
69
|
+
);
|
|
68
70
|
|
|
69
71
|
return {
|
|
70
72
|
...this.getTargetAndPath(),
|