mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-28 22:16:01 +00:00
browse view data
This commit is contained in:
@@ -1,15 +1,9 @@
|
|||||||
const _ = require('lodash');
|
|
||||||
const fp = require('lodash/fp');
|
|
||||||
const uuidv1 = require('uuid/v1');
|
const uuidv1 = require('uuid/v1');
|
||||||
const connections = require('./connections');
|
const connections = require('./connections');
|
||||||
const socket = require('../utility/socket');
|
const socket = require('../utility/socket');
|
||||||
const { fork } = require('child_process');
|
const { fork } = require('child_process');
|
||||||
const DatabaseAnalyser = require('@dbgate/engines/default/DatabaseAnalyser');
|
const DatabaseAnalyser = require('@dbgate/engines/default/DatabaseAnalyser');
|
||||||
|
|
||||||
function pickObjectNames(array) {
|
|
||||||
return _.sortBy(array, (x) => `${x.schemaName}.${x.pureName}`).map(fp.pick(['pureName', 'schemaName']));
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
/** @type {import('@dbgate/types').OpenedDatabaseConnection[]} */
|
/** @type {import('@dbgate/types').OpenedDatabaseConnection[]} */
|
||||||
opened: [],
|
opened: [],
|
||||||
@@ -62,19 +56,6 @@ module.exports = {
|
|||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
listObjects_meta: 'get',
|
|
||||||
async listObjects({ conid, database }) {
|
|
||||||
const opened = await this.ensureOpened(conid, database);
|
|
||||||
const types = ['tables', 'views', 'procedures', 'functions', 'triggers'];
|
|
||||||
return types.reduce(
|
|
||||||
(res, type) => ({
|
|
||||||
...res,
|
|
||||||
[type]: pickObjectNames(opened.structure[type]),
|
|
||||||
}),
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
queryData_meta: 'post',
|
queryData_meta: 'post',
|
||||||
async queryData({ conid, database, sql }) {
|
async queryData({ conid, database, sql }) {
|
||||||
console.log(`Processing query, conid=${conid}, database=${database}, sql=${sql}`);
|
console.log(`Processing query, conid=${conid}, database=${database}, sql=${sql}`);
|
||||||
|
|||||||
47
packages/api/src/controllers/metadata.js
Normal file
47
packages/api/src/controllers/metadata.js
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
const _ = require('lodash');
|
||||||
|
const fp = require('lodash/fp');
|
||||||
|
const databaseConnections = require('./databaseConnections');
|
||||||
|
|
||||||
|
function pickObjectNames(array) {
|
||||||
|
return _.sortBy(array, (x) => `${x.schemaName}.${x.pureName}`).map(fp.pick(['pureName', 'schemaName']));
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// tableData_meta: 'get',
|
||||||
|
// async tableData({ conid, database, schemaName, pureName }) {
|
||||||
|
// const opened = await databaseConnections.ensureOpened(conid, database);
|
||||||
|
// const res = await databaseConnections.sendRequest(opened, { msgtype: 'tableData', schemaName, pureName });
|
||||||
|
// return res;
|
||||||
|
// },
|
||||||
|
|
||||||
|
listObjects_meta: 'get',
|
||||||
|
async listObjects({ conid, database }) {
|
||||||
|
const opened = await databaseConnections.ensureOpened(conid, database);
|
||||||
|
const types = ['tables', 'views', 'procedures', 'functions', 'triggers'];
|
||||||
|
return types.reduce(
|
||||||
|
(res, type) => ({
|
||||||
|
...res,
|
||||||
|
[type]: pickObjectNames(opened.structure[type]),
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
tableInfo_meta: 'get',
|
||||||
|
async tableInfo({ conid, database, schemaName, pureName }) {
|
||||||
|
const opened = await databaseConnections.ensureOpened(conid, database);
|
||||||
|
const table = opened.structure.tables.find((x) => x.pureName == pureName && x.schemaName == schemaName);
|
||||||
|
const allForeignKeys = _.flatten(opened.structure.tables.map((x) => x.foreignKeys));
|
||||||
|
return {
|
||||||
|
...table,
|
||||||
|
dependencies: allForeignKeys.filter((x) => x.refSchemaName == schemaName && x.refTableName == pureName),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
viewInfo_meta: 'get',
|
||||||
|
async viewInfo({ conid, database, schemaName, pureName }) {
|
||||||
|
const opened = await databaseConnections.ensureOpened(conid, database);
|
||||||
|
const view = opened.structure.views.find((x) => x.pureName == pureName && x.schemaName == schemaName);
|
||||||
|
return view;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
const _ = require('lodash');
|
|
||||||
const databaseConnections = require('./databaseConnections');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
// tableData_meta: 'get',
|
|
||||||
// async tableData({ conid, database, schemaName, pureName }) {
|
|
||||||
// const opened = await databaseConnections.ensureOpened(conid, database);
|
|
||||||
// const res = await databaseConnections.sendRequest(opened, { msgtype: 'tableData', schemaName, pureName });
|
|
||||||
// return res;
|
|
||||||
// },
|
|
||||||
|
|
||||||
tableInfo_meta: 'get',
|
|
||||||
async tableInfo({ conid, database, schemaName, pureName }) {
|
|
||||||
const opened = await databaseConnections.ensureOpened(conid, database);
|
|
||||||
const table = opened.structure.tables.find(x => x.pureName == pureName && x.schemaName == schemaName);
|
|
||||||
const allForeignKeys = _.flatten(opened.structure.tables.map(x => x.foreignKeys));
|
|
||||||
return {
|
|
||||||
...table,
|
|
||||||
dependencies: allForeignKeys.filter(x => x.refSchemaName == schemaName && x.refTableName == pureName),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -12,7 +12,7 @@ const socket = require('./utility/socket');
|
|||||||
const connections = require('./controllers/connections');
|
const connections = require('./controllers/connections');
|
||||||
const serverConnections = require('./controllers/serverConnections');
|
const serverConnections = require('./controllers/serverConnections');
|
||||||
const databaseConnections = require('./controllers/databaseConnections');
|
const databaseConnections = require('./controllers/databaseConnections');
|
||||||
const tables = require('./controllers/tables');
|
const metadata = require('./controllers/metadata');
|
||||||
const sessions = require('./controllers/sessions');
|
const sessions = require('./controllers/sessions');
|
||||||
const jsldata = require('./controllers/jsldata');
|
const jsldata = require('./controllers/jsldata');
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ function start(argument = null) {
|
|||||||
useController(app, '/connections', connections);
|
useController(app, '/connections', connections);
|
||||||
useController(app, '/server-connections', serverConnections);
|
useController(app, '/server-connections', serverConnections);
|
||||||
useController(app, '/database-connections', databaseConnections);
|
useController(app, '/database-connections', databaseConnections);
|
||||||
useController(app, '/tables', tables);
|
useController(app, '/metadata', metadata);
|
||||||
useController(app, '/sessions', sessions);
|
useController(app, '/sessions', sessions);
|
||||||
useController(app, '/jsldata', jsldata);
|
useController(app, '/jsldata', jsldata);
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export function findExistingChangeSetItem(
|
|||||||
changeSet: ChangeSet,
|
changeSet: ChangeSet,
|
||||||
definition: ChangeSetRowDefinition
|
definition: ChangeSetRowDefinition
|
||||||
): [keyof ChangeSet, ChangeSetItem] {
|
): [keyof ChangeSet, ChangeSetItem] {
|
||||||
if (!changeSet) return ['updates', null];
|
if (!changeSet || !definition) return ['updates', null];
|
||||||
if (definition.insertedRowIndex != null) {
|
if (definition.insertedRowIndex != null) {
|
||||||
return [
|
return [
|
||||||
'inserts',
|
'inserts',
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { GridConfig, GridCache, GridConfigColumns } from './GridConfig';
|
import { GridConfig, GridCache, GridConfigColumns } from './GridConfig';
|
||||||
import { ForeignKeyInfo, TableInfo, ColumnInfo, DbType, EngineDriver } from '@dbgate/types';
|
import { ForeignKeyInfo, TableInfo, ColumnInfo, DbType, EngineDriver, NamedObjectInfo } from '@dbgate/types';
|
||||||
import { parseFilter, getFilterType } from '@dbgate/filterparser';
|
import { parseFilter, getFilterType } from '@dbgate/filterparser';
|
||||||
import { filterName } from './filterName';
|
import { filterName } from './filterName';
|
||||||
import { Select, Expression } from '@dbgate/sqltree';
|
|
||||||
import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet';
|
import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet';
|
||||||
|
import { Expression, Select, treeToSql, dumpSqlSelect } from '@dbgate/sqltree';
|
||||||
|
|
||||||
export interface DisplayColumn {
|
export interface DisplayColumn {
|
||||||
schemaName: string;
|
schemaName: string;
|
||||||
@@ -46,12 +46,8 @@ export abstract class GridDisplay {
|
|||||||
protected setConfig: (config: GridConfig) => void,
|
protected setConfig: (config: GridConfig) => void,
|
||||||
public cache: GridCache,
|
public cache: GridCache,
|
||||||
protected setCache: ChangeCacheFunc,
|
protected setCache: ChangeCacheFunc,
|
||||||
protected getTableInfo: ({ schemaName, pureName }) => Promise<TableInfo>,
|
|
||||||
public driver?: EngineDriver
|
public driver?: EngineDriver
|
||||||
) {}
|
) {}
|
||||||
getPageQuery(offset: number, count: number): string {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
columns: DisplayColumn[];
|
columns: DisplayColumn[];
|
||||||
baseTable?: TableInfo;
|
baseTable?: TableInfo;
|
||||||
changeSetKeyFields: string[] = null;
|
changeSetKeyFields: string[] = null;
|
||||||
@@ -113,39 +109,6 @@ export abstract class GridDisplay {
|
|||||||
return (this.config.hiddenColumns || []).map((x) => _.findIndex(this.columns, (y) => y.uniqueName == x));
|
return (this.config.hiddenColumns || []).map((x) => _.findIndex(this.columns, (y) => y.uniqueName == x));
|
||||||
}
|
}
|
||||||
|
|
||||||
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.cache.tables[column.uniqueName];
|
|
||||||
if (table) {
|
|
||||||
return this.enrichExpandedColumns(this.getDisplayColumns(table, column.uniquePath));
|
|
||||||
} else {
|
|
||||||
// load expanded columns
|
|
||||||
this.requireFkTarget(column);
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
requireFkTarget(column: DisplayColumn) {
|
|
||||||
const { uniqueName, foreignKey } = column;
|
|
||||||
this.getTableInfo({ schemaName: foreignKey.refSchemaName, pureName: foreignKey.refTableName }).then((table) => {
|
|
||||||
this.setCache((cache) => ({
|
|
||||||
...cache,
|
|
||||||
tables: {
|
|
||||||
...cache.tables,
|
|
||||||
[uniqueName]: table,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
isColumnChecked(column: DisplayColumn) {
|
isColumnChecked(column: DisplayColumn) {
|
||||||
// console.log('isColumnChecked', column, this.config.hiddenColumns);
|
// console.log('isColumnChecked', column, this.config.hiddenColumns);
|
||||||
return column.uniquePath.length == 1
|
return column.uniquePath.length == 1
|
||||||
@@ -153,142 +116,6 @@ export abstract class GridDisplay {
|
|||||||
: this.config.addedColumns.includes(column.uniqueName);
|
: this.config.addedColumns.includes(column.uniqueName);
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
): ReferenceActionResult {
|
|
||||||
let res: ReferenceActionResult = 'noAction';
|
|
||||||
for (const column of columns) {
|
|
||||||
if (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,
|
|
||||||
};
|
|
||||||
res = 'refAdded';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
addJoinsFromExpandedColumns(
|
|
||||||
select: Select,
|
|
||||||
columns: DisplayColumn[],
|
|
||||||
parentAlias: string,
|
|
||||||
columnSources
|
|
||||||
): ReferenceActionResult {
|
|
||||||
let res: ReferenceActionResult = 'noAction';
|
|
||||||
for (const column of columns) {
|
|
||||||
if (this.isExpandedColumn(column.uniqueName)) {
|
|
||||||
const table = this.cache.tables[column.uniqueName];
|
|
||||||
if (table) {
|
|
||||||
const childAlias = `${column.uniqueName}_ref`;
|
|
||||||
const subcolumns = this.getDisplayColumns(table, column.uniquePath);
|
|
||||||
const tableAction = combineReferenceActions(
|
|
||||||
this.addJoinsFromExpandedColumns(select, subcolumns, childAlias, columnSources),
|
|
||||||
this.addAddedColumnsToSelect(select, subcolumns, childAlias, columnSources)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (tableAction == 'refAdded') {
|
|
||||||
this.addReferenceToSelect(select, parentAlias, column);
|
|
||||||
res = 'refAdded';
|
|
||||||
}
|
|
||||||
if (tableAction == 'loadRequired') {
|
|
||||||
return 'loadRequired';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.requireFkTarget(column);
|
|
||||||
res = 'loadRequired';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
// const addedColumns = this.getGridColumns().filter(x=>x.)
|
|
||||||
}
|
|
||||||
|
|
||||||
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.cache.tables[column.uniqueName];
|
|
||||||
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): ReferenceActionResult {
|
|
||||||
let res: ReferenceActionResult = 'noAction';
|
|
||||||
for (const column of this.getGridColumns()) {
|
|
||||||
if (column.foreignKey) {
|
|
||||||
const table = this.cache.tables[column.uniqueName];
|
|
||||||
if (table) {
|
|
||||||
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 = 'refAdded';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.requireFkTarget(column);
|
|
||||||
res = 'loadRequired';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
applyFilterOnSelect(select: Select, displayedColumnInfo: DisplayedColumnInfo) {
|
applyFilterOnSelect(select: Select, displayedColumnInfo: DisplayedColumnInfo) {
|
||||||
for (const uniqueName in this.config.filters) {
|
for (const uniqueName in this.config.filters) {
|
||||||
const filter = this.config.filters[uniqueName];
|
const filter = this.config.filters[uniqueName];
|
||||||
@@ -328,20 +155,8 @@ export abstract class GridDisplay {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|
||||||
})) || []
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
getColumns(columnFilter) {
|
getColumns(columnFilter) {
|
||||||
return this.enrichExpandedColumns(this.columns.filter((col) => filterName(columnFilter, col.columnName)));
|
return this.columns.filter((col) => filterName(columnFilter, col.columnName));
|
||||||
}
|
}
|
||||||
|
|
||||||
getGridColumns() {
|
getGridColumns() {
|
||||||
@@ -421,4 +236,54 @@ export abstract class GridDisplay {
|
|||||||
condition: insertedRowIndex == null ? this.getChangeSetCondition(row) : null,
|
condition: insertedRowIndex == null ? this.getChangeSetCondition(row) : null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createSelect(): Select {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
processReferences(select: Select, displayedColumnInfo: DisplayedColumnInfo): ReferenceActionResult {
|
||||||
|
return 'noAction';
|
||||||
|
}
|
||||||
|
|
||||||
|
createSelectBase(name: NamedObjectInfo, columns: ColumnInfo[]) {
|
||||||
|
if (!columns) return null;
|
||||||
|
const orderColumnName = columns[0].columnName;
|
||||||
|
const select: Select = {
|
||||||
|
commandType: 'select',
|
||||||
|
from: { name, alias: 'basetbl' },
|
||||||
|
columns: columns.map((col) => ({
|
||||||
|
exprType: 'column',
|
||||||
|
alias: col.columnName,
|
||||||
|
source: { alias: 'basetbl' },
|
||||||
|
...col,
|
||||||
|
})),
|
||||||
|
orderBy: [
|
||||||
|
{
|
||||||
|
exprType: 'column',
|
||||||
|
columnName: orderColumnName,
|
||||||
|
direction: 'ASC',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const displayedColumnInfo = _.keyBy(
|
||||||
|
this.columns.map((col) => ({ ...col, sourceAlias: 'basetbl' })),
|
||||||
|
'uniqueName'
|
||||||
|
);
|
||||||
|
const action = this.processReferences(select, displayedColumnInfo)
|
||||||
|
this.applyFilterOnSelect(select, displayedColumnInfo);
|
||||||
|
this.applySortOnSelect(select, displayedColumnInfo);
|
||||||
|
if (action == 'loadRequired') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return select;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPageQuery(offset: number, count: number) {
|
||||||
|
const select = this.createSelect();
|
||||||
|
if (!select) return null;
|
||||||
|
if (this.driver.dialect.rangeSelect) select.range = { offset: offset, limit: count };
|
||||||
|
else if (this.driver.dialect.limitSelect) select.topRecords = count;
|
||||||
|
const sql = treeToSql(this.driver, select, dumpSqlSelect);
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { GridDisplay, combineReferenceActions, ChangeCacheFunc } from './GridDisplay';
|
import {
|
||||||
import { Select, treeToSql, dumpSqlSelect } from '@dbgate/sqltree';
|
GridDisplay,
|
||||||
import { TableInfo, EngineDriver } from '@dbgate/types';
|
combineReferenceActions,
|
||||||
|
ChangeCacheFunc,
|
||||||
|
DisplayColumn,
|
||||||
|
ReferenceActionResult,
|
||||||
|
DisplayedColumnInfo,
|
||||||
|
} from './GridDisplay';
|
||||||
|
import { TableInfo, EngineDriver, ViewInfo, ColumnInfo } from '@dbgate/types';
|
||||||
import { GridConfig, GridCache } from './GridConfig';
|
import { GridConfig, GridCache } from './GridConfig';
|
||||||
|
import { Expression, Select, treeToSql, dumpSqlSelect } from '@dbgate/sqltree';
|
||||||
|
import { filterName } from './filterName';
|
||||||
|
|
||||||
export class TableGridDisplay extends GridDisplay {
|
export class TableGridDisplay extends GridDisplay {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -12,9 +20,9 @@ export class TableGridDisplay extends GridDisplay {
|
|||||||
setConfig: (config: GridConfig) => void,
|
setConfig: (config: GridConfig) => void,
|
||||||
cache: GridCache,
|
cache: GridCache,
|
||||||
setCache: ChangeCacheFunc,
|
setCache: ChangeCacheFunc,
|
||||||
getTableInfo: ({ schemaName, pureName }) => Promise<TableInfo>
|
protected getTableInfo: ({ schemaName, pureName }) => Promise<TableInfo>
|
||||||
) {
|
) {
|
||||||
super(config, setConfig, cache, setCache, getTableInfo, driver);
|
super(config, setConfig, cache, setCache, driver);
|
||||||
this.columns = this.getDisplayColumns(table, []);
|
this.columns = this.getDisplayColumns(table, []);
|
||||||
this.filterable = true;
|
this.filterable = true;
|
||||||
this.sortable = true;
|
this.sortable = true;
|
||||||
@@ -27,48 +35,202 @@ export class TableGridDisplay extends GridDisplay {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createSelect() {
|
getDisplayColumns(table: TableInfo, parentPath: string[]) {
|
||||||
if (!this.table.columns) return null;
|
return (
|
||||||
const orderColumnName = this.table.columns[0].columnName;
|
table?.columns
|
||||||
const select: Select = {
|
?.map((col) => this.getDisplayColumn(table, col, parentPath))
|
||||||
commandType: 'select',
|
?.map((col) => ({
|
||||||
from: { name: this.table, alias: 'basetbl' },
|
...col,
|
||||||
columns: this.table.columns.map((col) => ({
|
isChecked: this.isColumnChecked(col),
|
||||||
exprType: 'column',
|
hintColumnName: col.foreignKey ? `hint_${col.uniqueName}` : null,
|
||||||
alias: col.columnName,
|
})) || []
|
||||||
source: { alias: 'basetbl' },
|
|
||||||
...col,
|
|
||||||
})),
|
|
||||||
orderBy: [
|
|
||||||
{
|
|
||||||
exprType: 'column',
|
|
||||||
columnName: orderColumnName,
|
|
||||||
direction: 'ASC',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
const displayedColumnInfo = _.keyBy(
|
|
||||||
this.columns.map((col) => ({ ...col, sourceAlias: 'basetbl' })),
|
|
||||||
'uniqueName'
|
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
addJoinsFromExpandedColumns(
|
||||||
|
select: Select,
|
||||||
|
columns: DisplayColumn[],
|
||||||
|
parentAlias: string,
|
||||||
|
columnSources
|
||||||
|
): ReferenceActionResult {
|
||||||
|
let res: ReferenceActionResult = 'noAction';
|
||||||
|
for (const column of columns) {
|
||||||
|
if (this.isExpandedColumn(column.uniqueName)) {
|
||||||
|
const table = this.cache.tables[column.uniqueName];
|
||||||
|
if (table) {
|
||||||
|
const childAlias = `${column.uniqueName}_ref`;
|
||||||
|
const subcolumns = this.getDisplayColumns(table, column.uniquePath);
|
||||||
|
const tableAction = combineReferenceActions(
|
||||||
|
this.addJoinsFromExpandedColumns(select, subcolumns, childAlias, columnSources),
|
||||||
|
this.addAddedColumnsToSelect(select, subcolumns, childAlias, columnSources)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (tableAction == 'refAdded') {
|
||||||
|
this.addReferenceToSelect(select, parentAlias, column);
|
||||||
|
res = 'refAdded';
|
||||||
|
}
|
||||||
|
if (tableAction == 'loadRequired') {
|
||||||
|
return 'loadRequired';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.requireFkTarget(column);
|
||||||
|
res = 'loadRequired';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
// const addedColumns = this.getGridColumns().filter(x=>x.)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.cache.tables[column.uniqueName];
|
||||||
|
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): ReferenceActionResult {
|
||||||
|
let res: ReferenceActionResult = 'noAction';
|
||||||
|
for (const column of this.getGridColumns()) {
|
||||||
|
if (column.foreignKey) {
|
||||||
|
const table = this.cache.tables[column.uniqueName];
|
||||||
|
if (table) {
|
||||||
|
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 = 'refAdded';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.requireFkTarget(column);
|
||||||
|
res = 'loadRequired';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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.cache.tables[column.uniqueName];
|
||||||
|
if (table) {
|
||||||
|
return this.enrichExpandedColumns(this.getDisplayColumns(table, column.uniquePath));
|
||||||
|
} else {
|
||||||
|
// load expanded columns
|
||||||
|
this.requireFkTarget(column);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
requireFkTarget(column: DisplayColumn) {
|
||||||
|
const { uniqueName, foreignKey } = column;
|
||||||
|
this.getTableInfo({ schemaName: foreignKey.refSchemaName, pureName: foreignKey.refTableName }).then((table) => {
|
||||||
|
this.setCache((cache) => ({
|
||||||
|
...cache,
|
||||||
|
tables: {
|
||||||
|
...cache.tables,
|
||||||
|
[uniqueName]: table,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
processReferences(select: Select, displayedColumnInfo: DisplayedColumnInfo): ReferenceActionResult {
|
||||||
const action = combineReferenceActions(
|
const action = combineReferenceActions(
|
||||||
this.addJoinsFromExpandedColumns(select, this.columns, 'basetbl', displayedColumnInfo),
|
this.addJoinsFromExpandedColumns(select, this.columns, 'basetbl', displayedColumnInfo),
|
||||||
this.addHintsToSelect(select)
|
this.addHintsToSelect(select)
|
||||||
);
|
);
|
||||||
this.applyFilterOnSelect(select, displayedColumnInfo);
|
return action;
|
||||||
this.applySortOnSelect(select, displayedColumnInfo);
|
}
|
||||||
if (action == 'loadRequired') {
|
|
||||||
return null;
|
createSelect() {
|
||||||
}
|
const select = this.createSelectBase(this.table, this.table.columns);
|
||||||
return select;
|
return select;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPageQuery(offset: number, count: number) {
|
getColumns(columnFilter) {
|
||||||
const select = this.createSelect();
|
return this.enrichExpandedColumns(this.columns.filter((col) => filterName(columnFilter, col.columnName)));
|
||||||
if (!select) return null;
|
}
|
||||||
if (this.driver.dialect.rangeSelect) select.range = { offset: offset, limit: count };
|
|
||||||
else if (this.driver.dialect.limitSelect) select.topRecords = count;
|
getDisplayColumn(table: TableInfo, col: ColumnInfo, parentPath: string[]) {
|
||||||
const sql = treeToSql(this.driver, select, dumpSqlSelect);
|
const uniquePath = [...parentPath, col.columnName];
|
||||||
return sql;
|
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
|
||||||
|
): ReferenceActionResult {
|
||||||
|
let res: ReferenceActionResult = 'noAction';
|
||||||
|
for (const column of columns) {
|
||||||
|
if (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,
|
||||||
|
};
|
||||||
|
res = 'refAdded';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
50
packages/datalib/src/ViewGridDisplay.ts
Normal file
50
packages/datalib/src/ViewGridDisplay.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import { GridDisplay, ChangeCacheFunc } from './GridDisplay';
|
||||||
|
import { EngineDriver, ViewInfo, ColumnInfo } from '@dbgate/types';
|
||||||
|
import { GridConfig, GridCache } from './GridConfig';
|
||||||
|
|
||||||
|
export class ViewGridDisplay extends GridDisplay {
|
||||||
|
constructor(
|
||||||
|
public view: ViewInfo,
|
||||||
|
driver: EngineDriver,
|
||||||
|
config: GridConfig,
|
||||||
|
setConfig: (config: GridConfig) => void,
|
||||||
|
cache: GridCache,
|
||||||
|
setCache: ChangeCacheFunc
|
||||||
|
) {
|
||||||
|
super(config, setConfig, cache, setCache, driver);
|
||||||
|
this.columns = this.getDisplayColumns(view);
|
||||||
|
this.filterable = true;
|
||||||
|
this.sortable = true;
|
||||||
|
this.editable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayColumns(view: ViewInfo) {
|
||||||
|
return (
|
||||||
|
view?.columns
|
||||||
|
?.map((col) => this.getDisplayColumn(view, col))
|
||||||
|
?.map((col) => ({
|
||||||
|
...col,
|
||||||
|
isChecked: this.isColumnChecked(col),
|
||||||
|
})) || []
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayColumn(view: ViewInfo, col: ColumnInfo) {
|
||||||
|
const uniquePath = [col.columnName];
|
||||||
|
const uniqueName = uniquePath.join('.');
|
||||||
|
return {
|
||||||
|
...col,
|
||||||
|
pureName: view.pureName,
|
||||||
|
schemaName: view.schemaName,
|
||||||
|
headerText: col.columnName,
|
||||||
|
uniqueName,
|
||||||
|
uniquePath,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
createSelect() {
|
||||||
|
const select = this.createSelectBase(this.view, this.view.columns);
|
||||||
|
return select;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
export * from "./GridDisplay";
|
export * from "./GridDisplay";
|
||||||
export * from "./GridConfig";
|
export * from "./GridConfig";
|
||||||
export * from "./TableGridDisplay";
|
export * from "./TableGridDisplay";
|
||||||
|
export * from "./ViewGridDisplay";
|
||||||
export * from "./JslGridDisplay";
|
export * from "./JslGridDisplay";
|
||||||
export * from "./ChangeSet";
|
export * from "./ChangeSet";
|
||||||
export * from "./filterName";
|
export * from "./filterName";
|
||||||
|
|||||||
@@ -227,6 +227,7 @@ class MsSqlAnalyser extends DatabaseAnalayser {
|
|||||||
this.pool,
|
this.pool,
|
||||||
this.createQuery('programmables', ['procedures', 'functions'])
|
this.createQuery('programmables', ['procedures', 'functions'])
|
||||||
);
|
);
|
||||||
|
const viewColumnRows = await this.driver.query(this.pool, this.createQuery('viewColumns', ['views']));
|
||||||
|
|
||||||
const tables = tablesRows.rows.map((row) => ({
|
const tables = tablesRows.rows.map((row) => ({
|
||||||
...row,
|
...row,
|
||||||
@@ -245,6 +246,14 @@ class MsSqlAnalyser extends DatabaseAnalayser {
|
|||||||
const views = viewsRows.rows.map((row) => ({
|
const views = viewsRows.rows.map((row) => ({
|
||||||
...row,
|
...row,
|
||||||
createSql: getCreateSql(row),
|
createSql: getCreateSql(row),
|
||||||
|
columns: viewColumnRows.rows
|
||||||
|
.filter((col) => (col.objectId = row.objectId))
|
||||||
|
.map(({ isNullable, isIdentity, ...col }) => ({
|
||||||
|
...col,
|
||||||
|
notNull: !isNullable,
|
||||||
|
autoIncrement: !!isIdentity,
|
||||||
|
commonType: detectType(col),
|
||||||
|
})),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const procedures = programmableRows.rows
|
const procedures = programmableRows.rows
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const modifications = require('./modifications');
|
|||||||
const loadSqlCode = require('./loadSqlCode');
|
const loadSqlCode = require('./loadSqlCode');
|
||||||
const views = require('./views');
|
const views = require('./views');
|
||||||
const programmables = require('./programmables');
|
const programmables = require('./programmables');
|
||||||
|
const viewColumns = require('./viewColumns');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
columns,
|
columns,
|
||||||
@@ -16,4 +17,5 @@ module.exports = {
|
|||||||
loadSqlCode,
|
loadSqlCode,
|
||||||
views,
|
views,
|
||||||
programmables,
|
programmables,
|
||||||
|
viewColumns,
|
||||||
};
|
};
|
||||||
|
|||||||
18
packages/engines/mssql/sql/viewColumns.js
Normal file
18
packages/engines/mssql/sql/viewColumns.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
o.object_id AS objectId,
|
||||||
|
col.TABLE_SCHEMA as schemaName,
|
||||||
|
col.TABLE_NAME as pureName,
|
||||||
|
col.COLUMN_NAME as columnName,
|
||||||
|
col.IS_NULLABLE as isNullable,
|
||||||
|
col.DATA_TYPE as dataType,
|
||||||
|
col.CHARACTER_MAXIMUM_LENGTH,
|
||||||
|
col.NUMERIC_PRECISION as precision,
|
||||||
|
col.NUMERIC_SCALE as scale,
|
||||||
|
col.COLUMN_DEFAULT
|
||||||
|
FROM sys.objects o
|
||||||
|
INNER JOIN sys.schemas u ON u.schema_id=o.schema_id
|
||||||
|
INNER JOIN INFORMATION_SCHEMA.COLUMNS col ON col.TABLE_NAME = o.name AND col.TABLE_SCHEMA = u.name
|
||||||
|
WHERE o.type in ('V') and o.object_id =[OBJECT_ID_CONDITION]
|
||||||
|
order by col.ORDINAL_POSITION
|
||||||
|
`;
|
||||||
4
packages/types/dbinfo.d.ts
vendored
4
packages/types/dbinfo.d.ts
vendored
@@ -61,7 +61,9 @@ export interface TableInfo extends DatabaseObjectInfo {
|
|||||||
dependencies?: ForeignKeyInfo[];
|
dependencies?: ForeignKeyInfo[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ViewInfo extends SqlObjectInfo {}
|
export interface ViewInfo extends SqlObjectInfo {
|
||||||
|
columns: ColumnInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface ProcedureInfo extends SqlObjectInfo {}
|
export interface ProcedureInfo extends SqlObjectInfo {}
|
||||||
|
|
||||||
|
|||||||
@@ -6,58 +6,54 @@ import getConnectionInfo from '../utility/getConnectionInfo';
|
|||||||
import fullDisplayName from '../utility/fullDisplayName';
|
import fullDisplayName from '../utility/fullDisplayName';
|
||||||
import { filterName } from '@dbgate/datalib';
|
import { filterName } from '@dbgate/datalib';
|
||||||
|
|
||||||
// async function openTableDetail(setOpenedTabs, tabComponent, { schemaName, pureName, conid, database }) {
|
async function openViewDetail(setOpenedTabs, tabComponent, { schemaName, pureName, conid, database }) {
|
||||||
// const connection = await getConnectionInfo(conid);
|
const connection = await getConnectionInfo(conid);
|
||||||
// const tooltip = `${connection.displayName || connection.server}\n${database}\n${fullDisplayName({
|
const tooltip = `${connection.displayName || connection.server}\n${database}\n${fullDisplayName({
|
||||||
// schemaName,
|
schemaName,
|
||||||
// pureName,
|
pureName,
|
||||||
// })}`;
|
})}`;
|
||||||
|
|
||||||
// openNewTab(setOpenedTabs, {
|
openNewTab(setOpenedTabs, {
|
||||||
// title: pureName,
|
title: pureName,
|
||||||
// tooltip,
|
tooltip,
|
||||||
// icon: 'table2.svg',
|
icon: 'view2.svg',
|
||||||
// tabComponent,
|
tabComponent,
|
||||||
// props: {
|
props: {
|
||||||
// schemaName,
|
schemaName,
|
||||||
// pureName,
|
pureName,
|
||||||
// conid,
|
conid,
|
||||||
// database,
|
database,
|
||||||
// },
|
},
|
||||||
// });
|
});
|
||||||
// }
|
}
|
||||||
|
|
||||||
// function Menu({ data, makeAppObj, setOpenedTabs }) {
|
function Menu({ data, makeAppObj, setOpenedTabs }) {
|
||||||
// const handleOpenData = () => {
|
const handleOpenData = () => {
|
||||||
// openTableDetail(setOpenedTabs, 'TableDataTab', data);
|
openViewDetail(setOpenedTabs, 'TableDataTab', data);
|
||||||
// };
|
};
|
||||||
// const handleOpenStructure = () => {
|
const handleOpenCreateScript = () => {
|
||||||
// openTableDetail(setOpenedTabs, 'TableStructureTab', data);
|
openViewDetail(setOpenedTabs, 'TableCreateScriptTab', data);
|
||||||
// };
|
};
|
||||||
// const handleOpenCreateScript = () => {
|
return (
|
||||||
// openTableDetail(setOpenedTabs, 'TableCreateScriptTab', data);
|
<>
|
||||||
// };
|
<DropDownMenuItem onClick={handleOpenData}>Open data</DropDownMenuItem>
|
||||||
// return (
|
<DropDownMenuItem onClick={handleOpenCreateScript}>Create SQL</DropDownMenuItem>
|
||||||
// <>
|
</>
|
||||||
// <DropDownMenuItem onClick={handleOpenData}>Open data</DropDownMenuItem>
|
);
|
||||||
// <DropDownMenuItem onClick={handleOpenStructure}>Open structure</DropDownMenuItem>
|
}
|
||||||
// <DropDownMenuItem onClick={handleOpenCreateScript}>Create SQL</DropDownMenuItem>
|
|
||||||
// </>
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
const viewAppObject = () => ({ conid, database, pureName, schemaName }, { setOpenedTabs }) => {
|
const viewAppObject = () => ({ conid, database, pureName, schemaName }, { setOpenedTabs }) => {
|
||||||
const title = schemaName ? `${schemaName}.${pureName}` : pureName;
|
const title = schemaName ? `${schemaName}.${pureName}` : pureName;
|
||||||
const key = title;
|
const key = title;
|
||||||
const Icon = ViewIcon;
|
const Icon = ViewIcon;
|
||||||
// const onClick = ({ schemaName, pureName }) => {
|
const onClick = ({ schemaName, pureName }) => {
|
||||||
// openTableDetail(setOpenedTabs, 'TableDataTab', {
|
openViewDetail(setOpenedTabs, 'ViewDataTab', {
|
||||||
// schemaName,
|
schemaName,
|
||||||
// pureName,
|
pureName,
|
||||||
// conid,
|
conid,
|
||||||
// database,
|
database,
|
||||||
// });
|
});
|
||||||
// };
|
};
|
||||||
const matcher = (filter) => filterName(filter, pureName);
|
const matcher = (filter) => filterName(filter, pureName);
|
||||||
const groupTitle = 'Views';
|
const groupTitle = 'Views';
|
||||||
|
|
||||||
@@ -65,7 +61,8 @@ const viewAppObject = () => ({ conid, database, pureName, schemaName }, { setOpe
|
|||||||
title,
|
title,
|
||||||
key,
|
key,
|
||||||
Icon,
|
Icon,
|
||||||
// Menu, onClick,
|
Menu,
|
||||||
|
onClick,
|
||||||
matcher,
|
matcher,
|
||||||
groupTitle,
|
groupTitle,
|
||||||
};
|
};
|
||||||
|
|||||||
50
packages/web/src/tabs/ViewDataTab.js
Normal file
50
packages/web/src/tabs/ViewDataTab.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import useFetch from '../utility/useFetch';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import theme from '../theme';
|
||||||
|
import DataGrid from '../datagrid/DataGrid';
|
||||||
|
import { ViewGridDisplay, createGridConfig, createGridCache, createChangeSet } from '@dbgate/datalib';
|
||||||
|
import useTableInfo from '../utility/useTableInfo';
|
||||||
|
import useConnectionInfo from '../utility/useConnectionInfo';
|
||||||
|
import engines from '@dbgate/engines';
|
||||||
|
import getTableInfo from '../utility/getTableInfo';
|
||||||
|
import useUndoReducer from '../utility/useUndoReducer';
|
||||||
|
import usePropsCompare from '../utility/usePropsCompare';
|
||||||
|
import { useUpdateDatabaseForTab } from '../utility/globalState';
|
||||||
|
import useViewInfo from '../utility/useViewInfo';
|
||||||
|
|
||||||
|
export default function ViewDataTab({ conid, database, schemaName, pureName, tabVisible, toolbarPortalRef }) {
|
||||||
|
const viewInfo = useViewInfo({ conid, database, schemaName, pureName });
|
||||||
|
const [config, setConfig] = React.useState(createGridConfig());
|
||||||
|
const [cache, setCache] = React.useState(createGridCache());
|
||||||
|
const [changeSetState, dispatchChangeSet] = useUndoReducer(createChangeSet());
|
||||||
|
|
||||||
|
useUpdateDatabaseForTab(tabVisible, conid, database);
|
||||||
|
const connection = useConnectionInfo(conid);
|
||||||
|
|
||||||
|
// usePropsCompare({ tableInfo, connection, config, cache });
|
||||||
|
|
||||||
|
const display = React.useMemo(
|
||||||
|
() =>
|
||||||
|
viewInfo && connection
|
||||||
|
? new ViewGridDisplay(viewInfo, engines(connection), config, setConfig, cache, setCache,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
[viewInfo, connection, config, cache]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!display) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DataGrid
|
||||||
|
// key={`${conid}, ${database}, ${schemaName}, ${pureName}`}
|
||||||
|
conid={conid}
|
||||||
|
database={database}
|
||||||
|
display={display}
|
||||||
|
tabVisible={tabVisible}
|
||||||
|
changeSetState={changeSetState}
|
||||||
|
dispatchChangeSet={dispatchChangeSet}
|
||||||
|
toolbarPortalRef={toolbarPortalRef}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
import TableDataTab from './TableDataTab';
|
import TableDataTab from './TableDataTab';
|
||||||
|
import ViewDataTab from './ViewDataTab';
|
||||||
import TableStructureTab from './TableStructureTab';
|
import TableStructureTab from './TableStructureTab';
|
||||||
import TableCreateScriptTab from './TableCreateScriptTab';
|
import TableCreateScriptTab from './TableCreateScriptTab';
|
||||||
import QueryTab from './QueryTab';
|
import QueryTab from './QueryTab';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
TableDataTab,
|
TableDataTab,
|
||||||
|
ViewDataTab,
|
||||||
TableStructureTab,
|
TableStructureTab,
|
||||||
TableCreateScriptTab,
|
TableCreateScriptTab,
|
||||||
QueryTab,
|
QueryTab,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import axios from './axios';
|
|||||||
export default async function getTableInfo({ conid, database, schemaName, pureName }) {
|
export default async function getTableInfo({ conid, database, schemaName, pureName }) {
|
||||||
const resp = await axios.request({
|
const resp = await axios.request({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: 'tables/table-info',
|
url: 'metadata/table-info',
|
||||||
params: { conid, database, schemaName, pureName },
|
params: { conid, database, schemaName, pureName },
|
||||||
});
|
});
|
||||||
/** @type {import('@dbgate/types').TableInfo} */
|
/** @type {import('@dbgate/types').TableInfo} */
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import useFetch from './useFetch';
|
|||||||
export default function useTableInfo({ conid, database, schemaName, pureName }) {
|
export default function useTableInfo({ conid, database, schemaName, pureName }) {
|
||||||
/** @type {import('@dbgate/types').TableInfo} */
|
/** @type {import('@dbgate/types').TableInfo} */
|
||||||
const tableInfo = useFetch({
|
const tableInfo = useFetch({
|
||||||
url: 'tables/table-info',
|
url: 'metadata/table-info',
|
||||||
params: { conid, database, schemaName, pureName },
|
params: { conid, database, schemaName, pureName },
|
||||||
reloadTrigger: `database-structure-changed-${conid}-${database}`,
|
reloadTrigger: `database-structure-changed-${conid}-${database}`,
|
||||||
});
|
});
|
||||||
|
|||||||
11
packages/web/src/utility/useViewInfo.js
Normal file
11
packages/web/src/utility/useViewInfo.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import useFetch from './useFetch';
|
||||||
|
|
||||||
|
export default function useViewInfo({ conid, database, schemaName, pureName }) {
|
||||||
|
/** @type {import('@dbgate/types').ViewInfo} */
|
||||||
|
const viewInfo = useFetch({
|
||||||
|
url: 'metadata/view-info',
|
||||||
|
params: { conid, database, schemaName, pureName },
|
||||||
|
reloadTrigger: `database-structure-changed-${conid}-${database}`,
|
||||||
|
});
|
||||||
|
return viewInfo;
|
||||||
|
}
|
||||||
@@ -95,7 +95,7 @@ function ConnectionList() {
|
|||||||
|
|
||||||
function SqlObjectList({ conid, database }) {
|
function SqlObjectList({ conid, database }) {
|
||||||
const objects = useFetch({
|
const objects = useFetch({
|
||||||
url: `database-connections/list-objects?conid=${conid}&database=${database}`,
|
url: `metadata/list-objects?conid=${conid}&database=${database}`,
|
||||||
reloadTrigger: `database-structure-changed-${conid}-${database}`,
|
reloadTrigger: `database-structure-changed-${conid}-${database}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user