table grid display, SQL for browse table is generated on FE

This commit is contained in:
Jan Prochazka 2020-03-05 09:40:05 +01:00
parent bbc969fa71
commit aad9512951
14 changed files with 152 additions and 39 deletions

View File

@ -66,4 +66,12 @@ module.exports = {
tables: _.sortBy(tables, x => `${x.schemaName}.${x.pureName}`),
}; // .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;
},
};

View File

@ -2,12 +2,12 @@ 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;
},
// 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 }) {

View File

@ -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();
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);
process.send({ msgtype: 'response', msgid, ...res });
}
const messageHandlers = {
connect: handleConnect,
tableData: handleTableData,
queryData: handleQueryData,
};
async function handleMessage({ msgtype, ...other }) {

1
packages/datalib/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
lib

View 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"
}
}

View File

@ -0,0 +1,5 @@
import {Select} from '@dbgate/sqltree'
export default abstract class GridDisplay {
abstract getPageQuery(offse: number, count: number): string;
}

View 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;
}
}

View File

@ -0,0 +1,2 @@
export { default as GridDisplay } from "./GridDisplay";
export { default as TableGridDisplay } from "./TableGridDisplay";

View File

@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "ES2015",
"module": "commonjs",
"declaration": true,
"skipLibCheck": true,
"outDir": "lib"
},
"include": [
"src/**/*"
]
}

View File

@ -30,7 +30,9 @@ class SqlDumper {
break;
case "k":
{
this.putRaw(value.toUpperCase());
if (value) {
this.putRaw(value.toUpperCase());
}
}
break;
case "f":
@ -46,6 +48,7 @@ class SqlDumper {
}
}
putFormattedList(c, collection) {
if (!collection) return;
this.putCollection(", ", collection, item =>
this.putFormattedValue(c, item)
);
@ -130,7 +133,7 @@ class SqlDumper {
if (column.isPersisted) this.put(" ^persisted");
return;
}
if (column.dataType) this.put("%k", column.dataType);
this.put("%k", column.dataType);
if (column.autoIncrement) {
this.autoIncrement();
}

View File

@ -22,6 +22,8 @@
"socket.io-client": "^2.3.0",
"styled-components": "^4.4.1",
"uuid": "^3.4.0",
"@dbgate/sqltree": "^0.1.0",
"@dbgate/datalib": "^0.1.0",
"@dbgate/engines": "^0.1.0"
},
"scripts": {

View File

@ -63,10 +63,26 @@ const TableBodyCell = styled.td`
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({
url: 'tables/table-data',
params,
url: 'database-connections/query-data',
method: 'post',
params: {
conid,
database,
},
data: { sql },
});
const { rows, columns } = data || {};
const [firstVisibleRowScrollIndex, setFirstVisibleRowScrollIndex] = React.useState(0);
@ -116,21 +132,21 @@ export default function DataGrid({ params }) {
columnSizes.setExtraordinaryIndexes([], []);
for (let colIndex = 0; colIndex < columns.length; colIndex++) {
//this.columnSizes.PutSizeOverride(col, this.columns[col].Name.length * 8);
let column = columns[colIndex];
//this.columnSizes.PutSizeOverride(col, this.columns[col].Name.length * 8);
let column = columns[colIndex];
// if (column.columnClientObject != null && column.columnClientObject.notNull) context.font = "bold 14px Helvetica";
// else context.font = "14px Helvetica";
context.font = "bold 14px Helvetica";
// if (column.columnClientObject != null && column.columnClientObject.notNull) context.font = "bold 14px Helvetica";
// else context.font = "14px Helvetica";
context.font = 'bold 14px Helvetica';
let text = column.name;
let headerWidth = context.measureText(text).width + 32;
let text = column.name;
let headerWidth = context.measureText(text).width + 32;
// if (column.columnClientObject != null && column.columnClientObject.icon != null) headerWidth += 16;
// if (this.getFilterOnColumn(column.uniquePath)) headerWidth += 16;
// if (this.getSortOrder(column.uniquePath)) headerWidth += 16;
// if (column.columnClientObject != null && column.columnClientObject.icon != null) headerWidth += 16;
// if (this.getFilterOnColumn(column.uniquePath)) headerWidth += 16;
// if (this.getSortOrder(column.uniquePath)) headerWidth += 16;
columnSizes.putSizeOverride(colIndex, headerWidth);
columnSizes.putSizeOverride(colIndex, headerWidth);
}
// let headerWidth = this.rowHeaderWidthDefault;

View File

@ -3,7 +3,22 @@ import useFetch from '../utility/useFetch';
import styled from 'styled-components';
import theme from '../theme';
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 }) {
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}
/>
);
}

View File

@ -1,16 +1,18 @@
import React from 'react';
import _ from 'lodash';
import axios from './axios';
import useSocket from './SocketProvider';
import stableStringify from 'json-stable-stringify';
export default function useFetch({
url,
data = undefined,
params = undefined,
defaultValue = undefined,
reloadTrigger = undefined,
...config
}) {
const [value, setValue] = React.useState(defaultValue);
const [value, setValue] = React.useState([defaultValue, []]);
const [loadCounter, setLoadCounter] = React.useState(0);
const socket = useSocket();
@ -18,24 +20,30 @@ export default function useFetch({
setLoadCounter(loadCounter + 1);
};
async function loadValue() {
const indicators = [url, stableStringify(data), stableStringify(params), loadCounter];
async function loadValue(loadedIndicators) {
const resp = await axios.request({
method: 'get',
params,
url,
data,
...config,
});
setValue(resp.data);
setValue([resp.data, loadedIndicators]);
}
React.useEffect(() => {
loadValue();
loadValue(indicators);
if (reloadTrigger && socket) {
socket.on(reloadTrigger, handleReload);
return () => {
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;
}