configurable dictionary description

This commit is contained in:
Jan Prochazka
2021-11-13 12:41:18 +01:00
parent 1f821fc654
commit 52e8831bcc
8 changed files with 90 additions and 33 deletions

View File

@@ -29,7 +29,7 @@ export interface DisplayColumn {
foreignKey?: ForeignKeyInfo;
isExpandable?: boolean;
isChecked?: boolean;
hintColumnName?: string;
hintColumnNames?: string[];
dataType?: string;
filterType?: boolean;
isStructured?: boolean;

View File

@@ -15,6 +15,7 @@ import {
import { TableGridDisplay } from './TableGridDisplay';
import stableStringify from 'json-stable-stringify';
import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet';
import { DictionaryDescriptionFunc } from '.';
export class TableFormViewDisplay extends FormViewDisplay {
// use utility functions from GridDisplay and publish result in FromViewDisplay interface
@@ -29,7 +30,8 @@ export class TableFormViewDisplay extends FormViewDisplay {
setCache: ChangeCacheFunc,
dbinfo: DatabaseInfo,
displayOptions,
serverVersion
serverVersion,
getDictionaryDescription: DictionaryDescriptionFunc = null
) {
super(config, setConfig, cache, setCache, driver, dbinfo, serverVersion);
this.gridDisplay = new TableGridDisplay(
@@ -41,7 +43,8 @@ export class TableFormViewDisplay extends FormViewDisplay {
setCache,
dbinfo,
displayOptions,
serverVersion
serverVersion,
getDictionaryDescription
);
this.gridDisplay.addAllExpandedColumnsToSelected = true;

View File

@@ -1,9 +1,25 @@
import _ from 'lodash';
import { filterName } from 'dbgate-tools';
import { GridDisplay, ChangeCacheFunc, DisplayColumn, DisplayedColumnInfo, ChangeConfigFunc } from './GridDisplay';
import { TableInfo, EngineDriver, ViewInfo, ColumnInfo, NamedObjectInfo, DatabaseInfo } from 'dbgate-types';
import {
TableInfo,
EngineDriver,
ViewInfo,
ColumnInfo,
NamedObjectInfo,
DatabaseInfo,
ForeignKeyInfo,
} from 'dbgate-types';
import { GridConfig, GridCache, createGridCache } from './GridConfig';
import { Expression, Select, treeToSql, dumpSqlSelect } from 'dbgate-sqltree';
import { Expression, Select, treeToSql, dumpSqlSelect, ColumnRefExpression } from 'dbgate-sqltree';
export interface DictionaryDescription {
expression: string;
columns: string[];
delimiter: string;
}
export type DictionaryDescriptionFunc = (table: TableInfo) => DictionaryDescription;
export class TableGridDisplay extends GridDisplay {
public table: TableInfo;
@@ -19,7 +35,8 @@ export class TableGridDisplay extends GridDisplay {
setCache: ChangeCacheFunc,
dbinfo: DatabaseInfo,
public displayOptions: any,
serverVersion
serverVersion,
public getDictionaryDescription: DictionaryDescriptionFunc = null
) {
super(config, setConfig, cache, setCache, driver, dbinfo, serverVersion);
@@ -61,7 +78,11 @@ export class TableGridDisplay extends GridDisplay {
?.map(col => ({
...col,
isChecked: this.isColumnChecked(col),
hintColumnName: col.foreignKey ? `hint_${col.uniqueName}` : null,
hintColumnNames:
this.getFkDictionaryDescription(col.foreignKey)?.columns?.map(
columnName => `hint_${col.uniqueName}_${columnName}`
) || null,
hintColumnDelimiter: this.getFkDictionaryDescription(col.foreignKey)?.delimiter,
isExpandable: !!col.foreignKey,
})) || []
);
@@ -116,6 +137,19 @@ export class TableGridDisplay extends GridDisplay {
}
}
getFkDictionaryDescription(foreignKey: ForeignKeyInfo) {
if (!foreignKey) return null;
const pureName = foreignKey.refTableName;
const schemaName = foreignKey.refSchemaName;
const table = this.findTable({ schemaName, pureName });
if (table && table.columns && table.columns.length > 0 && table.primaryKey) {
const hintDescription = this.getDictionaryDescription(table);
return hintDescription;
}
return null;
}
addHintsToSelect(select: Select): boolean {
let res = false;
const groupColumns = this.groupColumns;
@@ -126,17 +160,23 @@ export class TableGridDisplay extends GridDisplay {
}
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 hintColumn = table.columns.find(x => x?.dataType?.toLowerCase()?.includes('char'));
const hintDescription = this.getDictionaryDescription(table);
if (hintDescription) {
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 },
});
select.columns.push(
...hintDescription.columns.map(
columnName =>
({
exprType: 'column',
columnName,
alias: `hint_${column.uniqueName}_${columnName}`,
source: { alias: childAlias },
} as ColumnRefExpression)
)
);
res = true;
}
}

View File

@@ -113,8 +113,10 @@
{value.toString()}
{/if}
{#if allowHintField && rowData && rowData[col.hintColumnName]}
<span class="hint">{rowData[col.hintColumnName]}</span>
{#if allowHintField && rowData && _.some(col.hintColumnNames, hintColumnName => rowData[hintColumnName])}
<span class="hint"
>{col.hintColumnNames.map(hintColumnName => rowData[hintColumnName]).join(col.hintColumnDelimiter || ' ')}</span
>
{/if}
{#if col.foreignKey && rowData && rowData[col.uniqueName]}

View File

@@ -26,7 +26,7 @@
$: hintFieldsAllowed = visibleRealColumns
.filter(col => {
if (!col.hintColumnName) return false;
if (!col.hintColumnNames) return false;
if (rowStatus.modifiedFields && rowStatus.modifiedFields.has(col.uniqueName)) return false;
return true;
})

View File

@@ -26,6 +26,7 @@
import SqlDataGridCore from './SqlDataGridCore.svelte';
import SqlFormView from '../formview/SqlFormView.svelte';
import { getBoolSettingsValue } from '../settings/settingsTools';
import { getDictionaryDescription } from '../utility/dictionaryDescriptionTools';
export let conid;
export let database;
@@ -64,7 +65,8 @@
setCache,
$dbinfo,
{ showHintColumns: getBoolSettingsValue('dataGrid.showHintColumns', true) },
$serverVersion
$serverVersion,
table => getDictionaryDescription(table, conid, database)
)
: null;
@@ -79,7 +81,8 @@
setCache,
$dbinfo,
{ showHintColumns: getBoolSettingsValue('dataGrid.showHintColumns', true) },
$serverVersion
$serverVersion,
table => getDictionaryDescription(table, conid, database)
)
: null;

View File

@@ -12,6 +12,7 @@
import FormProviderCore from '../forms/FormProviderCore.svelte';
import {
changeDelimitedColumnList,
checkDescriptionExpression,
getDictionaryDescription,
parseDelimitedColumnList,
saveDictionaryDescription,
@@ -27,7 +28,7 @@
$: tableInfo = useTableInfo({ conid, database, schemaName, pureName });
$: descriptionInfo = getDictionaryDescription($tableInfo, conid, database);
$: descriptionInfo = getDictionaryDescription($tableInfo, conid, database, true);
const values = writable({});
@@ -78,6 +79,7 @@
<svelte:fragment slot="footer">
<FormSubmit
value="OK"
disabled={!checkDescriptionExpression($values?.columns, $tableInfo)}
on:click={() => {
closeCurrentModal();
saveDictionaryDescription(

View File

@@ -1,26 +1,27 @@
import { DictionaryDescription } from 'dbgate-datalib';
import { TableInfo } from 'dbgate-types';
import _ from 'lodash';
import { getLocalStorage, setLocalStorage, removeLocalStorage } from './storageCache';
interface DictionaryDescription {
expression: string;
columns: string[];
delimiter: string;
function checkDescriptionColumns(columns: string[], table: TableInfo) {
return columns.length > 0 && columns.every(x => table.columns.find(y => y.columnName == x));
}
function checkDescription(desc: DictionaryDescription, table: TableInfo) {
return desc.columns.length > 0 && desc.columns.every(x => table.columns.find(y => y.columnName == x));
}
export function getDictionaryDescription(table: TableInfo, conid: string, database: string): DictionaryDescription {
export function getDictionaryDescription(
table: TableInfo,
conid: string,
database: string,
skipCheckSaved: boolean = false
): DictionaryDescription {
const keySpecific = `dictionary_spec_${table.schemaName}||${table.pureName}||${conid}||${database}`;
const keyCommon = `dictionary_spec_${table.schemaName}||${table.pureName}`;
const cachedSpecific = getLocalStorage(keySpecific);
const cachedCommon = getLocalStorage(keyCommon);
if (cachedSpecific && checkDescription(cachedSpecific, table)) return cachedSpecific;
if (cachedCommon && checkDescription(cachedCommon, table)) return cachedCommon;
if (cachedSpecific && (skipCheckSaved || checkDescriptionColumns(cachedSpecific.columns, table)))
return cachedSpecific;
if (cachedCommon && (skipCheckSaved || checkDescriptionColumns(cachedCommon.columns, table))) return cachedCommon;
const descColumn = table.columns.find(x => x?.dataType?.toLowerCase()?.includes('char'));
if (descColumn) {
@@ -34,10 +35,16 @@ export function getDictionaryDescription(table: TableInfo, conid: string, databa
return null;
}
export function parseDelimitedColumnList(columns) {
export function parseDelimitedColumnList(columns): string[] {
return _.compact((columns || '').split(',').map(x => x.trim()));
}
export function checkDescriptionExpression(expression: string, table: TableInfo) {
if (!expression) return false;
if (!table) return false;
return checkDescriptionColumns(parseDelimitedColumnList(expression), table);
}
export function changeDelimitedColumnList(columns, columnName, isChecked) {
const parsed = parseDelimitedColumnList(columns);
const includes = parsed.includes(columnName);