diff --git a/packages/filterparser/src/parseFilter.ts b/packages/filterparser/src/parseFilter.ts index a2997a9e9..f6a24d53e 100644 --- a/packages/filterparser/src/parseFilter.ts +++ b/packages/filterparser/src/parseFilter.ts @@ -33,7 +33,7 @@ function interpretEscapes(str) { }); } -const binaryCondition = operator => value => ({ +const binaryCondition = (operator) => (value) => ({ conditionType: 'binary', operator, left: { @@ -45,7 +45,7 @@ const binaryCondition = operator => value => ({ }, }); -const likeCondition = (conditionType, likeString) => value => ({ +const likeCondition = (conditionType, likeString) => (value) => ({ conditionType, left: { exprType: 'placeholder', @@ -56,7 +56,7 @@ const likeCondition = (conditionType, likeString) => value => ({ }, }); -const compoudCondition = conditionType => conditions => { +const compoudCondition = (conditionType) => (conditions) => { if (conditions.length == 1) return conditions[0]; return { conditionType, @@ -64,7 +64,7 @@ const compoudCondition = conditionType => conditions => { }; }; -const unaryCondition = conditionType => () => { +const unaryCondition = (conditionType) => () => { return { conditionType, expr: { @@ -73,7 +73,7 @@ const unaryCondition = conditionType => () => { }; }; -const binaryFixedValueCondition = value => () => { +const binaryFixedValueCondition = (value) => () => { return { conditionType: 'binary', operator: '=', @@ -87,7 +87,7 @@ const binaryFixedValueCondition = value => () => { }; }; -const negateCondition = condition => { +const negateCondition = (condition) => { return { conditionType: 'not', condition, @@ -106,6 +106,16 @@ const createParser = (filterType: FilterType) => { .map(interpretEscapes) .desc('string quoted'), + string1Num: () => + token(P.regexp(/"-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?"/, 1)) + .map(Number) + .desc('numer quoted'), + + string2Num: () => + token(P.regexp(/'-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?'/, 1)) + .map(Number) + .desc('numer quoted'), + number: () => token(P.regexp(/-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?/)) .map(Number) @@ -113,78 +123,39 @@ const createParser = (filterType: FilterType) => { noQuotedString: () => P.regexp(/[^\s^,^'^"]+/).desc('string unquoted'), - value: r => P.alt(...allowedValues.map(x => r[x])), - valueTestEq: r => r.value.map(binaryCondition('=')), - valueTestStr: r => r.value.map(likeCondition('like', '%#VALUE#%')), + value: (r) => P.alt(...allowedValues.map((x) => r[x])), + valueTestEq: (r) => r.value.map(binaryCondition('=')), + valueTestStr: (r) => r.value.map(likeCondition('like', '%#VALUE#%')), comma: () => word(','), not: () => word('NOT'), - notNull: r => r.not.then(r.null).map(unaryCondition('isNotNull')), + notNull: (r) => r.not.then(r.null).map(unaryCondition('isNotNull')), null: () => word('NULL').map(unaryCondition('isNull')), empty: () => word('EMPTY').map(unaryCondition('isEmpty')), - notEmpty: r => r.not.then(r.empty).map(unaryCondition('isNotEmpty')), + notEmpty: (r) => r.not.then(r.empty).map(unaryCondition('isNotEmpty')), true: () => word('TRUE').map(binaryFixedValueCondition(1)), false: () => word('FALSE').map(binaryFixedValueCondition(0)), - eq: r => - word('=') - .then(r.value) - .map(binaryCondition('=')), - ne: 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('<=')), - ge: r => - word('>=') - .then(r.value) - .map(binaryCondition('>=')), - startsWith: 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#%')), - startsWithNot: r => - word('!^') - .then(r.value) - .map(likeCondition('like', '#VALUE#%')) - .map(negateCondition), - endsWithNot: r => - word('!$') - .then(r.value) - .map(likeCondition('like', '%#VALUE#')) - .map(negateCondition), - containsNot: r => - word('~') - .then(r.value) - .map(likeCondition('like', '%#VALUE#%')) - .map(negateCondition), + eq: (r) => word('=').then(r.value).map(binaryCondition('=')), + ne: (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('<=')), + ge: (r) => word('>=').then(r.value).map(binaryCondition('>=')), + startsWith: (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#%')), + startsWithNot: (r) => word('!^').then(r.value).map(likeCondition('like', '#VALUE#%')).map(negateCondition), + endsWithNot: (r) => word('!$').then(r.value).map(likeCondition('like', '%#VALUE#')).map(negateCondition), + containsNot: (r) => word('~').then(r.value).map(likeCondition('like', '%#VALUE#%')).map(negateCondition), - element: r => P.alt(...allowedElements.map(x => r[x])).trim(whitespace), - factor: r => r.element.sepBy(whitespace).map(compoudCondition('and')), - list: r => r.factor.sepBy(r.comma).map(compoudCondition('or')), + element: (r) => P.alt(...allowedElements.map((x) => r[x])).trim(whitespace), + factor: (r) => r.element.sepBy(whitespace).map(compoudCondition('and')), + list: (r) => r.factor.sepBy(r.comma).map(compoudCondition('or')), }; const allowedValues = []; // 'string1', 'string2', 'number', 'noQuotedString']; if (filterType == 'string') allowedValues.push('string1', 'string2', 'noQuotedString'); - if (filterType == 'number') allowedValues.push('number'); + if (filterType == 'number') allowedValues.push('string1Num', 'string2Num', 'number'); const allowedElements = ['null', 'notNull', 'eq', 'ne']; if (filterType == 'number' || filterType == 'datetime') allowedElements.push('lt', 'gt', 'le', 'ge'); diff --git a/packages/web/src/datagrid/DataGridCore.js b/packages/web/src/datagrid/DataGridCore.js index 4854710da..115b172d2 100644 --- a/packages/web/src/datagrid/DataGridCore.js +++ b/packages/web/src/datagrid/DataGridCore.js @@ -426,8 +426,10 @@ export default function DataGridCore(props) { }, [jslid]); React.useEffect(() => { - if (props.onSelectedRowsChanged) props.onSelectedRowsChanged(getSelectedRowData()) - }, [selectedCells]); + if (props.onRefSourceRowsChanged) { + props.onRefSourceRowsChanged(getSelectedRowData()); + } + }, [selectedCells, props.refReloadToken]); // const handleCloseInplaceEditor = React.useCallback( // mode => { diff --git a/packages/web/src/datagrid/TableDataGrid.js b/packages/web/src/datagrid/TableDataGrid.js index 8c8934850..cd7d4fddb 100644 --- a/packages/web/src/datagrid/TableDataGrid.js +++ b/packages/web/src/datagrid/TableDataGrid.js @@ -27,10 +27,15 @@ export default function TableDataGrid({ const [childConfig, setChildConfig] = React.useState(createGridConfig()); const [myCache, setMyCache] = React.useState(createGridCache()); const [childCache, setChildCache] = React.useState(createGridCache()); + const [refReloadToken, setRefReloadToken] = React.useState(0); const connection = useConnectionInfo({ conid }); const [reference, setReference] = React.useState(null); + React.useEffect(() => { + setRefReloadToken((v) => v + 1); + }, [reference]); + const display = React.useMemo( () => connection @@ -64,27 +69,31 @@ export default function TableDataGrid({ } }, [conid, database, display]); - const handleSelectedRowsChanged = (selectedRows) => { - const filters = { - ...(config || myConfig).filters, - ..._.fromPairs( - reference.columns.map((col) => [ - col.refName, - selectedRows.map((x) => getFilterValueExpression(x[col.baseName])).join(','), - ]) - ), - }; - if (stableStringify(filters) != stableStringify((config || myConfig).filters)) { - setChildConfig((cfg) => ({ - ...cfg, - filters, - })); - setChildCache((ca) => ({ - ...ca, - refreshTime: new Date().getTime(), - })); - } - }; + const handleRefSourcedRowsChanged = React.useCallback( + (selectedRows) => { + if (!reference) return; + const filters = { + ...(config || myConfig).filters, + ..._.fromPairs( + reference.columns.map((col) => [ + col.refName, + selectedRows.map((x) => getFilterValueExpression(x[col.baseName])).join(','), + ]) + ), + }; + if (stableStringify(filters) != stableStringify((config || childConfig).filters)) { + setChildConfig((cfg) => ({ + ...cfg, + filters, + })); + setChildCache((ca) => ({ + ...ca, + refreshTime: new Date().getTime(), + })); + } + }, + [config || childConfig, reference] + ); if (!display) return null; @@ -101,7 +110,8 @@ export default function TableDataGrid({ toolbarPortalRef={toolbarPortalRef} showReferences onReferenceClick={setReference} - onSelectedRowsChanged={reference ? handleSelectedRowsChanged : null} + onRefSourceRowsChanged={reference ? handleRefSourcedRowsChanged : null} + refReloadToken={refReloadToken.toString()} /> {reference && ( void; - onSelectedRowsChanged?: Function; + onRefSourceRowsChanged?: Function; + refReloadToken?: string; }