mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-18 00:56:02 +00:00
table grid display, SQL for browse table is generated on FE
This commit is contained in:
@@ -66,4 +66,12 @@ module.exports = {
|
|||||||
tables: _.sortBy(tables, x => `${x.schemaName}.${x.pureName}`),
|
tables: _.sortBy(tables, x => `${x.schemaName}.${x.pureName}`),
|
||||||
}; // .map(fp.pick(['tableName', 'schemaName']));
|
}; // .map(fp.pick(['tableName', 'schemaName']));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
queryData_meta: 'post',
|
||||||
|
async queryData({ conid, database, sql }) {
|
||||||
|
console.log(`Processing query, conid=${conid}, database=${database}, sql=${sql}`);
|
||||||
|
const opened = await this.ensureOpened(conid, database);
|
||||||
|
const res = await this.sendRequest(opened, { msgtype: 'queryData', sql });
|
||||||
|
return res;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ const _ = require('lodash');
|
|||||||
const databaseConnections = require('./databaseConnections');
|
const databaseConnections = require('./databaseConnections');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
tableData_meta: 'get',
|
// tableData_meta: 'get',
|
||||||
async tableData({ conid, database, schemaName, pureName }) {
|
// async tableData({ conid, database, schemaName, pureName }) {
|
||||||
const opened = await databaseConnections.ensureOpened(conid, database);
|
// const opened = await databaseConnections.ensureOpened(conid, database);
|
||||||
const res = await databaseConnections.sendRequest(opened, { msgtype: 'tableData', schemaName, pureName });
|
// const res = await databaseConnections.sendRequest(opened, { msgtype: 'tableData', schemaName, pureName });
|
||||||
return res;
|
// return res;
|
||||||
},
|
// },
|
||||||
|
|
||||||
tableInfo_meta: 'get',
|
tableInfo_meta: 'get',
|
||||||
async tableInfo({ conid, database, schemaName, pureName }) {
|
async tableInfo({ conid, database, schemaName, pureName }) {
|
||||||
|
|||||||
@@ -32,24 +32,23 @@ function waitConnected() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleTableData({ msgid, schemaName, pureName }) {
|
async function handleQueryData({ msgid, sql }) {
|
||||||
|
// const select = new Select();
|
||||||
|
// if (driver.dialect.limitSelect) select.topRecords = 100;
|
||||||
|
// if (driver.dialect.rangeSelect) select.range = { offset: 0, limit: 100 };
|
||||||
|
// select.from = { schemaName, pureName };
|
||||||
|
// select.selectAll = true;
|
||||||
|
// const sql = select.toSql(driver);
|
||||||
|
|
||||||
await waitConnected();
|
await waitConnected();
|
||||||
const driver = engines(storedConnection);
|
const driver = engines(storedConnection);
|
||||||
|
|
||||||
const select = new Select();
|
|
||||||
if (driver.dialect.limitSelect) select.topRecords = 100;
|
|
||||||
if (driver.dialect.rangeSelect) select.range = { offset: 0, limit: 100 };
|
|
||||||
select.from = { schemaName, pureName };
|
|
||||||
select.selectAll = true;
|
|
||||||
const sql = select.toSql(driver);
|
|
||||||
const res = await driver.query(systemConnection, sql);
|
const res = await driver.query(systemConnection, sql);
|
||||||
|
|
||||||
process.send({ msgtype: 'response', msgid, ...res });
|
process.send({ msgtype: 'response', msgid, ...res });
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageHandlers = {
|
const messageHandlers = {
|
||||||
connect: handleConnect,
|
connect: handleConnect,
|
||||||
tableData: handleTableData,
|
queryData: handleQueryData,
|
||||||
};
|
};
|
||||||
|
|
||||||
async function handleMessage({ msgtype, ...other }) {
|
async function handleMessage({ msgtype, ...other }) {
|
||||||
|
|||||||
1
packages/datalib/.gitignore
vendored
Normal file
1
packages/datalib/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
lib
|
||||||
22
packages/datalib/package.json
Normal file
22
packages/datalib/package.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"version": "0.1.0",
|
||||||
|
"name": "@dbgate/datalib",
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"typings": "lib/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"prepare": "yarn build",
|
||||||
|
"build": "tsc",
|
||||||
|
"start": "tsc --watch"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@dbgate/sqltree": "^0.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@dbgate/types": "^0.1.0",
|
||||||
|
"@types/node": "^13.7.0",
|
||||||
|
"typescript": "^3.7.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
5
packages/datalib/src/GridDisplay.ts
Normal file
5
packages/datalib/src/GridDisplay.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import {Select} from '@dbgate/sqltree'
|
||||||
|
|
||||||
|
export default abstract class GridDisplay {
|
||||||
|
abstract getPageQuery(offse: number, count: number): string;
|
||||||
|
}
|
||||||
20
packages/datalib/src/TableGridDisplay.ts
Normal file
20
packages/datalib/src/TableGridDisplay.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import GridDisplay from "./GridDisplay";
|
||||||
|
import { Select } from "@dbgate/sqltree";
|
||||||
|
import { TableInfo, EngineDriver } from "@dbgate/types";
|
||||||
|
|
||||||
|
export default class TableGridDisplay extends GridDisplay {
|
||||||
|
constructor(public table: TableInfo, public driver: EngineDriver) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
getPageQuery(offset: number, count: number) {
|
||||||
|
const select = new Select();
|
||||||
|
if (this.driver.dialect.limitSelect) select.topRecords = count;
|
||||||
|
if (this.driver.dialect.rangeSelect)
|
||||||
|
select.range = { offset: offset, limit: count };
|
||||||
|
select.from = this.table;
|
||||||
|
select.selectAll = true;
|
||||||
|
const sql = select.toSql(this.driver);
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
}
|
||||||
2
packages/datalib/src/index.ts
Normal file
2
packages/datalib/src/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export { default as GridDisplay } from "./GridDisplay";
|
||||||
|
export { default as TableGridDisplay } from "./TableGridDisplay";
|
||||||
12
packages/datalib/tsconfig.json
Normal file
12
packages/datalib/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2015",
|
||||||
|
"module": "commonjs",
|
||||||
|
"declaration": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"outDir": "lib"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -30,7 +30,9 @@ class SqlDumper {
|
|||||||
break;
|
break;
|
||||||
case "k":
|
case "k":
|
||||||
{
|
{
|
||||||
this.putRaw(value.toUpperCase());
|
if (value) {
|
||||||
|
this.putRaw(value.toUpperCase());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "f":
|
case "f":
|
||||||
@@ -46,6 +48,7 @@ class SqlDumper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
putFormattedList(c, collection) {
|
putFormattedList(c, collection) {
|
||||||
|
if (!collection) return;
|
||||||
this.putCollection(", ", collection, item =>
|
this.putCollection(", ", collection, item =>
|
||||||
this.putFormattedValue(c, item)
|
this.putFormattedValue(c, item)
|
||||||
);
|
);
|
||||||
@@ -130,7 +133,7 @@ class SqlDumper {
|
|||||||
if (column.isPersisted) this.put(" ^persisted");
|
if (column.isPersisted) this.put(" ^persisted");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (column.dataType) this.put("%k", column.dataType);
|
this.put("%k", column.dataType);
|
||||||
if (column.autoIncrement) {
|
if (column.autoIncrement) {
|
||||||
this.autoIncrement();
|
this.autoIncrement();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
"socket.io-client": "^2.3.0",
|
"socket.io-client": "^2.3.0",
|
||||||
"styled-components": "^4.4.1",
|
"styled-components": "^4.4.1",
|
||||||
"uuid": "^3.4.0",
|
"uuid": "^3.4.0",
|
||||||
|
"@dbgate/sqltree": "^0.1.0",
|
||||||
|
"@dbgate/datalib": "^0.1.0",
|
||||||
"@dbgate/engines": "^0.1.0"
|
"@dbgate/engines": "^0.1.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -63,10 +63,26 @@ const TableBodyCell = styled.td`
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default function DataGrid({ params }) {
|
/**
|
||||||
|
* @param {object} props
|
||||||
|
* @param {number} props.conid
|
||||||
|
* @param {string} props.database
|
||||||
|
* @param {import('@dbgate/datalib').GridDisplay} props.display
|
||||||
|
*/
|
||||||
|
export default function DataGrid(props) {
|
||||||
|
const { conid, database, display } = props;
|
||||||
|
const sql = display.getPageQuery(0, 100);
|
||||||
|
|
||||||
|
console.log(`GRID, conid=${conid}, database=${database}, sql=${sql}`);
|
||||||
|
|
||||||
const data = useFetch({
|
const data = useFetch({
|
||||||
url: 'tables/table-data',
|
url: 'database-connections/query-data',
|
||||||
params,
|
method: 'post',
|
||||||
|
params: {
|
||||||
|
conid,
|
||||||
|
database,
|
||||||
|
},
|
||||||
|
data: { sql },
|
||||||
});
|
});
|
||||||
const { rows, columns } = data || {};
|
const { rows, columns } = data || {};
|
||||||
const [firstVisibleRowScrollIndex, setFirstVisibleRowScrollIndex] = React.useState(0);
|
const [firstVisibleRowScrollIndex, setFirstVisibleRowScrollIndex] = React.useState(0);
|
||||||
@@ -116,21 +132,21 @@ export default function DataGrid({ params }) {
|
|||||||
columnSizes.setExtraordinaryIndexes([], []);
|
columnSizes.setExtraordinaryIndexes([], []);
|
||||||
|
|
||||||
for (let colIndex = 0; colIndex < columns.length; colIndex++) {
|
for (let colIndex = 0; colIndex < columns.length; colIndex++) {
|
||||||
//this.columnSizes.PutSizeOverride(col, this.columns[col].Name.length * 8);
|
//this.columnSizes.PutSizeOverride(col, this.columns[col].Name.length * 8);
|
||||||
let column = columns[colIndex];
|
let column = columns[colIndex];
|
||||||
|
|
||||||
// if (column.columnClientObject != null && column.columnClientObject.notNull) context.font = "bold 14px Helvetica";
|
// if (column.columnClientObject != null && column.columnClientObject.notNull) context.font = "bold 14px Helvetica";
|
||||||
// else context.font = "14px Helvetica";
|
// else context.font = "14px Helvetica";
|
||||||
context.font = "bold 14px Helvetica";
|
context.font = 'bold 14px Helvetica';
|
||||||
|
|
||||||
let text = column.name;
|
let text = column.name;
|
||||||
let headerWidth = context.measureText(text).width + 32;
|
let headerWidth = context.measureText(text).width + 32;
|
||||||
|
|
||||||
// if (column.columnClientObject != null && column.columnClientObject.icon != null) headerWidth += 16;
|
// if (column.columnClientObject != null && column.columnClientObject.icon != null) headerWidth += 16;
|
||||||
// if (this.getFilterOnColumn(column.uniquePath)) headerWidth += 16;
|
// if (this.getFilterOnColumn(column.uniquePath)) headerWidth += 16;
|
||||||
// if (this.getSortOrder(column.uniquePath)) headerWidth += 16;
|
// if (this.getSortOrder(column.uniquePath)) headerWidth += 16;
|
||||||
|
|
||||||
columnSizes.putSizeOverride(colIndex, headerWidth);
|
columnSizes.putSizeOverride(colIndex, headerWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// let headerWidth = this.rowHeaderWidthDefault;
|
// let headerWidth = this.rowHeaderWidthDefault;
|
||||||
|
|||||||
@@ -3,7 +3,22 @@ import useFetch from '../utility/useFetch';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import theme from '../theme';
|
import theme from '../theme';
|
||||||
import DataGrid from '../datagrid/DataGrid';
|
import DataGrid from '../datagrid/DataGrid';
|
||||||
|
import { TableGridDisplay } from '@dbgate/datalib';
|
||||||
|
import useTableInfo from '../utility/useTableInfo';
|
||||||
|
import useConnectionInfo from '../utility/useConnectionInfo';
|
||||||
|
import engines from '@dbgate/engines';
|
||||||
|
|
||||||
export default function TableDataTab({ conid, database, schemaName, pureName }) {
|
export default function TableDataTab({ conid, database, schemaName, pureName }) {
|
||||||
return <DataGrid params={{ conid, database, schemaName, pureName }} />;
|
const tableInfo = useTableInfo({ conid, database, schemaName, pureName });
|
||||||
|
const connection = useConnectionInfo(conid);
|
||||||
|
if (!tableInfo || !connection) return null;
|
||||||
|
const display = new TableGridDisplay(tableInfo, engines(connection));
|
||||||
|
return (
|
||||||
|
<DataGrid
|
||||||
|
// key={`${conid}, ${database}, ${schemaName}, ${pureName}`}
|
||||||
|
conid={conid}
|
||||||
|
database={database}
|
||||||
|
display={display}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import _ from 'lodash';
|
||||||
import axios from './axios';
|
import axios from './axios';
|
||||||
import useSocket from './SocketProvider';
|
import useSocket from './SocketProvider';
|
||||||
import stableStringify from 'json-stable-stringify';
|
import stableStringify from 'json-stable-stringify';
|
||||||
|
|
||||||
export default function useFetch({
|
export default function useFetch({
|
||||||
url,
|
url,
|
||||||
|
data = undefined,
|
||||||
params = undefined,
|
params = undefined,
|
||||||
defaultValue = undefined,
|
defaultValue = undefined,
|
||||||
reloadTrigger = undefined,
|
reloadTrigger = undefined,
|
||||||
...config
|
...config
|
||||||
}) {
|
}) {
|
||||||
const [value, setValue] = React.useState(defaultValue);
|
const [value, setValue] = React.useState([defaultValue, []]);
|
||||||
const [loadCounter, setLoadCounter] = React.useState(0);
|
const [loadCounter, setLoadCounter] = React.useState(0);
|
||||||
const socket = useSocket();
|
const socket = useSocket();
|
||||||
|
|
||||||
@@ -18,24 +20,30 @@ export default function useFetch({
|
|||||||
setLoadCounter(loadCounter + 1);
|
setLoadCounter(loadCounter + 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
async function loadValue() {
|
const indicators = [url, stableStringify(data), stableStringify(params), loadCounter];
|
||||||
|
|
||||||
|
async function loadValue(loadedIndicators) {
|
||||||
const resp = await axios.request({
|
const resp = await axios.request({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params,
|
params,
|
||||||
url,
|
url,
|
||||||
|
data,
|
||||||
...config,
|
...config,
|
||||||
});
|
});
|
||||||
setValue(resp.data);
|
setValue([resp.data, loadedIndicators]);
|
||||||
}
|
}
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
loadValue();
|
loadValue(indicators);
|
||||||
if (reloadTrigger && socket) {
|
if (reloadTrigger && socket) {
|
||||||
socket.on(reloadTrigger, handleReload);
|
socket.on(reloadTrigger, handleReload);
|
||||||
return () => {
|
return () => {
|
||||||
socket.off(reloadTrigger, handleReload);
|
socket.off(reloadTrigger, handleReload);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, [url, stableStringify(params), socket, loadCounter]);
|
}, [...indicators, socket]);
|
||||||
|
|
||||||
return value;
|
const [returnValue, loadedIndicators] = value;
|
||||||
|
if (_.isEqual(indicators, loadedIndicators)) return returnValue;
|
||||||
|
|
||||||
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user