query result shown

This commit is contained in:
Jan Prochazka 2020-04-10 10:47:54 +02:00
parent 3bc6f60f75
commit 8be7c0aa6b
11 changed files with 121 additions and 73 deletions

View File

@ -34,7 +34,7 @@ module.exports = {
openReader(jslid) {
const file = path.join(jsldir(), `${jslid}.jsonl`);
return new Promise((resolve, reject) =>
lineReader.open(file, function (err, reader) {
lineReader.open(file, (err, reader) => {
if (err) reject(err);
resolve();
this.openedReaders[jslid] = {
@ -50,7 +50,7 @@ module.exports = {
await this.closeReader();
}
if (!this.openedReaders[jslid]) {
await this.openReader();
await this.openReader(jslid);
}
while (this.openedReaders[jslid].readedCount < offset) {
await this.readLine(jslid);

View File

@ -40,11 +40,12 @@ export function findExistingChangeSetItem(
changeSet: ChangeSet,
definition: ChangeSetRowDefinition
): [keyof ChangeSet, ChangeSetItem] {
if (!changeSet) return ['updates', null];
if (definition.insertedRowIndex != null) {
return [
'inserts',
changeSet.inserts.find(
x =>
(x) =>
x.pureName == definition.pureName &&
x.schemaName == definition.schemaName &&
x.insertedRowIndex == definition.insertedRowIndex
@ -52,7 +53,7 @@ export function findExistingChangeSetItem(
];
} else {
const inUpdates = changeSet.updates.find(
x =>
(x) =>
x.pureName == definition.pureName &&
x.schemaName == definition.schemaName &&
_.isEqual(x.condition, definition.condition)
@ -60,7 +61,7 @@ export function findExistingChangeSetItem(
if (inUpdates) return ['updates', inUpdates];
const inDeletes = changeSet.deletes.find(
x =>
(x) =>
x.pureName == definition.pureName &&
x.schemaName == definition.schemaName &&
_.isEqual(x.condition, definition.condition)
@ -84,7 +85,7 @@ export function setChangeSetValue(
if (existingItem) {
return {
...changeSet,
[fieldName]: changeSet[fieldName].map(item =>
[fieldName]: changeSet[fieldName].map((item) =>
item == existingItem
? {
...item,
@ -164,7 +165,7 @@ export function batchUpdateChangeSet(
}
function extractFields(item: ChangeSetItem): UpdateField[] {
return _.keys(item.fields).map(targetColumn => ({
return _.keys(item.fields).map((targetColumn) => ({
targetColumn,
exprType: 'value',
value: item.fields[targetColumn],
@ -185,7 +186,7 @@ function insertToSql(item: ChangeSetItem): Insert {
function extractCondition(item: ChangeSetItem): Condition {
return {
conditionType: 'and',
conditions: _.keys(item.condition).map(columnName => ({
conditions: _.keys(item.condition).map((columnName) => ({
conditionType: 'binary',
operator: '=',
left: {
@ -248,7 +249,7 @@ export function revertChangeSetRowChanges(changeSet: ChangeSet, definition: Chan
if (item)
return {
...changeSet,
[field]: changeSet[field].filter(x => x != item),
[field]: changeSet[field].filter((x) => x != item),
};
return changeSet;
}
@ -280,8 +281,8 @@ export function deleteChangeSetRows(changeSet: ChangeSet, definition: ChangeSetR
export function getChangeSetInsertedRows(changeSet: ChangeSet, name?: NamedObjectInfo) {
if (!name) return [];
if (!changeSet) return [];
const rows = changeSet.inserts.filter(x => x.pureName == name.pureName && x.schemaName == name.schemaName);
const maxIndex = _.maxBy(rows, x => x.insertedRowIndex)?.insertedRowIndex;
const rows = changeSet.inserts.filter((x) => x.pureName == name.pureName && x.schemaName == name.schemaName);
const maxIndex = _.maxBy(rows, (x) => x.insertedRowIndex)?.insertedRowIndex;
if (maxIndex == null) return [];
const res = Array(maxIndex + 1).fill({});
for (const row of rows) {

View File

@ -55,6 +55,9 @@ export abstract class GridDisplay {
columns: DisplayColumn[];
baseTable?: TableInfo;
changeSetKeyFields: string[] = null;
sortable = false;
filterable = false;
editable = false;
setColumnVisibility(uniquePath: string[], isVisible: boolean) {
const uniqueName = uniquePath.join('.');

View File

@ -16,11 +16,14 @@ export class TableGridDisplay extends GridDisplay {
) {
super(config, setConfig, cache, setCache, getTableInfo, driver);
this.columns = this.getDisplayColumns(table, []);
this.filterable = true;
this.sortable = true;
this.editable = true;
this.baseTable = table;
if (table && table.columns) {
this.changeSetKeyFields = table.primaryKey
? table.primaryKey.columns.map(x => x.columnName)
: table.columns.map(x => x.columnName);
? table.primaryKey.columns.map((x) => x.columnName)
: table.columns.map((x) => x.columnName);
}
}
@ -30,7 +33,7 @@ export class TableGridDisplay extends GridDisplay {
const select: Select = {
commandType: 'select',
from: { name: this.table, alias: 'basetbl' },
columns: this.table.columns.map(col => ({
columns: this.table.columns.map((col) => ({
exprType: 'column',
alias: col.columnName,
source: { alias: 'basetbl' },
@ -45,7 +48,7 @@ export class TableGridDisplay extends GridDisplay {
],
};
const displayedColumnInfo = _.keyBy(
this.columns.map(col => ({ ...col, sourceAlias: 'basetbl' })),
this.columns.map((col) => ({ ...col, sourceAlias: 'basetbl' })),
'uniqueName'
);
const action = combineReferenceActions(

View File

@ -10,6 +10,7 @@ const TabContainer = styled.div`
top: 0;
right: 0;
bottom: 0;
display: flex;
visibility: ${props =>
// @ts-ignore
props.tabVisible ? 'visible' : 'hidden'};

View File

@ -12,7 +12,8 @@ const HeaderDiv = styled.div`
const LabelDiv = styled.div`
flex: 1;
min-width: 10px;
padding-left: 2px;
// padding-left: 2px;
padding: 2px;
margin: auto;
`;
@ -36,10 +37,12 @@ export default function ColumnHeaderControl({ column, setSort, order }) {
</IconWrapper>
)}
</LabelDiv>
<DropDownButton>
<DropDownMenuItem onClick={() => setSort('ASC')}>Sort ascending</DropDownMenuItem>
<DropDownMenuItem onClick={() => setSort('DESC')}>Sort descending</DropDownMenuItem>
</DropDownButton>
{setSort && (
<DropDownButton>
<DropDownMenuItem onClick={() => setSort('ASC')}>Sort ascending</DropDownMenuItem>
<DropDownMenuItem onClick={() => setSort('DESC')}>Sort descending</DropDownMenuItem>
</DropDownButton>
)}
</HeaderDiv>
);
}

View File

@ -90,6 +90,7 @@ const TableHeaderCell = styled.td`
// border-collapse: collapse;
text-align: left;
padding: 0;
// padding: 2px;
margin: 0;
background-color: #f6f7f9;
overflow: hidden;
@ -112,12 +113,10 @@ const FocusField = styled.input`
async function loadDataPage(props, offset, limit) {
const { display, conid, database, jslid } = props;
console.log('LOAD PAGE', jslid);
if (jslid) {
const response = await axios.request({
url: 'jsldata/get-rows',
method: 'post',
method: 'get',
params: {
jslid,
offset,
@ -256,6 +255,7 @@ export default function DataGridCore(props) {
const [inplaceEditorState, dispatchInsplaceEditor] = React.useReducer((state, action) => {
switch (action.type) {
case 'show':
if (!display.editable) return {};
return {
cell: action.cell,
text: action.text,
@ -914,39 +914,41 @@ export default function DataGridCore(props) {
>
<ColumnHeaderControl
column={col}
setSort={(order) => display.setSort(col.uniqueName, order)}
setSort={display.sortable ? (order) => display.setSort(col.uniqueName, order) : null}
order={display.getSortOrder(col.uniqueName)}
/>
</TableHeaderCell>
))}
</TableHeaderRow>
<TableHeaderRow>
<TableHeaderCell
style={{ width: hederColwidthPx, minWidth: hederColwidthPx, maxWidth: hederColwidthPx }}
data-row="filter"
data-col="header"
>
{filterCount > 0 && (
<InlineButton onClick={handleClearFilters} square>
<i className="fas fa-times" />
</InlineButton>
)}
</TableHeaderCell>
{visibleRealColumns.map((col) => (
<TableFilterCell
key={col.uniqueName}
style={{ width: col.widthPx, minWidth: col.widthPx, maxWidth: col.widthPx }}
{display.filterable && (
<TableHeaderRow>
<TableHeaderCell
style={{ width: hederColwidthPx, minWidth: hederColwidthPx, maxWidth: hederColwidthPx }}
data-row="filter"
data-col={col.colIndex}
data-col="header"
>
<DataFilterControl
filterType={getFilterType(col.commonType ? col.commonType.typeCode : null)}
filter={display.getFilter(col.uniqueName)}
setFilter={(value) => display.setFilter(col.uniqueName, value)}
/>
</TableFilterCell>
))}
</TableHeaderRow>
{filterCount > 0 && (
<InlineButton onClick={handleClearFilters} square>
<i className="fas fa-times" />
</InlineButton>
)}
</TableHeaderCell>
{visibleRealColumns.map((col) => (
<TableFilterCell
key={col.uniqueName}
style={{ width: col.widthPx, minWidth: col.widthPx, maxWidth: col.widthPx }}
data-row="filter"
data-col={col.colIndex}
>
<DataFilterControl
filterType={getFilterType(col.commonType ? col.commonType.typeCode : null)}
filter={display.getFilter(col.uniqueName)}
setFilter={(value) => display.setFilter(col.uniqueName, value)}
/>
</TableFilterCell>
))}
</TableHeaderRow>
)}
</TableHead>
<TableBody ref={tableBodyRef}>
{loadedAndInsertedRows

View File

@ -1,8 +1,13 @@
import React from 'react';
import styled from 'styled-components';
const StyledTable = styled.table`
flex: 1;
`;
export default function MessagesView({ items }) {
return (
<table>
<StyledTable>
<tr>
<th>Number</th>
<th>Message</th>
@ -19,6 +24,6 @@ export default function MessagesView({ items }) {
<td>{row.line}</td>
</tr>
))}
</table>
</StyledTable>
);
}

View File

@ -13,17 +13,18 @@ import SessionMessagesView from '../query/SessionMessagesView';
import { TabPage, TabControl } from '../widgets/TabControl';
import getResultTabs 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`
height: 600px;
position: relative;
`;
// const EditorContainer = styled.div`
// height: 600px;
// position: relative;
// `;
const MessagesContainer = styled.div`
height: 200px;
`;
// const MessagesContainer = styled.div`
// height: 200px;
// `;
export default function QueryTab({ tabid, conid, database, tabVisible, toolbarPortalRef }) {
const localStorageKey = `sql_${tabid}`;
@ -73,8 +74,8 @@ export default function QueryTab({ tabid, conid, database, tabVisible, toolbarPo
const handleKeyDown = (e) => {};
return (
<MainContainer>
<EditorContainer>
<>
<VerticalSplitter>
<SqlEditor
value={queryText}
onChange={handleChange}
@ -82,22 +83,19 @@ export default function QueryTab({ tabid, conid, database, tabVisible, toolbarPo
engine={connection && connection.engine}
onKeyDown={handleKeyDown}
/>
{toolbarPortalRef &&
toolbarPortalRef.current &&
tabVisible &&
ReactDOM.createPortal(
<QueryToolbar isDatabaseDefined={conid && database} execute={handleExecute} />,
toolbarPortalRef.current
)}
</EditorContainer>
<MessagesContainer>
<ResultTabs sessionId={sessionId}>
<TabPage label="Messages">
<SessionMessagesView sessionId={sessionId} />
</TabPage>
</ResultTabs>
</MessagesContainer>
</MainContainer>
</VerticalSplitter>
{toolbarPortalRef &&
toolbarPortalRef.current &&
tabVisible &&
ReactDOM.createPortal(
<QueryToolbar isDatabaseDefined={conid && database} execute={handleExecute} />,
toolbarPortalRef.current
)}
</>
);
}

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

View File

@ -24,6 +24,7 @@ const TabNameWrapper = styled.span`
const TabContainer = styled.div`
position: relative;
display: flex;
flex-grow: 1;
`;
@ -36,6 +37,7 @@ const TabsContainer = styled.div`
const MainContainer = styled.div`
display: flex;
flex: 1;
flex-direction: column;
`;