@onn-software/ddl-to-gql
Version:
Convert a SQL DDL to a GraphQL implementation with all relations.
117 lines (116 loc) • 5.56 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.HeuristicEngine = void 0;
class HeuristicEngine {
execute(tableDefs, options) {
const flatTableDefs = this.flattenNames(tableDefs);
const suffixes = options.suffixes.map(s => s.toUpperCase());
const res = [];
const heuristics = {};
flatTableDefs.forEach((t) => (heuristics[t.tableName] = { tableName: t.tableName, columns: [], relations: [] }));
this.crossAllTableAndColumnDefinitions(flatTableDefs, (leftTable, leftCol, rightTable, rightCol) => {
const relationsByNameMatch = this.missingRelationByNameMatch(leftTable, leftCol, rightTable, rightCol, suffixes, options.heurEnableAll ?? false);
if (relationsByNameMatch) {
heuristics[leftTable.tableName].relations.push(relationsByNameMatch);
}
const relationsBySuffix = this.missingRelationBySuffix(leftTable, leftCol, rightTable, rightCol, suffixes, options.heurEnableAll ?? false);
if (relationsBySuffix) {
heuristics[leftTable.tableName].relations.push(relationsBySuffix);
}
});
return Object.values(heuristics);
}
flattenNames(tableDefs) {
const res = JSON.parse(JSON.stringify(tableDefs));
res.forEach((table) => {
table.flatTableName = table.tableName.replaceAll(/[^a-zA-Z0-9]/g, '').toUpperCase();
table.columns.forEach((col) => {
col.flatKeyName = col.key.replaceAll(/[^a-zA-Z0-9]/g, '').toUpperCase();
});
});
return res;
}
missingRelationByNameMatch(leftTableDef, leftCol, rightTableDef, rightCol, suffixes, heurEnableAll) {
const nameMatch = leftCol.flatKeyName === rightCol.flatKeyName;
const typeMatch = leftCol.type === rightCol.type;
const isSuffix = suffixes.indexOf(leftCol.flatKeyName) >= 0;
if (nameMatch && typeMatch && !isSuffix) {
return this.buildRelation(leftTableDef, leftCol, rightTableDef, rightCol, true, 'nameMatch', heurEnableAll);
}
return null;
}
missingRelationBySuffix(leftTableDef, leftCol, rightTableDef, rightCol, suffixes, heurEnableAll) {
if (leftCol.type !== rightCol.type) {
return null;
}
const leftSuffix = suffixes.find((suf) => leftCol.flatKeyName.endsWith(suf));
const rightSuffix = suffixes.find((suf) => rightCol.flatKeyName.endsWith(suf));
if (!leftSuffix || !rightSuffix) {
return null;
}
if (leftSuffix !== rightSuffix) {
return null;
}
const leftSuffixIndex = leftCol.flatKeyName.indexOf(leftSuffix);
const rightSuffixIndex = rightCol.flatKeyName.indexOf(rightSuffix);
const leftEndsWithSuffix = leftSuffixIndex > 0;
const leftIsSuffix = leftSuffixIndex == 0;
const rightEndsWithSuffix = rightSuffixIndex > 0;
const rightIsSuffix = rightSuffixIndex == 0;
if (!((leftEndsWithSuffix && rightIsSuffix) || (rightEndsWithSuffix && leftIsSuffix))) {
return null;
}
const leftFlatKey = leftCol.flatKeyName.substring(0, leftSuffixIndex) || leftCol.flatKeyName;
const rightFlatKey = rightCol.flatKeyName.substring(0, rightSuffixIndex) || rightCol.flatKeyName;
if (leftTableDef.flatTableName !== rightFlatKey &&
leftTableDef.flatTableName !== `${rightFlatKey}S` &&
rightTableDef.flatTableName !== leftFlatKey &&
rightTableDef.flatTableName !== `${leftFlatKey}S`) {
return null;
}
return this.buildRelation(leftTableDef, leftCol, rightTableDef, rightCol, leftIsSuffix, 'suffixMatch', heurEnableAll);
}
buildRelation(leftTableDef, leftCol, rightTableDef, rightCol, many, type, heurEnableAll) {
const relationsAlreadyExists = leftTableDef.relations.findIndex((value) => {
return ((value.from.table === leftTableDef.tableName &&
value.from.key === leftCol.key &&
value.to.table === rightTableDef.tableName &&
value.to.key === rightCol.key) ||
(value.to.table === leftTableDef.tableName &&
value.to.key === leftCol.key &&
value.from.table === rightTableDef.tableName &&
value.from.key === rightCol.key));
}) >= 0;
if (!relationsAlreadyExists) {
return {
from: {
table: leftTableDef.tableName,
key: leftCol.key,
},
to: {
table: rightTableDef.tableName,
key: rightCol.key,
},
many,
type,
enabled: heurEnableAll,
nullable: !many,
};
}
return null;
}
crossAllTableAndColumnDefinitions(flatTableDefs, block) {
flatTableDefs.forEach((leftTableDef) => {
leftTableDef.columns.forEach((leftCol) => {
flatTableDefs.forEach((rightTableDef) => {
if (rightTableDef.flatTableName !== leftTableDef.flatTableName) {
rightTableDef.columns.forEach((rightCol) => {
block(leftTableDef, leftCol, rightTableDef, rightCol);
});
}
});
});
});
}
}
exports.HeuristicEngine = HeuristicEngine;