@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.
@@ -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
- // Process table-by-table to avoid exhausting DB connection pool (e.g. Cloud SQL limits)
110
- const data = (await Promise.all(tables.map((x) => Promise.all([
111
- getGetOneData(x, includeMappedFields, tables),
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, tables),
116
+ getPostOneData(x, specialCaseUuidColumn, includeMappedFields),
115
117
  getPatchOneData(x, specialCaseUuidColumn, includeMappedFields),
116
118
  getPatchListData(x),
117
119
  getDeleteOneData(x),
118
120
  getDeleteListData(x)
119
- ])))).flat();
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, tables) {
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, tables),
898
+ typeFields: await getTypeFields(table, typeFieldsName, includeMappedFields),
896
899
  typeFieldsName,
897
- typeReturnBase: await getTypeReturnBase(table, typeReturnBaseName, includeMappedFields, tables),
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, tables) {
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, tables),
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, tables) {
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, tables)).filter((x) => x.type === "one-to-many__many-to-one" && x.kind === "one-to-many");
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, tables) {
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, tables);
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, tables) {
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, tables);
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, tables);
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, tables) {
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
- const relationsManyToMany = (await getJunctionTables(tables)).reduce((acc, x) => {
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
- const getJunctionTables = (0, memoize_1.default)(async function getJunctionTables(tables) {
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@technicity/data-service-generator",
3
- "version": "0.23.0-next.13",
3
+ "version": "0.23.0-next.15",
4
4
  "main": "./dist/index.js",
5
5
  "files": [
6
6
  "dist"