mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-22 02:56:01 +00:00
Merge branch 'filter-refactor'
This commit is contained in:
@@ -2,6 +2,7 @@ import _ from 'lodash';
|
|||||||
import { GridDisplay, ChangeCacheFunc, ChangeConfigFunc, DisplayColumn } from './GridDisplay';
|
import { GridDisplay, ChangeCacheFunc, ChangeConfigFunc, DisplayColumn } from './GridDisplay';
|
||||||
import type { EngineDriver, ViewInfo, ColumnInfo, CollectionInfo } from 'dbgate-types';
|
import type { EngineDriver, ViewInfo, ColumnInfo, CollectionInfo } from 'dbgate-types';
|
||||||
import { GridConfig, GridCache } from './GridConfig';
|
import { GridConfig, GridCache } from './GridConfig';
|
||||||
|
import { mongoFilterBehaviour, standardFilterBehaviours } from 'dbgate-tools';
|
||||||
|
|
||||||
function getObjectKeys(obj) {
|
function getObjectKeys(obj) {
|
||||||
if (_.isArray(obj)) {
|
if (_.isArray(obj)) {
|
||||||
@@ -52,7 +53,7 @@ function getColumnsForObject(basePath, obj, res: any[], display) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayColumn(basePath, columnName, display) {
|
function getDisplayColumn(basePath, columnName, display: CollectionGridDisplay) {
|
||||||
const uniquePath = [...basePath, columnName];
|
const uniquePath = [...basePath, columnName];
|
||||||
const uniqueName = uniquePath.join('.');
|
const uniqueName = uniquePath.join('.');
|
||||||
return {
|
return {
|
||||||
@@ -62,7 +63,7 @@ function getDisplayColumn(basePath, columnName, display) {
|
|||||||
uniquePath,
|
uniquePath,
|
||||||
isStructured: true,
|
isStructured: true,
|
||||||
parentHeaderText: createHeaderText(basePath),
|
parentHeaderText: createHeaderText(basePath),
|
||||||
filterType: 'mongo',
|
filterBehaviour: display?.driver?.getFilterBehaviour(null, standardFilterBehaviours) ?? mongoFilterBehaviour,
|
||||||
pureName: display.collection?.pureName,
|
pureName: display.collection?.pureName,
|
||||||
schemaName: display.collection?.schemaName,
|
schemaName: display.collection?.schemaName,
|
||||||
};
|
};
|
||||||
@@ -95,7 +96,7 @@ export class CollectionGridDisplay extends GridDisplay {
|
|||||||
cache: GridCache,
|
cache: GridCache,
|
||||||
setCache: ChangeCacheFunc,
|
setCache: ChangeCacheFunc,
|
||||||
loadedRows,
|
loadedRows,
|
||||||
changeSet,
|
changeSet,
|
||||||
readOnly = false
|
readOnly = false
|
||||||
) {
|
) {
|
||||||
super(config, setConfig, cache, setCache, driver);
|
super(config, setConfig, cache, setCache, driver);
|
||||||
|
|||||||
@@ -10,12 +10,13 @@ import type {
|
|||||||
CollectionInfo,
|
CollectionInfo,
|
||||||
SqlDialect,
|
SqlDialect,
|
||||||
ViewInfo,
|
ViewInfo,
|
||||||
|
FilterBehaviour,
|
||||||
} from 'dbgate-types';
|
} from 'dbgate-types';
|
||||||
import { parseFilter, getFilterType } from 'dbgate-filterparser';
|
import { parseFilter } from 'dbgate-filterparser';
|
||||||
import { filterName } from 'dbgate-tools';
|
import { filterName } from 'dbgate-tools';
|
||||||
import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet';
|
import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet';
|
||||||
import { Expression, Select, treeToSql, dumpSqlSelect, Condition, CompoudCondition } from 'dbgate-sqltree';
|
import { Expression, Select, treeToSql, dumpSqlSelect, Condition, CompoudCondition } from 'dbgate-sqltree';
|
||||||
import { isTypeLogical } from 'dbgate-tools';
|
import { isTypeLogical, standardFilterBehaviours, detectSqlFilterBehaviour, stringFilterBehaviour } from 'dbgate-tools';
|
||||||
|
|
||||||
export interface DisplayColumn {
|
export interface DisplayColumn {
|
||||||
schemaName: string;
|
schemaName: string;
|
||||||
@@ -33,7 +34,7 @@ export interface DisplayColumn {
|
|||||||
isChecked?: boolean;
|
isChecked?: boolean;
|
||||||
hintColumnNames?: string[];
|
hintColumnNames?: string[];
|
||||||
dataType?: string;
|
dataType?: string;
|
||||||
filterType?: boolean;
|
filterBehaviour?: FilterBehaviour;
|
||||||
isStructured?: boolean;
|
isStructured?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +93,7 @@ export abstract class GridDisplay {
|
|||||||
isLoadedCorrectly = true;
|
isLoadedCorrectly = true;
|
||||||
supportsReload = false;
|
supportsReload = false;
|
||||||
isDynamicStructure = false;
|
isDynamicStructure = false;
|
||||||
filterTypeOverride = null;
|
filterBehaviourOverride = null;
|
||||||
|
|
||||||
setColumnVisibility(uniquePath: string[], isVisible: boolean) {
|
setColumnVisibility(uniquePath: string[], isVisible: boolean) {
|
||||||
const uniqueName = uniquePath.join('.');
|
const uniqueName = uniquePath.join('.');
|
||||||
@@ -192,7 +193,11 @@ export abstract class GridDisplay {
|
|||||||
const column = displayedColumnInfo[uniqueName];
|
const column = displayedColumnInfo[uniqueName];
|
||||||
if (!column) continue;
|
if (!column) continue;
|
||||||
try {
|
try {
|
||||||
const condition = parseFilter(filter, getFilterType(column.dataType));
|
const condition = parseFilter(
|
||||||
|
filter,
|
||||||
|
this.driver?.getFilterBehaviour(column.dataType, standardFilterBehaviours) ??
|
||||||
|
detectSqlFilterBehaviour(column.dataType)
|
||||||
|
);
|
||||||
if (condition) {
|
if (condition) {
|
||||||
conditions.push(
|
conditions.push(
|
||||||
_.cloneDeepWith(condition, (expr: Expression) => {
|
_.cloneDeepWith(condition, (expr: Expression) => {
|
||||||
@@ -220,7 +225,7 @@ export abstract class GridDisplay {
|
|||||||
};
|
};
|
||||||
for (const column of this.baseTableOrView.columns) {
|
for (const column of this.baseTableOrView.columns) {
|
||||||
try {
|
try {
|
||||||
const condition = parseFilter(this.config.multiColumnFilter, getFilterType(column.dataType));
|
const condition = parseFilter(this.config.multiColumnFilter, detectSqlFilterBehaviour(column.dataType));
|
||||||
if (condition) {
|
if (condition) {
|
||||||
orCondition.conditions.push(
|
orCondition.conditions.push(
|
||||||
_.cloneDeepWith(condition, (expr: Expression) => {
|
_.cloneDeepWith(condition, (expr: Expression) => {
|
||||||
@@ -748,10 +753,12 @@ export abstract class GridDisplay {
|
|||||||
for (const name in filters) {
|
for (const name in filters) {
|
||||||
const column = this.isDynamicStructure ? null : this.columns.find(x => x.columnName == name);
|
const column = this.isDynamicStructure ? null : this.columns.find(x => x.columnName == name);
|
||||||
if (!this.isDynamicStructure && !column) continue;
|
if (!this.isDynamicStructure && !column) continue;
|
||||||
const filterType =
|
const filterBehaviour =
|
||||||
this.filterTypeOverride ?? (this.isDynamicStructure ? 'mongo' : getFilterType(column.dataType));
|
this.filterBehaviourOverride ??
|
||||||
|
this.driver?.getFilterBehaviour(column.dataType, standardFilterBehaviours) ??
|
||||||
|
detectSqlFilterBehaviour(column.dataType);
|
||||||
try {
|
try {
|
||||||
const condition = parseFilter(filters[name], filterType);
|
const condition = parseFilter(filters[name], filterBehaviour);
|
||||||
const replaced = _.cloneDeepWith(condition, (expr: Expression) => {
|
const replaced = _.cloneDeepWith(condition, (expr: Expression) => {
|
||||||
if (expr.exprType == 'placeholder')
|
if (expr.exprType == 'placeholder')
|
||||||
return {
|
return {
|
||||||
@@ -766,7 +773,7 @@ export abstract class GridDisplay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.config.multiColumnFilter) {
|
if (this.config.multiColumnFilter) {
|
||||||
const placeholderCondition = parseFilter(this.config.multiColumnFilter, 'string');
|
const placeholderCondition = parseFilter(this.config.multiColumnFilter, stringFilterBehaviour);
|
||||||
if (placeholderCondition) {
|
if (placeholderCondition) {
|
||||||
conditions.push({
|
conditions.push({
|
||||||
conditionType: 'anyColumnPass',
|
conditionType: 'anyColumnPass',
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import _ from 'lodash';
|
|||||||
import { GridDisplay, ChangeCacheFunc, ChangeConfigFunc } from './GridDisplay';
|
import { GridDisplay, ChangeCacheFunc, ChangeConfigFunc } from './GridDisplay';
|
||||||
import { GridConfig, GridCache } from './GridConfig';
|
import { GridConfig, GridCache } from './GridConfig';
|
||||||
import { analyseCollectionDisplayColumns } from './CollectionGridDisplay';
|
import { analyseCollectionDisplayColumns } from './CollectionGridDisplay';
|
||||||
|
import { evalFilterBehaviour } from 'dbgate-tools';
|
||||||
|
|
||||||
export class JslGridDisplay extends GridDisplay {
|
export class JslGridDisplay extends GridDisplay {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -22,7 +23,7 @@ export class JslGridDisplay extends GridDisplay {
|
|||||||
this.sortable = true;
|
this.sortable = true;
|
||||||
this.supportsReload = supportsReload;
|
this.supportsReload = supportsReload;
|
||||||
this.isDynamicStructure = isDynamicStructure;
|
this.isDynamicStructure = isDynamicStructure;
|
||||||
this.filterTypeOverride = 'eval';
|
this.filterBehaviourOverride = evalFilterBehaviour;
|
||||||
this.editable = editable;
|
this.editable = editable;
|
||||||
this.editableStructure = editable ? structure : null;
|
this.editableStructure = editable ? structure : null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { DatabaseInfo, ForeignKeyInfo, NamedObjectInfo, TableInfo } from 'dbgate-types';
|
import type { DatabaseInfo, FilterBehaviour, ForeignKeyInfo, NamedObjectInfo, TableInfo } from 'dbgate-types';
|
||||||
import uuidv1 from 'uuid/v1';
|
import uuidv1 from 'uuid/v1';
|
||||||
|
|
||||||
// export interface PerspectiveConfigColumns {
|
// export interface PerspectiveConfigColumns {
|
||||||
@@ -31,7 +31,7 @@ export interface PerspectiveCustomJoinConfig {
|
|||||||
|
|
||||||
export interface PerspectiveFilterColumnInfo {
|
export interface PerspectiveFilterColumnInfo {
|
||||||
columnName: string;
|
columnName: string;
|
||||||
filterType: string;
|
filterBehaviour: FilterBehaviour;
|
||||||
pureName: string;
|
pureName: string;
|
||||||
schemaName: string;
|
schemaName: string;
|
||||||
foreignKey: ForeignKeyInfo;
|
foreignKey: ForeignKeyInfo;
|
||||||
|
|||||||
@@ -2,13 +2,22 @@ import type {
|
|||||||
CollectionInfo,
|
CollectionInfo,
|
||||||
ColumnInfo,
|
ColumnInfo,
|
||||||
DatabaseInfo,
|
DatabaseInfo,
|
||||||
|
FilterBehaviour,
|
||||||
ForeignKeyInfo,
|
ForeignKeyInfo,
|
||||||
NamedObjectInfo,
|
NamedObjectInfo,
|
||||||
RangeDefinition,
|
RangeDefinition,
|
||||||
TableInfo,
|
TableInfo,
|
||||||
ViewInfo,
|
ViewInfo,
|
||||||
} from 'dbgate-types';
|
} from 'dbgate-types';
|
||||||
import { equalFullName, isCollectionInfo, isTableInfo, isViewInfo } from 'dbgate-tools';
|
import {
|
||||||
|
detectSqlFilterBehaviour,
|
||||||
|
equalFullName,
|
||||||
|
isCollectionInfo,
|
||||||
|
isTableInfo,
|
||||||
|
isViewInfo,
|
||||||
|
mongoFilterBehaviour,
|
||||||
|
stringFilterBehaviour,
|
||||||
|
} from 'dbgate-tools';
|
||||||
import {
|
import {
|
||||||
ChangePerspectiveConfigFunc,
|
ChangePerspectiveConfigFunc,
|
||||||
createPerspectiveNodeConfig,
|
createPerspectiveNodeConfig,
|
||||||
@@ -33,8 +42,7 @@ import _cloneDeepWith from 'lodash/cloneDeepWith';
|
|||||||
import _findIndex from 'lodash/findIndex';
|
import _findIndex from 'lodash/findIndex';
|
||||||
import { PerspectiveDataLoadProps, PerspectiveDataProvider } from './PerspectiveDataProvider';
|
import { PerspectiveDataLoadProps, PerspectiveDataProvider } from './PerspectiveDataProvider';
|
||||||
import stableStringify from 'json-stable-stringify';
|
import stableStringify from 'json-stable-stringify';
|
||||||
import { getFilterType, parseFilter } from 'dbgate-filterparser';
|
import { parseFilter } from 'dbgate-filterparser';
|
||||||
import { FilterType } from 'dbgate-filterparser/lib/types';
|
|
||||||
import { CompoudCondition, Condition, Expression, Select } from 'dbgate-sqltree';
|
import { CompoudCondition, Condition, Expression, Select } from 'dbgate-sqltree';
|
||||||
// import { getPerspectiveDefaultColumns } from './getPerspectiveDefaultColumns';
|
// import { getPerspectiveDefaultColumns } from './getPerspectiveDefaultColumns';
|
||||||
import uuidv1 from 'uuid/v1';
|
import uuidv1 from 'uuid/v1';
|
||||||
@@ -197,8 +205,8 @@ export abstract class PerspectiveTreeNode {
|
|||||||
get columnTitle() {
|
get columnTitle() {
|
||||||
return this.title;
|
return this.title;
|
||||||
}
|
}
|
||||||
get filterType(): FilterType {
|
get filterBehaviour(): FilterBehaviour {
|
||||||
return 'string';
|
return stringFilterBehaviour;
|
||||||
}
|
}
|
||||||
get columnName() {
|
get columnName() {
|
||||||
return null;
|
return null;
|
||||||
@@ -346,7 +354,7 @@ export abstract class PerspectiveTreeNode {
|
|||||||
const base = this.getBaseTableFromThis() as TableInfo | ViewInfo;
|
const base = this.getBaseTableFromThis() as TableInfo | ViewInfo;
|
||||||
if (!base) return null;
|
if (!base) return null;
|
||||||
try {
|
try {
|
||||||
const condition = parseFilter(this.nodeConfig?.multiColumnFilter, 'string');
|
const condition = parseFilter(this.nodeConfig?.multiColumnFilter, stringFilterBehaviour);
|
||||||
if (condition) {
|
if (condition) {
|
||||||
const orCondition: CompoudCondition = {
|
const orCondition: CompoudCondition = {
|
||||||
conditionType: 'or',
|
conditionType: 'or',
|
||||||
@@ -380,7 +388,7 @@ export abstract class PerspectiveTreeNode {
|
|||||||
const pattern = this.dataProvider?.dataPatterns?.[this.designerId];
|
const pattern = this.dataProvider?.dataPatterns?.[this.designerId];
|
||||||
if (!pattern) return null;
|
if (!pattern) return null;
|
||||||
|
|
||||||
const condition = parseFilter(this.nodeConfig?.multiColumnFilter, 'mongo');
|
const condition = parseFilter(this.nodeConfig?.multiColumnFilter, mongoFilterBehaviour);
|
||||||
if (!condition) return null;
|
if (!condition) return null;
|
||||||
const res = pattern.columns.map(col => {
|
const res = pattern.columns.map(col => {
|
||||||
return _cloneDeepWith(condition, expr => {
|
return _cloneDeepWith(condition, expr => {
|
||||||
@@ -714,8 +722,8 @@ export class PerspectiveTableColumnNode extends PerspectiveTreeNode {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
get filterType(): FilterType {
|
get filterBehaviour(): FilterBehaviour {
|
||||||
return getFilterType(this.column.dataType);
|
return detectSqlFilterBehaviour(this.column.dataType);
|
||||||
}
|
}
|
||||||
|
|
||||||
get isCircular() {
|
get isCircular() {
|
||||||
@@ -767,7 +775,7 @@ export class PerspectiveTableColumnNode extends PerspectiveTreeNode {
|
|||||||
get filterInfo(): PerspectiveFilterColumnInfo {
|
get filterInfo(): PerspectiveFilterColumnInfo {
|
||||||
return {
|
return {
|
||||||
columnName: this.columnName,
|
columnName: this.columnName,
|
||||||
filterType: this.filterType,
|
filterBehaviour: this.filterBehaviour,
|
||||||
pureName: this.column.pureName,
|
pureName: this.column.pureName,
|
||||||
schemaName: this.column.schemaName,
|
schemaName: this.column.schemaName,
|
||||||
foreignKey: this.foreignKey,
|
foreignKey: this.foreignKey,
|
||||||
@@ -777,7 +785,7 @@ export class PerspectiveTableColumnNode extends PerspectiveTreeNode {
|
|||||||
parseFilterCondition(source = null): Condition {
|
parseFilterCondition(source = null): Condition {
|
||||||
const filter = this.getFilter();
|
const filter = this.getFilter();
|
||||||
if (!filter) return null;
|
if (!filter) return null;
|
||||||
const condition = parseFilter(filter, this.filterType);
|
const condition = parseFilter(filter, this.filterBehaviour);
|
||||||
if (!condition) return null;
|
if (!condition) return null;
|
||||||
return _cloneDeepWith(condition, (expr: Expression) => {
|
return _cloneDeepWith(condition, (expr: Expression) => {
|
||||||
if (expr.exprType == 'placeholder') {
|
if (expr.exprType == 'placeholder') {
|
||||||
@@ -949,9 +957,9 @@ export class PerspectivePatternColumnNode extends PerspectiveTreeNode {
|
|||||||
return !this.isChildColumn;
|
return !this.isChildColumn;
|
||||||
}
|
}
|
||||||
|
|
||||||
get filterType(): FilterType {
|
get filterBehaviour(): FilterBehaviour {
|
||||||
if (this.tableColumn) return getFilterType(this.tableColumn.dataType);
|
if (this.tableColumn) return detectSqlFilterBehaviour(this.tableColumn.dataType);
|
||||||
return 'mongo';
|
return mongoFilterBehaviour;
|
||||||
}
|
}
|
||||||
|
|
||||||
get preloadedLevelData() {
|
get preloadedLevelData() {
|
||||||
@@ -1083,7 +1091,7 @@ export class PerspectivePatternColumnNode extends PerspectiveTreeNode {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
columnName: this.columnName,
|
columnName: this.columnName,
|
||||||
filterType: this.filterType,
|
filterBehaviour: this.filterBehaviour,
|
||||||
pureName: this.table.pureName,
|
pureName: this.table.pureName,
|
||||||
schemaName: this.table.schemaName,
|
schemaName: this.table.schemaName,
|
||||||
foreignKey: this.foreignKey,
|
foreignKey: this.foreignKey,
|
||||||
@@ -1093,7 +1101,7 @@ export class PerspectivePatternColumnNode extends PerspectiveTreeNode {
|
|||||||
parseFilterCondition(source = null): {} {
|
parseFilterCondition(source = null): {} {
|
||||||
const filter = this.getFilter();
|
const filter = this.getFilter();
|
||||||
if (!filter) return null;
|
if (!filter) return null;
|
||||||
const condition = parseFilter(filter, 'mongo');
|
const condition = parseFilter(filter, mongoFilterBehaviour);
|
||||||
if (!condition) return null;
|
if (!condition) return null;
|
||||||
return _cloneDeepWith(condition, expr => {
|
return _cloneDeepWith(condition, expr => {
|
||||||
if (expr.__placeholder__) {
|
if (expr.__placeholder__) {
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import P from 'parsimmon';
|
import P from 'parsimmon';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { FilterType } from './types';
|
|
||||||
import { Condition } from 'dbgate-sqltree';
|
|
||||||
import type { TransformType } from 'dbgate-types';
|
import type { TransformType } from 'dbgate-types';
|
||||||
import { interpretEscapes, token, word, whitespace } from './common';
|
import { token, word, whitespace } from './common';
|
||||||
|
|
||||||
const compoudCondition = conditionType => conditions => {
|
const compoudCondition = conditionType => conditions => {
|
||||||
if (conditions.length == 1) return conditions[0];
|
if (conditions.length == 1) return conditions[0];
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import { isTypeNumber, isTypeString, isTypeLogical, isTypeDateTime } from 'dbgate-tools';
|
|
||||||
import { FilterType } from './types';
|
|
||||||
|
|
||||||
export function getFilterType(dataType: string): FilterType {
|
|
||||||
if (!dataType) return 'string';
|
|
||||||
if (isTypeNumber(dataType)) return 'number';
|
|
||||||
if (isTypeString(dataType)) return 'string';
|
|
||||||
if (isTypeLogical(dataType)) return 'logical';
|
|
||||||
if (isTypeDateTime(dataType)) return 'datetime';
|
|
||||||
return 'string';
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,2 @@
|
|||||||
export * from './parseFilter';
|
export * from './parseFilter';
|
||||||
export * from './getFilterType';
|
|
||||||
export * from './filterTool';
|
export * from './filterTool';
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import P from 'parsimmon';
|
import P from 'parsimmon';
|
||||||
import moment from 'moment';
|
|
||||||
import { FilterType } from './types';
|
|
||||||
import { Condition } from 'dbgate-sqltree';
|
import { Condition } from 'dbgate-sqltree';
|
||||||
import { interpretEscapes, token, word, whitespace } from './common';
|
import { interpretEscapes, token, word, whitespace } from './common';
|
||||||
import { mongoParser } from './mongoParser';
|
import { mongoParser } from './mongoParser';
|
||||||
import { datetimeParser } from './datetimeParser';
|
import { datetimeParser } from './datetimeParser';
|
||||||
import { hexStringToArray } from 'dbgate-tools';
|
import { hexStringToArray } from 'dbgate-tools';
|
||||||
|
import { FilterBehaviour } from 'dbgate-types';
|
||||||
|
|
||||||
const binaryCondition = operator => value => ({
|
const binaryCondition = operator => value => ({
|
||||||
conditionType: 'binary',
|
conditionType: 'binary',
|
||||||
@@ -78,7 +77,7 @@ const sqlTemplate = templateSql => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const createParser = (filterType: FilterType) => {
|
const createParser = (filterBehaviour: FilterBehaviour) => {
|
||||||
const langDef = {
|
const langDef = {
|
||||||
string1: () =>
|
string1: () =>
|
||||||
token(P.regexp(/"((?:\\.|.)*?)"/, 1))
|
token(P.regexp(/"((?:\\.|.)*?)"/, 1))
|
||||||
@@ -156,32 +155,52 @@ const createParser = (filterType: FilterType) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const allowedValues = []; // 'string1', 'string2', 'number', 'noQuotedString'];
|
const allowedValues = []; // 'string1', 'string2', 'number', 'noQuotedString'];
|
||||||
if (filterType == 'string' || filterType == 'eval') {
|
if (filterBehaviour.allowStringToken) {
|
||||||
allowedValues.push('string1', 'string2', 'noQuotedString');
|
allowedValues.push('string1', 'string2', 'noQuotedString');
|
||||||
}
|
}
|
||||||
if (filterType == 'number') {
|
if (filterBehaviour.allowNumberToken) {
|
||||||
allowedValues.push('string1Num', 'string2Num', 'number');
|
allowedValues.push('string1Num', 'string2Num', 'number');
|
||||||
}
|
}
|
||||||
|
|
||||||
const allowedElements = ['null', 'notNull', 'eq', 'ne', 'ne2', 'sql'];
|
const allowedElements = [];
|
||||||
if (filterType == 'number' || filterType == 'datetime' || filterType == 'eval') {
|
|
||||||
|
if (filterBehaviour.supportNullTesting) {
|
||||||
|
allowedElements.push('null', 'notNull');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportEquals) {
|
||||||
|
allowedElements.push('eq', 'ne', 'ne2');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportSqlCondition) {
|
||||||
|
allowedElements.push('sql');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportNumberLikeComparison || filterBehaviour.supportDatetimeComparison) {
|
||||||
allowedElements.push('le', 'ge', 'lt', 'gt');
|
allowedElements.push('le', 'ge', 'lt', 'gt');
|
||||||
}
|
}
|
||||||
if (filterType == 'string') {
|
|
||||||
allowedElements.push('empty', 'notEmpty', 'hexTestEq');
|
if (filterBehaviour.supportEmpty) {
|
||||||
|
allowedElements.push('empty', 'notEmpty');
|
||||||
}
|
}
|
||||||
if (filterType == 'eval' || filterType == 'string') {
|
|
||||||
|
if (filterBehaviour.allowHexString) {
|
||||||
|
allowedElements.push('hexTestEq');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportStringInclusion) {
|
||||||
allowedElements.push('startsWith', 'endsWith', 'contains', 'startsWithNot', 'endsWithNot', 'containsNot');
|
allowedElements.push('startsWith', 'endsWith', 'contains', 'startsWithNot', 'endsWithNot', 'containsNot');
|
||||||
}
|
}
|
||||||
if (filterType == 'logical') {
|
if (filterBehaviour.supportBooleanValues) {
|
||||||
allowedElements.push('true', 'false', 'trueNum', 'falseNum');
|
if (filterBehaviour.allowNumberToken || filterBehaviour.allowStringToken) {
|
||||||
}
|
allowedElements.push('true', 'false');
|
||||||
if (filterType == 'eval') {
|
} else {
|
||||||
allowedElements.push('true', 'false');
|
allowedElements.push('true', 'false', 'trueNum', 'falseNum');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// must be last
|
// must be last
|
||||||
if (filterType == 'string' || filterType == 'eval') {
|
if (filterBehaviour.allowStringToken) {
|
||||||
allowedElements.push('valueTestStr');
|
allowedElements.push('valueTestStr');
|
||||||
} else {
|
} else {
|
||||||
allowedElements.push('valueTestEq');
|
allowedElements.push('valueTestEq');
|
||||||
@@ -190,18 +209,27 @@ const createParser = (filterType: FilterType) => {
|
|||||||
return P.createLanguage(langDef);
|
return P.createLanguage(langDef);
|
||||||
};
|
};
|
||||||
|
|
||||||
const parsers = {
|
const cachedFilters: { [key: string]: P.Language } = {};
|
||||||
number: createParser('number'),
|
|
||||||
string: createParser('string'),
|
|
||||||
logical: createParser('logical'),
|
|
||||||
eval: createParser('eval'),
|
|
||||||
mongo: mongoParser,
|
|
||||||
datetime: datetimeParser,
|
|
||||||
};
|
|
||||||
|
|
||||||
export function parseFilter(value: string, filterType: FilterType): Condition {
|
function getParser(filterBehaviour: FilterBehaviour) {
|
||||||
// console.log('PARSING', value, 'WITH', filterType);
|
if (filterBehaviour.compilerType == 'mongoCondition') {
|
||||||
const ast = parsers[filterType].list.tryParse(value);
|
return mongoParser;
|
||||||
|
}
|
||||||
|
if (filterBehaviour.compilerType == 'datetime') {
|
||||||
|
return datetimeParser;
|
||||||
|
}
|
||||||
|
const key = JSON.stringify(filterBehaviour);
|
||||||
|
if (!cachedFilters[key]) {
|
||||||
|
cachedFilters[key] = createParser(filterBehaviour);
|
||||||
|
}
|
||||||
|
return cachedFilters[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseFilter(value: string, filterBehaviour: FilterBehaviour): Condition {
|
||||||
|
const parser = getParser(filterBehaviour);
|
||||||
|
// console.log('value', value);
|
||||||
|
// console.log('filterBehaviour', filterBehaviour);
|
||||||
|
const ast = parser.list.tryParse(value);
|
||||||
// console.log('AST', ast);
|
// console.log('AST', ast);
|
||||||
return ast;
|
return ast;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
const { parseFilter } = require('./parseFilter');
|
const { parseFilter } = require('./parseFilter');
|
||||||
|
const { stringFilterBehaviour } = require('dbgate-tools');
|
||||||
|
|
||||||
test('parse string', () => {
|
test('parse string', () => {
|
||||||
const ast = parseFilter('"123"', 'string');
|
const ast = parseFilter('"123"', stringFilterBehaviour);
|
||||||
console.log(JSON.stringify(ast));
|
console.log(JSON.stringify(ast));
|
||||||
expect(ast).toEqual({
|
expect(ast).toEqual({
|
||||||
conditionType: 'like',
|
conditionType: 'like',
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
// import types from 'dbgate-types';
|
|
||||||
|
|
||||||
export type FilterType = 'number' | 'string' | 'datetime' | 'logical' | 'eval' | 'mongo';
|
|
||||||
17
packages/tools/src/detectSqlFilterBehaviour.ts
Normal file
17
packages/tools/src/detectSqlFilterBehaviour.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { FilterBehaviour } from 'dbgate-types';
|
||||||
|
import {
|
||||||
|
datetimeFilterBehaviour,
|
||||||
|
logicalFilterBehaviour,
|
||||||
|
numberFilterBehaviour,
|
||||||
|
stringFilterBehaviour,
|
||||||
|
} from './filterBehaviours';
|
||||||
|
import { isTypeDateTime, isTypeLogical, isTypeNumber, isTypeString } from './commonTypeParser';
|
||||||
|
|
||||||
|
export function detectSqlFilterBehaviour(dataType: string): FilterBehaviour {
|
||||||
|
if (!dataType) return stringFilterBehaviour;
|
||||||
|
if (isTypeNumber(dataType)) return numberFilterBehaviour;
|
||||||
|
if (isTypeString(dataType)) return stringFilterBehaviour;
|
||||||
|
if (isTypeLogical(dataType)) return logicalFilterBehaviour;
|
||||||
|
if (isTypeDateTime(dataType)) return datetimeFilterBehaviour;
|
||||||
|
return stringFilterBehaviour;
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ import { SqlDumper } from './SqlDumper';
|
|||||||
import { splitQuery } from 'dbgate-query-splitter';
|
import { splitQuery } from 'dbgate-query-splitter';
|
||||||
import { dumpSqlSelect } from 'dbgate-sqltree';
|
import { dumpSqlSelect } from 'dbgate-sqltree';
|
||||||
import { EngineDriver, QueryResult, RunScriptOptions } from 'dbgate-types';
|
import { EngineDriver, QueryResult, RunScriptOptions } from 'dbgate-types';
|
||||||
|
import { detectSqlFilterBehaviour } from './detectSqlFilterBehaviour';
|
||||||
|
|
||||||
const dialect = {
|
const dialect = {
|
||||||
limitSelect: true,
|
limitSelect: true,
|
||||||
@@ -150,4 +151,7 @@ export const driverBase = {
|
|||||||
showConnectionField: (field, values) => false,
|
showConnectionField: (field, values) => false,
|
||||||
showConnectionTab: field => true,
|
showConnectionTab: field => true,
|
||||||
getAccessTokenFromAuth: async (connection, req) => null,
|
getAccessTokenFromAuth: async (connection, req) => null,
|
||||||
|
getFilterBehaviour(dataType: string, standardFilterBehaviours) {
|
||||||
|
return detectSqlFilterBehaviour(dataType);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
69
packages/tools/src/filterBehaviours.ts
Normal file
69
packages/tools/src/filterBehaviours.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import { FilterBehaviour } from 'dbgate-types';
|
||||||
|
|
||||||
|
export const numberFilterBehaviour: FilterBehaviour = {
|
||||||
|
compilerType: 'sqlTree',
|
||||||
|
supportEquals: true,
|
||||||
|
supportNumberLikeComparison: true,
|
||||||
|
supportNullTesting: true,
|
||||||
|
supportSqlCondition: true,
|
||||||
|
|
||||||
|
allowNumberToken: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const stringFilterBehaviour: FilterBehaviour = {
|
||||||
|
compilerType: 'sqlTree',
|
||||||
|
supportEquals: true,
|
||||||
|
supportStringInclusion: true,
|
||||||
|
supportEmpty: true,
|
||||||
|
supportNumberLikeComparison: true,
|
||||||
|
supportNullTesting: true,
|
||||||
|
supportSqlCondition: true,
|
||||||
|
|
||||||
|
allowStringToken: true,
|
||||||
|
allowHexString: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const logicalFilterBehaviour: FilterBehaviour = {
|
||||||
|
compilerType: 'sqlTree',
|
||||||
|
supportBooleanValues: true,
|
||||||
|
supportNullTesting: true,
|
||||||
|
supportSqlCondition: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const datetimeFilterBehaviour: FilterBehaviour = {
|
||||||
|
compilerType: 'datetime',
|
||||||
|
supportNullTesting: true,
|
||||||
|
supportSqlCondition: true,
|
||||||
|
supportDatetimeSymbols: true,
|
||||||
|
supportDatetimeComparison: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mongoFilterBehaviour: FilterBehaviour = {
|
||||||
|
compilerType: 'mongoCondition',
|
||||||
|
supportEquals: true,
|
||||||
|
supportArrayTesting: true,
|
||||||
|
supportNumberLikeComparison: true,
|
||||||
|
supportStringInclusion: true,
|
||||||
|
supportBooleanValues: true,
|
||||||
|
supportExistsTesting: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const evalFilterBehaviour: FilterBehaviour = {
|
||||||
|
compilerType: 'sqlTree',
|
||||||
|
supportEquals: true,
|
||||||
|
supportStringInclusion: true,
|
||||||
|
supportEmpty: true,
|
||||||
|
supportNumberLikeComparison: true,
|
||||||
|
supportNullTesting: true,
|
||||||
|
|
||||||
|
allowStringToken: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const standardFilterBehaviours: { [id: string]: FilterBehaviour } = {
|
||||||
|
numberFilterBehaviour,
|
||||||
|
stringFilterBehaviour,
|
||||||
|
logicalFilterBehaviour,
|
||||||
|
datetimeFilterBehaviour,
|
||||||
|
mongoFilterBehaviour,
|
||||||
|
evalFilterBehaviour,
|
||||||
|
};
|
||||||
@@ -21,3 +21,5 @@ export * from './preloadedRowsTools';
|
|||||||
export * from './ScriptWriter';
|
export * from './ScriptWriter';
|
||||||
export * from './getLogger';
|
export * from './getLogger';
|
||||||
export * from './getConnectionLabel';
|
export * from './getConnectionLabel';
|
||||||
|
export * from './detectSqlFilterBehaviour';
|
||||||
|
export * from './filterBehaviours';
|
||||||
|
|||||||
7
packages/types/engines.d.ts
vendored
7
packages/types/engines.d.ts
vendored
@@ -3,6 +3,7 @@ import { QueryResult } from './query';
|
|||||||
import { SqlDialect } from './dialect';
|
import { SqlDialect } from './dialect';
|
||||||
import { SqlDumper } from './dumper';
|
import { SqlDumper } from './dumper';
|
||||||
import { DatabaseInfo, NamedObjectInfo, TableInfo, ViewInfo, ProcedureInfo, FunctionInfo, TriggerInfo } from './dbinfo';
|
import { DatabaseInfo, NamedObjectInfo, TableInfo, ViewInfo, ProcedureInfo, FunctionInfo, TriggerInfo } from './dbinfo';
|
||||||
|
import { FilterBehaviour } from './filter-type';
|
||||||
|
|
||||||
export interface StreamOptions {
|
export interface StreamOptions {
|
||||||
recordset: (columns) => void;
|
recordset: (columns) => void;
|
||||||
@@ -71,7 +72,11 @@ export interface ServerSummary {
|
|||||||
databases: ServerSummaryDatabase[];
|
databases: ServerSummaryDatabase[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EngineDriver {
|
export interface FilterBehaviourProvider {
|
||||||
|
getFilterBehaviour(dataType: string, standardFilterBehaviours: { [id: string]: FilterBehaviour }): FilterBehaviour;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EngineDriver extends FilterBehaviourProvider {
|
||||||
engine: string;
|
engine: string;
|
||||||
title: string;
|
title: string;
|
||||||
defaultPort?: number;
|
defaultPort?: number;
|
||||||
|
|||||||
21
packages/types/filter-type.d.ts
vendored
Normal file
21
packages/types/filter-type.d.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
export type FilterParserCompilerType = 'sqlTree' | 'mongoCondition' | 'datetime';
|
||||||
|
|
||||||
|
export interface FilterBehaviour {
|
||||||
|
compilerType: FilterParserCompilerType;
|
||||||
|
|
||||||
|
supportEquals?: boolean;
|
||||||
|
supportStringInclusion?: boolean;
|
||||||
|
supportEmpty?: boolean;
|
||||||
|
supportNumberLikeComparison?: boolean;
|
||||||
|
supportDatetimeComparison?: boolean;
|
||||||
|
supportDatetimeSymbols?: boolean;
|
||||||
|
supportNullTesting?: boolean;
|
||||||
|
supportExistsTesting?: boolean;
|
||||||
|
supportBooleanValues?: boolean;
|
||||||
|
supportSqlCondition?: boolean;
|
||||||
|
supportArrayTesting?: boolean;
|
||||||
|
|
||||||
|
allowStringToken?: boolean;
|
||||||
|
allowNumberToken?: boolean;
|
||||||
|
allowHexString?: boolean;
|
||||||
|
}
|
||||||
1
packages/types/index.d.ts
vendored
1
packages/types/index.d.ts
vendored
@@ -47,3 +47,4 @@ export * from './dbtypes';
|
|||||||
export * from './extensions';
|
export * from './extensions';
|
||||||
export * from './alter-processor';
|
export * from './alter-processor';
|
||||||
export * from './appdefs';
|
export * from './appdefs';
|
||||||
|
export * from './filter-type';
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
for (const uniqueName in filters || {}) {
|
for (const uniqueName in filters || {}) {
|
||||||
if (!filters[uniqueName]) continue;
|
if (!filters[uniqueName]) continue;
|
||||||
try {
|
try {
|
||||||
const ast = parseFilter(filters[uniqueName], 'mongo');
|
const ast = parseFilter(filters[uniqueName], mongoFilterBehaviour);
|
||||||
// console.log('AST', ast);
|
// console.log('AST', ast);
|
||||||
const cond = _.cloneDeepWith(ast, expr => {
|
const cond = _.cloneDeepWith(ast, expr => {
|
||||||
if (expr.__placeholder__) {
|
if (expr.__placeholder__) {
|
||||||
@@ -123,6 +123,7 @@
|
|||||||
import ChangeSetGrider from './ChangeSetGrider';
|
import ChangeSetGrider from './ChangeSetGrider';
|
||||||
|
|
||||||
import LoadingDataGridCore from './LoadingDataGridCore.svelte';
|
import LoadingDataGridCore from './LoadingDataGridCore.svelte';
|
||||||
|
import { mongoFilterBehaviour } from 'dbgate-tools';
|
||||||
|
|
||||||
export let conid;
|
export let conid;
|
||||||
export let display;
|
export let display;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
import ValueLookupModal from '../modals/ValueLookupModal.svelte';
|
import ValueLookupModal from '../modals/ValueLookupModal.svelte';
|
||||||
|
|
||||||
export let isReadOnly = false;
|
export let isReadOnly = false;
|
||||||
export let filterType;
|
export let filterBehaviour;
|
||||||
export let filter;
|
export let filter;
|
||||||
export let setFilter;
|
export let setFilter;
|
||||||
export let showResizeSplitter = false;
|
export let showResizeSplitter = false;
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
$: if (onGetReference && domInput) onGetReference(domInput);
|
$: if (onGetReference && domInput) onGetReference(domInput);
|
||||||
|
|
||||||
function openFilterWindow(condition1) {
|
function openFilterWindow(condition1) {
|
||||||
showModal(SetFilterModal, { condition1, filterType, onFilter: setFilter });
|
showModal(SetFilterModal, { condition1, filterBehaviour, onFilter: setFilter });
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterMultipleValues = () => {
|
const filterMultipleValues = () => {
|
||||||
@@ -60,167 +60,121 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
function createMenu() {
|
function createMenu() {
|
||||||
switch (filterType) {
|
const res = [
|
||||||
case 'number':
|
{ onClick: () => setFilter(''), text: 'Clear Filter' },
|
||||||
return [
|
{ onClick: () => filterMultipleValues(), text: 'Filter multiple values' },
|
||||||
{ onClick: () => setFilter(''), text: 'Clear Filter' },
|
];
|
||||||
{ onClick: () => filterMultipleValues(), text: 'Filter multiple values' },
|
|
||||||
{ onClick: () => openFilterWindow('='), text: 'Equals...' },
|
|
||||||
{ onClick: () => openFilterWindow('<>'), text: 'Does Not Equal...' },
|
|
||||||
{ onClick: () => setFilter('NULL'), text: 'Is Null' },
|
|
||||||
{ onClick: () => setFilter('NOT NULL'), text: 'Is Not Null' },
|
|
||||||
{ onClick: () => openFilterWindow('>'), text: 'Greater Than...' },
|
|
||||||
{ onClick: () => openFilterWindow('>='), text: 'Greater Than Or Equal To...' },
|
|
||||||
{ onClick: () => openFilterWindow('<'), text: 'Less Than...' },
|
|
||||||
{ onClick: () => openFilterWindow('<='), text: 'Less Than Or Equal To...' },
|
|
||||||
|
|
||||||
{ divider: true },
|
if (filterBehaviour.supportEquals) {
|
||||||
|
res.push(
|
||||||
{ onClick: () => openFilterWindow('sql'), text: 'SQL condition ...' },
|
{ onClick: () => openFilterWindow('='), text: 'Equals...' },
|
||||||
{ onClick: () => openFilterWindow('sqlRight'), text: 'SQL condition - right side ...' },
|
{ onClick: () => openFilterWindow('<>'), text: 'Does Not Equal...' }
|
||||||
];
|
);
|
||||||
case 'logical':
|
|
||||||
return [
|
|
||||||
{ onClick: () => setFilter(''), text: 'Clear Filter' },
|
|
||||||
{ onClick: () => filterMultipleValues(), text: 'Filter multiple values' },
|
|
||||||
{ onClick: () => setFilter('NULL'), text: 'Is Null' },
|
|
||||||
{ onClick: () => setFilter('NOT NULL'), text: 'Is Not Null' },
|
|
||||||
{ onClick: () => setFilter('TRUE'), text: 'Is True' },
|
|
||||||
{ onClick: () => setFilter('FALSE'), text: 'Is False' },
|
|
||||||
{ onClick: () => setFilter('TRUE, NULL'), text: 'Is True or NULL' },
|
|
||||||
{ onClick: () => setFilter('FALSE, NULL'), text: 'Is False or NULL' },
|
|
||||||
|
|
||||||
{ divider: true },
|
|
||||||
|
|
||||||
{ onClick: () => openFilterWindow('sql'), text: 'SQL condition ...' },
|
|
||||||
{ onClick: () => openFilterWindow('sqlRight'), text: 'SQL condition - right side ...' },
|
|
||||||
];
|
|
||||||
case 'datetime':
|
|
||||||
return [
|
|
||||||
{ onClick: () => setFilter(''), text: 'Clear Filter' },
|
|
||||||
{ onClick: () => filterMultipleValues(), text: 'Filter multiple values' },
|
|
||||||
{ onClick: () => setFilter('NULL'), text: 'Is Null' },
|
|
||||||
{ onClick: () => setFilter('NOT NULL'), text: 'Is Not Null' },
|
|
||||||
|
|
||||||
{ divider: true },
|
|
||||||
|
|
||||||
{ onClick: () => openFilterWindow('<='), text: 'Before...' },
|
|
||||||
{ onClick: () => openFilterWindow('>='), text: 'After...' },
|
|
||||||
{ onClick: () => openFilterWindow('>=;<='), text: 'Between...' },
|
|
||||||
|
|
||||||
{ divider: true },
|
|
||||||
|
|
||||||
{ onClick: () => setFilter('TOMORROW'), text: 'Tomorrow' },
|
|
||||||
{ onClick: () => setFilter('TODAY'), text: 'Today' },
|
|
||||||
{ onClick: () => setFilter('YESTERDAY'), text: 'Yesterday' },
|
|
||||||
|
|
||||||
{ divider: true },
|
|
||||||
|
|
||||||
{ onClick: () => setFilter('NEXT WEEK'), text: 'Next Week' },
|
|
||||||
{ onClick: () => setFilter('THIS WEEK'), text: 'This Week' },
|
|
||||||
{ onClick: () => setFilter('LAST WEEK'), text: 'Last Week' },
|
|
||||||
|
|
||||||
{ divider: true },
|
|
||||||
|
|
||||||
{ onClick: () => setFilter('NEXT MONTH'), text: 'Next Month' },
|
|
||||||
{ onClick: () => setFilter('THIS MONTH'), text: 'This Month' },
|
|
||||||
{ onClick: () => setFilter('LAST MONTH'), text: 'Last Month' },
|
|
||||||
|
|
||||||
{ divider: true },
|
|
||||||
|
|
||||||
{ onClick: () => setFilter('NEXT YEAR'), text: 'Next Year' },
|
|
||||||
{ onClick: () => setFilter('THIS YEAR'), text: 'This Year' },
|
|
||||||
{ onClick: () => setFilter('LAST YEAR'), text: 'Last Year' },
|
|
||||||
|
|
||||||
{ divider: true },
|
|
||||||
|
|
||||||
{ onClick: () => openFilterWindow('sql'), text: 'SQL condition ...' },
|
|
||||||
{ onClick: () => openFilterWindow('sqlRight'), text: 'SQL condition - right side ...' },
|
|
||||||
];
|
|
||||||
case 'string':
|
|
||||||
return [
|
|
||||||
{ onClick: () => setFilter(''), text: 'Clear Filter' },
|
|
||||||
{ onClick: () => filterMultipleValues(), text: 'Filter multiple values' },
|
|
||||||
|
|
||||||
{ onClick: () => openFilterWindow('='), text: 'Equals...' },
|
|
||||||
{ onClick: () => openFilterWindow('<>'), text: 'Does Not Equal...' },
|
|
||||||
{ onClick: () => setFilter('NULL'), text: 'Is Null' },
|
|
||||||
{ onClick: () => setFilter('NOT NULL'), text: 'Is Not Null' },
|
|
||||||
{ onClick: () => setFilter('EMPTY, NULL'), text: 'Is Empty Or Null' },
|
|
||||||
{ onClick: () => setFilter('NOT EMPTY NOT NULL'), text: 'Has Not Empty Value' },
|
|
||||||
|
|
||||||
{ divider: true },
|
|
||||||
|
|
||||||
{ onClick: () => openFilterWindow('+'), text: 'Contains...' },
|
|
||||||
{ onClick: () => openFilterWindow('~'), text: 'Does Not Contain...' },
|
|
||||||
{ onClick: () => openFilterWindow('^'), text: 'Begins With...' },
|
|
||||||
{ onClick: () => openFilterWindow('!^'), text: 'Does Not Begin With...' },
|
|
||||||
{ onClick: () => openFilterWindow('$'), text: 'Ends With...' },
|
|
||||||
{ onClick: () => openFilterWindow('!$'), text: 'Does Not End With...' },
|
|
||||||
|
|
||||||
{ divider: true },
|
|
||||||
|
|
||||||
{ onClick: () => openFilterWindow('sql'), text: 'SQL condition ...' },
|
|
||||||
{ onClick: () => openFilterWindow('sqlRight'), text: 'SQL condition - right side ...' },
|
|
||||||
];
|
|
||||||
case 'mongo':
|
|
||||||
return [
|
|
||||||
{ onClick: () => setFilter(''), text: 'Clear Filter' },
|
|
||||||
{ onClick: () => filterMultipleValues(), text: 'Filter multiple values' },
|
|
||||||
{ onClick: () => openFilterWindow('='), text: 'Equals...' },
|
|
||||||
{ onClick: () => openFilterWindow('<>'), text: 'Does Not Equal...' },
|
|
||||||
{ onClick: () => setFilter('EXISTS'), text: 'Field exists' },
|
|
||||||
{ onClick: () => setFilter('NOT EXISTS'), text: 'Field does not exist' },
|
|
||||||
{ onClick: () => setFilter('NOT EMPTY ARRAY'), text: 'Array is not empty' },
|
|
||||||
{ onClick: () => setFilter('EMPTY ARRAY'), text: 'Array is empty' },
|
|
||||||
{ onClick: () => openFilterWindow('>'), text: 'Greater Than...' },
|
|
||||||
{ onClick: () => openFilterWindow('>='), text: 'Greater Than Or Equal To...' },
|
|
||||||
{ onClick: () => openFilterWindow('<'), text: 'Less Than...' },
|
|
||||||
{ onClick: () => openFilterWindow('<='), text: 'Less Than Or Equal To...' },
|
|
||||||
{ divider: true },
|
|
||||||
{ onClick: () => openFilterWindow('+'), text: 'Contains...' },
|
|
||||||
{ onClick: () => openFilterWindow('~'), text: 'Does Not Contain...' },
|
|
||||||
{ onClick: () => openFilterWindow('^'), text: 'Begins With...' },
|
|
||||||
{ onClick: () => openFilterWindow('!^'), text: 'Does Not Begin With...' },
|
|
||||||
{ onClick: () => openFilterWindow('$'), text: 'Ends With...' },
|
|
||||||
{ onClick: () => openFilterWindow('!$'), text: 'Does Not End With...' },
|
|
||||||
{ divider: true },
|
|
||||||
{ onClick: () => setFilter('TRUE'), text: 'Is True' },
|
|
||||||
{ onClick: () => setFilter('FALSE'), text: 'Is False' },
|
|
||||||
];
|
|
||||||
case 'eval':
|
|
||||||
return [
|
|
||||||
{ onClick: () => setFilter(''), text: 'Clear Filter' },
|
|
||||||
{ onClick: () => filterMultipleValues(), text: 'Filter multiple values' },
|
|
||||||
|
|
||||||
{ onClick: () => openFilterWindow('='), text: 'Equals...' },
|
|
||||||
{ onClick: () => openFilterWindow('<>'), text: 'Does Not Equal...' },
|
|
||||||
{ onClick: () => setFilter('NULL'), text: 'Is Null' },
|
|
||||||
{ onClick: () => setFilter('NOT NULL'), text: 'Is Not Null' },
|
|
||||||
|
|
||||||
{ divider: true },
|
|
||||||
|
|
||||||
{ onClick: () => openFilterWindow('>'), text: 'Greater Than...' },
|
|
||||||
{ onClick: () => openFilterWindow('>='), text: 'Greater Than Or Equal To...' },
|
|
||||||
{ onClick: () => openFilterWindow('<'), text: 'Less Than...' },
|
|
||||||
{ onClick: () => openFilterWindow('<='), text: 'Less Than Or Equal To...' },
|
|
||||||
|
|
||||||
{ divider: true },
|
|
||||||
|
|
||||||
{ onClick: () => openFilterWindow('+'), text: 'Contains...' },
|
|
||||||
{ onClick: () => openFilterWindow('~'), text: 'Does Not Contain...' },
|
|
||||||
{ onClick: () => openFilterWindow('^'), text: 'Begins With...' },
|
|
||||||
{ onClick: () => openFilterWindow('!^'), text: 'Does Not Begin With...' },
|
|
||||||
{ onClick: () => openFilterWindow('$'), text: 'Ends With...' },
|
|
||||||
{ onClick: () => openFilterWindow('!$'), text: 'Does Not End With...' },
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return [
|
if (filterBehaviour.supportExistsTesting) {
|
||||||
// { text: 'Clear filter', onClick: () => (value = '') },
|
res.push(
|
||||||
// { text: 'Is Null', onClick: () => (value = 'NULL') },
|
{ onClick: () => setFilter('EXISTS'), text: 'Field exists' },
|
||||||
// { text: 'Is Not Null', onClick: () => (value = 'NOT NULL') },
|
{ onClick: () => setFilter('NOT EXISTS'), text: 'Field does not exist' }
|
||||||
// ];
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportArrayTesting) {
|
||||||
|
res.push(
|
||||||
|
{ onClick: () => setFilter('NOT EMPTY ARRAY'), text: 'Array is not empty' },
|
||||||
|
{ onClick: () => setFilter('EMPTY ARRAY'), text: 'Array is empty' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportNullTesting) {
|
||||||
|
res.push(
|
||||||
|
{ onClick: () => setFilter('NULL'), text: 'Is Null' },
|
||||||
|
{ onClick: () => setFilter('NOT NULL'), text: 'Is Not Null' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportNumberLikeComparison) {
|
||||||
|
res.push(
|
||||||
|
{ onClick: () => openFilterWindow('>'), text: 'Greater Than...' },
|
||||||
|
{ onClick: () => openFilterWindow('>='), text: 'Greater Than Or Equal To...' },
|
||||||
|
{ onClick: () => openFilterWindow('<'), text: 'Less Than...' },
|
||||||
|
{ onClick: () => openFilterWindow('<='), text: 'Less Than Or Equal To...' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportStringInclusion) {
|
||||||
|
res.push(
|
||||||
|
{ divider: true },
|
||||||
|
|
||||||
|
{ onClick: () => openFilterWindow('+'), text: 'Contains...' },
|
||||||
|
{ onClick: () => openFilterWindow('~'), text: 'Does Not Contain...' },
|
||||||
|
{ onClick: () => openFilterWindow('^'), text: 'Begins With...' },
|
||||||
|
{ onClick: () => openFilterWindow('!^'), text: 'Does Not Begin With...' },
|
||||||
|
{ onClick: () => openFilterWindow('$'), text: 'Ends With...' },
|
||||||
|
{ onClick: () => openFilterWindow('!$'), text: 'Does Not End With...' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportBooleanValues) {
|
||||||
|
res.push(
|
||||||
|
{ onClick: () => setFilter('TRUE'), text: 'Is True' },
|
||||||
|
{ onClick: () => setFilter('FALSE'), text: 'Is False' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportBooleanValues && filterBehaviour.supportNullTesting) {
|
||||||
|
res.push(
|
||||||
|
{ onClick: () => setFilter('TRUE, NULL'), text: 'Is True or NULL' },
|
||||||
|
{ onClick: () => setFilter('FALSE, NULL'), text: 'Is False or NULL' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportDatetimeSymbols) {
|
||||||
|
res.push(
|
||||||
|
{ divider: true },
|
||||||
|
|
||||||
|
{ onClick: () => setFilter('TOMORROW'), text: 'Tomorrow' },
|
||||||
|
{ onClick: () => setFilter('TODAY'), text: 'Today' },
|
||||||
|
{ onClick: () => setFilter('YESTERDAY'), text: 'Yesterday' },
|
||||||
|
|
||||||
|
{ divider: true },
|
||||||
|
|
||||||
|
{ onClick: () => setFilter('NEXT WEEK'), text: 'Next Week' },
|
||||||
|
{ onClick: () => setFilter('THIS WEEK'), text: 'This Week' },
|
||||||
|
{ onClick: () => setFilter('LAST WEEK'), text: 'Last Week' },
|
||||||
|
|
||||||
|
{ divider: true },
|
||||||
|
|
||||||
|
{ onClick: () => setFilter('NEXT MONTH'), text: 'Next Month' },
|
||||||
|
{ onClick: () => setFilter('THIS MONTH'), text: 'This Month' },
|
||||||
|
{ onClick: () => setFilter('LAST MONTH'), text: 'Last Month' },
|
||||||
|
|
||||||
|
{ divider: true },
|
||||||
|
|
||||||
|
{ onClick: () => setFilter('NEXT YEAR'), text: 'Next Year' },
|
||||||
|
{ onClick: () => setFilter('THIS YEAR'), text: 'This Year' },
|
||||||
|
{ onClick: () => setFilter('LAST YEAR'), text: 'Last Year' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportDatetimeComparison) {
|
||||||
|
res.push(
|
||||||
|
{ divider: true },
|
||||||
|
{ onClick: () => openFilterWindow('<='), text: 'Before...' },
|
||||||
|
{ onClick: () => openFilterWindow('>='), text: 'After...' },
|
||||||
|
{ onClick: () => openFilterWindow('>=;<='), text: 'Between...' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportSqlCondition) {
|
||||||
|
res.push(
|
||||||
|
{ divider: true },
|
||||||
|
{ onClick: () => openFilterWindow('sql'), text: 'SQL condition ...' },
|
||||||
|
{ onClick: () => openFilterWindow('sqlRight'), text: 'SQL condition - right side ...' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleKeyDown = ev => {
|
const handleKeyDown = ev => {
|
||||||
@@ -291,7 +245,7 @@
|
|||||||
isOk = false;
|
isOk = false;
|
||||||
isError = false;
|
isError = false;
|
||||||
if (value) {
|
if (value) {
|
||||||
parseFilter(value, filterType);
|
parseFilter(value, filterBehaviour);
|
||||||
isOk = true;
|
isOk = true;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -78,7 +78,6 @@
|
|||||||
export let display;
|
export let display;
|
||||||
export let changeSetState;
|
export let changeSetState;
|
||||||
export let dispatchChangeSet;
|
export let dispatchChangeSet;
|
||||||
export let useEvalFilters = false;
|
|
||||||
|
|
||||||
export let isDetailView = false;
|
export let isDetailView = false;
|
||||||
export let showReferences = false;
|
export let showReferences = false;
|
||||||
@@ -184,7 +183,6 @@
|
|||||||
{...$$props}
|
{...$$props}
|
||||||
{managerSize}
|
{managerSize}
|
||||||
{isDynamicStructure}
|
{isDynamicStructure}
|
||||||
{useEvalFilters}
|
|
||||||
{isFormView}
|
{isFormView}
|
||||||
{hasMultiColumnFilter}
|
{hasMultiColumnFilter}
|
||||||
driver={display?.driver}
|
driver={display?.driver}
|
||||||
|
|||||||
@@ -343,13 +343,13 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { GridDisplay } from 'dbgate-datalib';
|
import { GridDisplay } from 'dbgate-datalib';
|
||||||
import { driverBase, parseCellValue } from 'dbgate-tools';
|
import { driverBase, parseCellValue, detectSqlFilterBehaviour } from 'dbgate-tools';
|
||||||
import { getContext, onDestroy } from 'svelte';
|
import { getContext, onDestroy } from 'svelte';
|
||||||
import _, { map } from 'lodash';
|
import _, { map } from 'lodash';
|
||||||
import registerCommand from '../commands/registerCommand';
|
import registerCommand from '../commands/registerCommand';
|
||||||
import ColumnHeaderControl from './ColumnHeaderControl.svelte';
|
import ColumnHeaderControl from './ColumnHeaderControl.svelte';
|
||||||
import DataGridRow from './DataGridRow.svelte';
|
import DataGridRow from './DataGridRow.svelte';
|
||||||
import { getFilterType, getFilterValueExpression } from 'dbgate-filterparser';
|
import { getFilterValueExpression } from 'dbgate-filterparser';
|
||||||
import stableStringify from 'json-stable-stringify';
|
import stableStringify from 'json-stable-stringify';
|
||||||
import contextMenu, { getContextMenu, registerMenu } from '../utility/contextMenu';
|
import contextMenu, { getContextMenu, registerMenu } from '../utility/contextMenu';
|
||||||
import { tick } from 'svelte';
|
import { tick } from 'svelte';
|
||||||
@@ -435,7 +435,6 @@
|
|||||||
export let tabControlHiddenTab = false;
|
export let tabControlHiddenTab = false;
|
||||||
export let onCustomGridRefresh = null;
|
export let onCustomGridRefresh = null;
|
||||||
export let onOpenQuery = null;
|
export let onOpenQuery = null;
|
||||||
export let useEvalFilters = false;
|
|
||||||
export let jslid;
|
export let jslid;
|
||||||
// export let generalAllowSave = false;
|
// export let generalAllowSave = false;
|
||||||
|
|
||||||
@@ -1901,7 +1900,9 @@
|
|||||||
{jslid}
|
{jslid}
|
||||||
{formatterFunction}
|
{formatterFunction}
|
||||||
driver={display?.driver}
|
driver={display?.driver}
|
||||||
filterType={useEvalFilters ? 'eval' : col.filterType || getFilterType(col.dataType)}
|
filterBehaviour={display?.filterBehaviourOverride ??
|
||||||
|
col.filterBehaviour ??
|
||||||
|
detectSqlFilterBehaviour(col.dataType)}
|
||||||
filter={display.getFilter(col.uniqueName)}
|
filter={display.getFilter(col.uniqueName)}
|
||||||
setFilter={value => display.setFilter(col.uniqueName, value)}
|
setFilter={value => display.setFilter(col.uniqueName, value)}
|
||||||
showResizeSplitter
|
showResizeSplitter
|
||||||
|
|||||||
@@ -87,7 +87,6 @@
|
|||||||
formViewComponent={JslFormView}
|
formViewComponent={JslFormView}
|
||||||
setLoadedRows={handleSetLoadedRows}
|
setLoadedRows={handleSetLoadedRows}
|
||||||
isDynamicStructure={!!infoUsed?.__isDynamicStructure}
|
isDynamicStructure={!!infoUsed?.__isDynamicStructure}
|
||||||
useEvalFilters
|
|
||||||
showMacros={!!dispatchChangeSet}
|
showMacros={!!dispatchChangeSet}
|
||||||
expandMacros={!!dispatchChangeSet}
|
expandMacros={!!dispatchChangeSet}
|
||||||
onRunMacro={handleRunMacro}
|
onRunMacro={handleRunMacro}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
referenceIsConnecting,
|
referenceIsConnecting,
|
||||||
mergeSelectsFromDesigner,
|
mergeSelectsFromDesigner,
|
||||||
findQuerySource,
|
findQuerySource,
|
||||||
findDesignerFilterType,
|
findDesignerFilterBehaviour,
|
||||||
} from './designerTools';
|
} from './designerTools';
|
||||||
import { parseFilter } from 'dbgate-filterparser';
|
import { parseFilter } from 'dbgate-filterparser';
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ export class DesignerQueryDumper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const condition = parseFilter(column[filterField], findDesignerFilterType(column, this.designer));
|
const condition = parseFilter(column[filterField], findDesignerFilterBehaviour(column, this.designer));
|
||||||
if (condition) {
|
if (condition) {
|
||||||
conditions.push(
|
conditions.push(
|
||||||
_.cloneDeepWith(condition, expr => {
|
_.cloneDeepWith(condition, expr => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { presetDarkPalettes, presetPalettes } from '@ant-design/colors';
|
import { presetDarkPalettes, presetPalettes } from '@ant-design/colors';
|
||||||
import { filterName } from 'dbgate-tools';
|
import { filterName, stringFilterBehaviour } from 'dbgate-tools';
|
||||||
|
|
||||||
import { tick } from 'svelte';
|
import { tick } from 'svelte';
|
||||||
import { createDatabaseObjectMenu } from '../appobj/DatabaseObjectAppObject.svelte';
|
import { createDatabaseObjectMenu } from '../appobj/DatabaseObjectAppObject.svelte';
|
||||||
@@ -303,7 +303,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{#if settings?.getMutliColumnFilter && settings?.setMutliColumnFilter}
|
{#if settings?.getMutliColumnFilter && settings?.setMutliColumnFilter}
|
||||||
<DataFilterControl
|
<DataFilterControl
|
||||||
filterType="string"
|
filterBehaviour={stringFilterBehaviour}
|
||||||
filter={settings?.getMutliColumnFilter(designerId)}
|
filter={settings?.getMutliColumnFilter(designerId)}
|
||||||
setFilter={value => settings?.setMutliColumnFilter(designerId, value)}
|
setFilter={value => settings?.setMutliColumnFilter(designerId, value)}
|
||||||
placeholder="Data filter"
|
placeholder="Data filter"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import type { EngineDriver } from 'dbgate-types';
|
|||||||
import type { DesignerInfo, DesignerTableInfo, DesignerReferenceInfo, DesignerJoinType } from './types';
|
import type { DesignerInfo, DesignerTableInfo, DesignerReferenceInfo, DesignerJoinType } from './types';
|
||||||
import { DesignerComponentCreator } from './DesignerComponentCreator';
|
import { DesignerComponentCreator } from './DesignerComponentCreator';
|
||||||
import { DesignerQueryDumper } from './DesignerQueryDumper';
|
import { DesignerQueryDumper } from './DesignerQueryDumper';
|
||||||
import { getFilterType } from 'dbgate-filterparser';
|
import { detectSqlFilterBehaviour } from 'dbgate-tools';
|
||||||
|
|
||||||
export function referenceIsConnecting(
|
export function referenceIsConnecting(
|
||||||
reference: DesignerReferenceInfo,
|
reference: DesignerReferenceInfo,
|
||||||
@@ -133,13 +133,13 @@ export function isConnectedByReference(
|
|||||||
return array1 == array2;
|
return array1 == array2;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findDesignerFilterType({ designerId, columnName }, designer) {
|
export function findDesignerFilterBehaviour({ designerId, columnName }, designer) {
|
||||||
const table = (designer.tables || []).find(x => x.designerId == designerId);
|
const table = (designer.tables || []).find(x => x.designerId == designerId);
|
||||||
if (table) {
|
if (table) {
|
||||||
const column = (table.columns || []).find(x => x.columnName == columnName);
|
const column = (table.columns || []).find(x => x.columnName == columnName);
|
||||||
if (column) {
|
if (column) {
|
||||||
const { dataType } = column;
|
const { dataType } = column;
|
||||||
return getFilterType(dataType);
|
return detectSqlFilterBehaviour(dataType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 'string';
|
return 'string';
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DataFilterControl from '../datagrid/DataFilterControl.svelte';
|
import DataFilterControl from '../datagrid/DataFilterControl.svelte';
|
||||||
import { findDesignerFilterType } from '../designer/designerTools';
|
import { findDesignerFilterBehaviour } from '../designer/designerTools';
|
||||||
import CheckboxField from '../forms/CheckboxField.svelte';
|
import CheckboxField from '../forms/CheckboxField.svelte';
|
||||||
import SelectField from '../forms/SelectField.svelte';
|
import SelectField from '../forms/SelectField.svelte';
|
||||||
import TextField from '../forms/TextField.svelte';
|
import TextField from '../forms/TextField.svelte';
|
||||||
@@ -238,7 +238,7 @@
|
|||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<svelte:fragment slot="5" let:row let:filterField>
|
<svelte:fragment slot="5" let:row let:filterField>
|
||||||
<DataFilterControl
|
<DataFilterControl
|
||||||
filterType={findDesignerFilterType(row, value)}
|
filterBehaviour={findDesignerFilterBehaviour(row, value)}
|
||||||
filter={row[filterField]}
|
filter={row[filterField]}
|
||||||
setFilter={filter => {
|
setFilter={filter => {
|
||||||
changeColumn({ ...row, [filterField]: filter });
|
changeColumn({ ...row, [filterField]: filter });
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getFilterType } from 'dbgate-filterparser';
|
import { detectSqlFilterBehaviour, standardFilterBehaviours, mongoFilterBehaviour } from 'dbgate-tools';
|
||||||
|
|
||||||
import DataFilterControl from '../datagrid/DataFilterControl.svelte';
|
import DataFilterControl from '../datagrid/DataFilterControl.svelte';
|
||||||
|
|
||||||
@@ -17,22 +17,20 @@
|
|||||||
export let schemaName;
|
export let schemaName;
|
||||||
export let pureName;
|
export let pureName;
|
||||||
|
|
||||||
export let useEvalFilters;
|
|
||||||
export let isDynamicStructure;
|
export let isDynamicStructure;
|
||||||
export let isFormView;
|
export let isFormView;
|
||||||
|
|
||||||
$: column = isFormView
|
$: column = isFormView ? display.formColumns?.find(x => x.uniqueName == uniqueName) : display?.findColumn(uniqueName);
|
||||||
? display.formColumns?.find(x => x.uniqueName == uniqueName)
|
|
||||||
: display?.findColumn(uniqueName);
|
|
||||||
|
|
||||||
function computeFilterType(column, isDynamicStructure, useEvalFilters) {
|
function computeFilterBehavoir(column, display, isDynamicStructure) {
|
||||||
if (useEvalFilters) return 'eval';
|
if (display?.filterBehaviourOverride) {
|
||||||
if (isDynamicStructure) return 'mongo';
|
return display?.filterBehaviourOverride;
|
||||||
|
|
||||||
if (column) {
|
|
||||||
return column.filterType || getFilterType(column.dataType);
|
|
||||||
}
|
}
|
||||||
return 'string';
|
const fromDriver = display?.driver?.getFilterBehaviour(column.dataType, standardFilterBehaviours);
|
||||||
|
if (fromDriver) return fromDriver;
|
||||||
|
if (isDynamicStructure) return mongoFilterBehaviour;
|
||||||
|
|
||||||
|
return detectSqlFilterBehaviour(column.dataType);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -51,7 +49,7 @@
|
|||||||
</InlineButton>
|
</InlineButton>
|
||||||
</div>
|
</div>
|
||||||
<DataFilterControl
|
<DataFilterControl
|
||||||
filterType={computeFilterType(column, isDynamicStructure, useEvalFilters)}
|
filterBehaviour={computeFilterBehavoir(column, display, isDynamicStructure)}
|
||||||
filter={filters[uniqueName]}
|
filter={filters[uniqueName]}
|
||||||
setFilter={value => display.setFilter(uniqueName, value)}
|
setFilter={value => display.setFilter(uniqueName, value)}
|
||||||
{driver}
|
{driver}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
import FontIcon from '../icons/FontIcon.svelte';
|
import FontIcon from '../icons/FontIcon.svelte';
|
||||||
import keycodes from '../utility/keycodes';
|
import keycodes from '../utility/keycodes';
|
||||||
import FormViewFilterColumn from './FormViewFilterColumn.svelte';
|
import FormViewFilterColumn from './FormViewFilterColumn.svelte';
|
||||||
|
import { stringFilterBehaviour } from 'dbgate-tools';
|
||||||
// import PrimaryKeyFilterEditor from './PrimaryKeyFilterEditor.svelte';
|
// import PrimaryKeyFilterEditor from './PrimaryKeyFilterEditor.svelte';
|
||||||
|
|
||||||
export let managerSize;
|
export let managerSize;
|
||||||
@@ -20,7 +21,6 @@
|
|||||||
export let pureName;
|
export let pureName;
|
||||||
|
|
||||||
export let isDynamicStructure;
|
export let isDynamicStructure;
|
||||||
export let useEvalFilters;
|
|
||||||
export let isFormView;
|
export let isFormView;
|
||||||
|
|
||||||
export let hasMultiColumnFilter;
|
export let hasMultiColumnFilter;
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DataFilterControl
|
<DataFilterControl
|
||||||
filterType="string"
|
filterBehaviour={stringFilterBehaviour}
|
||||||
filter={multiColumnFilter}
|
filter={multiColumnFilter}
|
||||||
setFilter={value => display.setMutliColumnFilter(value)}
|
setFilter={value => display.setMutliColumnFilter(value)}
|
||||||
{driver}
|
{driver}
|
||||||
@@ -93,7 +93,6 @@
|
|||||||
{#each allFilterNames as uniqueName}
|
{#each allFilterNames as uniqueName}
|
||||||
<FormViewFilterColumn
|
<FormViewFilterColumn
|
||||||
{isDynamicStructure}
|
{isDynamicStructure}
|
||||||
{useEvalFilters}
|
|
||||||
{isFormView}
|
{isFormView}
|
||||||
{uniqueName}
|
{uniqueName}
|
||||||
{display}
|
{display}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
export let condition1;
|
export let condition1;
|
||||||
export let onFilter;
|
export let onFilter;
|
||||||
export let filterType;
|
export let filterBehaviour;
|
||||||
|
|
||||||
const hasOperand = condition => {
|
const hasOperand = condition => {
|
||||||
return condition != 'NULL' && condition != 'NOT NULL' && condition != 'EXISTS' && condition != 'NOT EXISTS';
|
return condition != 'NULL' && condition != 'NOT NULL' && condition != 'EXISTS' && condition != 'NOT EXISTS';
|
||||||
@@ -24,7 +24,9 @@
|
|||||||
if (!value) return null;
|
if (!value) return null;
|
||||||
if (condition == 'sql') return `{${value}}`;
|
if (condition == 'sql') return `{${value}}`;
|
||||||
if (condition == 'sqlRight') return `{$$ ${value}}`;
|
if (condition == 'sqlRight') return `{$$ ${value}}`;
|
||||||
if (filterType == 'string') return `${condition}"${value}"`;
|
if (filterBehaviour.allowStringToken) {
|
||||||
|
return `${condition}"${value}"`;
|
||||||
|
}
|
||||||
return `${condition}${value}`;
|
return `${condition}${value}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -48,7 +50,7 @@
|
|||||||
<div class="row">Show rows where</div>
|
<div class="row">Show rows where</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6 mr-1">
|
<div class="col-6 mr-1">
|
||||||
<SetFilterModal_Select {filterType} name="condition1" />
|
<SetFilterModal_Select {filterBehaviour} name="condition1" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 mr-1">
|
<div class="col-6 mr-1">
|
||||||
<FormValues let:values>
|
<FormValues let:values>
|
||||||
@@ -66,7 +68,7 @@
|
|||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6 mr-1">
|
<div class="col-6 mr-1">
|
||||||
<SetFilterModal_Select {filterType} name="condition2" />
|
<SetFilterModal_Select {filterBehaviour} name="condition2" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 mr-1">
|
<div class="col-6 mr-1">
|
||||||
<FormValues let:values>
|
<FormValues let:values>
|
||||||
|
|||||||
@@ -2,90 +2,59 @@
|
|||||||
import FormSelectFieldRaw from '../forms/FormSelectFieldRaw.svelte';
|
import FormSelectFieldRaw from '../forms/FormSelectFieldRaw.svelte';
|
||||||
|
|
||||||
export let name;
|
export let name;
|
||||||
export let filterType;
|
export let filterBehaviour;
|
||||||
|
|
||||||
function getOptions() {
|
function getOptions() {
|
||||||
switch (filterType) {
|
const res = [];
|
||||||
case 'number':
|
if (filterBehaviour.supportEquals) {
|
||||||
return [
|
res.push({ value: '=', label: 'equals' }, { value: '<>', label: 'does not equal' });
|
||||||
{ value: '=', label: 'equals' },
|
|
||||||
{ value: '<>', label: 'does not equal' },
|
|
||||||
{ value: '<', label: 'is smaller' },
|
|
||||||
{ value: '>', label: 'is greater' },
|
|
||||||
{ value: '<=', label: 'is smaller or equal' },
|
|
||||||
{ value: '>=', label: 'is greater or equal' },
|
|
||||||
{ value: 'NULL', label: 'is NULL' },
|
|
||||||
{ value: 'NOT NULL', label: 'is not NULL' },
|
|
||||||
{ value: 'sql', label: 'SQL condition' },
|
|
||||||
{ value: 'sqlRight', label: 'SQL condition - right side only' },
|
|
||||||
];
|
|
||||||
case 'string':
|
|
||||||
return [
|
|
||||||
{ value: '+', label: 'contains' },
|
|
||||||
{ value: '~', label: 'does not contain' },
|
|
||||||
{ value: '^', label: 'begins with' },
|
|
||||||
{ value: '!^', label: 'does not begin with' },
|
|
||||||
{ value: '$', label: 'ends with' },
|
|
||||||
{ value: '!$', label: 'does not end with' },
|
|
||||||
{ value: '=', label: 'equals' },
|
|
||||||
{ value: '<>', label: 'does not equal' },
|
|
||||||
{ value: '<', label: 'is smaller' },
|
|
||||||
{ value: '>', label: 'is greater' },
|
|
||||||
{ value: '<=', label: 'is smaller or equal' },
|
|
||||||
{ value: '>=', label: 'is greater or equal' },
|
|
||||||
{ value: 'NULL', label: 'is NULL' },
|
|
||||||
{ value: 'NOT NULL', label: 'is not NULL' },
|
|
||||||
{ value: 'sql', label: 'SQL condition' },
|
|
||||||
{ value: 'sqlRight', label: 'SQL condition - right side only' },
|
|
||||||
];
|
|
||||||
case 'datetime':
|
|
||||||
return [
|
|
||||||
{ value: '=', label: 'equals' },
|
|
||||||
{ value: '<>', label: 'does not equal' },
|
|
||||||
{ value: '<', label: 'is before' },
|
|
||||||
{ value: '>', label: 'is after' },
|
|
||||||
{ value: '<=', label: 'is before or equal' },
|
|
||||||
{ value: '>=', label: 'is after or equal' },
|
|
||||||
{ value: 'NULL', label: 'is NULL' },
|
|
||||||
{ value: 'NOT NULL', label: 'is not NULL' },
|
|
||||||
{ value: 'sql', label: 'SQL condition' },
|
|
||||||
{ value: 'sqlRight', label: 'SQL condition - right side only' },
|
|
||||||
];
|
|
||||||
case 'mongo':
|
|
||||||
return [
|
|
||||||
{ value: '=', label: 'equals' },
|
|
||||||
{ value: '<>', label: 'does not equal' },
|
|
||||||
{ value: '<', label: 'is smaller' },
|
|
||||||
{ value: '>', label: 'is greater' },
|
|
||||||
{ value: '<=', label: 'is smaller or equal' },
|
|
||||||
{ value: '>=', label: 'is greater or equal' },
|
|
||||||
{ value: '+', label: 'contains' },
|
|
||||||
{ value: '~', label: 'does not contain' },
|
|
||||||
{ value: '^', label: 'begins with' },
|
|
||||||
{ value: '!^', label: 'does not begin with' },
|
|
||||||
{ value: '$', label: 'ends with' },
|
|
||||||
{ value: '!$', label: 'does not end with' },
|
|
||||||
{ value: 'EXISTS', label: 'field exists' },
|
|
||||||
{ value: 'NOT EXISTS', label: 'field does not exist' },
|
|
||||||
];
|
|
||||||
case 'eval':
|
|
||||||
return [
|
|
||||||
{ value: '=', label: 'equals' },
|
|
||||||
{ value: '<>', label: 'does not equal' },
|
|
||||||
{ value: '<', label: 'is smaller' },
|
|
||||||
{ value: '>', label: 'is greater' },
|
|
||||||
{ value: '<=', label: 'is smaller or equal' },
|
|
||||||
{ value: '>=', label: 'is greater or equal' },
|
|
||||||
{ value: '+', label: 'contains' },
|
|
||||||
{ value: '~', label: 'does not contain' },
|
|
||||||
{ value: '^', label: 'begins with' },
|
|
||||||
{ value: '!^', label: 'does not begin with' },
|
|
||||||
{ value: '$', label: 'ends with' },
|
|
||||||
{ value: '!$', label: 'does not end with' },
|
|
||||||
{ value: 'NULL', label: 'is NULL' },
|
|
||||||
{ value: 'NOT NULL', label: 'is not NULL' },
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportStringInclusion) {
|
||||||
|
res.push(
|
||||||
|
{ value: '+', label: 'contains' },
|
||||||
|
{ value: '~', label: 'does not contain' },
|
||||||
|
{ value: '^', label: 'begins with' },
|
||||||
|
{ value: '!^', label: 'does not begin with' },
|
||||||
|
{ value: '$', label: 'ends with' },
|
||||||
|
{ value: '!$', label: 'does not end with' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportNumberLikeComparison) {
|
||||||
|
res.push(
|
||||||
|
{ value: '<', label: 'is smaller' },
|
||||||
|
{ value: '>', label: 'is greater' },
|
||||||
|
{ value: '<=', label: 'is smaller or equal' },
|
||||||
|
{ value: '>=', label: 'is greater or equal' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportDatetimeComparison) {
|
||||||
|
res.push(
|
||||||
|
{ value: '<', label: 'is before' },
|
||||||
|
{ value: '>', label: 'is after' },
|
||||||
|
{ value: '<=', label: 'is before or equal' },
|
||||||
|
{ value: '>=', label: 'is after or equal' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportNullTesting) {
|
||||||
|
res.push({ value: 'NULL', label: 'is NULL' }, { value: 'NOT NULL', label: 'is not NULL' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportExistsTesting) {
|
||||||
|
res.push({ value: 'EXISTS', label: 'field exists' }, { value: 'NOT EXISTS', label: 'field does not exist' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterBehaviour.supportSqlCondition) {
|
||||||
|
res.push(
|
||||||
|
{ value: 'sql', label: 'SQL condition' },
|
||||||
|
{ value: 'sqlRight', label: 'SQL condition - right side only' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
</InlineButton>
|
</InlineButton>
|
||||||
</div>
|
</div>
|
||||||
<DataFilterControl
|
<DataFilterControl
|
||||||
filterType={filterInfo.filterType}
|
filterBehaviour={filterInfo.filterBehaviour}
|
||||||
{filter}
|
{filter}
|
||||||
setFilter={onSetFilter}
|
setFilter={onSetFilter}
|
||||||
{conid}
|
{conid}
|
||||||
|
|||||||
@@ -557,7 +557,7 @@
|
|||||||
filter={column.dataNode.getFilter()}
|
filter={column.dataNode.getFilter()}
|
||||||
setFilter={value => column.dataNode.setFilter(value)}
|
setFilter={value => column.dataNode.setFilter(value)}
|
||||||
columnName={column.dataNode.uniqueName}
|
columnName={column.dataNode.uniqueName}
|
||||||
filterType={column.dataNode.filterType}
|
filterBehaviour={column.dataNode.filterBehaviour}
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
{/each}
|
{/each}
|
||||||
|
|||||||
@@ -93,6 +93,10 @@ const driver = {
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getFilterBehaviour(dataType, standardFilterBehaviours) {
|
||||||
|
return standardFilterBehaviours.mongoFilterBehaviour;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = driver;
|
module.exports = driver;
|
||||||
|
|||||||
Reference in New Issue
Block a user