@technicity/data-service-generator 0.23.0-next.13 → 0.23.0-next.15
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/generation/generate.js +98 -20
- package/package.json +1 -1
|
@@ -106,17 +106,19 @@ async function generate(input) {
|
|
|
106
106
|
tables = tables.filter((x) => !input.excludeTables?.includes(x));
|
|
107
107
|
}
|
|
108
108
|
ctx.log.debug({ tableCount: tables.length, tables }, "tables after filter");
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
ctx.log.debug("getJunctionTables() warming cache (used by getRelationInfo)");
|
|
110
|
+
await getJunctionTables();
|
|
111
|
+
ctx.log.debug("getJunctionTables() cache warmed");
|
|
112
|
+
const data = await Promise.all(tables.flatMap((x) => [
|
|
113
|
+
getGetOneData(x, includeMappedFields),
|
|
112
114
|
getGetListData(x),
|
|
113
115
|
getGetListPaginatedData(x),
|
|
114
|
-
getPostOneData(x, specialCaseUuidColumn, includeMappedFields
|
|
116
|
+
getPostOneData(x, specialCaseUuidColumn, includeMappedFields),
|
|
115
117
|
getPatchOneData(x, specialCaseUuidColumn, includeMappedFields),
|
|
116
118
|
getPatchListData(x),
|
|
117
119
|
getDeleteOneData(x),
|
|
118
120
|
getDeleteListData(x)
|
|
119
|
-
]))
|
|
121
|
+
]));
|
|
120
122
|
ctx.log.debug({ inputLength: data.length }, "SDK input data collected");
|
|
121
123
|
const artifacts = await getArtifacts(tables, includeMappedFields, specialCaseUuidColumn);
|
|
122
124
|
ctx.log.debug("getArtifacts() completed");
|
|
@@ -885,20 +887,22 @@ function getTypeOrderByName(table) {
|
|
|
885
887
|
function getTypeDataPostName(table) {
|
|
886
888
|
return "DataPost" + changeCase.pascalCase(table);
|
|
887
889
|
}
|
|
888
|
-
async function getGetOneData(table, includeMappedFields
|
|
890
|
+
async function getGetOneData(table, includeMappedFields) {
|
|
891
|
+
getCtx().log.debug({ table }, "getGetOneData() start");
|
|
889
892
|
const typeFieldsName = getTypeFieldsName(table);
|
|
890
893
|
const typeReturnBaseName = getTypeReturnBaseName(table);
|
|
891
894
|
return {
|
|
892
895
|
kind: "getOne",
|
|
893
896
|
table,
|
|
894
897
|
methodName: "get" + changeCase.pascalCase(table),
|
|
895
|
-
typeFields: await getTypeFields(table, typeFieldsName, includeMappedFields
|
|
898
|
+
typeFields: await getTypeFields(table, typeFieldsName, includeMappedFields),
|
|
896
899
|
typeFieldsName,
|
|
897
|
-
typeReturnBase: await getTypeReturnBase(table, typeReturnBaseName, includeMappedFields
|
|
900
|
+
typeReturnBase: await getTypeReturnBase(table, typeReturnBaseName, includeMappedFields),
|
|
898
901
|
typeReturnBaseName
|
|
899
902
|
};
|
|
900
903
|
}
|
|
901
904
|
async function getGetListData(table) {
|
|
905
|
+
getCtx().log.debug({ table }, "getGetListData() start");
|
|
902
906
|
const typeFieldsName = getTypeFieldsName(table);
|
|
903
907
|
const typeReturnBaseName = getTypeReturnBaseName(table);
|
|
904
908
|
const typeWhereName = getTypeWhereName(table);
|
|
@@ -918,6 +922,7 @@ async function getGetListData(table) {
|
|
|
918
922
|
};
|
|
919
923
|
}
|
|
920
924
|
async function getGetListPaginatedData(table) {
|
|
925
|
+
getCtx().log.debug({ table }, "getGetListPaginatedData() start");
|
|
921
926
|
const typeFieldsName = getTypeFieldsName(table);
|
|
922
927
|
const typeReturnBaseName = getTypeReturnBaseName(table);
|
|
923
928
|
const typeWhereName = getTypeWhereName(table);
|
|
@@ -932,7 +937,8 @@ async function getGetListPaginatedData(table) {
|
|
|
932
937
|
typeOrderByName
|
|
933
938
|
};
|
|
934
939
|
}
|
|
935
|
-
async function getPostOneData(table, specialCaseUuidColumn, includeMappedFields
|
|
940
|
+
async function getPostOneData(table, specialCaseUuidColumn, includeMappedFields) {
|
|
941
|
+
getCtx().log.debug({ table }, "getPostOneData() start");
|
|
936
942
|
const typeFieldsName = getTypeFieldsName(table);
|
|
937
943
|
const typeReturnBaseName = getTypeReturnBaseName(table);
|
|
938
944
|
const typeDataName = getTypeDataPostName(table);
|
|
@@ -942,11 +948,12 @@ async function getPostOneData(table, specialCaseUuidColumn, includeMappedFields,
|
|
|
942
948
|
methodName: "post" + changeCase.pascalCase(table),
|
|
943
949
|
typeFieldsName,
|
|
944
950
|
typeReturnBaseName,
|
|
945
|
-
typeData: await getTypeDataPost(table, typeDataName, specialCaseUuidColumn, includeMappedFields
|
|
951
|
+
typeData: await getTypeDataPost(table, typeDataName, specialCaseUuidColumn, includeMappedFields),
|
|
946
952
|
typeDataName
|
|
947
953
|
};
|
|
948
954
|
}
|
|
949
955
|
async function getPatchOneData(table, specialCaseUuidColumn, includeMappedFields) {
|
|
956
|
+
getCtx().log.debug({ table }, "getPatchOneData() start");
|
|
950
957
|
const typeFieldsName = getTypeFieldsName(table);
|
|
951
958
|
const typeReturnBaseName = getTypeReturnBaseName(table);
|
|
952
959
|
const typeDataName = "DataPatch" + changeCase.pascalCase(table);
|
|
@@ -961,6 +968,7 @@ async function getPatchOneData(table, specialCaseUuidColumn, includeMappedFields
|
|
|
961
968
|
};
|
|
962
969
|
}
|
|
963
970
|
async function getPatchListData(table) {
|
|
971
|
+
getCtx().log.debug({ table }, "getPatchListData() start");
|
|
964
972
|
const typeFieldsName = getTypeFieldsName(table);
|
|
965
973
|
const typeReturnBaseName = getTypeReturnBaseName(table);
|
|
966
974
|
const typeWhereName = getTypeWhereName(table);
|
|
@@ -978,6 +986,7 @@ async function getPatchListData(table) {
|
|
|
978
986
|
};
|
|
979
987
|
}
|
|
980
988
|
function getDeleteOneData(table) {
|
|
989
|
+
getCtx().log.debug({ table }, "getDeleteOneData() start");
|
|
981
990
|
return {
|
|
982
991
|
kind: "deleteOne",
|
|
983
992
|
table,
|
|
@@ -985,6 +994,7 @@ function getDeleteOneData(table) {
|
|
|
985
994
|
};
|
|
986
995
|
}
|
|
987
996
|
function getDeleteListData(table) {
|
|
997
|
+
getCtx().log.debug({ table }, "getDeleteListData() start");
|
|
988
998
|
const typeWhereName = getTypeWhereName(table);
|
|
989
999
|
return {
|
|
990
1000
|
kind: "deleteList",
|
|
@@ -994,10 +1004,12 @@ function getDeleteListData(table) {
|
|
|
994
1004
|
};
|
|
995
1005
|
}
|
|
996
1006
|
async function getTypeWhere(table, name) {
|
|
1007
|
+
getCtx().log.debug({ table, name }, "getTypeWhere() start");
|
|
997
1008
|
const jsonSchemaWhere = await getJSONSchemaWhere(table);
|
|
998
1009
|
return (0, json_schema_to_typescript_1.compile)(jsonSchemaWhere, name, json2TsOpts);
|
|
999
1010
|
}
|
|
1000
|
-
async function getTypeDataPost(table, name, specialCaseUuidColumn, includeMappedFields
|
|
1011
|
+
async function getTypeDataPost(table, name, specialCaseUuidColumn, includeMappedFields) {
|
|
1012
|
+
getCtx().log.debug({ table, name }, "getTypeDataPost() start");
|
|
1001
1013
|
const primaryColumn = await getPrimaryColumn(table);
|
|
1002
1014
|
const tableMeta = (await getTableMeta(table)).filter((x) => x.Field !== primaryColumn.name);
|
|
1003
1015
|
const nullable = tableMeta.reduce((acc, m) => ({
|
|
@@ -1010,7 +1022,7 @@ async function getTypeDataPost(table, name, specialCaseUuidColumn, includeMapped
|
|
|
1010
1022
|
}), {});
|
|
1011
1023
|
let properties = getJSONSchemaObjProperties(tableMeta);
|
|
1012
1024
|
let notRequiredList = [];
|
|
1013
|
-
const oneToManyRelations = (await getRelationInfo(table
|
|
1025
|
+
const oneToManyRelations = (await getRelationInfo(table)).filter((x) => x.type === "one-to-many__many-to-one" && x.kind === "one-to-many");
|
|
1014
1026
|
const mappedFields = includeMappedFields ? await getMappedFields(table) : [];
|
|
1015
1027
|
let mappedFieldsMap = new Map();
|
|
1016
1028
|
if (includeMappedFields) {
|
|
@@ -1068,6 +1080,7 @@ async function getTypeDataPost(table, name, specialCaseUuidColumn, includeMapped
|
|
|
1068
1080
|
return type;
|
|
1069
1081
|
}
|
|
1070
1082
|
async function getTypeDataPatch(table, name, specialCaseUuidColumn, includeMappedFields) {
|
|
1083
|
+
getCtx().log.debug({ table, name }, "getTypeDataPatch() start");
|
|
1071
1084
|
const primaryColumn = await getPrimaryColumn(table);
|
|
1072
1085
|
let tableMeta = (await getTableMeta(table)).filter((x) => x.Field !== primaryColumn.name);
|
|
1073
1086
|
if (specialCaseUuidColumn) {
|
|
@@ -1134,6 +1147,7 @@ function unwrapJSONType(type) {
|
|
|
1134
1147
|
return type;
|
|
1135
1148
|
}
|
|
1136
1149
|
async function getMappedFields(table) {
|
|
1150
|
+
getCtx().log.debug({ table }, "getMappedFields() start");
|
|
1137
1151
|
const relationsManyToOne = await getRelationsManyToOne(table).then((xs) => xs.filter((x) => x.foreignKey.endsWith("Id")));
|
|
1138
1152
|
let out = [];
|
|
1139
1153
|
for (let x of relationsManyToOne) {
|
|
@@ -1157,6 +1171,7 @@ async function getMappedFields(table) {
|
|
|
1157
1171
|
return out;
|
|
1158
1172
|
}
|
|
1159
1173
|
async function getJSONSchemaWhere(table) {
|
|
1174
|
+
getCtx().log.debug({ table }, "getJSONSchemaWhere() start");
|
|
1160
1175
|
const whereSchemaName = `_Where${changeCase.pascalCase(table)}`;
|
|
1161
1176
|
const defWhere = {
|
|
1162
1177
|
oneOf: [
|
|
@@ -1310,9 +1325,11 @@ async function getJSONSchemaWhere(table) {
|
|
|
1310
1325
|
};
|
|
1311
1326
|
}
|
|
1312
1327
|
async function getTypeOrderBy(table, name) {
|
|
1328
|
+
getCtx().log.debug({ table, name }, "getTypeOrderBy() start");
|
|
1313
1329
|
return (0, json_schema_to_typescript_1.compile)((await getJSONSchemaOrderBy(table, name)), name, json2TsOpts);
|
|
1314
1330
|
}
|
|
1315
1331
|
async function getJSONSchemaOrderBy(table, name) {
|
|
1332
|
+
getCtx().log.debug({ table, name }, "getJSONSchemaOrderBy() start");
|
|
1316
1333
|
const fieldNames = await getTableMeta(table).then((xs) => xs.map((x) => x.Field));
|
|
1317
1334
|
const def = {
|
|
1318
1335
|
oneOf: fieldNames.map((k) => ({
|
|
@@ -1391,9 +1408,10 @@ export type TUpdateOperationsNumber = {$increment: number} | {$decrement: number
|
|
|
1391
1408
|
`;
|
|
1392
1409
|
return prettier.format(src, { parser: "typescript" });
|
|
1393
1410
|
}
|
|
1394
|
-
async function getTypeFields(table, name, includeMappedFields
|
|
1411
|
+
async function getTypeFields(table, name, includeMappedFields) {
|
|
1412
|
+
getCtx().log.debug({ table, name }, "getTypeFields() start");
|
|
1395
1413
|
const scalarKeys = Object.keys(getJSONSchemaObjProperties(await getTableMeta(table)));
|
|
1396
|
-
const relations = await getRelationInfo(table
|
|
1414
|
+
const relations = await getRelationInfo(table);
|
|
1397
1415
|
const mappedFields = includeMappedFields ? await getMappedFields(table) : [];
|
|
1398
1416
|
const keyWhere = "$where";
|
|
1399
1417
|
const keyOrderBy = "$orderBy";
|
|
@@ -1453,10 +1471,11 @@ async function getTypeFields(table, name, includeMappedFields, tables) {
|
|
|
1453
1471
|
type = imports + "\n\n" + type;
|
|
1454
1472
|
return type;
|
|
1455
1473
|
}
|
|
1456
|
-
async function getTypeReturnBase(table, name, includeMappedFields
|
|
1474
|
+
async function getTypeReturnBase(table, name, includeMappedFields) {
|
|
1475
|
+
getCtx().log.debug({ table, name }, "getTypeReturnBase() start");
|
|
1457
1476
|
const tableMeta = await getTableMeta(table);
|
|
1458
1477
|
const scalarProperties = getJSONSchemaObjProperties(tableMeta);
|
|
1459
|
-
const relations = await getRelationInfo(table
|
|
1478
|
+
const relations = await getRelationInfo(table);
|
|
1460
1479
|
const mappedFields = includeMappedFields ? await getMappedFields(table) : [];
|
|
1461
1480
|
const jsonSchemaReturn = {
|
|
1462
1481
|
type: "object",
|
|
@@ -1515,7 +1534,7 @@ async function getArtifacts(tables, includeMappedFields, specialCaseUuidColumn)
|
|
|
1515
1534
|
getShowCreateTable(table)
|
|
1516
1535
|
]);
|
|
1517
1536
|
const scalarFields = tableMeta.map((x) => x.Field);
|
|
1518
|
-
const relationInfo = await getRelationInfo(table
|
|
1537
|
+
const relationInfo = await getRelationInfo(table);
|
|
1519
1538
|
const relationFields = relationInfo.reduce((acc, x) => {
|
|
1520
1539
|
if (x.type === "one-to-many__many-to-one") {
|
|
1521
1540
|
acc[x.name] = {
|
|
@@ -1618,9 +1637,13 @@ async function getArtifacts(tables, includeMappedFields, specialCaseUuidColumn)
|
|
|
1618
1637
|
}, {});
|
|
1619
1638
|
return artifacts;
|
|
1620
1639
|
}
|
|
1621
|
-
const getRelationInfo = (0, memoize_1.default)(async function getRelationInfo(table
|
|
1640
|
+
const getRelationInfo = (0, memoize_1.default)(async function getRelationInfo(table) {
|
|
1641
|
+
const ctx = getCtx();
|
|
1642
|
+
ctx.log.debug({ table }, "getRelationInfo() start");
|
|
1622
1643
|
const relationsManyToOne = await getRelationsManyToOne(table);
|
|
1644
|
+
ctx.log.debug({ table, count: relationsManyToOne.length }, "getRelationInfo() getRelationsManyToOne done");
|
|
1623
1645
|
const relationsOneToMany = await getRelationsOneToMany(table);
|
|
1646
|
+
ctx.log.debug({ table, count: relationsOneToMany.length }, "getRelationInfo() getRelationsOneToMany done");
|
|
1624
1647
|
let out = [];
|
|
1625
1648
|
out = out.concat(relationsManyToOne.reduce((acc, x) => {
|
|
1626
1649
|
if (!x.foreignKey.endsWith("Id")) {
|
|
@@ -1638,6 +1661,7 @@ const getRelationInfo = (0, memoize_1.default)(async function getRelationInfo(ta
|
|
|
1638
1661
|
});
|
|
1639
1662
|
return acc;
|
|
1640
1663
|
}, []));
|
|
1664
|
+
ctx.log.debug({ table, manyToOneOutCount: out.length }, "getRelationInfo() many-to-one concat done");
|
|
1641
1665
|
const relationsOneToManyDuplicates = (0, getDuplicates_1.getDuplicates)(relationsOneToMany.map((x) => x.referencedTable));
|
|
1642
1666
|
out = out.concat(relationsOneToMany.reduce((acc, x) => {
|
|
1643
1667
|
if (!x.referencedKey.endsWith("Id")) {
|
|
@@ -1665,7 +1689,11 @@ const getRelationInfo = (0, memoize_1.default)(async function getRelationInfo(ta
|
|
|
1665
1689
|
});
|
|
1666
1690
|
return acc;
|
|
1667
1691
|
}, []));
|
|
1668
|
-
|
|
1692
|
+
ctx.log.debug({ table, afterOneToManyCount: out.length }, "getRelationInfo() one-to-many concat done");
|
|
1693
|
+
ctx.log.debug({ table }, "getRelationInfo() getJunctionTables() calling");
|
|
1694
|
+
const junctionTables = await getJunctionTables();
|
|
1695
|
+
ctx.log.debug({ table, junctionTableCount: junctionTables.length }, "getRelationInfo() getJunctionTables() done");
|
|
1696
|
+
const relationsManyToMany = junctionTables.reduce((acc, x) => {
|
|
1669
1697
|
const dataForParentTable = x.relations.find((r) => r.referencedTable === table);
|
|
1670
1698
|
if (dataForParentTable == null) {
|
|
1671
1699
|
return acc;
|
|
@@ -1685,15 +1713,62 @@ const getRelationInfo = (0, memoize_1.default)(async function getRelationInfo(ta
|
|
|
1685
1713
|
});
|
|
1686
1714
|
return acc;
|
|
1687
1715
|
}, []);
|
|
1716
|
+
ctx.log.debug({ table, manyToManyCount: relationsManyToMany.length }, "getRelationInfo() many-to-many reduce done");
|
|
1688
1717
|
out = out.concat(relationsManyToMany);
|
|
1689
1718
|
out = _.sortBy([(x) => x.table, (x) => x.name], out);
|
|
1719
|
+
ctx.log.debug({ table, totalCount: out.length }, "getRelationInfo() done");
|
|
1690
1720
|
return out;
|
|
1691
1721
|
}, (table) => getCtx().runId + ":" + table);
|
|
1692
1722
|
function getRelationManyToOneFieldName(x) {
|
|
1693
1723
|
return changeCase.camelCase(x.foreignKey.replace(new RegExp(x.referencedKey + "$", "i"), ""));
|
|
1694
1724
|
}
|
|
1695
1725
|
// TODO: not sure if this logic is correct
|
|
1696
|
-
|
|
1726
|
+
// Note: intentionally not the filtered tables
|
|
1727
|
+
const getJunctionTables = (0, memoize_1.default)(async function getJunctionTables() {
|
|
1728
|
+
const { dialect, query } = getCtx();
|
|
1729
|
+
if (dialect === "postgresql") {
|
|
1730
|
+
// Single bulk query instead of getRelationsManyToOne(table) per table (avoids N-way pool contention)
|
|
1731
|
+
const rows = await query(`SELECT kcu.table_name AS t1, kcu.column_name AS "t1Field",
|
|
1732
|
+
ccu.table_name AS t2, ccu.column_name AS "t2Field",
|
|
1733
|
+
col.is_nullable
|
|
1734
|
+
FROM information_schema.key_column_usage kcu
|
|
1735
|
+
JOIN information_schema.referential_constraints rc ON kcu.constraint_name = rc.constraint_name AND kcu.table_schema = rc.constraint_schema
|
|
1736
|
+
JOIN information_schema.constraint_column_usage ccu ON rc.unique_constraint_name = ccu.constraint_name AND rc.unique_constraint_schema = ccu.table_schema
|
|
1737
|
+
LEFT JOIN information_schema.columns col ON col.table_schema = kcu.table_schema AND col.table_name = kcu.table_name AND col.column_name = kcu.column_name
|
|
1738
|
+
WHERE kcu.table_schema = 'public'
|
|
1739
|
+
ORDER BY kcu.table_name, ccu.table_name, ccu.column_name`);
|
|
1740
|
+
const byTable = new Map();
|
|
1741
|
+
for (const r of rows) {
|
|
1742
|
+
const list = byTable.get(r.t1) ?? [];
|
|
1743
|
+
list.push({
|
|
1744
|
+
t1Field: r.t1Field,
|
|
1745
|
+
t2: r.t2,
|
|
1746
|
+
t2Field: r.t2Field,
|
|
1747
|
+
nullable: r.is_nullable === "YES"
|
|
1748
|
+
});
|
|
1749
|
+
byTable.set(r.t1, list);
|
|
1750
|
+
}
|
|
1751
|
+
const result = [];
|
|
1752
|
+
for (const [table, fks] of byTable) {
|
|
1753
|
+
if (fks.length === 2 &&
|
|
1754
|
+
fks[0].t2 !== fks[1].t2 &&
|
|
1755
|
+
[
|
|
1756
|
+
fks[0].t2 + fks[1].t2,
|
|
1757
|
+
fks[1].t2 + fks[0].t2
|
|
1758
|
+
].includes(table)) {
|
|
1759
|
+
const relations = _.sortBy([(x) => x.referencedTable, (x) => x.referencedKey, (x) => x.foreignKey], fks.map((f) => ({
|
|
1760
|
+
table,
|
|
1761
|
+
foreignKey: f.t1Field,
|
|
1762
|
+
referencedTable: f.t2,
|
|
1763
|
+
referencedKey: f.t2Field,
|
|
1764
|
+
nullable: f.nullable
|
|
1765
|
+
})));
|
|
1766
|
+
result.push({ table, relations });
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
return result;
|
|
1770
|
+
}
|
|
1771
|
+
const tables = await getTableNames();
|
|
1697
1772
|
return (await Promise.all(tables.map(async (table) => {
|
|
1698
1773
|
const relations = await getRelationsManyToOne(table);
|
|
1699
1774
|
if (relations.length === 2 &&
|
|
@@ -1711,6 +1786,7 @@ const getJunctionTables = (0, memoize_1.default)(async function getJunctionTable
|
|
|
1711
1786
|
// `from` relations
|
|
1712
1787
|
// https://stackoverflow.com/a/54732547
|
|
1713
1788
|
const getRelationsManyToOne = (0, memoize_1.default)(async function getRelationsManyToOne(table) {
|
|
1789
|
+
getCtx().log.debug({ table }, "getRelationsManyToOne() start");
|
|
1714
1790
|
const { dialect, query } = getCtx();
|
|
1715
1791
|
const tableMeta = await getTableMeta(table);
|
|
1716
1792
|
let rs;
|
|
@@ -1756,6 +1832,7 @@ const getRelationsManyToOne = (0, memoize_1.default)(async function getRelations
|
|
|
1756
1832
|
}, (table) => getCtx().runId + ":" + table);
|
|
1757
1833
|
// `to` relations
|
|
1758
1834
|
const getRelationsOneToMany = (0, memoize_1.default)(async function getRelationsOneToMany(table) {
|
|
1835
|
+
getCtx().log.debug({ table }, "getRelationsOneToMany() start");
|
|
1759
1836
|
const { dialect, query } = getCtx();
|
|
1760
1837
|
let rs;
|
|
1761
1838
|
if (dialect === "mysql") {
|
|
@@ -1799,6 +1876,7 @@ const getRelationsOneToMany = (0, memoize_1.default)(async function getRelations
|
|
|
1799
1876
|
return _.sortBy([(x) => x.referencedTable, (x) => x.referencedKey, (x) => x.foreignKey], xs);
|
|
1800
1877
|
}, (table) => getCtx().runId + ":" + table);
|
|
1801
1878
|
async function getPrimaryColumn(table) {
|
|
1879
|
+
getCtx().log.debug({ table }, "getPrimaryColumn() start");
|
|
1802
1880
|
const tableMeta = await getTableMeta(table);
|
|
1803
1881
|
const columns = tableMeta.filter((x) => x.Key === "PRI");
|
|
1804
1882
|
if (columns.length !== 1) {
|