mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-21 17:36:01 +00:00
perspective filters
This commit is contained in:
@@ -88,7 +88,7 @@ export class PerspectiveCache {
|
||||
|
||||
getTableCache(props: PerspectiveDataLoadProps) {
|
||||
const tableKey = stableStringify(
|
||||
_pick(props, ['schemaName', 'pureName', 'bindingColumns', 'databaseConfig', 'orderBy'])
|
||||
_pick(props, ['schemaName', 'pureName', 'bindingColumns', 'databaseConfig', 'orderBy', 'condition'])
|
||||
);
|
||||
let res = this.tables[tableKey];
|
||||
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
export interface PerspectiveConfig {
|
||||
export interface PerspectiveConfigColumns {
|
||||
expandedColumns: string[];
|
||||
checkedColumns: string[];
|
||||
uncheckedColumns: string[];
|
||||
}
|
||||
|
||||
export interface PerspectiveConfig extends PerspectiveConfigColumns {
|
||||
filters: { [uniqueName: string]: string };
|
||||
}
|
||||
|
||||
export function createPerspectiveConfig(): PerspectiveConfig {
|
||||
return {
|
||||
expandedColumns: [],
|
||||
checkedColumns: [],
|
||||
uncheckedColumns: [],
|
||||
filters: {},
|
||||
};
|
||||
}
|
||||
|
||||
export type ChangePerspectiveConfigFunc = (changeFunc: (config: PerspectiveConfig) => PerspectiveConfig) => void;
|
||||
export type ChangePerspectiveConfigFunc = (
|
||||
changeFunc: (config: PerspectiveConfig) => PerspectiveConfig,
|
||||
reload?: boolean
|
||||
) => void;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Expression, Select } from 'dbgate-sqltree';
|
||||
import { Condition, Expression, Select } from 'dbgate-sqltree';
|
||||
import { PerspectiveDataLoadProps } from './PerspectiveDataProvider';
|
||||
import debug from 'debug';
|
||||
|
||||
@@ -7,6 +7,37 @@ const dbg = debug('dbgate:PerspectiveDataLoader');
|
||||
export class PerspectiveDataLoader {
|
||||
constructor(public apiCall) {}
|
||||
|
||||
buildCondition(props: PerspectiveDataLoadProps): Condition {
|
||||
const { schemaName, pureName, bindingColumns, bindingValues, dataColumns, orderBy, condition } = props;
|
||||
|
||||
const conditions = [];
|
||||
|
||||
if (condition) {
|
||||
conditions.push(condition);
|
||||
}
|
||||
|
||||
if (bindingColumns?.length == 1) {
|
||||
conditions.push({
|
||||
conditionType: 'in',
|
||||
expr: {
|
||||
exprType: 'column',
|
||||
columnName: bindingColumns[0],
|
||||
source: {
|
||||
name: { schemaName, pureName },
|
||||
},
|
||||
},
|
||||
values: bindingValues.map(x => x[0]),
|
||||
});
|
||||
}
|
||||
|
||||
return conditions.length > 0
|
||||
? {
|
||||
conditionType: 'and',
|
||||
conditions,
|
||||
}
|
||||
: null;
|
||||
}
|
||||
|
||||
async loadGrouping(props: PerspectiveDataLoadProps) {
|
||||
const { schemaName, pureName, bindingColumns, bindingValues, dataColumns } = props;
|
||||
|
||||
@@ -40,20 +71,8 @@ export class PerspectiveDataLoader {
|
||||
},
|
||||
...bindingColumnExpressions,
|
||||
],
|
||||
where: this.buildCondition(props),
|
||||
};
|
||||
if (bindingColumns?.length == 1) {
|
||||
select.where = {
|
||||
conditionType: 'in',
|
||||
expr: {
|
||||
exprType: 'column',
|
||||
columnName: bindingColumns[0],
|
||||
source: {
|
||||
name: { schemaName, pureName },
|
||||
},
|
||||
},
|
||||
values: bindingValues.map(x => x[0]),
|
||||
};
|
||||
}
|
||||
|
||||
select.groupBy = bindingColumnExpressions;
|
||||
|
||||
@@ -75,7 +94,8 @@ export class PerspectiveDataLoader {
|
||||
}
|
||||
|
||||
async loadData(props: PerspectiveDataLoadProps) {
|
||||
const { schemaName, pureName, bindingColumns, bindingValues, dataColumns, orderBy } = props;
|
||||
const { schemaName, pureName, bindingColumns, bindingValues, dataColumns, orderBy, condition } = props;
|
||||
|
||||
const select: Select = {
|
||||
commandType: 'select',
|
||||
from: {
|
||||
@@ -98,20 +118,8 @@ export class PerspectiveDataLoader {
|
||||
},
|
||||
})),
|
||||
range: props.range,
|
||||
where: this.buildCondition(props),
|
||||
};
|
||||
if (bindingColumns?.length == 1) {
|
||||
select.where = {
|
||||
conditionType: 'in',
|
||||
expr: {
|
||||
exprType: 'column',
|
||||
columnName: bindingColumns[0],
|
||||
source: {
|
||||
name: { schemaName, pureName },
|
||||
},
|
||||
},
|
||||
values: bindingValues.map(x => x[0]),
|
||||
};
|
||||
}
|
||||
|
||||
if (dbg?.enabled) {
|
||||
dbg(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Condition } from 'dbgate-sqltree';
|
||||
import { RangeDefinition } from 'dbgate-types';
|
||||
import { format } from 'path';
|
||||
import { PerspectiveBindingGroup, PerspectiveCache } from './PerspectiveCache';
|
||||
@@ -20,6 +21,7 @@ export interface PerspectiveDataLoadProps {
|
||||
bindingValues?: any[][];
|
||||
range?: RangeDefinition;
|
||||
topCount?: number;
|
||||
condition?: Condition;
|
||||
}
|
||||
|
||||
export class PerspectiveDataProvider {
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
import { ColumnInfo, DatabaseInfo, ForeignKeyInfo, RangeDefinition, TableInfo } from 'dbgate-types';
|
||||
import { clearConfigCache } from 'prettier';
|
||||
import { ChangePerspectiveConfigFunc, PerspectiveConfig } from './PerspectiveConfig';
|
||||
import { ChangePerspectiveConfigFunc, PerspectiveConfig, PerspectiveConfigColumns } from './PerspectiveConfig';
|
||||
import _isEqual from 'lodash/isEqual';
|
||||
import _cloneDeep from 'lodash/cloneDeep';
|
||||
import _compact from 'lodash/compact';
|
||||
import _uniq from 'lodash/uniq';
|
||||
import _flatten from 'lodash/flatten';
|
||||
import _uniqBy from 'lodash/uniqBy';
|
||||
import _cloneDeepWith from 'lodash/cloneDeepWith';
|
||||
import {
|
||||
PerspectiveDatabaseConfig,
|
||||
PerspectiveDataLoadProps,
|
||||
PerspectiveDataProvider,
|
||||
} from './PerspectiveDataProvider';
|
||||
import stableStringify from 'json-stable-stringify';
|
||||
import { getFilterType, parseFilter } from 'dbgate-filterparser';
|
||||
import { FilterType } from 'dbgate-filterparser/lib/types';
|
||||
import { Condition, Expression } from 'dbgate-sqltree';
|
||||
|
||||
export interface PerspectiveDataLoadPropsWithNode {
|
||||
props: PerspectiveDataLoadProps;
|
||||
@@ -84,6 +88,9 @@ export abstract class PerspectiveTreeNode {
|
||||
get columnTitle() {
|
||||
return this.title;
|
||||
}
|
||||
get filterType(): FilterType {
|
||||
return 'string';
|
||||
}
|
||||
|
||||
getChildMatchColumns() {
|
||||
return [];
|
||||
@@ -93,6 +100,10 @@ export abstract class PerspectiveTreeNode {
|
||||
return [];
|
||||
}
|
||||
|
||||
parseFilterCondition() {
|
||||
return null;
|
||||
}
|
||||
|
||||
get childDataColumn() {
|
||||
if (!this.isExpandable && this.isChecked) {
|
||||
return this.codeName;
|
||||
@@ -108,7 +119,7 @@ export abstract class PerspectiveTreeNode {
|
||||
this.includeInColumnSet('checkedColumns', this.uniqueName, value == null ? !this.isChecked : value);
|
||||
}
|
||||
|
||||
includeInColumnSet(field: keyof PerspectiveConfig, uniqueName: string, isIncluded: boolean) {
|
||||
includeInColumnSet(field: keyof PerspectiveConfigColumns, uniqueName: string, isIncluded: boolean) {
|
||||
if (isIncluded) {
|
||||
this.setConfig(cfg => ({
|
||||
...cfg,
|
||||
@@ -122,6 +133,23 @@ export abstract class PerspectiveTreeNode {
|
||||
}
|
||||
}
|
||||
|
||||
setFilter(value) {
|
||||
this.setConfig(
|
||||
cfg => ({
|
||||
...cfg,
|
||||
filters: {
|
||||
...cfg.filters,
|
||||
[this.uniqueName]: value,
|
||||
},
|
||||
}),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
getFilter() {
|
||||
return this.config.filters[this.uniqueName];
|
||||
}
|
||||
|
||||
getDataLoadColumns() {
|
||||
return _compact(
|
||||
_uniq([
|
||||
@@ -131,6 +159,20 @@ export abstract class PerspectiveTreeNode {
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
getChildrenCondition(): Condition {
|
||||
const conditions = _compact(this.childNodes.map(x => x.parseFilterCondition()));
|
||||
if (conditions.length == 0) {
|
||||
return null;
|
||||
}
|
||||
if (conditions.length == 1) {
|
||||
return conditions[0];
|
||||
}
|
||||
return {
|
||||
conditionType: 'and',
|
||||
conditions,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class PerspectiveTableColumnNode extends PerspectiveTreeNode {
|
||||
@@ -205,6 +247,10 @@ export class PerspectiveTableColumnNode extends PerspectiveTreeNode {
|
||||
return !!this.foreignKey;
|
||||
}
|
||||
|
||||
get filterType(): FilterType {
|
||||
return getFilterType(this.column.dataType);
|
||||
}
|
||||
|
||||
get childNodes(): PerspectiveTreeNode[] {
|
||||
if (!this.foreignKey) return [];
|
||||
const tbl = this?.db?.tables?.find(
|
||||
@@ -220,6 +266,23 @@ export class PerspectiveTableColumnNode extends PerspectiveTreeNode {
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
parseFilterCondition() {
|
||||
const filter = this.getFilter();
|
||||
if (!filter) return null;
|
||||
const condition = parseFilter(filter, this.filterType);
|
||||
if (!condition) return null;
|
||||
return _cloneDeepWith(condition, (expr: Expression) => {
|
||||
if (expr.exprType == 'placeholder') {
|
||||
return {
|
||||
exprType: 'column',
|
||||
columnName: this.column.columnName,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return condition;
|
||||
}
|
||||
}
|
||||
|
||||
export class PerspectiveTableNode extends PerspectiveTreeNode {
|
||||
@@ -235,13 +298,14 @@ export class PerspectiveTableNode extends PerspectiveTreeNode {
|
||||
super(config, setConfig, parentNode, dataProvider, databaseConfig);
|
||||
}
|
||||
|
||||
getNodeLoadProps(parentRows: any[]) {
|
||||
getNodeLoadProps(parentRows: any[]): PerspectiveDataLoadProps {
|
||||
return {
|
||||
schemaName: this.table.schemaName,
|
||||
pureName: this.table.pureName,
|
||||
dataColumns: this.getDataLoadColumns(),
|
||||
databaseConfig: this.databaseConfig,
|
||||
orderBy: this.table.primaryKey?.columns.map(x => x.columnName) || [this.table.columns[0].columnName],
|
||||
condition: this.getChildrenCondition(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user