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; foreignKey?: ForeignKeyInfo;
isExpandable?: boolean; isExpandable?: boolean;
isChecked?: boolean; isChecked?: boolean;
hintColumnName?: string; hintColumnNames?: string[];
dataType?: string; dataType?: string;
filterType?: boolean; filterType?: boolean;
isStructured?: boolean; isStructured?: boolean;

View File

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

View File

@@ -1,9 +1,25 @@
import _ from 'lodash'; import _ from 'lodash';
import { filterName } from 'dbgate-tools'; import { filterName } from 'dbgate-tools';
import { GridDisplay, ChangeCacheFunc, DisplayColumn, DisplayedColumnInfo, ChangeConfigFunc } from './GridDisplay'; 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 { 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 { export class TableGridDisplay extends GridDisplay {
public table: TableInfo; public table: TableInfo;
@@ -19,7 +35,8 @@ export class TableGridDisplay extends GridDisplay {
setCache: ChangeCacheFunc, setCache: ChangeCacheFunc,
dbinfo: DatabaseInfo, dbinfo: DatabaseInfo,
public displayOptions: any, public displayOptions: any,
serverVersion serverVersion,
public getDictionaryDescription: DictionaryDescriptionFunc = null
) { ) {
super(config, setConfig, cache, setCache, driver, dbinfo, serverVersion); super(config, setConfig, cache, setCache, driver, dbinfo, serverVersion);
@@ -61,7 +78,11 @@ export class TableGridDisplay extends GridDisplay {
?.map(col => ({ ?.map(col => ({
...col, ...col,
isChecked: this.isColumnChecked(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, 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 { addHintsToSelect(select: Select): boolean {
let res = false; let res = false;
const groupColumns = this.groupColumns; const groupColumns = this.groupColumns;
@@ -126,17 +160,23 @@ export class TableGridDisplay extends GridDisplay {
} }
const table = this.getFkTarget(column); const table = this.getFkTarget(column);
if (table && table.columns && table.columns.length > 0 && table.primaryKey) { if (table && table.columns && table.columns.length > 0 && table.primaryKey) {
const hintColumn = table.columns.find(x => x?.dataType?.toLowerCase()?.includes('char')); // const hintColumn = table.columns.find(x => x?.dataType?.toLowerCase()?.includes('char'));
if (hintColumn) { const hintDescription = this.getDictionaryDescription(table);
if (hintDescription) {
const parentUniqueName = column.uniquePath.slice(0, -1).join('.'); const parentUniqueName = column.uniquePath.slice(0, -1).join('.');
this.addReferenceToSelect(select, parentUniqueName ? `${parentUniqueName}_ref` : 'basetbl', column); this.addReferenceToSelect(select, parentUniqueName ? `${parentUniqueName}_ref` : 'basetbl', column);
const childAlias = `${column.uniqueName}_ref`; const childAlias = `${column.uniqueName}_ref`;
select.columns.push({ select.columns.push(
exprType: 'column', ...hintDescription.columns.map(
columnName: hintColumn.columnName, columnName =>
alias: `hint_${column.uniqueName}`, ({
source: { alias: childAlias }, exprType: 'column',
}); columnName,
alias: `hint_${column.uniqueName}_${columnName}`,
source: { alias: childAlias },
} as ColumnRefExpression)
)
);
res = true; res = true;
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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