mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-28 14:06:00 +00:00
144 lines
4.5 KiB
TypeScript
144 lines
4.5 KiB
TypeScript
import _ from 'lodash';
|
|
import { dumpSqlSelect, Select, JoinType, Condition } from 'dbgate-sqltree';
|
|
import { EngineDriver } from 'dbgate-types';
|
|
import { DesignerInfo, DesignerTableInfo, DesignerReferenceInfo, DesignerJoinType } from './types';
|
|
|
|
function groupByComponents(
|
|
tables: DesignerTableInfo[],
|
|
references: DesignerReferenceInfo[],
|
|
joinTypes: string[],
|
|
primaryTable: DesignerTableInfo
|
|
) {
|
|
let components = tables.map((table) => [table]);
|
|
for (const ref of references) {
|
|
if (joinTypes.includes(ref.joinType)) {
|
|
const comp1 = components.find((comp) => comp.find((t) => t.designerId == ref.sourceId));
|
|
const comp2 = components.find((comp) => comp.find((t) => t.designerId == ref.targetId));
|
|
if (comp1 && comp2 && comp1 != comp2) {
|
|
// join components
|
|
components = [...components.filter((x) => x != comp1 && x != comp2), [...comp1, ...comp2]];
|
|
}
|
|
}
|
|
}
|
|
if (primaryTable) {
|
|
const primaryComponent = components.find((comp) => comp.find((t) => t == primaryTable));
|
|
if (primaryComponent) {
|
|
components = [primaryComponent, ...components.filter((x) => x != primaryComponent)];
|
|
}
|
|
}
|
|
return components;
|
|
}
|
|
|
|
function findPrimaryTable(tables: DesignerTableInfo[]) {
|
|
return _.minBy(tables, (x) => x.left + x.top);
|
|
}
|
|
|
|
function findJoinType(
|
|
table: DesignerTableInfo,
|
|
dumpedTables: DesignerTableInfo[],
|
|
references: DesignerReferenceInfo[],
|
|
joinTypes: DesignerJoinType[]
|
|
): DesignerJoinType {
|
|
const dumpedTableIds = dumpedTables.map((x) => x.designerId);
|
|
const reference = references.find(
|
|
(x) =>
|
|
(x.sourceId == table.designerId && dumpedTableIds.includes(x.targetId)) ||
|
|
(x.targetId == table.designerId && dumpedTableIds.includes(x.sourceId))
|
|
);
|
|
if (reference) return reference.joinType || 'CROSS JOIN';
|
|
return 'CROSS JOIN';
|
|
}
|
|
|
|
function findConditions(
|
|
table: DesignerTableInfo,
|
|
dumpedTables: DesignerTableInfo[],
|
|
references: DesignerReferenceInfo[],
|
|
tables: DesignerTableInfo[]
|
|
): Condition[] {
|
|
const dumpedTableIds = dumpedTables.map((x) => x.designerId);
|
|
const res = [];
|
|
for (const reference of references.filter(
|
|
(x) =>
|
|
(x.sourceId == table.designerId && dumpedTableIds.includes(x.targetId)) ||
|
|
(x.targetId == table.designerId && dumpedTableIds.includes(x.sourceId))
|
|
)) {
|
|
const sourceTable = tables.find((x) => x.designerId == reference.sourceId);
|
|
const targetTable = tables.find((x) => x.designerId == reference.targetId);
|
|
res.push(
|
|
...reference.columns.map((col) => ({
|
|
conditionType: 'binary',
|
|
operator: '=',
|
|
left: {
|
|
exprType: 'column',
|
|
columnName: col.source,
|
|
source: {
|
|
name: sourceTable,
|
|
alias: sourceTable.alias,
|
|
},
|
|
},
|
|
right: {
|
|
exprType: 'column',
|
|
columnName: col.target,
|
|
source: {
|
|
name: targetTable,
|
|
alias: targetTable.alias,
|
|
},
|
|
},
|
|
}))
|
|
);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
export default function generateDesignedQuery(designer: DesignerInfo, engine: EngineDriver) {
|
|
const { tables, columns, references } = designer;
|
|
const primaryTable = findPrimaryTable(designer.tables);
|
|
if (!primaryTable) return '';
|
|
const components = groupByComponents(
|
|
designer.tables,
|
|
designer.references,
|
|
['INNER JOIN', 'LEFT JOIN', 'RIGHT JOIN', 'FULL OUTER JOIN', 'WHERE EXISTS', 'WHERE NOT EXISTS'],
|
|
primaryTable
|
|
);
|
|
|
|
const select: Select = {
|
|
commandType: 'select',
|
|
from: {
|
|
name: primaryTable,
|
|
alias: primaryTable.alias,
|
|
relations: [],
|
|
},
|
|
};
|
|
|
|
const dumpedTables = [primaryTable];
|
|
for (const component of components) {
|
|
const subComponents = groupByComponents(
|
|
component,
|
|
designer.references,
|
|
['INNER JOIN', 'LEFT JOIN', 'RIGHT JOIN', 'FULL OUTER JOIN'],
|
|
primaryTable
|
|
);
|
|
for (const subComponent of subComponents) {
|
|
for (const table of subComponent) {
|
|
if (dumpedTables.includes(table)) continue;
|
|
select.from.relations.push({
|
|
name: table,
|
|
alias: table.alias,
|
|
joinType: findJoinType(table, dumpedTables, designer.references, [
|
|
'INNER JOIN',
|
|
'LEFT JOIN',
|
|
'RIGHT JOIN',
|
|
'FULL OUTER JOIN',
|
|
]) as JoinType,
|
|
conditions: findConditions(table, dumpedTables, designer.references, designer.tables),
|
|
});
|
|
dumpedTables.push(table);
|
|
}
|
|
}
|
|
}
|
|
|
|
const dmp = engine.createDumper();
|
|
dumpSqlSelect(dmp, select);
|
|
return dmp.s;
|
|
}
|