diff --git a/packages/api/src/controllers/databaseConnections.js b/packages/api/src/controllers/databaseConnections.js
index d5b150864..2d5bc8672 100644
--- a/packages/api/src/controllers/databaseConnections.js
+++ b/packages/api/src/controllers/databaseConnections.js
@@ -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;
+ },
};
diff --git a/packages/api/src/controllers/tables.js b/packages/api/src/controllers/tables.js
index 5581ea258..c679b8e1e 100644
--- a/packages/api/src/controllers/tables.js
+++ b/packages/api/src/controllers/tables.js
@@ -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 }) {
diff --git a/packages/api/src/proc/databaseConnectionProcess.js b/packages/api/src/proc/databaseConnectionProcess.js
index 8198d3c23..59bed790e 100644
--- a/packages/api/src/proc/databaseConnectionProcess.js
+++ b/packages/api/src/proc/databaseConnectionProcess.js
@@ -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 }) {
diff --git a/packages/datalib/.gitignore b/packages/datalib/.gitignore
new file mode 100644
index 000000000..7951405f8
--- /dev/null
+++ b/packages/datalib/.gitignore
@@ -0,0 +1 @@
+lib
\ No newline at end of file
diff --git a/packages/datalib/package.json b/packages/datalib/package.json
new file mode 100644
index 000000000..c16d32c32
--- /dev/null
+++ b/packages/datalib/package.json
@@ -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"
+ }
+}
\ No newline at end of file
diff --git a/packages/datalib/src/GridDisplay.ts b/packages/datalib/src/GridDisplay.ts
new file mode 100644
index 000000000..326557db1
--- /dev/null
+++ b/packages/datalib/src/GridDisplay.ts
@@ -0,0 +1,5 @@
+import {Select} from '@dbgate/sqltree'
+
+export default abstract class GridDisplay {
+ abstract getPageQuery(offse: number, count: number): string;
+}
diff --git a/packages/datalib/src/TableGridDisplay.ts b/packages/datalib/src/TableGridDisplay.ts
new file mode 100644
index 000000000..a70b8ae12
--- /dev/null
+++ b/packages/datalib/src/TableGridDisplay.ts
@@ -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;
+ }
+}
diff --git a/packages/datalib/src/index.ts b/packages/datalib/src/index.ts
new file mode 100644
index 000000000..906defb86
--- /dev/null
+++ b/packages/datalib/src/index.ts
@@ -0,0 +1,2 @@
+export { default as GridDisplay } from "./GridDisplay";
+export { default as TableGridDisplay } from "./TableGridDisplay";
diff --git a/packages/datalib/tsconfig.json b/packages/datalib/tsconfig.json
new file mode 100644
index 000000000..4dfd0a5f7
--- /dev/null
+++ b/packages/datalib/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "target": "ES2015",
+ "module": "commonjs",
+ "declaration": true,
+ "skipLibCheck": true,
+ "outDir": "lib"
+ },
+ "include": [
+ "src/**/*"
+ ]
+ }
\ No newline at end of file
diff --git a/packages/engines/default/SqlDumper.js b/packages/engines/default/SqlDumper.js
index 3a9c3196e..5f34bc14e 100644
--- a/packages/engines/default/SqlDumper.js
+++ b/packages/engines/default/SqlDumper.js
@@ -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();
}
diff --git a/packages/web/package.json b/packages/web/package.json
index 370b29afb..6bd0ec991 100644
--- a/packages/web/package.json
+++ b/packages/web/package.json
@@ -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": {
diff --git a/packages/web/src/datagrid/DataGrid.js b/packages/web/src/datagrid/DataGrid.js
index 820bebb34..ee25a57c3 100644
--- a/packages/web/src/datagrid/DataGrid.js
+++ b/packages/web/src/datagrid/DataGrid.js
@@ -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;
diff --git a/packages/web/src/tabs/TableDataTab.js b/packages/web/src/tabs/TableDataTab.js
index 86c897b19..2c14ecd49 100644
--- a/packages/web/src/tabs/TableDataTab.js
+++ b/packages/web/src/tabs/TableDataTab.js
@@ -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 ;
+ const tableInfo = useTableInfo({ conid, database, schemaName, pureName });
+ const connection = useConnectionInfo(conid);
+ if (!tableInfo || !connection) return null;
+ const display = new TableGridDisplay(tableInfo, engines(connection));
+ return (
+
+ );
}
diff --git a/packages/web/src/utility/useFetch.js b/packages/web/src/utility/useFetch.js
index 87883f7b6..490aa2991 100644
--- a/packages/web/src/utility/useFetch.js
+++ b/packages/web/src/utility/useFetch.js
@@ -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;
}