Skip to content
This repository was archived by the owner on Jun 4, 2024. It is now read-only.

Improve Filtering #397

Merged
merged 56 commits into from
Apr 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
53380d1
refactor syntax tree into various trees and lexicons
Mar 13, 2019
6c6fba9
- single column tests
Mar 13, 2019
86b0929
- lexer state machine
Mar 13, 2019
a158c3c
fix build
Mar 13, 2019
e9a35cf
- fix multi column query
Mar 14, 2019
e0d9d37
- fix UI filtering tests (+ new breaking test)
Mar 14, 2019
ba1f414
- fix filters behavior on invalid query fragments
Mar 14, 2019
e3b3631
- fix empty table styling issue
Mar 14, 2019
fd8540e
- table rendering with different filters
Mar 14, 2019
77cc573
- fix closing syntax (can't be first item)
Mar 15, 2019
90de09d
unary lexemes use left and right instead of block
Mar 15, 2019
60a5914
update operand syntax
Mar 26, 2019
a806ec2
fix filtering tests
Mar 26, 2019
89e6231
percy - fix filtering
Mar 26, 2019
c308141
remove waitfor
Mar 26, 2019
ba1b015
refactor single & multi query mapping logic
Mar 27, 2019
fc4645d
refactor relational operators
Mar 27, 2019
9489652
one file per relational operator
Mar 27, 2019
529c39b
rework - all in same file again..
Mar 27, 2019
88baf5f
rework unary operators
Mar 27, 2019
dcd9af8
fix standalone filtering tests
Mar 27, 2019
efb9a70
reorganize code
Mar 27, 2019
3da02a1
lexeme nomenclature
Mar 27, 2019
f497ce2
rework, add presentation, add sub-type enums
Mar 28, 2019
c4d7849
rework expression lexeme formatting
Mar 28, 2019
6e58593
rework regexp for lexemes,
Mar 28, 2019
747b9e6
same expression and operand tests for operand section
Mar 28, 2019
d85091a
- fix expression value
Mar 29, 2019
d82b2e3
- second filter for `filtering` app case
Mar 29, 2019
785373d
fix lint
Mar 29, 2019
1689b86
- break up expression into sub types
Mar 29, 2019
1b3bf51
update subtype
Apr 1, 2019
4fabf22
add derived_query_structure prop
Apr 5, 2019
d936a0e
fix filtering tests
Apr 5, 2019
edfd865
fix filtering tests
Apr 5, 2019
6b9f737
Updating Cypress
Apr 12, 2019
fb894bf
fix review comments
Apr 12, 2019
5bea8b5
update styling tests
Apr 12, 2019
e3bac4a
Merge branch 'master' into refactor-syntax-tree
Marc-Andre-Rivet Apr 12, 2019
2f05a3f
add back test delay
Apr 12, 2019
12c7c9e
Merge branch 'refactor-syntax-tree' of github.com:plotly/dash-table i…
Apr 12, 2019
914089e
fix py dropdown test
Apr 15, 2019
614b138
indentation
Apr 15, 2019
40eb328
remove v1 tests (deprecated)
Apr 15, 2019
96e1ee3
(test) super long delay on screenshot
Apr 15, 2019
ce18be8
rewrite some tests as storybook tests
Apr 15, 2019
4e7ec15
new virtualization test
Apr 15, 2019
050fad7
rewrite header test
Apr 15, 2019
491b586
rewrite simple table test
Apr 16, 2019
0e64101
rewrite dropdown tests
Apr 16, 2019
15e3df4
rewrite sizing tests
Apr 16, 2019
0718537
add tests for alt whitespace characters trimming
Apr 16, 2019
d69b98d
- fix typo (GreaterThan)
Apr 16, 2019
3f96b5b
escape `\`
Apr 16, 2019
8793613
fix lexeme tests
Apr 16, 2019
45963e7
- rename derived_query_structure to derived_filter_structure
Apr 16, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 6 additions & 108 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: 2

jobs:
"test-v0":
"test":
docker:
- image: circleci/python:3.6.7-node-browsers
- image: cypress/base:10
Expand Down Expand Up @@ -30,67 +30,7 @@ jobs:
sudo pip install --upgrade virtualenv
python -m venv venv || virtualenv venv
. venv/bin/activate
pip install -r requirements-base.txt --quiet

- run:
name: Install dependencies (dash)
command: |
git clone [email protected]:plotly/dash.git
git clone [email protected]:plotly/dash-renderer.git
git clone [email protected]:plotly/dash-core-components.git
git clone [email protected]:plotly/dash-html-components.git
. venv/bin/activate
pip install -e ./dash --quiet
cd dash-renderer && npm install --ignore-scripts && npm run build && pip install -e . && cd ..
cd dash-core-components && npm install --ignore-scripts && npm run build && pip install -e . && cd ..
cd dash-html-components && npm install --ignore-scripts && npm run build && pip install -e . && cd ..

- run:
name: Build
command: |
. venv/bin/activate
npm run private::build:js-test
npm run private::build:py
pip install -e .

- run:
name: Run tests
command: |
. venv/bin/activate
npm run test-v0


"test-v1":
docker:
- image: circleci/python:3.6.7-node-browsers
- image: cypress/base:10

steps:
- checkout
- restore_cache:
key: deps1-{{ .Branch }}-{{ checksum "package-lock.json" }}-{{ checksum "package.json" }}-{{ checksum ".circleci/config.yml" }}
- run:
name: Install npm packages
command: npm install
- run:
name: Cypress Install
command: |
$(npm bin)/cypress install

- save_cache:
key: deps1-{{ .Branch }}-{{ checksum "package-lock.json" }}-{{ checksum "package.json" }}-{{ checksum ".circleci/config.yml" }}
paths:
- node_modules
- /home/circleci/.cache/Cypress

- run:
name: Install requirements
command: |
sudo pip install --upgrade virtualenv
python -m venv venv || virtualenv venv
. venv/bin/activate
pip install -r requirements-base.txt --quiet
pip install -r requirements-v1.txt --quiet
pip install -r requirements.txt --quiet

- run:
name: Build
Expand All @@ -104,7 +44,7 @@ jobs:
name: Run tests
command: |
. venv/bin/activate
npm run test-v1
npm run test


"visual-test":
Expand Down Expand Up @@ -172,7 +112,7 @@ jobs:
when: always


"python-3.6-v0":
"python-3.6":
docker:
- image: circleci/python:3.6.7-stretch-node-browsers

Expand Down Expand Up @@ -224,53 +164,11 @@ jobs:
python -m unittest tests.dash.test_integration


"python-3.6-v1":
docker:
- image: circleci/python:3.6.7-stretch-node-browsers

environment:
PERCY_ENABLED: True
PERCY_PROJECT: plotly/dash-table-python-v1

steps:
- checkout

- run:
name: Inject Percy Environment variables
command: |
echo 'export PERCY_TOKEN="$PERCY_PYTHON_TOKEN_V1"' >> $BASH_ENV

- run:
name: Install requirements
command: |
sudo pip install --upgrade virtualenv
python -m venv venv || virtualenv venv
. venv/bin/activate
pip install -r requirements-base.txt --quiet
pip install -r requirements-v1.txt --quiet
npm install

- run:
name: Install test requirements
command: |
. venv/bin/activate
npm run build
pip install -e .

- run:
name: Run integration tests
command: |
. venv/bin/activate
python -m unittest tests.dash.test_integration


workflows:
version: 2
build:
jobs:
- "python-3.6-v0"
- "python-3.6-v1"
- "python-3.6"
- "node"
- "test-v0"
- "test-v1"
- "test"
- "visual-test"
4 changes: 4 additions & 0 deletions .config/webpack/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ module.exports = (preprocessor = {}, mode = 'development') => {
test: /demo[/\\]index.html?$/,
loader: 'file-loader?name=index.[ext]'
},
{
test: /\.csv$/,
loader: 'raw-loader'
},
{
test: /\.ts(x?)$/,
exclude: /node_modules/,
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]
### Added
[#397](https://github.com/plotly/dash-table/pull/397)
- Improve filtering syntax and capabilities
- new field syntax `{myField}`
- short form by-column filter
- implicit column and `eq` operator (e.g `"value"`)
- implicit column (e.g `ne "value"`)
- explicit form (e.g `{field} ne "value"`)
- new `contains` relational operator for strings
- new readonly `derived_filter_structure` prop exposing the query structure in a programmatically friendlier way

### Changed
[#397](https://github.com/plotly/dash-table/pull/397)
- Rename `filtering_settings` to `filter`

## [3.6.0] - 2019-03-04
### Fixed
[#189](https://github.com/plotly/dash-table/issues/189)
Expand Down
34 changes: 25 additions & 9 deletions demo/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class App extends Component {
super();

this.state = AppState;
this.state.temp_filtering = '';

const setProps = memoizeOne(() => {
return newProps => {
Expand All @@ -33,15 +34,30 @@ class App extends Component {
const mode = Environment.searchParams.get('mode');

if (mode === AppMode.Filtering) {
return (<button
className='clear-filters'
onClick={() => {
const tableProps = R.clone(this.state.tableProps);
tableProps.filtering_settings = '';

this.setState({ tableProps });
}}
>Clear Filter</button>);
return (
<div>
<button
className='clear-filters'
onClick={() => {
const tableProps = R.clone(this.state.tableProps);
tableProps.filter = '';

this.setState({ tableProps });
}}
>Clear Filter</button>
<input
style={{ width: '500px' }}
value={this.state.temp_filtering}
onChange={
e => this.setState({ temp_filtering: e.target.value })
}
onBlur={e => {
const tableProps = R.clone(this.state.tableProps);
tableProps.filter = e.target.value;

this.setState({ tableProps });
}} />
</div>);
}
}

Expand Down
4 changes: 2 additions & 2 deletions demo/AppMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ function getBaseTableProps(mock: IDataMock) {
max_width: '1000px',
width: '1000px'
},
style_data_conditional: [
style_cell_conditional: [
{ max_width: 150, min_width: 150, width: 150 },
{ if: { column_id: 'rows' }, max_width: 60, min_width: 60, width: 60 },
{ if: { column_id: 'bbb' }, max_width: 200, min_width: 200, width: 200 },
Expand Down Expand Up @@ -150,7 +150,7 @@ function getTooltipsState() {
state.tableProps.column_conditional_tooltips = [{
if: {
column_id: 'aaa-readonly',
filter: `aaa is prime`
filter: `{aaa} is prime`
},
type: TooltipSyntax.Markdown,
value: `### Go Proverbs\nCapture three to get an eye`
Expand Down
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,11 @@
"private::runtests:unit": "cypress run --browser chrome --spec 'tests/cypress/tests/unit/**/*'",
"private::runtests:standalone": "cypress run --browser chrome --spec 'tests/cypress/tests/standalone/**/*'",
"private::runtests:server": "cypress run --browser chrome --spec 'tests/cypress/tests/server/**/*'",
"private::runtests-v0": "run-s private::runtests:server",
"private::runtests-v1": "run-s private::runtests:python private::runtests:unit private::runtests:standalone private::runtests:server",
"private::runtests": "run-s private::runtests:python private::runtests:unit private::runtests:standalone private::runtests:server",
"build.watch": "webpack-dev-server --content-base dash_table --mode development",
"build": "run-s private::build:js private::build:py",
"lint": "run-s private::lint:*",
"test-v0": "run-p --race private::host* private::runtests-v0",
"test-v1": "run-p --race private::host* private::runtests-v1",
"test": "run-p --race private::host* private::runtests",
"test.visual": "build-storybook && percy-storybook",
"test.visual-local": "build-storybook",
"test.watch": "run-p --race \"private::build:js-test-watch\" --race private::host* private::opentests"
Expand All @@ -55,6 +53,7 @@
"@storybook/cli": "^5.0.5",
"@storybook/react": "^5.0.5",
"@types/d3-format": "^1.3.1",
"@types/papaparse": "^4.5.9",
"@types/ramda": "^0.26.5",
"@types/react": "^16.8.8",
"@types/react-dom": "^16.8.3",
Expand All @@ -71,7 +70,9 @@
"less-loader": "^4.1.0",
"npm": "^6.9.0",
"npm-run-all": "^4.1.5",
"papaparse": "^4.6.3",
"ramda": "^0.26.1",
"raw-loader": "^2.0.0",
"react": "16.8.5",
"react-docgen": "^4.1.0",
"react-dom": "16.8.5",
Expand Down
4 changes: 0 additions & 4 deletions requirements-v1.txt

This file was deleted.

2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
-r requirements-base.txt
-r requirements-v1.txt
-r requirements-v0.txt
71 changes: 64 additions & 7 deletions src/core/syntax-tree/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,63 @@
import * as R from 'ramda';

import Logger from 'core/Logger';
import lexer from 'core/syntax-tree/lexer';
import syntaxer, { ISyntaxerResult } from 'core/syntax-tree/syntaxer';
import lexer, { ILexerResult } from 'core/syntax-tree/lexer';
import syntaxer, { ISyntaxerResult, ISyntaxTree } from 'core/syntax-tree/syntaxer';
import { Lexicon } from './lexicon';

interface IStructure {
subType?: string;
type: string;
value: any;

block?: IStructure;
left?: IStructure;
right?: IStructure;
}

function toStructure(tree: ISyntaxTree): IStructure {
const { block, left, lexeme, right, value } = tree;

const res: IStructure = {
subType: lexeme.subType,
type: lexeme.type,
value: lexeme.present ? lexeme.present(tree) : value
};

if (block) {
res.block = toStructure(block);
}

if (left) {
res.left = toStructure(left);
}

if (right) {
res.right = toStructure(right);
}

return res;
}

export default class SyntaxTree {
private result: ISyntaxerResult;
protected lexerResult: ILexerResult;
protected syntaxerResult: ISyntaxerResult;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping the intermediary results allows for finer manipulations in the derived syntax tree classes


get isValid() {
return this.result.valid;
return this.syntaxerResult.valid;
}

private get tree() {
return this.result.tree;
return this.syntaxerResult.tree;
}

constructor(private readonly query: string) {
this.result = syntaxer(lexer(this.query));
constructor(
public readonly lexicon: Lexicon,
public readonly query: string,
postProcessor: (res: ILexerResult) => ILexerResult = res => res
) {
this.lexerResult = postProcessor(lexer(this.lexicon, this.query));
this.syntaxerResult = syntaxer(this.lexerResult);
}

evaluate = (target: any) => {
Expand All @@ -33,4 +76,18 @@ export default class SyntaxTree {
filter = (targets: any[]) => {
return targets.filter(this.evaluate);
}

toQueryString() {
return this.lexerResult.valid ?
R.map(l => l.value, this.lexerResult.lexemes).join(' ') :
'';
}

toStructure() {
if (!this.isValid || !this.syntaxerResult.tree) {
return null;
}

return toStructure(this.syntaxerResult.tree);
}
}
Loading