dbgate/packages/web/src/designer/designerTools.ts
2024-08-19 12:49:26 +02:00

147 lines
4.7 KiB
TypeScript

import _ from 'lodash';
import type { Select, Condition, Source } from 'dbgate-sqltree';
import { dumpSqlSelect, mergeConditions } from 'dbgate-sqltree';
import type { EngineDriver } from 'dbgate-types';
import type { DesignerInfo, DesignerTableInfo, DesignerReferenceInfo, DesignerJoinType } from './types';
import { DesignerComponentCreator } from './DesignerComponentCreator';
import { DesignerQueryDumper } from './DesignerQueryDumper';
import { detectSqlFilterBehaviour } from 'dbgate-tools';
export function referenceIsConnecting(
reference: DesignerReferenceInfo,
tables1: DesignerTableInfo[],
tables2: DesignerTableInfo[]
) {
return (
(tables1.find(x => x.designerId == reference.sourceId) && tables2.find(x => x.designerId == reference.targetId)) ||
(tables1.find(x => x.designerId == reference.targetId) && tables2.find(x => x.designerId == reference.sourceId))
);
}
export function referenceIsJoin(reference) {
return ['INNER JOIN', 'LEFT JOIN', 'RIGHT JOIN', 'FULL OUTER JOIN'].includes(reference.joinType);
}
export function referenceIsExists(reference) {
return ['WHERE EXISTS', 'WHERE NOT EXISTS'].includes(reference.joinType);
}
export function referenceIsCrossJoin(reference) {
return !reference.joinType || reference.joinType == 'CROSS JOIN';
}
export function findConnectingReference(
designer: DesignerInfo,
tables1: DesignerTableInfo[],
tables2: DesignerTableInfo[],
additionalCondition: (ref: DesignerReferenceInfo) => boolean
) {
for (const ref of designer.references || []) {
if (additionalCondition(ref) && referenceIsConnecting(ref, tables1, tables2)) {
return ref;
}
}
return null;
}
export function findQuerySource(designer: DesignerInfo, designerId: string): Source {
const table = designer.tables.find(x => x.designerId == designerId);
if (!table) return null;
return {
name: table,
alias: table.alias,
};
}
export function mergeSelectsFromDesigner(select1: Select, select2: Select): Select {
return {
commandType: 'select',
from: {
...select1.from,
relations: [
...select1.from.relations,
{
joinType: 'CROSS JOIN',
name: select2.from.name,
alias: select2.from.alias,
},
...select2.from.relations,
],
},
where: mergeConditions(select1.where, select2.where),
};
}
export function findPrimaryTable(tables: DesignerTableInfo[]) {
return _.minBy(tables, x => x.top);
}
export function getReferenceConditions(reference: DesignerReferenceInfo, designer: DesignerInfo): Condition[] {
const sourceTable = designer.tables.find(x => x.designerId == reference.sourceId);
const targetTable = designer.tables.find(x => x.designerId == reference.targetId);
return 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,
},
},
}));
}
export function generateDesignedQuery(designer: DesignerInfo, engine: EngineDriver) {
const { tables, columns, references } = designer;
const primaryTable = findPrimaryTable(designer.tables);
if (!primaryTable) return '';
const componentCreator = new DesignerComponentCreator(designer);
const designerDumper = new DesignerQueryDumper(designer, componentCreator.components);
const select = designerDumper.run();
select.distinct = !!designer?.settings?.isDistinct;
const dmp = engine.createDumper();
dumpSqlSelect(dmp, select);
return dmp.s;
}
export function isConnectedByReference(
designer: DesignerInfo,
table1: { designerId: string },
table2: { designerId: string },
withoutRef: { designerId: string }
) {
if (!designer.references) return false;
const creator = new DesignerComponentCreator({
...designer,
references: withoutRef
? designer.references.filter(x => x.designerId != withoutRef.designerId)
: designer.references,
});
const arrays = creator.components.map(x => x.thisAndSubComponentsTables);
const array1 = arrays.find(a => a.find(x => x.designerId == table1.designerId));
const array2 = arrays.find(a => a.find(x => x.designerId == table2.designerId));
return array1 == array2;
}
export function findDesignerFilterBehaviour({ designerId, columnName }, designer) {
const table = (designer.tables || []).find(x => x.designerId == designerId);
if (table) {
const column = (table.columns || []).find(x => x.columnName == columnName);
if (column) {
const { dataType } = column;
return detectSqlFilterBehaviour(dataType);
}
}
return 'string';
}