fixed evaluated filters

This commit is contained in:
Jan Prochazka
2022-03-31 15:15:15 +02:00
parent 25380ee0a8
commit 5aac142e4c
12 changed files with 90 additions and 30 deletions

View File

@@ -163,6 +163,7 @@ class JsonLinesDatastore {
const res = []; const res = [];
await lock.acquire('reader', async () => { await lock.acquire('reader', async () => {
await this._ensureReader(offset, filter); await this._ensureReader(offset, filter);
// console.log(JSON.stringify(this.currentFilter, undefined, 2));
for (let i = 0; i < limit; i += 1) { for (let i = 0; i < limit; i += 1) {
const line = await this._readLine(true); const line = await this._readLine(true);
if (line == null) break; if (line == null) break;

View File

@@ -652,7 +652,8 @@ 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 = this.isDynamicStructure ? this.filterTypeOverride ?? 'mongo' : getFilterType(column.dataType); const filterType =
this.filterTypeOverride ?? (this.isDynamicStructure ? 'mongo' : getFilterType(column.dataType));
try { try {
const condition = parseFilter(filters[name], filterType); const condition = parseFilter(filters[name], filterType);
const replaced = _.cloneDeepWith(condition, (expr: Expression) => { const replaced = _.cloneDeepWith(condition, (expr: Expression) => {

View File

@@ -21,7 +21,7 @@ export class JslGridDisplay extends GridDisplay {
this.filterable = true; this.filterable = true;
this.supportsReload = supportsReload; this.supportsReload = supportsReload;
this.isDynamicStructure = isDynamicStructure; this.isDynamicStructure = isDynamicStructure;
if (isDynamicStructure) this.filterTypeOverride = 'string'; this.filterTypeOverride = 'eval';
if (structure?.columns) { if (structure?.columns) {
this.columns = _.uniqBy( this.columns = _.uniqBy(

View File

@@ -254,10 +254,10 @@ const createParser = (filterType: FilterType) => {
eq: r => word('=').then(r.value).map(binaryCondition('=')), eq: r => word('=').then(r.value).map(binaryCondition('=')),
ne: r => word('!=').then(r.value).map(binaryCondition('<>')), ne: r => word('!=').then(r.value).map(binaryCondition('<>')),
ne2: r => word('<>').then(r.value).map(binaryCondition('<>')), ne2: r => word('<>').then(r.value).map(binaryCondition('<>')),
lt: r => word('<').then(r.value).map(binaryCondition('<')),
gt: r => word('>').then(r.value).map(binaryCondition('>')),
le: r => word('<=').then(r.value).map(binaryCondition('<=')), le: r => word('<=').then(r.value).map(binaryCondition('<=')),
ge: r => word('>=').then(r.value).map(binaryCondition('>=')), ge: r => word('>=').then(r.value).map(binaryCondition('>=')),
lt: r => word('<').then(r.value).map(binaryCondition('<')),
gt: r => word('>').then(r.value).map(binaryCondition('>')),
startsWith: r => word('^').then(r.value).map(likeCondition('like', '#VALUE#%')), startsWith: r => word('^').then(r.value).map(likeCondition('like', '#VALUE#%')),
endsWith: r => word('$').then(r.value).map(likeCondition('like', '%#VALUE#')), endsWith: r => word('$').then(r.value).map(likeCondition('like', '%#VALUE#')),
contains: r => word('+').then(r.value).map(likeCondition('like', '%#VALUE#%')), contains: r => word('+').then(r.value).map(likeCondition('like', '%#VALUE#%')),
@@ -271,24 +271,30 @@ const createParser = (filterType: FilterType) => {
}; };
const allowedValues = []; // 'string1', 'string2', 'number', 'noQuotedString']; const allowedValues = []; // 'string1', 'string2', 'number', 'noQuotedString'];
if (filterType == 'string') allowedValues.push('string1', 'string2', 'noQuotedString'); if (filterType == 'string' || filterType == 'eval') {
if (filterType == 'number') allowedValues.push('string1Num', 'string2Num', 'number'); allowedValues.push('string1', 'string2', 'noQuotedString');
}
if (filterType == 'number') {
allowedValues.push('string1Num', 'string2Num', 'number');
}
const allowedElements = ['null', 'notNull', 'eq', 'ne', 'ne2']; const allowedElements = ['null', 'notNull', 'eq', 'ne', 'ne2'];
if (filterType == 'number' || filterType == 'datetime') allowedElements.push('lt', 'gt', 'le', 'ge'); if (filterType == 'number' || filterType == 'datetime' || filterType == 'eval') {
if (filterType == 'string') allowedElements.push('le', 'ge', 'lt', 'gt');
allowedElements.push( }
'empty', if (filterType == 'string') {
'notEmpty', allowedElements.push('empty', 'notEmpty');
'startsWith', }
'endsWith', if (filterType == 'eval' || filterType == 'string') {
'contains', allowedElements.push('startsWith', 'endsWith', 'contains', 'startsWithNot', 'endsWithNot', 'containsNot');
'startsWithNot', }
'endsWithNot', if (filterType == 'logical') {
'containsNot' allowedElements.push('true', 'false', 'trueNum', 'falseNum');
); }
if (filterType == 'logical') allowedElements.push('true', 'false', 'trueNum', 'falseNum'); if (filterType == 'eval') {
if (filterType == 'datetime') allowedElements.push('true', 'false');
}
if (filterType == 'datetime') {
allowedElements.push( allowedElements.push(
'yearMonthDaySecond', 'yearMonthDaySecond',
'yearMonthDayMinute', 'yearMonthDayMinute',
@@ -308,10 +314,13 @@ const createParser = (filterType: FilterType) => {
'thisYear', 'thisYear',
'nextYear' 'nextYear'
); );
}
// must be last // must be last
if (filterType == 'string') allowedElements.push('valueTestStr'); if (filterType == 'string' || filterType == 'eval') {
else allowedElements.push('valueTestEq'); allowedElements.push('valueTestStr');
} else {
allowedElements.push('valueTestEq');
}
return P.createLanguage(langDef); return P.createLanguage(langDef);
}; };
@@ -321,6 +330,7 @@ const parsers = {
string: createParser('string'), string: createParser('string'),
datetime: createParser('datetime'), datetime: createParser('datetime'),
logical: createParser('logical'), logical: createParser('logical'),
eval: createParser('eval'),
mongo: mongoParser, mongo: mongoParser,
}; };

View File

@@ -1,3 +1,3 @@
// import types from 'dbgate-types'; // import types from 'dbgate-types';
export type FilterType = 'number' | 'string' | 'datetime' | 'logical' | 'mongo'; export type FilterType = 'number' | 'string' | 'datetime' | 'logical' | 'eval' | 'mongo';

View File

@@ -161,6 +161,33 @@
{ onClick: () => setFilter('TRUE'), text: 'Is True' }, { onClick: () => setFilter('TRUE'), text: 'Is True' },
{ onClick: () => setFilter('FALSE'), text: 'Is False' }, { 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 [ // return [

View File

@@ -80,6 +80,7 @@
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;
@@ -181,7 +182,7 @@
height={'30%'} height={'30%'}
skip={!isDynamicStructure || !display?.filterable} skip={!isDynamicStructure || !display?.filterable}
> >
<JsonViewFilters {...$$props} {managerSize} {isDynamicStructure} /> <JsonViewFilters {...$$props} {managerSize} {isDynamicStructure} {useEvalFilters} />
</WidgetColumnBarItem> </WidgetColumnBarItem>
<WidgetColumnBarItem <WidgetColumnBarItem
@@ -191,7 +192,7 @@
skip={!display?.filterable || isDynamicStructure || display.filterCount == 0 || isFormView} skip={!display?.filterable || isDynamicStructure || display.filterCount == 0 || isFormView}
collapsed={isDetailView} collapsed={isDetailView}
> >
<JsonViewFilters {...$$props} {managerSize} {isDynamicStructure} /> <JsonViewFilters {...$$props} {managerSize} {isDynamicStructure} {useEvalFilters} />
</WidgetColumnBarItem> </WidgetColumnBarItem>
<WidgetColumnBarItem <WidgetColumnBarItem

View File

@@ -335,6 +335,7 @@
export let multipleGridsOnTab = false; export let multipleGridsOnTab = false;
export let tabControlHiddenTab = false; export let tabControlHiddenTab = false;
export let onCustomGridRefresh; export let onCustomGridRefresh;
export let useEvalFilters = false;
// export let generalAllowSave = false; // export let generalAllowSave = false;
export const activator = createActivator('DataGridCore', false); export const activator = createActivator('DataGridCore', false);
@@ -1548,7 +1549,7 @@
{conid} {conid}
{database} {database}
driver={display?.driver} driver={display?.driver}
filterType={col.filterType || getFilterType(col.dataType)} filterType={useEvalFilters ? 'eval' : col.filterType || getFilterType(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

View File

@@ -58,5 +58,6 @@
gridCoreComponent={JslDataGridCore} gridCoreComponent={JslDataGridCore}
bind:loadedRows bind:loadedRows
isDynamicStructure={$info?.__isDynamicStructure} isDynamicStructure={$info?.__isDynamicStructure}
useEvalFilters
/> />
{/key} {/key}

View File

@@ -10,8 +10,10 @@
export let display; export let display;
export let filters; export let filters;
export let isDynamicStructure; export let isDynamicStructure;
export let useEvalFilters;
function computeFilterType(isDynamicStructure, display, uniqueName) { function computeFilterType(isDynamicStructure, display, uniqueName, useEvalFilters) {
if (useEvalFilters) return 'eval';
if (isDynamicStructure) return 'mongo'; if (isDynamicStructure) return 'mongo';
const col = display.findColumn(uniqueName); const col = display.findColumn(uniqueName);
if (col) { if (col) {
@@ -35,7 +37,7 @@
</InlineButton> </InlineButton>
</div> </div>
<DataFilterControl <DataFilterControl
filterType={computeFilterType(isDynamicStructure, display, uniqueName)} filterType={computeFilterType(isDynamicStructure, display, uniqueName, useEvalFilters)}
filter={filters[uniqueName]} filter={filters[uniqueName]}
setFilter={value => display.setFilter(uniqueName, value)} setFilter={value => display.setFilter(uniqueName, value)}
/> />

View File

@@ -7,6 +7,7 @@
export let managerSize; export let managerSize;
export let display; export let display;
export let isDynamicStructure; export let isDynamicStructure;
export let useEvalFilters;
$: filters = display?.config?.filters; $: filters = display?.config?.filters;
@@ -15,6 +16,6 @@
<ManagerInnerContainer width={managerSize}> <ManagerInnerContainer width={managerSize}>
{#each allFilterNames as uniqueName} {#each allFilterNames as uniqueName}
<JsonViewFilterColumn {uniqueName} {display} {filters} {isDynamicStructure} /> <JsonViewFilterColumn {uniqueName} {display} {filters} {isDynamicStructure} {useEvalFilters} />
{/each} {/each}
</ManagerInnerContainer> </ManagerInnerContainer>

View File

@@ -54,6 +54,21 @@
{ value: '$', label: 'ends with' }, { value: '$', label: 'ends with' },
{ value: '!$', label: 'does not end with' }, { value: '!$', label: 'does not end with' },
]; ];
case 'eval':
return [
{ value: '=', label: 'eqals' },
{ 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' },
];
} }
} }
</script> </script>