diff --git a/packages/datalib/src/CollectionGridDisplay.ts b/packages/datalib/src/CollectionGridDisplay.ts index 6af931bb5..572341c82 100644 --- a/packages/datalib/src/CollectionGridDisplay.ts +++ b/packages/datalib/src/CollectionGridDisplay.ts @@ -2,6 +2,7 @@ import _ from 'lodash'; import { GridDisplay, ChangeCacheFunc, ChangeConfigFunc, DisplayColumn } from './GridDisplay'; import type { EngineDriver, ViewInfo, ColumnInfo, CollectionInfo } from 'dbgate-types'; import { GridConfig, GridCache } from './GridConfig'; +import { mongoFilterBehaviour, standardFilterBehaviours } from 'dbgate-tools'; function getObjectKeys(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 uniqueName = uniquePath.join('.'); return { @@ -62,7 +63,7 @@ function getDisplayColumn(basePath, columnName, display) { uniquePath, isStructured: true, parentHeaderText: createHeaderText(basePath), - filterType: 'mongo', + filterBehaviour: display?.driver?.getFilterBehaviour(null, standardFilterBehaviours) ?? mongoFilterBehaviour, pureName: display.collection?.pureName, schemaName: display.collection?.schemaName, }; @@ -95,7 +96,7 @@ export class CollectionGridDisplay extends GridDisplay { cache: GridCache, setCache: ChangeCacheFunc, loadedRows, - changeSet, + changeSet, readOnly = false ) { super(config, setConfig, cache, setCache, driver); diff --git a/packages/datalib/src/GridDisplay.ts b/packages/datalib/src/GridDisplay.ts index 84f031af6..5b4d49a7e 100644 --- a/packages/datalib/src/GridDisplay.ts +++ b/packages/datalib/src/GridDisplay.ts @@ -10,12 +10,13 @@ import type { CollectionInfo, SqlDialect, ViewInfo, + FilterBehaviour, } from 'dbgate-types'; -import { parseFilter, getFilterType } from 'dbgate-filterparser'; +import { parseFilter } from 'dbgate-filterparser'; import { filterName } from 'dbgate-tools'; import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet'; 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 { schemaName: string; @@ -33,7 +34,7 @@ export interface DisplayColumn { isChecked?: boolean; hintColumnNames?: string[]; dataType?: string; - filterType?: boolean; + filterBehaviour?: FilterBehaviour; isStructured?: boolean; } @@ -92,7 +93,7 @@ export abstract class GridDisplay { isLoadedCorrectly = true; supportsReload = false; isDynamicStructure = false; - filterTypeOverride = null; + filterBehaviourOverride = null; setColumnVisibility(uniquePath: string[], isVisible: boolean) { const uniqueName = uniquePath.join('.'); @@ -192,7 +193,11 @@ export abstract class GridDisplay { const column = displayedColumnInfo[uniqueName]; if (!column) continue; try { - const condition = parseFilter(filter, getFilterType(column.dataType)); + const condition = parseFilter( + filter, + this.driver?.getFilterBehaviour(column.dataType, standardFilterBehaviours) ?? + detectSqlFilterBehaviour(column.dataType) + ); if (condition) { conditions.push( _.cloneDeepWith(condition, (expr: Expression) => { @@ -220,7 +225,7 @@ export abstract class GridDisplay { }; for (const column of this.baseTableOrView.columns) { try { - const condition = parseFilter(this.config.multiColumnFilter, getFilterType(column.dataType)); + const condition = parseFilter(this.config.multiColumnFilter, detectSqlFilterBehaviour(column.dataType)); if (condition) { orCondition.conditions.push( _.cloneDeepWith(condition, (expr: Expression) => { @@ -748,10 +753,12 @@ export abstract class GridDisplay { for (const name in filters) { const column = this.isDynamicStructure ? null : this.columns.find(x => x.columnName == name); if (!this.isDynamicStructure && !column) continue; - const filterType = - this.filterTypeOverride ?? (this.isDynamicStructure ? 'mongo' : getFilterType(column.dataType)); + const filterBehaviour = + this.filterBehaviourOverride ?? + this.driver?.getFilterBehaviour(column.dataType, standardFilterBehaviours) ?? + detectSqlFilterBehaviour(column.dataType); try { - const condition = parseFilter(filters[name], filterType); + const condition = parseFilter(filters[name], filterBehaviour); const replaced = _.cloneDeepWith(condition, (expr: Expression) => { if (expr.exprType == 'placeholder') return { @@ -766,7 +773,7 @@ export abstract class GridDisplay { } if (this.config.multiColumnFilter) { - const placeholderCondition = parseFilter(this.config.multiColumnFilter, 'string'); + const placeholderCondition = parseFilter(this.config.multiColumnFilter, stringFilterBehaviour); if (placeholderCondition) { conditions.push({ conditionType: 'anyColumnPass', diff --git a/packages/datalib/src/JslGridDisplay.ts b/packages/datalib/src/JslGridDisplay.ts index 030471bea..99149c994 100644 --- a/packages/datalib/src/JslGridDisplay.ts +++ b/packages/datalib/src/JslGridDisplay.ts @@ -2,6 +2,7 @@ import _ from 'lodash'; import { GridDisplay, ChangeCacheFunc, ChangeConfigFunc } from './GridDisplay'; import { GridConfig, GridCache } from './GridConfig'; import { analyseCollectionDisplayColumns } from './CollectionGridDisplay'; +import { evalFilterBehaviour } from 'dbgate-tools'; export class JslGridDisplay extends GridDisplay { constructor( @@ -22,7 +23,7 @@ export class JslGridDisplay extends GridDisplay { this.sortable = true; this.supportsReload = supportsReload; this.isDynamicStructure = isDynamicStructure; - this.filterTypeOverride = 'eval'; + this.filterBehaviourOverride = evalFilterBehaviour; this.editable = editable; this.editableStructure = editable ? structure : null; diff --git a/packages/datalib/src/PerspectiveConfig.ts b/packages/datalib/src/PerspectiveConfig.ts index c8a421a6a..a0646b999 100644 --- a/packages/datalib/src/PerspectiveConfig.ts +++ b/packages/datalib/src/PerspectiveConfig.ts @@ -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'; // export interface PerspectiveConfigColumns { @@ -31,7 +31,7 @@ export interface PerspectiveCustomJoinConfig { export interface PerspectiveFilterColumnInfo { columnName: string; - filterType: string; + filterBehaviour: FilterBehaviour; pureName: string; schemaName: string; foreignKey: ForeignKeyInfo; diff --git a/packages/datalib/src/PerspectiveTreeNode.ts b/packages/datalib/src/PerspectiveTreeNode.ts index 953cd3d7e..5176cafd4 100644 --- a/packages/datalib/src/PerspectiveTreeNode.ts +++ b/packages/datalib/src/PerspectiveTreeNode.ts @@ -2,13 +2,22 @@ import type { CollectionInfo, ColumnInfo, DatabaseInfo, + FilterBehaviour, ForeignKeyInfo, NamedObjectInfo, RangeDefinition, TableInfo, ViewInfo, } from 'dbgate-types'; -import { equalFullName, isCollectionInfo, isTableInfo, isViewInfo } from 'dbgate-tools'; +import { + detectSqlFilterBehaviour, + equalFullName, + isCollectionInfo, + isTableInfo, + isViewInfo, + mongoFilterBehaviour, + stringFilterBehaviour, +} from 'dbgate-tools'; import { ChangePerspectiveConfigFunc, createPerspectiveNodeConfig, @@ -33,8 +42,7 @@ import _cloneDeepWith from 'lodash/cloneDeepWith'; import _findIndex from 'lodash/findIndex'; import { PerspectiveDataLoadProps, PerspectiveDataProvider } from './PerspectiveDataProvider'; import stableStringify from 'json-stable-stringify'; -import { getFilterType, parseFilter } from 'dbgate-filterparser'; -import { FilterType } from 'dbgate-filterparser/lib/types'; +import { parseFilter } from 'dbgate-filterparser'; import { CompoudCondition, Condition, Expression, Select } from 'dbgate-sqltree'; // import { getPerspectiveDefaultColumns } from './getPerspectiveDefaultColumns'; import uuidv1 from 'uuid/v1'; @@ -197,8 +205,8 @@ export abstract class PerspectiveTreeNode { get columnTitle() { return this.title; } - get filterType(): FilterType { - return 'string'; + get filterBehaviour(): FilterBehaviour { + return stringFilterBehaviour; } get columnName() { return null; @@ -346,7 +354,7 @@ export abstract class PerspectiveTreeNode { const base = this.getBaseTableFromThis() as TableInfo | ViewInfo; if (!base) return null; try { - const condition = parseFilter(this.nodeConfig?.multiColumnFilter, 'string'); + const condition = parseFilter(this.nodeConfig?.multiColumnFilter, stringFilterBehaviour); if (condition) { const orCondition: CompoudCondition = { conditionType: 'or', @@ -380,7 +388,7 @@ export abstract class PerspectiveTreeNode { const pattern = this.dataProvider?.dataPatterns?.[this.designerId]; if (!pattern) return null; - const condition = parseFilter(this.nodeConfig?.multiColumnFilter, 'mongo'); + const condition = parseFilter(this.nodeConfig?.multiColumnFilter, mongoFilterBehaviour); if (!condition) return null; const res = pattern.columns.map(col => { return _cloneDeepWith(condition, expr => { @@ -714,8 +722,8 @@ export class PerspectiveTableColumnNode extends PerspectiveTreeNode { return true; } - get filterType(): FilterType { - return getFilterType(this.column.dataType); + get filterBehaviour(): FilterBehaviour { + return detectSqlFilterBehaviour(this.column.dataType); } get isCircular() { @@ -767,7 +775,7 @@ export class PerspectiveTableColumnNode extends PerspectiveTreeNode { get filterInfo(): PerspectiveFilterColumnInfo { return { columnName: this.columnName, - filterType: this.filterType, + filterBehaviour: this.filterBehaviour, pureName: this.column.pureName, schemaName: this.column.schemaName, foreignKey: this.foreignKey, @@ -777,7 +785,7 @@ export class PerspectiveTableColumnNode extends PerspectiveTreeNode { parseFilterCondition(source = null): Condition { const filter = this.getFilter(); if (!filter) return null; - const condition = parseFilter(filter, this.filterType); + const condition = parseFilter(filter, this.filterBehaviour); if (!condition) return null; return _cloneDeepWith(condition, (expr: Expression) => { if (expr.exprType == 'placeholder') { @@ -949,9 +957,9 @@ export class PerspectivePatternColumnNode extends PerspectiveTreeNode { return !this.isChildColumn; } - get filterType(): FilterType { - if (this.tableColumn) return getFilterType(this.tableColumn.dataType); - return 'mongo'; + get filterBehaviour(): FilterBehaviour { + if (this.tableColumn) return detectSqlFilterBehaviour(this.tableColumn.dataType); + return mongoFilterBehaviour; } get preloadedLevelData() { @@ -1083,7 +1091,7 @@ export class PerspectivePatternColumnNode extends PerspectiveTreeNode { return { columnName: this.columnName, - filterType: this.filterType, + filterBehaviour: this.filterBehaviour, pureName: this.table.pureName, schemaName: this.table.schemaName, foreignKey: this.foreignKey, @@ -1093,7 +1101,7 @@ export class PerspectivePatternColumnNode extends PerspectiveTreeNode { parseFilterCondition(source = null): {} { const filter = this.getFilter(); if (!filter) return null; - const condition = parseFilter(filter, 'mongo'); + const condition = parseFilter(filter, mongoFilterBehaviour); if (!condition) return null; return _cloneDeepWith(condition, expr => { if (expr.__placeholder__) { diff --git a/packages/filterparser/src/datetimeParser.ts b/packages/filterparser/src/datetimeParser.ts index d4355122c..06f501340 100644 --- a/packages/filterparser/src/datetimeParser.ts +++ b/packages/filterparser/src/datetimeParser.ts @@ -1,9 +1,7 @@ import P from 'parsimmon'; import moment from 'moment'; -import { FilterType } from './types'; -import { Condition } from 'dbgate-sqltree'; import type { TransformType } from 'dbgate-types'; -import { interpretEscapes, token, word, whitespace } from './common'; +import { token, word, whitespace } from './common'; const compoudCondition = conditionType => conditions => { if (conditions.length == 1) return conditions[0]; diff --git a/packages/filterparser/src/getFilterType.ts b/packages/filterparser/src/getFilterType.ts deleted file mode 100644 index 7a1ce75fb..000000000 --- a/packages/filterparser/src/getFilterType.ts +++ /dev/null @@ -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'; -} diff --git a/packages/filterparser/src/index.ts b/packages/filterparser/src/index.ts index 77f9df246..6c894f8c5 100644 --- a/packages/filterparser/src/index.ts +++ b/packages/filterparser/src/index.ts @@ -1,3 +1,2 @@ export * from './parseFilter'; -export * from './getFilterType'; export * from './filterTool'; diff --git a/packages/filterparser/src/parseFilter.ts b/packages/filterparser/src/parseFilter.ts index 8a3755b4b..9850462ce 100644 --- a/packages/filterparser/src/parseFilter.ts +++ b/packages/filterparser/src/parseFilter.ts @@ -1,11 +1,10 @@ import P from 'parsimmon'; -import moment from 'moment'; -import { FilterType } from './types'; import { Condition } from 'dbgate-sqltree'; import { interpretEscapes, token, word, whitespace } from './common'; import { mongoParser } from './mongoParser'; import { datetimeParser } from './datetimeParser'; import { hexStringToArray } from 'dbgate-tools'; +import { FilterBehaviour } from 'dbgate-types'; const binaryCondition = operator => value => ({ conditionType: 'binary', @@ -78,7 +77,7 @@ const sqlTemplate = templateSql => { }; }; -const createParser = (filterType: FilterType) => { +const createParser = (filterBehaviour: FilterBehaviour) => { const langDef = { string1: () => token(P.regexp(/"((?:\\.|.)*?)"/, 1)) @@ -156,32 +155,52 @@ const createParser = (filterType: FilterType) => { }; const allowedValues = []; // 'string1', 'string2', 'number', 'noQuotedString']; - if (filterType == 'string' || filterType == 'eval') { + if (filterBehaviour.allowStringToken) { allowedValues.push('string1', 'string2', 'noQuotedString'); } - if (filterType == 'number') { + if (filterBehaviour.allowNumberToken) { allowedValues.push('string1Num', 'string2Num', 'number'); } - const allowedElements = ['null', 'notNull', 'eq', 'ne', 'ne2', 'sql']; - if (filterType == 'number' || filterType == 'datetime' || filterType == 'eval') { + const allowedElements = []; + + 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'); } - 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'); } - if (filterType == 'logical') { - allowedElements.push('true', 'false', 'trueNum', 'falseNum'); - } - if (filterType == 'eval') { - allowedElements.push('true', 'false'); + if (filterBehaviour.supportBooleanValues) { + if (filterBehaviour.allowNumberToken || filterBehaviour.allowStringToken) { + allowedElements.push('true', 'false'); + } else { + allowedElements.push('true', 'false', 'trueNum', 'falseNum'); + } } // must be last - if (filterType == 'string' || filterType == 'eval') { + if (filterBehaviour.allowStringToken) { allowedElements.push('valueTestStr'); } else { allowedElements.push('valueTestEq'); @@ -190,18 +209,27 @@ const createParser = (filterType: FilterType) => { return P.createLanguage(langDef); }; -const parsers = { - number: createParser('number'), - string: createParser('string'), - logical: createParser('logical'), - eval: createParser('eval'), - mongo: mongoParser, - datetime: datetimeParser, -}; +const cachedFilters: { [key: string]: P.Language } = {}; -export function parseFilter(value: string, filterType: FilterType): Condition { - // console.log('PARSING', value, 'WITH', filterType); - const ast = parsers[filterType].list.tryParse(value); +function getParser(filterBehaviour: FilterBehaviour) { + if (filterBehaviour.compilerType == 'mongoCondition') { + 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); return ast; } diff --git a/packages/filterparser/src/parserFilter.test.ts b/packages/filterparser/src/parserFilter.test.ts index 56e7a78b8..d1df53484 100644 --- a/packages/filterparser/src/parserFilter.test.ts +++ b/packages/filterparser/src/parserFilter.test.ts @@ -1,7 +1,8 @@ const { parseFilter } = require('./parseFilter'); +const { stringFilterBehaviour } = require('dbgate-tools'); test('parse string', () => { - const ast = parseFilter('"123"', 'string'); + const ast = parseFilter('"123"', stringFilterBehaviour); console.log(JSON.stringify(ast)); expect(ast).toEqual({ conditionType: 'like', diff --git a/packages/filterparser/src/types.ts b/packages/filterparser/src/types.ts deleted file mode 100644 index 367e07d90..000000000 --- a/packages/filterparser/src/types.ts +++ /dev/null @@ -1,3 +0,0 @@ -// import types from 'dbgate-types'; - -export type FilterType = 'number' | 'string' | 'datetime' | 'logical' | 'eval' | 'mongo'; diff --git a/packages/tools/src/detectSqlFilterBehaviour.ts b/packages/tools/src/detectSqlFilterBehaviour.ts new file mode 100644 index 000000000..a219cf34a --- /dev/null +++ b/packages/tools/src/detectSqlFilterBehaviour.ts @@ -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; +} diff --git a/packages/tools/src/driverBase.ts b/packages/tools/src/driverBase.ts index e3ea86f91..1517269c6 100644 --- a/packages/tools/src/driverBase.ts +++ b/packages/tools/src/driverBase.ts @@ -3,6 +3,7 @@ import { SqlDumper } from './SqlDumper'; import { splitQuery } from 'dbgate-query-splitter'; import { dumpSqlSelect } from 'dbgate-sqltree'; import { EngineDriver, QueryResult, RunScriptOptions } from 'dbgate-types'; +import { detectSqlFilterBehaviour } from './detectSqlFilterBehaviour'; const dialect = { limitSelect: true, @@ -150,4 +151,7 @@ export const driverBase = { showConnectionField: (field, values) => false, showConnectionTab: field => true, getAccessTokenFromAuth: async (connection, req) => null, + getFilterBehaviour(dataType: string, standardFilterBehaviours) { + return detectSqlFilterBehaviour(dataType); + }, }; diff --git a/packages/tools/src/filterBehaviours.ts b/packages/tools/src/filterBehaviours.ts new file mode 100644 index 000000000..1a1e07100 --- /dev/null +++ b/packages/tools/src/filterBehaviours.ts @@ -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, +}; diff --git a/packages/tools/src/index.ts b/packages/tools/src/index.ts index 69e972cac..900f7aebe 100644 --- a/packages/tools/src/index.ts +++ b/packages/tools/src/index.ts @@ -21,3 +21,5 @@ export * from './preloadedRowsTools'; export * from './ScriptWriter'; export * from './getLogger'; export * from './getConnectionLabel'; +export * from './detectSqlFilterBehaviour'; +export * from './filterBehaviours'; diff --git a/packages/types/engines.d.ts b/packages/types/engines.d.ts index b2f3afea6..5523cea3f 100644 --- a/packages/types/engines.d.ts +++ b/packages/types/engines.d.ts @@ -3,6 +3,7 @@ import { QueryResult } from './query'; import { SqlDialect } from './dialect'; import { SqlDumper } from './dumper'; import { DatabaseInfo, NamedObjectInfo, TableInfo, ViewInfo, ProcedureInfo, FunctionInfo, TriggerInfo } from './dbinfo'; +import { FilterBehaviour } from './filter-type'; export interface StreamOptions { recordset: (columns) => void; @@ -71,7 +72,11 @@ export interface ServerSummary { databases: ServerSummaryDatabase[]; } -export interface EngineDriver { +export interface FilterBehaviourProvider { + getFilterBehaviour(dataType: string, standardFilterBehaviours: { [id: string]: FilterBehaviour }): FilterBehaviour; +} + +export interface EngineDriver extends FilterBehaviourProvider { engine: string; title: string; defaultPort?: number; diff --git a/packages/types/filter-type.d.ts b/packages/types/filter-type.d.ts new file mode 100644 index 000000000..2fa506479 --- /dev/null +++ b/packages/types/filter-type.d.ts @@ -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; +} diff --git a/packages/types/index.d.ts b/packages/types/index.d.ts index 9de4b755f..916af27a2 100644 --- a/packages/types/index.d.ts +++ b/packages/types/index.d.ts @@ -47,3 +47,4 @@ export * from './dbtypes'; export * from './extensions'; export * from './alter-processor'; export * from './appdefs'; +export * from './filter-type'; diff --git a/packages/web/src/datagrid/CollectionDataGridCore.svelte b/packages/web/src/datagrid/CollectionDataGridCore.svelte index 2062fede8..d5da3b59a 100644 --- a/packages/web/src/datagrid/CollectionDataGridCore.svelte +++ b/packages/web/src/datagrid/CollectionDataGridCore.svelte @@ -26,7 +26,7 @@ for (const uniqueName in filters || {}) { if (!filters[uniqueName]) continue; try { - const ast = parseFilter(filters[uniqueName], 'mongo'); + const ast = parseFilter(filters[uniqueName], mongoFilterBehaviour); // console.log('AST', ast); const cond = _.cloneDeepWith(ast, expr => { if (expr.__placeholder__) { @@ -123,6 +123,7 @@ import ChangeSetGrider from './ChangeSetGrider'; import LoadingDataGridCore from './LoadingDataGridCore.svelte'; + import { mongoFilterBehaviour } from 'dbgate-tools'; export let conid; export let display; diff --git a/packages/web/src/datagrid/DataFilterControl.svelte b/packages/web/src/datagrid/DataFilterControl.svelte index 540d4dd91..0e71504e0 100644 --- a/packages/web/src/datagrid/DataFilterControl.svelte +++ b/packages/web/src/datagrid/DataFilterControl.svelte @@ -19,7 +19,7 @@ import ValueLookupModal from '../modals/ValueLookupModal.svelte'; export let isReadOnly = false; - export let filterType; + export let filterBehaviour; export let filter; export let setFilter; export let showResizeSplitter = false; @@ -50,7 +50,7 @@ $: if (onGetReference && domInput) onGetReference(domInput); function openFilterWindow(condition1) { - showModal(SetFilterModal, { condition1, filterType, onFilter: setFilter }); + showModal(SetFilterModal, { condition1, filterBehaviour, onFilter: setFilter }); } const filterMultipleValues = () => { @@ -60,167 +60,121 @@ }; function createMenu() { - switch (filterType) { - case 'number': - 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: () => 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...' }, + const res = [ + { onClick: () => setFilter(''), text: 'Clear Filter' }, + { onClick: () => filterMultipleValues(), text: 'Filter multiple values' }, + ]; - { divider: true }, - - { onClick: () => openFilterWindow('sql'), text: 'SQL condition ...' }, - { onClick: () => openFilterWindow('sqlRight'), text: 'SQL condition - right side ...' }, - ]; - 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...' }, - ]; + if (filterBehaviour.supportEquals) { + res.push( + { onClick: () => openFilterWindow('='), text: 'Equals...' }, + { onClick: () => openFilterWindow('<>'), text: 'Does Not Equal...' } + ); } - // return [ - // { text: 'Clear filter', onClick: () => (value = '') }, - // { text: 'Is Null', onClick: () => (value = 'NULL') }, - // { text: 'Is Not Null', onClick: () => (value = 'NOT NULL') }, - // ]; + if (filterBehaviour.supportExistsTesting) { + res.push( + { onClick: () => setFilter('EXISTS'), text: 'Field exists' }, + { 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 => { @@ -291,7 +245,7 @@ isOk = false; isError = false; if (value) { - parseFilter(value, filterType); + parseFilter(value, filterBehaviour); isOk = true; } } catch (err) { diff --git a/packages/web/src/datagrid/DataGrid.svelte b/packages/web/src/datagrid/DataGrid.svelte index d3a0d04a0..66e96ff89 100644 --- a/packages/web/src/datagrid/DataGrid.svelte +++ b/packages/web/src/datagrid/DataGrid.svelte @@ -78,7 +78,6 @@ export let display; export let changeSetState; export let dispatchChangeSet; - export let useEvalFilters = false; export let isDetailView = false; export let showReferences = false; @@ -184,7 +183,6 @@ {...$$props} {managerSize} {isDynamicStructure} - {useEvalFilters} {isFormView} {hasMultiColumnFilter} driver={display?.driver} diff --git a/packages/web/src/datagrid/DataGridCore.svelte b/packages/web/src/datagrid/DataGridCore.svelte index 2ab4edb94..486a10975 100644 --- a/packages/web/src/datagrid/DataGridCore.svelte +++ b/packages/web/src/datagrid/DataGridCore.svelte @@ -343,13 +343,13 @@ @@ -51,7 +49,7 @@ display.setFilter(uniqueName, value)} {driver} diff --git a/packages/web/src/formview/FormViewFilters.svelte b/packages/web/src/formview/FormViewFilters.svelte index 18aca5bca..2fa0721fb 100644 --- a/packages/web/src/formview/FormViewFilters.svelte +++ b/packages/web/src/formview/FormViewFilters.svelte @@ -7,6 +7,7 @@ import FontIcon from '../icons/FontIcon.svelte'; import keycodes from '../utility/keycodes'; import FormViewFilterColumn from './FormViewFilterColumn.svelte'; + import { stringFilterBehaviour } from 'dbgate-tools'; // import PrimaryKeyFilterEditor from './PrimaryKeyFilterEditor.svelte'; export let managerSize; @@ -20,7 +21,6 @@ export let pureName; export let isDynamicStructure; - export let useEvalFilters; export let isFormView; export let hasMultiColumnFilter; @@ -77,7 +77,7 @@ display.setMutliColumnFilter(value)} {driver} @@ -93,7 +93,6 @@ {#each allFilterNames as uniqueName} { return condition != 'NULL' && condition != 'NOT NULL' && condition != 'EXISTS' && condition != 'NOT EXISTS'; @@ -24,7 +24,9 @@ if (!value) return null; if (condition == 'sql') return `{${value}}`; if (condition == 'sqlRight') return `{$$ ${value}}`; - if (filterType == 'string') return `${condition}"${value}"`; + if (filterBehaviour.allowStringToken) { + return `${condition}"${value}"`; + } return `${condition}${value}`; }; @@ -48,7 +50,7 @@
Show rows where
- +
@@ -66,7 +68,7 @@
- +
diff --git a/packages/web/src/modals/SetFilterModal_Select.svelte b/packages/web/src/modals/SetFilterModal_Select.svelte index dba3365ea..dd4b54b15 100644 --- a/packages/web/src/modals/SetFilterModal_Select.svelte +++ b/packages/web/src/modals/SetFilterModal_Select.svelte @@ -2,90 +2,59 @@ import FormSelectFieldRaw from '../forms/FormSelectFieldRaw.svelte'; export let name; - export let filterType; + export let filterBehaviour; function getOptions() { - switch (filterType) { - case 'number': - 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: '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' }, - ]; + const res = []; + if (filterBehaviour.supportEquals) { + res.push({ value: '=', label: 'equals' }, { value: '<>', label: 'does not equal' }); } + + 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; } diff --git a/packages/web/src/perspectives/PerspectiveFiltersColumn.svelte b/packages/web/src/perspectives/PerspectiveFiltersColumn.svelte index 97499a8ff..1f7e42ccf 100644 --- a/packages/web/src/perspectives/PerspectiveFiltersColumn.svelte +++ b/packages/web/src/perspectives/PerspectiveFiltersColumn.svelte @@ -57,7 +57,7 @@
column.dataNode.setFilter(value)} columnName={column.dataNode.uniqueName} - filterType={column.dataNode.filterType} + filterBehaviour={column.dataNode.filterBehaviour} /> {/each} diff --git a/plugins/dbgate-plugin-mongo/src/frontend/driver.js b/plugins/dbgate-plugin-mongo/src/frontend/driver.js index 4ad54613a..4945c19e3 100644 --- a/plugins/dbgate-plugin-mongo/src/frontend/driver.js +++ b/plugins/dbgate-plugin-mongo/src/frontend/driver.js @@ -93,6 +93,10 @@ const driver = { } return res; }, + + getFilterBehaviour(dataType, standardFilterBehaviours) { + return standardFilterBehaviours.mongoFilterBehaviour; + }, }; module.exports = driver;