Files
dbgate/packages/datalib/src/TableGridDisplay.ts
2021-04-03 20:45:57 +02:00

233 lines
7.8 KiB
TypeScript

import _ from 'lodash';
import { GridDisplay, ChangeCacheFunc, DisplayColumn, DisplayedColumnInfo, ChangeConfigFunc } from './GridDisplay';
import { TableInfo, EngineDriver, ViewInfo, ColumnInfo, NamedObjectInfo, DatabaseInfo } from 'dbgate-types';
import { GridConfig, GridCache, createGridCache } from './GridConfig';
import { Expression, Select, treeToSql, dumpSqlSelect } from 'dbgate-sqltree';
import { filterName } from './filterName';
export class TableGridDisplay extends GridDisplay {
public table: TableInfo;
public addAllExpandedColumnsToSelected = false;
public hintBaseColumns: DisplayColumn[];
constructor(
public tableName: NamedObjectInfo,
driver: EngineDriver,
config: GridConfig,
setConfig: ChangeConfigFunc,
cache: GridCache,
setCache: ChangeCacheFunc,
dbinfo: DatabaseInfo
) {
super(config, setConfig, cache, setCache, driver, dbinfo);
this.table = this.findTable(tableName);
if (!this.table) {
this.isLoadedCorrectly = false;
} else {
if (!this.table.columns || this.table.columns.length == 0) {
this.isLoadedCorrectly = false;
}
}
this.columns = this.getDisplayColumns(this.table, []);
this.filterable = true;
this.sortable = true;
this.editable = true;
this.supportsReload = true;
this.baseTable = this.table;
if (this.table && this.table.columns) {
this.changeSetKeyFields = this.table.primaryKey
? this.table.primaryKey.columns.map(x => x.columnName)
: this.table.columns.map(x => x.columnName);
}
}
findTable({ schemaName = undefined, pureName }) {
return (
this.dbinfo &&
this.dbinfo.tables &&
this.dbinfo.tables.find(x => x.pureName == pureName && x.schemaName == schemaName)
);
}
getDisplayColumns(table: TableInfo, parentPath: string[]) {
return (
table?.columns
?.map(col => this.getDisplayColumn(table, col, parentPath))
?.map(col => ({
...col,
isChecked: this.isColumnChecked(col),
hintColumnName: col.foreignKey ? `hint_${col.uniqueName}` : null,
isExpandable: !!col.foreignKey,
})) || []
);
}
addJoinsFromExpandedColumns(select: Select, columns: DisplayColumn[], parentAlias: string, columnSources) {
for (const column of columns) {
if (this.isExpandedColumn(column.uniqueName)) {
const table = this.getFkTarget(column);
if (table) {
const childAlias = `${column.uniqueName}_ref`;
const subcolumns = this.getDisplayColumns(table, column.uniquePath);
this.addReferenceToSelect(select, parentAlias, column);
this.addJoinsFromExpandedColumns(select, subcolumns, childAlias, columnSources);
this.addAddedColumnsToSelect(select, subcolumns, childAlias, columnSources);
}
}
}
}
addReferenceToSelect(select: Select, parentAlias: string, column: DisplayColumn) {
const childAlias = `${column.uniqueName}_ref`;
if ((select.from.relations || []).find(x => x.alias == childAlias)) return;
const table = this.getFkTarget(column);
if (table && table.primaryKey) {
select.from.relations = [
...(select.from.relations || []),
{
joinType: 'LEFT JOIN',
name: table,
alias: childAlias,
conditions: [
{
conditionType: 'binary',
operator: '=',
left: {
exprType: 'column',
columnName: column.columnName,
source: { name: column, alias: parentAlias },
},
right: {
exprType: 'column',
columnName: table.primaryKey.columns[0].columnName,
source: { name: table, alias: childAlias },
},
},
],
},
];
}
}
addHintsToSelect(select: Select): boolean {
let res = false;
const groupColumns = this.groupColumns;
for (const column of this.hintBaseColumns || this.getGridColumns()) {
if (column.foreignKey) {
if (groupColumns && !groupColumns.includes(column.uniqueName)) {
continue;
}
const table = this.getFkTarget(column);
if (table && table.columns && table.columns.length > 0 && table.primaryKey) {
const hintColumn = table.columns.find(x => x?.dataType?.toLowerCase()?.includes('char'));
if (hintColumn) {
const parentUniqueName = column.uniquePath.slice(0, -1).join('.');
this.addReferenceToSelect(select, parentUniqueName ? `${parentUniqueName}_ref` : 'basetbl', column);
const childAlias = `${column.uniqueName}_ref`;
select.columns.push({
exprType: 'column',
columnName: hintColumn.columnName,
alias: `hint_${column.uniqueName}`,
source: { alias: childAlias },
});
res = true;
}
}
}
}
return res;
}
enrichExpandedColumns(list: DisplayColumn[]): DisplayColumn[] {
const res = [];
for (const item of list) {
res.push(item);
if (this.isExpandedColumn(item.uniqueName)) res.push(...this.getExpandedColumns(item));
}
return res;
}
getExpandedColumns(column: DisplayColumn) {
const table = this.getFkTarget(column);
if (table) {
return this.enrichExpandedColumns(this.getDisplayColumns(table, column.uniquePath));
}
return [];
}
getFkTarget(column: DisplayColumn) {
const { uniqueName, foreignKey } = column;
const pureName = foreignKey.refTableName;
const schemaName = foreignKey.refSchemaName;
return this.findTable({ schemaName, pureName });
}
processReferences(select: Select, displayedColumnInfo: DisplayedColumnInfo, options) {
this.addJoinsFromExpandedColumns(select, this.columns, 'basetbl', displayedColumnInfo);
if (!options.isExport) {
this.addHintsToSelect(select);
}
}
createSelect(options = {}) {
if (!this.table) return null;
const select = this.createSelectBase(this.table, this.table.columns, options);
return select;
}
getColumns(columnFilter) {
return this.enrichExpandedColumns(this.columns.filter(col => filterName(columnFilter, col.columnName)));
}
getDisplayColumn(table: TableInfo, col: ColumnInfo, parentPath: string[]) {
const uniquePath = [...parentPath, col.columnName];
const uniqueName = uniquePath.join('.');
// console.log('this.config.addedColumns', this.config.addedColumns, uniquePath);
return {
...col,
pureName: table.pureName,
schemaName: table.schemaName,
headerText: uniquePath.length == 1 ? col.columnName : `${table.pureName}.${col.columnName}`,
uniqueName,
uniquePath,
isPrimaryKey: table.primaryKey && !!table.primaryKey.columns.find(x => x.columnName == col.columnName),
foreignKey:
table.foreignKeys &&
table.foreignKeys.find(fk => fk.columns.length == 1 && fk.columns[0].columnName == col.columnName),
};
}
addAddedColumnsToSelect(
select: Select,
columns: DisplayColumn[],
parentAlias: string,
displayedColumnInfo: DisplayedColumnInfo
) {
for (const column of columns) {
if (this.addAllExpandedColumnsToSelected || this.config.addedColumns.includes(column.uniqueName)) {
select.columns.push({
exprType: 'column',
columnName: column.columnName,
alias: column.uniqueName,
source: { name: column, alias: parentAlias },
});
displayedColumnInfo[column.uniqueName] = {
...column,
sourceAlias: parentAlias,
};
}
}
}
get hasReferences() {
if (!this.table) return false;
if (this.table.foreignKeys && this.table.foreignKeys.length > 0) return true;
if (this.table.dependencies && this.table.dependencies.length > 0) return true;
return false;
}
}