mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-28 06:06:00 +00:00
configurable dictionary description
This commit is contained in:
@@ -29,7 +29,7 @@ export interface DisplayColumn {
|
||||
foreignKey?: ForeignKeyInfo;
|
||||
isExpandable?: boolean;
|
||||
isChecked?: boolean;
|
||||
hintColumnName?: string;
|
||||
hintColumnNames?: string[];
|
||||
dataType?: string;
|
||||
filterType?: boolean;
|
||||
isStructured?: boolean;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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]}
|
||||
|
||||
@@ -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;
|
||||
})
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user