Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 15 additions & 16 deletions webapp/packages/data-viewer-plugin/src/DataViewerTableService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';


Expand Down Expand Up @@ -98,33 +97,33 @@ export class DataViewerTableService {
}

private async requestDataAsync(
data: TableViewerModel,
rowOffset: number,
count: number,
options: IRequestDataResultOptions,
model: TableViewerModel,
offset: number,
count: number
): Promise<IRequestDataResult> {
if (!data.containerNodePath) {
if (!model.containerNodePath) {
throw new Error('containerNodePath must be provided for table');
}
if (!data.executionContext) {
if (!model.executionContext) {

// it is first data request
const executionContext: IExecutionContext = await this.createExecutionContext(data.connectionId);
data.executionContext = executionContext;
const executionContext: IExecutionContext = await this.createExecutionContext(model.connectionId);
model.executionContext = executionContext;
}

const { readDataFromContainer } = await this.graphQLService.gql.readDataFromContainer({
connectionId: data.executionContext.connectionId,
contextId: data.executionContext.contextId,
containerNodePath: data.containerNodePath,
connectionId: model.executionContext.connectionId,
contextId: model.executionContext.contextId,
containerNodePath: model.containerNodePath,
filter: {
offset: rowOffset,
offset,
limit: count,
constraints: RequestDataOptionsToConstrains(options),
constraints: Array.from(model.getSortedColumns()),
where: model.getQueryWhereFilter() || undefined,
},
});
const dataSet = readDataFromContainer!.results[0].resultSet!; // we expect only one dataset for a table
data.resultId = dataSet.id; // server generates new resultId on each fetch
model.resultId = dataSet.id; // server generates new resultId on each fetch

const result: IRequestDataResult = {
rows: dataSet.rows!,
Expand Down
19 changes: 0 additions & 19 deletions webapp/packages/data-viewer-plugin/src/DataViewerUtils.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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' })} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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>;
}

Expand All @@ -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 = {
Expand All @@ -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 = '';
Expand All @@ -108,10 +108,14 @@ export class TableViewerModel implements ITableViewerModelOptions {
@observable private _hasMoreRows = true
@observable private _isLoaderVisible = false;
@observable private _chunkSize: number = this.getDefaultRowsCount();
@observable private queryWhereFilter: string | null = null;

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,
Expand All @@ -137,6 +141,32 @@ export class TableViewerModel implements ITableViewerModelOptions {
}
}

getQueryWhereFilter() {
return this.queryWhereFilter;
}

setQueryWhereFilter(where: string | null) {
this.queryWhereFilter = where;
this.resetData();
}

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;
Expand All @@ -159,7 +189,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 = {
Expand All @@ -173,7 +203,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) {
Expand Down Expand Up @@ -261,7 +291,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();
}

Expand Down
2 changes: 0 additions & 2 deletions webapp/packages/data-viewer-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@ import { PromiseCancelledError } from '@dbeaver/core/utils';
import {
fetchingSettings,
IRequestDataResult,
IRequestDataResultOptions,
RowDiff,
TableViewerStorageService,
TableViewerModel,
IExecutionContext,
} from '@dbeaver/data-viewer-plugin';

import { ISqlResultPanelParams } from '../../ISqlEditorTabState';
Expand Down Expand Up @@ -140,16 +138,24 @@ 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()),
where: model.getQueryWhereFilter() || undefined,
});
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
Expand Down
39 changes: 20 additions & 19 deletions webapp/packages/sql-editor/src/SqlResultTabs/SqlResultService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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,
Expand All @@ -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

Expand Down
Loading