mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
refactor(data-viewer-plugin): data filter
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
+12
-5
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user