mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-05-03 08:13:57 +00:00
query result shown
This commit is contained in:
@@ -34,7 +34,7 @@ module.exports = {
|
|||||||
openReader(jslid) {
|
openReader(jslid) {
|
||||||
const file = path.join(jsldir(), `${jslid}.jsonl`);
|
const file = path.join(jsldir(), `${jslid}.jsonl`);
|
||||||
return new Promise((resolve, reject) =>
|
return new Promise((resolve, reject) =>
|
||||||
lineReader.open(file, function (err, reader) {
|
lineReader.open(file, (err, reader) => {
|
||||||
if (err) reject(err);
|
if (err) reject(err);
|
||||||
resolve();
|
resolve();
|
||||||
this.openedReaders[jslid] = {
|
this.openedReaders[jslid] = {
|
||||||
@@ -50,7 +50,7 @@ module.exports = {
|
|||||||
await this.closeReader();
|
await this.closeReader();
|
||||||
}
|
}
|
||||||
if (!this.openedReaders[jslid]) {
|
if (!this.openedReaders[jslid]) {
|
||||||
await this.openReader();
|
await this.openReader(jslid);
|
||||||
}
|
}
|
||||||
while (this.openedReaders[jslid].readedCount < offset) {
|
while (this.openedReaders[jslid].readedCount < offset) {
|
||||||
await this.readLine(jslid);
|
await this.readLine(jslid);
|
||||||
|
|||||||
@@ -40,11 +40,12 @@ export function findExistingChangeSetItem(
|
|||||||
changeSet: ChangeSet,
|
changeSet: ChangeSet,
|
||||||
definition: ChangeSetRowDefinition
|
definition: ChangeSetRowDefinition
|
||||||
): [keyof ChangeSet, ChangeSetItem] {
|
): [keyof ChangeSet, ChangeSetItem] {
|
||||||
|
if (!changeSet) return ['updates', null];
|
||||||
if (definition.insertedRowIndex != null) {
|
if (definition.insertedRowIndex != null) {
|
||||||
return [
|
return [
|
||||||
'inserts',
|
'inserts',
|
||||||
changeSet.inserts.find(
|
changeSet.inserts.find(
|
||||||
x =>
|
(x) =>
|
||||||
x.pureName == definition.pureName &&
|
x.pureName == definition.pureName &&
|
||||||
x.schemaName == definition.schemaName &&
|
x.schemaName == definition.schemaName &&
|
||||||
x.insertedRowIndex == definition.insertedRowIndex
|
x.insertedRowIndex == definition.insertedRowIndex
|
||||||
@@ -52,7 +53,7 @@ export function findExistingChangeSetItem(
|
|||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
const inUpdates = changeSet.updates.find(
|
const inUpdates = changeSet.updates.find(
|
||||||
x =>
|
(x) =>
|
||||||
x.pureName == definition.pureName &&
|
x.pureName == definition.pureName &&
|
||||||
x.schemaName == definition.schemaName &&
|
x.schemaName == definition.schemaName &&
|
||||||
_.isEqual(x.condition, definition.condition)
|
_.isEqual(x.condition, definition.condition)
|
||||||
@@ -60,7 +61,7 @@ export function findExistingChangeSetItem(
|
|||||||
if (inUpdates) return ['updates', inUpdates];
|
if (inUpdates) return ['updates', inUpdates];
|
||||||
|
|
||||||
const inDeletes = changeSet.deletes.find(
|
const inDeletes = changeSet.deletes.find(
|
||||||
x =>
|
(x) =>
|
||||||
x.pureName == definition.pureName &&
|
x.pureName == definition.pureName &&
|
||||||
x.schemaName == definition.schemaName &&
|
x.schemaName == definition.schemaName &&
|
||||||
_.isEqual(x.condition, definition.condition)
|
_.isEqual(x.condition, definition.condition)
|
||||||
@@ -84,7 +85,7 @@ export function setChangeSetValue(
|
|||||||
if (existingItem) {
|
if (existingItem) {
|
||||||
return {
|
return {
|
||||||
...changeSet,
|
...changeSet,
|
||||||
[fieldName]: changeSet[fieldName].map(item =>
|
[fieldName]: changeSet[fieldName].map((item) =>
|
||||||
item == existingItem
|
item == existingItem
|
||||||
? {
|
? {
|
||||||
...item,
|
...item,
|
||||||
@@ -164,7 +165,7 @@ export function batchUpdateChangeSet(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function extractFields(item: ChangeSetItem): UpdateField[] {
|
function extractFields(item: ChangeSetItem): UpdateField[] {
|
||||||
return _.keys(item.fields).map(targetColumn => ({
|
return _.keys(item.fields).map((targetColumn) => ({
|
||||||
targetColumn,
|
targetColumn,
|
||||||
exprType: 'value',
|
exprType: 'value',
|
||||||
value: item.fields[targetColumn],
|
value: item.fields[targetColumn],
|
||||||
@@ -185,7 +186,7 @@ function insertToSql(item: ChangeSetItem): Insert {
|
|||||||
function extractCondition(item: ChangeSetItem): Condition {
|
function extractCondition(item: ChangeSetItem): Condition {
|
||||||
return {
|
return {
|
||||||
conditionType: 'and',
|
conditionType: 'and',
|
||||||
conditions: _.keys(item.condition).map(columnName => ({
|
conditions: _.keys(item.condition).map((columnName) => ({
|
||||||
conditionType: 'binary',
|
conditionType: 'binary',
|
||||||
operator: '=',
|
operator: '=',
|
||||||
left: {
|
left: {
|
||||||
@@ -248,7 +249,7 @@ export function revertChangeSetRowChanges(changeSet: ChangeSet, definition: Chan
|
|||||||
if (item)
|
if (item)
|
||||||
return {
|
return {
|
||||||
...changeSet,
|
...changeSet,
|
||||||
[field]: changeSet[field].filter(x => x != item),
|
[field]: changeSet[field].filter((x) => x != item),
|
||||||
};
|
};
|
||||||
return changeSet;
|
return changeSet;
|
||||||
}
|
}
|
||||||
@@ -280,8 +281,8 @@ export function deleteChangeSetRows(changeSet: ChangeSet, definition: ChangeSetR
|
|||||||
export function getChangeSetInsertedRows(changeSet: ChangeSet, name?: NamedObjectInfo) {
|
export function getChangeSetInsertedRows(changeSet: ChangeSet, name?: NamedObjectInfo) {
|
||||||
if (!name) return [];
|
if (!name) return [];
|
||||||
if (!changeSet) return [];
|
if (!changeSet) return [];
|
||||||
const rows = changeSet.inserts.filter(x => x.pureName == name.pureName && x.schemaName == name.schemaName);
|
const rows = changeSet.inserts.filter((x) => x.pureName == name.pureName && x.schemaName == name.schemaName);
|
||||||
const maxIndex = _.maxBy(rows, x => x.insertedRowIndex)?.insertedRowIndex;
|
const maxIndex = _.maxBy(rows, (x) => x.insertedRowIndex)?.insertedRowIndex;
|
||||||
if (maxIndex == null) return [];
|
if (maxIndex == null) return [];
|
||||||
const res = Array(maxIndex + 1).fill({});
|
const res = Array(maxIndex + 1).fill({});
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ export abstract class GridDisplay {
|
|||||||
columns: DisplayColumn[];
|
columns: DisplayColumn[];
|
||||||
baseTable?: TableInfo;
|
baseTable?: TableInfo;
|
||||||
changeSetKeyFields: string[] = null;
|
changeSetKeyFields: string[] = null;
|
||||||
|
sortable = false;
|
||||||
|
filterable = false;
|
||||||
|
editable = false;
|
||||||
|
|
||||||
setColumnVisibility(uniquePath: string[], isVisible: boolean) {
|
setColumnVisibility(uniquePath: string[], isVisible: boolean) {
|
||||||
const uniqueName = uniquePath.join('.');
|
const uniqueName = uniquePath.join('.');
|
||||||
|
|||||||
@@ -16,11 +16,14 @@ export class TableGridDisplay extends GridDisplay {
|
|||||||
) {
|
) {
|
||||||
super(config, setConfig, cache, setCache, getTableInfo, driver);
|
super(config, setConfig, cache, setCache, getTableInfo, driver);
|
||||||
this.columns = this.getDisplayColumns(table, []);
|
this.columns = this.getDisplayColumns(table, []);
|
||||||
|
this.filterable = true;
|
||||||
|
this.sortable = true;
|
||||||
|
this.editable = true;
|
||||||
this.baseTable = table;
|
this.baseTable = table;
|
||||||
if (table && table.columns) {
|
if (table && table.columns) {
|
||||||
this.changeSetKeyFields = table.primaryKey
|
this.changeSetKeyFields = table.primaryKey
|
||||||
? table.primaryKey.columns.map(x => x.columnName)
|
? table.primaryKey.columns.map((x) => x.columnName)
|
||||||
: table.columns.map(x => x.columnName);
|
: table.columns.map((x) => x.columnName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +33,7 @@ export class TableGridDisplay extends GridDisplay {
|
|||||||
const select: Select = {
|
const select: Select = {
|
||||||
commandType: 'select',
|
commandType: 'select',
|
||||||
from: { name: this.table, alias: 'basetbl' },
|
from: { name: this.table, alias: 'basetbl' },
|
||||||
columns: this.table.columns.map(col => ({
|
columns: this.table.columns.map((col) => ({
|
||||||
exprType: 'column',
|
exprType: 'column',
|
||||||
alias: col.columnName,
|
alias: col.columnName,
|
||||||
source: { alias: 'basetbl' },
|
source: { alias: 'basetbl' },
|
||||||
@@ -45,7 +48,7 @@ export class TableGridDisplay extends GridDisplay {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
const displayedColumnInfo = _.keyBy(
|
const displayedColumnInfo = _.keyBy(
|
||||||
this.columns.map(col => ({ ...col, sourceAlias: 'basetbl' })),
|
this.columns.map((col) => ({ ...col, sourceAlias: 'basetbl' })),
|
||||||
'uniqueName'
|
'uniqueName'
|
||||||
);
|
);
|
||||||
const action = combineReferenceActions(
|
const action = combineReferenceActions(
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ const TabContainer = styled.div`
|
|||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
display: flex;
|
||||||
visibility: ${props =>
|
visibility: ${props =>
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
props.tabVisible ? 'visible' : 'hidden'};
|
props.tabVisible ? 'visible' : 'hidden'};
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ const HeaderDiv = styled.div`
|
|||||||
const LabelDiv = styled.div`
|
const LabelDiv = styled.div`
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 10px;
|
min-width: 10px;
|
||||||
padding-left: 2px;
|
// padding-left: 2px;
|
||||||
|
padding: 2px;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -36,10 +37,12 @@ export default function ColumnHeaderControl({ column, setSort, order }) {
|
|||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
)}
|
)}
|
||||||
</LabelDiv>
|
</LabelDiv>
|
||||||
|
{setSort && (
|
||||||
<DropDownButton>
|
<DropDownButton>
|
||||||
<DropDownMenuItem onClick={() => setSort('ASC')}>Sort ascending</DropDownMenuItem>
|
<DropDownMenuItem onClick={() => setSort('ASC')}>Sort ascending</DropDownMenuItem>
|
||||||
<DropDownMenuItem onClick={() => setSort('DESC')}>Sort descending</DropDownMenuItem>
|
<DropDownMenuItem onClick={() => setSort('DESC')}>Sort descending</DropDownMenuItem>
|
||||||
</DropDownButton>
|
</DropDownButton>
|
||||||
|
)}
|
||||||
</HeaderDiv>
|
</HeaderDiv>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ const TableHeaderCell = styled.td`
|
|||||||
// border-collapse: collapse;
|
// border-collapse: collapse;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
// padding: 2px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background-color: #f6f7f9;
|
background-color: #f6f7f9;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -112,12 +113,10 @@ const FocusField = styled.input`
|
|||||||
async function loadDataPage(props, offset, limit) {
|
async function loadDataPage(props, offset, limit) {
|
||||||
const { display, conid, database, jslid } = props;
|
const { display, conid, database, jslid } = props;
|
||||||
|
|
||||||
console.log('LOAD PAGE', jslid);
|
|
||||||
|
|
||||||
if (jslid) {
|
if (jslid) {
|
||||||
const response = await axios.request({
|
const response = await axios.request({
|
||||||
url: 'jsldata/get-rows',
|
url: 'jsldata/get-rows',
|
||||||
method: 'post',
|
method: 'get',
|
||||||
params: {
|
params: {
|
||||||
jslid,
|
jslid,
|
||||||
offset,
|
offset,
|
||||||
@@ -256,6 +255,7 @@ export default function DataGridCore(props) {
|
|||||||
const [inplaceEditorState, dispatchInsplaceEditor] = React.useReducer((state, action) => {
|
const [inplaceEditorState, dispatchInsplaceEditor] = React.useReducer((state, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'show':
|
case 'show':
|
||||||
|
if (!display.editable) return {};
|
||||||
return {
|
return {
|
||||||
cell: action.cell,
|
cell: action.cell,
|
||||||
text: action.text,
|
text: action.text,
|
||||||
@@ -914,12 +914,13 @@ export default function DataGridCore(props) {
|
|||||||
>
|
>
|
||||||
<ColumnHeaderControl
|
<ColumnHeaderControl
|
||||||
column={col}
|
column={col}
|
||||||
setSort={(order) => display.setSort(col.uniqueName, order)}
|
setSort={display.sortable ? (order) => display.setSort(col.uniqueName, order) : null}
|
||||||
order={display.getSortOrder(col.uniqueName)}
|
order={display.getSortOrder(col.uniqueName)}
|
||||||
/>
|
/>
|
||||||
</TableHeaderCell>
|
</TableHeaderCell>
|
||||||
))}
|
))}
|
||||||
</TableHeaderRow>
|
</TableHeaderRow>
|
||||||
|
{display.filterable && (
|
||||||
<TableHeaderRow>
|
<TableHeaderRow>
|
||||||
<TableHeaderCell
|
<TableHeaderCell
|
||||||
style={{ width: hederColwidthPx, minWidth: hederColwidthPx, maxWidth: hederColwidthPx }}
|
style={{ width: hederColwidthPx, minWidth: hederColwidthPx, maxWidth: hederColwidthPx }}
|
||||||
@@ -947,6 +948,7 @@ export default function DataGridCore(props) {
|
|||||||
</TableFilterCell>
|
</TableFilterCell>
|
||||||
))}
|
))}
|
||||||
</TableHeaderRow>
|
</TableHeaderRow>
|
||||||
|
)}
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody ref={tableBodyRef}>
|
<TableBody ref={tableBodyRef}>
|
||||||
{loadedAndInsertedRows
|
{loadedAndInsertedRows
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
const StyledTable = styled.table`
|
||||||
|
flex: 1;
|
||||||
|
`;
|
||||||
|
|
||||||
export default function MessagesView({ items }) {
|
export default function MessagesView({ items }) {
|
||||||
return (
|
return (
|
||||||
<table>
|
<StyledTable>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Number</th>
|
<th>Number</th>
|
||||||
<th>Message</th>
|
<th>Message</th>
|
||||||
@@ -19,6 +24,6 @@ export default function MessagesView({ items }) {
|
|||||||
<td>{row.line}</td>
|
<td>{row.line}</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</table>
|
</StyledTable>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,17 +13,18 @@ import SessionMessagesView from '../query/SessionMessagesView';
|
|||||||
import { TabPage, TabControl } from '../widgets/TabControl';
|
import { TabPage, TabControl } from '../widgets/TabControl';
|
||||||
import getResultTabs from '../sqleditor/ResultTabs';
|
import getResultTabs from '../sqleditor/ResultTabs';
|
||||||
import ResultTabs from '../sqleditor/ResultTabs';
|
import ResultTabs from '../sqleditor/ResultTabs';
|
||||||
|
import { VerticalSplitter } from '../widgets/Splitter';
|
||||||
|
|
||||||
const MainContainer = styled.div``;
|
// const MainContainer = styled.div``;
|
||||||
|
|
||||||
const EditorContainer = styled.div`
|
// const EditorContainer = styled.div`
|
||||||
height: 600px;
|
// height: 600px;
|
||||||
position: relative;
|
// position: relative;
|
||||||
`;
|
// `;
|
||||||
|
|
||||||
const MessagesContainer = styled.div`
|
// const MessagesContainer = styled.div`
|
||||||
height: 200px;
|
// height: 200px;
|
||||||
`;
|
// `;
|
||||||
|
|
||||||
export default function QueryTab({ tabid, conid, database, tabVisible, toolbarPortalRef }) {
|
export default function QueryTab({ tabid, conid, database, tabVisible, toolbarPortalRef }) {
|
||||||
const localStorageKey = `sql_${tabid}`;
|
const localStorageKey = `sql_${tabid}`;
|
||||||
@@ -73,8 +74,8 @@ export default function QueryTab({ tabid, conid, database, tabVisible, toolbarPo
|
|||||||
const handleKeyDown = (e) => {};
|
const handleKeyDown = (e) => {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainContainer>
|
<>
|
||||||
<EditorContainer>
|
<VerticalSplitter>
|
||||||
<SqlEditor
|
<SqlEditor
|
||||||
value={queryText}
|
value={queryText}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
@@ -82,7 +83,12 @@ export default function QueryTab({ tabid, conid, database, tabVisible, toolbarPo
|
|||||||
engine={connection && connection.engine}
|
engine={connection && connection.engine}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
/>
|
/>
|
||||||
|
<ResultTabs sessionId={sessionId}>
|
||||||
|
<TabPage label="Messages">
|
||||||
|
<SessionMessagesView sessionId={sessionId} />
|
||||||
|
</TabPage>
|
||||||
|
</ResultTabs>
|
||||||
|
</VerticalSplitter>
|
||||||
{toolbarPortalRef &&
|
{toolbarPortalRef &&
|
||||||
toolbarPortalRef.current &&
|
toolbarPortalRef.current &&
|
||||||
tabVisible &&
|
tabVisible &&
|
||||||
@@ -90,14 +96,6 @@ export default function QueryTab({ tabid, conid, database, tabVisible, toolbarPo
|
|||||||
<QueryToolbar isDatabaseDefined={conid && database} execute={handleExecute} />,
|
<QueryToolbar isDatabaseDefined={conid && database} execute={handleExecute} />,
|
||||||
toolbarPortalRef.current
|
toolbarPortalRef.current
|
||||||
)}
|
)}
|
||||||
</EditorContainer>
|
</>
|
||||||
<MessagesContainer>
|
|
||||||
<ResultTabs sessionId={sessionId}>
|
|
||||||
<TabPage label="Messages">
|
|
||||||
<SessionMessagesView sessionId={sessionId} />
|
|
||||||
</TabPage>
|
|
||||||
</ResultTabs>
|
|
||||||
</MessagesContainer>
|
|
||||||
</MainContainer>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
30
packages/web/src/widgets/Splitter.js
Normal file
30
packages/web/src/widgets/Splitter.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
const MainContainer = styled.div`
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ChildContainer = styled.div`
|
||||||
|
flex: 1;
|
||||||
|
// flex: 0 0 50%;
|
||||||
|
// flex-basis: 100px;
|
||||||
|
// flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export function VerticalSplitter({ children }) {
|
||||||
|
if (!_.isArray(children) || children.length !== 2) {
|
||||||
|
throw new Error('Splitter must have exactly 2 children');
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<MainContainer>
|
||||||
|
<ChildContainer>{children[0]}</ChildContainer>
|
||||||
|
<ChildContainer>{children[1]}</ChildContainer>
|
||||||
|
</MainContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ const TabNameWrapper = styled.span`
|
|||||||
|
|
||||||
const TabContainer = styled.div`
|
const TabContainer = styled.div`
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: flex;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -36,6 +37,7 @@ const TabsContainer = styled.div`
|
|||||||
|
|
||||||
const MainContainer = styled.div`
|
const MainContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user