refactor(data-viewer-plugin): data filter

This commit is contained in:
Wroud
2020-06-11 18:09:24 +03:00
parent aa985a01a3
commit a70c23e056
9 changed files with 94 additions and 83 deletions
@@ -9,10 +9,9 @@
import { injectable } from '@dbeaver/core/di';
import { GraphQLService } from '@dbeaver/core/sdk';
import { RequestDataOptionsToConstrains } from './DataViewerUtils';
import { IExecutionContext } from './IExecutionContext';
import { RowDiff } from './TableViewer/TableDataModel/EditedRow';
import { IRequestDataResult, IRequestDataResultOptions, TableViewerModel } from './TableViewer/TableViewerModel';
import { IRequestDataResult, TableViewerModel } from './TableViewer/TableViewerModel';
import { TableViewerStorageService } from './TableViewer/TableViewerStorageService';
@@ -99,9 +98,8 @@ export class DataViewerTableService {
private async requestDataAsync(
data: TableViewerModel,
rowOffset: number,
count: number,
options: IRequestDataResultOptions,
offset: number,
count: number
): Promise<IRequestDataResult> {
if (!data.containerNodePath) {
throw new Error('containerNodePath must be provided for table');
@@ -118,9 +116,9 @@ export class DataViewerTableService {
contextId: data.executionContext.contextId,
containerNodePath: data.containerNodePath,
filter: {
offset: rowOffset,
offset,
limit: count,
constraints: RequestDataOptionsToConstrains(options),
constraints: Array.from(data.getSortedColumns()),
},
});
const dataSet = readDataFromContainer!.results[0].resultSet!; // we expect only one dataset for a table
@@ -1,19 +0,0 @@
import { SqlDataFilterConstraint } from '@dbeaver/core/sdk';
import { IRequestDataResultOptions } from './TableViewer/TableViewerModel';
export function RequestDataOptionsToConstrains(
options?: IRequestDataResultOptions
): SqlDataFilterConstraint[] | undefined {
const constraints: SqlDataFilterConstraint[] = (options?.sorting || [])
.map((columnSorting, index) => {
const constrain: SqlDataFilterConstraint = {
attribute: columnSorting.colId,
orderPosition: index,
orderAsc: columnSorting.sort === 'asc',
};
return constrain;
});
return constraints.length ? constraints : undefined;
}
@@ -81,7 +81,7 @@ export const TableFooter = observer(function TableFooter({
return styled(useStyles(tableFooterStyles))(
<table-footer as="div">
<reload as="div">
<IconButton type="button" name='reload' onClick={model.handleRefresh} viewBox=""/>
<IconButton type="button" name='reload' onClick={model.refresh} viewBox=""/>
</reload>
<count as="div">
<input type="number" value={model.getChunkSize()} onBlur={handleChange} {...use({ mod: 'surface' })} />
@@ -13,8 +13,8 @@ import {
} from '@dbeaver/ag-grid-plugin';
import { ErrorDetailsDialog } from '@dbeaver/core/app';
import { CommonDialogService } from '@dbeaver/core/dialogs';
import { GQLError } from '@dbeaver/core/sdk';
import { uuid } from '@dbeaver/core/utils';
import { GQLError, SqlDataFilterConstraint } from '@dbeaver/core/sdk';
import { uuid, MetadataMap } from '@dbeaver/core/utils';
import { IExecutionContext } from '../IExecutionContext';
import { ErrorDialog } from './ErrorDialog';
@@ -46,8 +46,8 @@ export interface ITableViewerModelOptions {
requestDataAsync(
model: TableViewerModel,
rowOffset: number,
count: number,
options?: IRequestDataResultOptions): Promise<IRequestDataResult>;
count: number
): Promise<IRequestDataResult>;
saveChanges(model: TableViewerModel, diffs: RowDiff[]): Promise<IRequestDataResult>;
}
@@ -70,8 +70,8 @@ export class TableViewerModel implements ITableViewerModelOptions {
requestDataAsync: (
model: TableViewerModel,
rowOffset: number,
count: number,
options?: IRequestDataResultOptions) => Promise<IRequestDataResult>;
count: number
) => Promise<IRequestDataResult>;
saveChanges: (model: TableViewerModel, diffs: RowDiff[]) => Promise<IRequestDataResult>;
agGridModel: IAgGridModel = {
@@ -97,7 +97,7 @@ export class TableViewerModel implements ITableViewerModelOptions {
getChunkSize = () => this._chunkSize;
setChunkSize = (count: number) => this.updateChunkSize(count);
handleRefresh = () => this.resetData();
refresh = () => this.resetData();
@observable queryDuration = 0;
@observable requestStatusMessage = '';
@@ -112,6 +112,9 @@ export class TableViewerModel implements ITableViewerModelOptions {
private exception: GQLError | null = null;
private tableDataModel = new TableDataModel();
private tableEditor = new TableEditor(this.tableDataModel);
private sortedColumns = new MetadataMap<string, SqlDataFilterConstraint>(
(colId, metadata) => ({ attribute: colId, orderPosition: metadata.count(), orderAsc: false })
);
constructor(
options: ITableViewerModelOptions,
@@ -137,6 +140,23 @@ export class TableViewerModel implements ITableViewerModelOptions {
}
}
getSortedColumns() {
return this.sortedColumns.values();
}
setColumnSorting(colId: string, orderAsc?: boolean, multiple?: boolean) {
if (!multiple) {
this.sortedColumns.clear();
}
const sorting = this.sortedColumns.get(colId);
sorting.orderAsc = orderAsc;
}
removeColumnSorting(colId: string) {
this.sortedColumns.delete(colId);
}
@action
insertRows(position: number, rows: TableRow[], hasMore: boolean) {
const isRowsAddition = this.tableDataModel.getRows().length < position + rows.length;
@@ -159,7 +179,7 @@ export class TableViewerModel implements ITableViewerModelOptions {
this.tableEditor.editCellValue(rowNumber, colNumber, value);
}
private async onRequestData(rowOffset: number, count: number, options: IRequestDataOptions): Promise<IRequestedData> {
private async onRequestData(rowOffset: number, count: number): Promise<IRequestedData> {
// try to return data from cache
if (this.tableDataModel.isChunkLoaded(rowOffset, count) || this.isFullyLoaded) {
const data: IRequestedData = {
@@ -173,7 +193,7 @@ export class TableViewerModel implements ITableViewerModelOptions {
this._isLoaderVisible = !this.noLoaderWhileRequestingDataAsync;
try {
const response = await this.requestDataAsync(this, rowOffset, count, options);
const response = await this.requestDataAsync(this, rowOffset, count);
this.insertRows(rowOffset, response.rows, !response.isFullyLoaded);
if (!this.tableDataModel.getColumns().length) {
@@ -261,7 +281,11 @@ export class TableViewerModel implements ITableViewerModelOptions {
}
}
private onSortChanged() {
private onSortChanged(sorting: SortModel) {
this.sortedColumns.clear();
for (const sort of sorting) {
this.setColumnSorting(sort.colId, sort.sort === 'asc', true);
}
this.resetData();
}
@@ -13,6 +13,4 @@ export * from './TableViewer/TableDataModel/TableColumn';
export * from './TableViewer/TableDataModel/TableRow';
export * from './TableViewer/TableDataModel/EditedRow';
export * from './DataViewerUtils';
export * from './IExecutionContext';
@@ -8,12 +8,11 @@
import { NotificationService } from '@dbeaver/core/eventsLog';
import {
AsyncTaskInfo, GraphQLService, ServerInternalError, SqlExecuteInfo,
AsyncTaskInfo, GraphQLService, ServerInternalError, SqlExecuteInfo, SqlDataFilter,
} from '@dbeaver/core/sdk';
import {
CancellablePromise, cancellableTimeout, Deferred, EDeferredState,
} from '@dbeaver/core/utils';
import { IRequestDataResultOptions, RequestDataOptionsToConstrains } from '@dbeaver/data-viewer-plugin';
import { ISqlQueryParams } from '../ISqlEditorTabState';
@@ -25,18 +24,20 @@ export class SQLQueryExecutionProcess extends Deferred<SqlExecuteInfo> {
private timeout?: CancellablePromise<void>;
private isCancelConfirmed = false; // true when server successfully executed cancelQueryAsync
constructor(private graphQLService: GraphQLService,
private notificationService: NotificationService) {
constructor(
private graphQLService: GraphQLService,
private notificationService: NotificationService
) {
super();
}
async start(sqlQueryParams: ISqlQueryParams,
rowOffset: number,
count: number,
options?: IRequestDataResultOptions): Promise<void> {
async start(
sqlQueryParams: ISqlQueryParams,
filter: SqlDataFilter
): Promise<void> {
// start async task
try {
const taskInfo = await this.executeQueryAsync(sqlQueryParams, rowOffset, count, options);
const taskInfo = await this.executeQueryAsync(sqlQueryParams, filter);
this.applyResult(taskInfo);
this.taskId = taskInfo.id;
if (this.getState() === EDeferredState.CANCELLING) {
@@ -104,20 +105,15 @@ export class SQLQueryExecutionProcess extends Deferred<SqlExecuteInfo> {
}
}
private async executeQueryAsync(sqlQueryParams: ISqlQueryParams,
rowOffset: number,
count: number,
options?: IRequestDataResultOptions): Promise<AsyncTaskInfo> {
private async executeQueryAsync(
sqlQueryParams: ISqlQueryParams,
filter: SqlDataFilter,
): Promise<AsyncTaskInfo> {
const { taskInfo } = await this.graphQLService.gql.asyncSqlExecuteQuery({
connectionId: sqlQueryParams.connectionId,
contextId: sqlQueryParams.contextId,
query: sqlQueryParams.query,
filter: {
offset: rowOffset,
limit: count,
constraints: RequestDataOptionsToConstrains(options),
},
filter,
});
return taskInfo;
}
@@ -140,16 +140,23 @@ implements IInitializableController, IDestructibleController {
private async requestDataAsync(
sqlExecutingState: SqlExecutionState,
model: TableViewerModel,
rowOffset: number,
count: number,
options: IRequestDataResultOptions,
offset: number,
count: number
): Promise<IRequestDataResult> {
const queryExecutionProcess = this.sqlResultService
.asyncSqlQuery(this.panelInit.sqlQueryParams, rowOffset, count, options);
.asyncSqlQuery(this.panelInit.sqlQueryParams, {
offset,
limit: count,
constraints: Array.from(model.getSortedColumns()),
});
sqlExecutingState.setCurrentlyExecutingQuery(queryExecutionProcess);
const response = await queryExecutionProcess.promise;
const dataResults = this.sqlResultService.sqlExecuteInfoToData(response, this.panelInit.indexInResultSet, count);
const dataResults = this.sqlResultService.sqlExecuteInfoToData(
response,
this.panelInit.indexInResultSet,
count
);
/**
* Note that each data fetching overwrites resultId
@@ -11,13 +11,10 @@ import { NotificationService } from '@dbeaver/core/eventsLog';
import {
GraphQLService,
SqlExecuteInfo,
SqlDataFilter,
SqlDataFilterConstraint,
} from '@dbeaver/core/sdk';
import {
IRequestDataResult,
RowDiff,
IRequestDataResultOptions,
RequestDataOptionsToConstrains,
} from '@dbeaver/data-viewer-plugin';
import { IRequestDataResult, RowDiff } from '@dbeaver/data-viewer-plugin';
import { ISqlQueryParams } from '../ISqlEditorTabState';
import { SQLQueryExecutionProcess } from './SQLQueryExecutionProcess';
@@ -31,10 +28,12 @@ export class SqlResultService {
/**
* @deprecated use asyncSqlQuery
*/
async fetchData(sqlQueryParams: ISqlQueryParams,
rowOffset: number,
count: number,
options: IRequestDataResultOptions): Promise<SqlExecuteInfo> {
async fetchData(
sqlQueryParams: ISqlQueryParams,
rowOffset: number,
count: number,
constraints?: SqlDataFilterConstraint[]
): Promise<SqlExecuteInfo> {
const response = await this.graphQLService.gql.executeSqlQuery({
connectionId: sqlQueryParams.connectionId,
contextId: sqlQueryParams.contextId,
@@ -43,25 +42,27 @@ export class SqlResultService {
filter: {
offset: rowOffset,
limit: count,
constraints: RequestDataOptionsToConstrains(options),
constraints,
},
});
return response.result!;
}
asyncSqlQuery(sqlQueryParams: ISqlQueryParams,
rowOffset: number,
count: number,
options?: IRequestDataResultOptions): SQLQueryExecutionProcess {
asyncSqlQuery(
sqlQueryParams: ISqlQueryParams,
filter: SqlDataFilter
): SQLQueryExecutionProcess {
const cancellableSqlQuery = new SQLQueryExecutionProcess(this.graphQLService, this.notificationService);
cancellableSqlQuery.start(sqlQueryParams, rowOffset, count, options);
cancellableSqlQuery.start(sqlQueryParams, filter);
return cancellableSqlQuery;
}
async saveChanges(sqlQueryParams: ISqlQueryParams,
resultId: string,
diffs: RowDiff[]): Promise<SqlExecuteInfo> {
async saveChanges(
sqlQueryParams: ISqlQueryParams,
resultId: string,
diffs: RowDiff[]
): Promise<SqlExecuteInfo> {
const firstRow = diffs[0]; // todo multiple row to be implemented later
@@ -34,7 +34,13 @@ export class SqlResultTabsService {
};
// we should first render table, because we expect that table request first data portion
const queryExecutionProcess = this.sqlResultService.asyncSqlQuery(sqlQueryParams, 0, fetchingSettings.fetchDefault);
const queryExecutionProcess = this.sqlResultService.asyncSqlQuery(
sqlQueryParams,
{
offset: 0,
limit: fetchingSettings.fetchDefault,
}
);
editorState.sqlExecutionState.setCurrentlyExecutingQuery(queryExecutionProcess);