feat(plugin-data-viewer): CB-751 database data actions API & select action

This commit is contained in:
Wroud
2021-03-12 10:23:50 +03:00
parent cfa0fb583c
commit f86bf46fc6
9 changed files with 284 additions and 0 deletions
@@ -0,0 +1,14 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2021 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import type { IDatabaseDataActionClass } from '../IDatabaseDataAction';
export function databaseDataAction<T extends IDatabaseDataActionClass<any, any>>() {
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
return <U extends T>(constructor: U) => { };
}
@@ -0,0 +1,31 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2021 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import type { IExecutor } from '@cloudbeaver/core-executor';
import type { IDatabaseDataAction } from '../IDatabaseDataAction';
import type { IDatabaseDataResult } from '../IDatabaseDataResult';
export type DatabaseDataEditorActionsData<TKey> = {
type: 'select';
resultId: string;
key: TKey;
selected: boolean;
} | {
type: 'clear';
resultId: string;
};
export interface IDatabaseDataSelectAction<TKey, TResult extends IDatabaseDataResult>
extends IDatabaseDataAction<TResult> {
readonly actions: IExecutor<DatabaseDataEditorActionsData<TKey>>;
isSelected: () => boolean;
isElementSelected: (key: TKey) => boolean;
set: (key: TKey, selected: boolean) => void;
clear: () => void;
}
@@ -0,0 +1,109 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2021 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { Executor, IExecutor } from '@cloudbeaver/core-executor';
import { ResultDataFormat } from '@cloudbeaver/core-sdk';
import type { IDatabaseResultSet } from '../IDatabaseResultSet';
import { databaseDataAction } from './DatabaseDataActionDecorator';
import type { DatabaseDataEditorActionsData, IDatabaseDataSelectAction } from './IDatabaseDataSelectAction';
export interface IResultSetSelectKey {
row: number;
column?: number;
}
@databaseDataAction()
export class ResultSetSelectAction implements IDatabaseDataSelectAction<IResultSetSelectKey, IDatabaseResultSet> {
static dataFormat = ResultDataFormat.Resultset;
result: IDatabaseResultSet;
readonly actions: IExecutor<DatabaseDataEditorActionsData<IResultSetSelectKey>>;
private selectedElements: Map<number, number[]>;
constructor(result: IDatabaseResultSet) {
this.result = result;
this.actions = new Executor();
this.selectedElements = new Map();
}
updateResult(result: IDatabaseResultSet): void {
this.result = result;
}
isSelected(): boolean {
return this.selectedElements.size > 0;
}
isElementSelected(key: IResultSetSelectKey): boolean {
const row = this.selectedElements.get(key.row);
if (!row) {
return false;
}
if (key.column !== undefined) {
return row.includes(key.column);
}
return row.length === this.result.data?.columns?.length;
}
set(key: IResultSetSelectKey, selected: boolean): void {
try {
if (!this.selectedElements.has(key.row)) {
if (!selected) {
return;
}
this.selectedElements.set(key.row, []);
}
const columns = this.selectedElements.get(key.row)!;
if (key.column) {
if (selected) {
if (!columns.includes(key.column)) {
columns.push(key.column);
}
} else {
const index = columns.indexOf(key.column);
if (index >= 0) {
columns.splice(index, 1);
}
if (columns.length === 0) {
this.selectedElements.delete(key.row);
}
}
return;
}
if (selected) {
columns.push(...(this.result.data?.columns?.map((c, i) => i) || []));
} else {
this.selectedElements.delete(key.row);
}
} finally {
this.actions.execute({
type: 'select',
resultId: this.result.id,
key,
selected,
});
}
}
clear(): void {
this.actions.execute({
type: 'clear',
resultId: this.result.id,
});
}
}
@@ -0,0 +1,57 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2021 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { makeObservable, observable } from 'mobx';
import type { IDatabaseDataAction, IDatabaseDataActionClass } from './IDatabaseDataAction';
import type { IDatabaseDataActions } from './IDatabaseDataActions';
import type { IDatabaseDataResult } from './IDatabaseDataResult';
type ActionsMap<TResult extends IDatabaseDataResult> = Map<
IDatabaseDataActionClass<TResult, IDatabaseDataAction<TResult>>,
IDatabaseDataAction<TResult>
>;
export class DatabaseDataActions<TResult extends IDatabaseDataResult> implements IDatabaseDataActions<TResult> {
private actions: Map<string, ActionsMap<TResult>>;
constructor() {
this.actions = new Map();
makeObservable<DatabaseDataActions<TResult>, 'actions'>(this, {
actions: observable.shallow,
});
}
get <T extends IDatabaseDataAction<TResult>>(
result: TResult,
Action: IDatabaseDataActionClass<TResult, T>
): T {
if (!this.actions.has(result.id)) {
this.actions.set(result.id, observable.map(undefined, { deep: false }));
}
const actionsMap = this.actions.get(result.id)!;
if (!actionsMap.has(Action)) {
actionsMap.set(Action, new Action(result));
}
return actionsMap.get(Action)! as T;
}
updateResults(results: TResult[]): void {
const keys = Array.from(this.actions.keys());
for (const key of keys) {
if (!results.some(result => result.id === key)) {
this.actions.delete(key);
}
}
}
}
@@ -11,6 +11,9 @@ import { observable, makeObservable } from 'mobx';
import { ResultDataFormat } from '@cloudbeaver/core-sdk';
import type { IExecutionContext } from '../IExecutionContext';
import { DatabaseDataActions } from './DatabaseDataActions';
import type { IDatabaseDataAction, IDatabaseDataActionClass } from './IDatabaseDataAction';
import type { IDatabaseDataActions } from './IDatabaseDataActions';
import type { IDatabaseDataEditor, IDatabaseDataResultEditor } from './IDatabaseDataEditor';
import type { IDatabaseDataResult } from './IDatabaseDataResult';
import { DatabaseDataAccessMode, IDatabaseDataSource, IRequestInfo } from './IDatabaseDataSource';
@@ -21,6 +24,7 @@ implements IDatabaseDataSource<TOptions, TResult> {
dataFormat: ResultDataFormat;
supportedDataFormats: ResultDataFormat[];
editor: IDatabaseDataEditor<TResult> | null;
actions: IDatabaseDataActions<TResult>;
results: TResult[];
offset: number;
count: number;
@@ -50,6 +54,7 @@ implements IDatabaseDataSource<TOptions, TResult> {
activeSave: observable,
});
this.actions = new DatabaseDataActions();
this.access = DatabaseDataAccessMode.Default;
this.results = [];
this.editor = null;
@@ -68,6 +73,17 @@ implements IDatabaseDataSource<TOptions, TResult> {
this.error = null;
}
getAction<T extends IDatabaseDataAction<TResult>>(
resultIndex: number,
action: IDatabaseDataActionClass<TResult, T>
): T {
if (!this.hasResult(resultIndex)) {
throw new Error('Result index out of range');
}
return this.actions.get(this.results[resultIndex], action);
}
abstract cancel(): Promise<boolean> | boolean;
hasResult(resultIndex: number): boolean {
@@ -0,0 +1,24 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2021 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import type { ResultDataFormat } from '@cloudbeaver/core-sdk';
import type { IDatabaseDataResult } from './IDatabaseDataResult';
export interface IDatabaseDataActionClass<
TResult extends IDatabaseDataResult,
TAction extends IDatabaseDataAction<TResult>
> {
new (result: TResult): TAction;
dataFormat: ResultDataFormat;
}
export interface IDatabaseDataAction<TResult extends IDatabaseDataResult> {
readonly result: TResult;
updateResult: (result: TResult) => void;
}
@@ -0,0 +1,19 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2021 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import type { IDatabaseDataAction, IDatabaseDataActionClass } from './IDatabaseDataAction';
import type { IDatabaseDataResult } from './IDatabaseDataResult';
export interface IDatabaseDataActions<TResult extends IDatabaseDataResult> {
get: <T extends IDatabaseDataAction<TResult>>(
result: TResult,
action: IDatabaseDataActionClass<TResult, T>
) => T;
updateResults: (results: TResult[]) => void;
}
@@ -9,6 +9,8 @@
import type { ResultDataFormat } from '@cloudbeaver/core-sdk';
import type { IExecutionContext } from '../IExecutionContext';
import type { IDatabaseDataAction, IDatabaseDataActionClass } from './IDatabaseDataAction';
import type { IDatabaseDataActions } from './IDatabaseDataActions';
import type { IDatabaseDataEditor, IDatabaseDataResultEditor } from './IDatabaseDataEditor';
import type { IDatabaseDataResult } from './IDatabaseDataResult';
@@ -26,6 +28,7 @@ export interface IDatabaseDataSource<TOptions, TResult extends IDatabaseDataResu
readonly access: DatabaseDataAccessMode;
readonly dataFormat: ResultDataFormat;
readonly supportedDataFormats: ResultDataFormat[];
readonly actions: IDatabaseDataActions<TResult>;
readonly editor: IDatabaseDataEditor<TResult> | null;
readonly results: TResult[];
readonly offset: number;
@@ -41,6 +44,12 @@ export interface IDatabaseDataSource<TOptions, TResult extends IDatabaseDataResu
hasResult: (resultIndex: number) => boolean;
getAction: <T extends IDatabaseDataAction<TResult>>(
resultIndex: number,
action: IDatabaseDataActionClass<TResult, T>
) => T;
/** @deprecated will be moved to getAction */
getEditor: (resultIndex: number) => IDatabaseDataResultEditor<TResult>;
getResult: (index: number) => TResult | null;
@@ -2,10 +2,15 @@ import { manifest } from './manifest';
export default manifest;
export * from './DatabaseDataModel/Actions/DatabaseDataActionDecorator';
export * from './DatabaseDataModel/Actions/DatabaseDataActionDecorator';
export * from './DatabaseDataModel/DatabaseDataActions';
export * from './DatabaseDataModel/DatabaseDataEditor';
export * from './DatabaseDataModel/DatabaseDataFormat';
export * from './DatabaseDataModel/DatabaseDataModel';
export * from './DatabaseDataModel/DatabaseDataSource';
export * from './DatabaseDataModel/IDatabaseDataAction';
export * from './DatabaseDataModel/IDatabaseDataActions';
export * from './DatabaseDataModel/IDatabaseDataEditor';
export * from './DatabaseDataModel/IDatabaseDataModel';
export * from './DatabaseDataModel/IDatabaseDataResult';