perspective filters

This commit is contained in:
Jan Prochazka
2022-07-25 21:42:01 +02:00
parent f504283002
commit 3bdb5c0152
8 changed files with 142 additions and 46 deletions

View File

@@ -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];

View File

@@ -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;

View File

@@ -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(

View File

@@ -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 {

View File

@@ -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(),
};
}