-
-
Notifications
You must be signed in to change notification settings - Fork 73
Issue 460 - datestartswith relational operator behavior on number expression #589
Changes from 4 commits
0bf2cc6
04bbe1d
8087b40
5bf60cb
4d6b44a
8f89f1b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -74,8 +74,8 @@ describe('Dash Table Queries', () => { | |
|
||
describe('contains', () => { | ||
processCases(c.syntaxer, [ | ||
{ name: 'cannot compare "11" to 1', query: `${c.hideOperand ? '' : '{a} '}contains 1`, target: { a: '11' }, valid: true, evaluate: true }, | ||
{ name: 'cannot compare 11 to 1', query: `${c.hideOperand ? '' : '{a} '}contains 1`, target: { a: 11 }, valid: true, evaluate: false }, | ||
{ name: 'compares "11" to 1', query: `${c.hideOperand ? '' : '{a} '}contains 1`, target: { a: '11' }, valid: true, evaluate: true }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typo |
||
{ name: 'compares 11 to 1', query: `${c.hideOperand ? '' : '{a} '}contains 1`, target: { a: 11 }, valid: true, evaluate: true }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
{ name: 'compares "11" to "1"', query: `${c.hideOperand ? '' : '{a} '}contains "1"`, target: { a: '11' }, valid: true, evaluate: true }, | ||
{ name: 'compares 11 to "1"', query: `${c.hideOperand ? '' : '{a} '}contains "1"`, target: { a: 11 }, valid: true, evaluate: true }, | ||
{ name: 'compares "1" to "1.0"', query: `${c.hideOperand ? '' : '{a} '}contains "1.0"`, target: { a: '1' }, valid: true, evaluate: false }, | ||
|
@@ -84,8 +84,8 @@ describe('Dash Table Queries', () => { | |
{ name: 'compares "abc" to "b"', query: `${c.hideOperand ? '' : '{a} '}contains "b"`, target: { a: 'abc' }, valid: true, evaluate: true }, | ||
{ name: 'compares "abc" to " b"', query: `${c.hideOperand ? '' : '{a} '}contains " b"`, target: { a: 'abc' }, valid: true, evaluate: false }, | ||
{ name: 'compares "abc" to "b "', query: `${c.hideOperand ? '' : '{a} '}contains "b "`, target: { a: 'abc' }, valid: true, evaluate: false }, | ||
{ name: 'compares "abc" to " b"', query: `${c.hideOperand ? '' : '{a} '}contains " b"`, target: { a: 'a bc' }, valid: true, evaluate: true }, | ||
{ name: 'compares "abc" to "b "', query: `${c.hideOperand ? '' : '{a} '}contains "b "`, target: { a: 'ab c' }, valid: true, evaluate: true } | ||
{ name: 'compares "a bc" to " b"', query: `${c.hideOperand ? '' : '{a} '}contains " b"`, target: { a: 'a bc' }, valid: true, evaluate: true }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typo |
||
{ name: 'compares "ab c" to "b "', query: `${c.hideOperand ? '' : '{a} '}contains "b "`, target: { a: 'ab c' }, valid: true, evaluate: true } | ||
]); | ||
}); | ||
|
||
|
@@ -96,7 +96,7 @@ describe('Dash Table Queries', () => { | |
{ name: '0yyy in "0yyy"', query: `${c.hideOperand ? '' : '{a} '}datestartswith "0987"`, target: { a: '0987' }, valid: true, evaluate: true }, | ||
{ name: 'yyyy in "yyyy"', query: `${c.hideOperand ? '' : '{a} '}datestartswith "2006"`, target: { a: '2005' }, valid: true, evaluate: false }, | ||
{ name: 'yyyy in "yyyy"', query: `${c.hideOperand ? '' : '{a} '}datestartswith "2005"`, target: { a: '2005' }, valid: true, evaluate: true }, | ||
{ name: 'yyyy in yyyy', query: `${c.hideOperand ? '' : '{a} '}datestartswith 2005`, target: { a: '2005' }, valid: true, evaluate: false }, | ||
{ name: 'yyyy in yyyy', query: `${c.hideOperand ? '' : '{a} '}datestartswith 2005`, target: { a: '2005' }, valid: true, evaluate: true }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the relational operator will now cast number to string for |
||
{ name: 'yyyy-mm in "yyyy"', query: `${c.hideOperand ? '' : '{a} '}datestartswith "2005"`, target: { a: '2005-01' }, valid: true, evaluate: true }, | ||
{ name: 'yyyy-mm-dd in "yyyy"', query: `${c.hideOperand ? '' : '{a} '}datestartswith "2005"`, target: { a: '2005-01-01' }, valid: true, evaluate: true }, | ||
{ name: 'yyyy-mm-dd hh in "yyyy"', query: `${c.hideOperand ? '' : '{a} '}datestartswith "2005"`, target: { a: '2005-01-01T10' }, valid: true, evaluate: true }, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,19 @@ | ||
import { SingleColumnSyntaxTree } from 'dash-table/syntax-tree'; | ||
import { ColumnType } from 'dash-table/components/Table/props'; | ||
import { SingleColumnConfig } from 'dash-table/syntax-tree/SingleColumnSyntaxTree'; | ||
import { RelationalOperator } from 'dash-table/syntax-tree/lexeme/relational'; | ||
import { LexemeType } from 'core/syntax-tree/lexicon'; | ||
|
||
const COLUMN_ANY: SingleColumnConfig = { | ||
id: 'a', | ||
type: ColumnType.Any | ||
}; | ||
|
||
const COLUMN_DATE: SingleColumnConfig = { | ||
id: 'a', | ||
type: ColumnType.Datetime | ||
}; | ||
|
||
const COLUMN_NUMERIC: SingleColumnConfig = { | ||
id: 'a', | ||
type: ColumnType.Numeric | ||
|
@@ -110,9 +117,119 @@ describe('Single Column Syntax Tree', () => { | |
const tree = new SingleColumnSyntaxTree('"1"', COLUMN_TEXT); | ||
|
||
expect(tree.isValid).to.equal(true); | ||
expect(tree.evaluate({ a: 1 })).to.equal(true); | ||
expect(tree.evaluate({ a: 2 })).to.equal(false); | ||
expect(tree.evaluate({ a: '1' })).to.equal(true); | ||
expect(tree.evaluate({ a: '2' })).to.equal(false); | ||
|
||
expect(tree.toQueryString()).to.equal('{a} contains "1"'); | ||
}); | ||
|
||
['1975', '"1975"'].forEach(value => { | ||
it(`can be expression '${value}' with datetime column type`, () => { | ||
const tree = new SingleColumnSyntaxTree(value, COLUMN_DATE); | ||
|
||
expect(tree.evaluate({ a: 1975 })).to.equal(true); | ||
expect(tree.evaluate({ a: '1975' })).to.equal(true); | ||
expect(tree.evaluate({ a: '1975-01' })).to.equal(true); | ||
expect(tree.evaluate({ a: '1975-01-01' })).to.equal(true); | ||
expect(tree.evaluate({ a: '1975-01-01 01:01:01' })).to.equal(true); | ||
|
||
expect(tree.evaluate({ a: 1976 })).to.equal(false); | ||
expect(tree.evaluate({ a: '1976' })).to.equal(false); | ||
expect(tree.evaluate({ a: '1976-01' })).to.equal(false); | ||
expect(tree.evaluate({ a: '1976-01-01' })).to.equal(false); | ||
expect(tree.evaluate({ a: '1976-01-01 01:01:01' })).to.equal(false); | ||
}); | ||
}); | ||
|
||
[ | ||
{ type: COLUMN_UNDEFINED, name: 'undefined' }, | ||
{ type: COLUMN_ANY, name: 'any' }, | ||
{ type: COLUMN_TEXT, name: 'text' } | ||
].forEach(({ type, name }) => { | ||
it(`returns the correct relational operator lexeme for '${name}' column type`, () => { | ||
const tree = new SingleColumnSyntaxTree('1', type); | ||
const structure = tree.toStructure(); | ||
|
||
expect(tree.toQueryString()).to.equal('{a} contains 1'); | ||
expect(structure).to.not.equal(null); | ||
|
||
if (structure) { | ||
expect(structure.value).to.equal(RelationalOperator.Contains); | ||
expect(structure.subType).to.equal(RelationalOperator.Contains); | ||
expect(structure.type).to.equal(LexemeType.RelationalOperator); | ||
|
||
expect(structure.left).to.not.equal(null); | ||
if (structure.left) { | ||
expect(structure.left.type).to.equal(LexemeType.Expression); | ||
expect(structure.left.subType).to.equal('field'); | ||
expect(structure.left.value).to.equal('a'); | ||
} | ||
|
||
expect(structure.right).to.not.equal(null); | ||
if (structure.right) { | ||
expect(structure.right.type).to.equal(LexemeType.Expression); | ||
expect(structure.right.subType).to.equal('value'); | ||
expect(structure.right.value).to.equal(1); | ||
} | ||
} | ||
}); | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Without the change to the single column syntax tree |
||
|
||
it(`returns the correct relational operator lexeme for 'date' column type`, () => { | ||
const tree = new SingleColumnSyntaxTree('1975', COLUMN_DATE); | ||
const structure = tree.toStructure(); | ||
|
||
expect(tree.toQueryString()).to.equal('{a} datestartswith 1975'); | ||
expect(structure).to.not.equal(null); | ||
|
||
if (structure) { | ||
expect(structure.value).to.equal(RelationalOperator.DateStartsWith); | ||
expect(structure.subType).to.equal(RelationalOperator.DateStartsWith); | ||
expect(structure.type).to.equal(LexemeType.RelationalOperator); | ||
|
||
expect(structure.left).to.not.equal(null); | ||
if (structure.left) { | ||
expect(structure.left.type).to.equal(LexemeType.Expression); | ||
expect(structure.left.subType).to.equal('field'); | ||
expect(structure.left.value).to.equal('a'); | ||
} | ||
|
||
expect(structure.right).to.not.equal(null); | ||
if (structure.right) { | ||
expect(structure.right.type).to.equal(LexemeType.Expression); | ||
expect(structure.right.subType).to.equal('value'); | ||
expect(structure.right.value).to.equal(1975); | ||
} | ||
} | ||
}); | ||
|
||
it(`returns the correct relational operator lexeme for 'numeric' column type`, () => { | ||
const tree = new SingleColumnSyntaxTree('1', COLUMN_NUMERIC); | ||
const structure = tree.toStructure(); | ||
|
||
expect(tree.toQueryString()).to.equal('{a} = 1'); | ||
expect(structure).to.not.equal(null); | ||
|
||
if (structure) { | ||
expect(structure.value).to.equal(RelationalOperator.Equal); | ||
expect(structure.subType).to.equal(RelationalOperator.Equal); | ||
expect(structure.type).to.equal(LexemeType.RelationalOperator); | ||
|
||
expect(structure.left).to.not.equal(null); | ||
if (structure.left) { | ||
expect(structure.left.type).to.equal(LexemeType.Expression); | ||
expect(structure.left.subType).to.equal('field'); | ||
expect(structure.left.value).to.equal('a'); | ||
} | ||
|
||
expect(structure.right).to.not.equal(null); | ||
if (structure.right) { | ||
expect(structure.right.type).to.equal(LexemeType.Expression); | ||
expect(structure.right.subType).to.equal('value'); | ||
expect(structure.right.value).to.equal(1); | ||
} | ||
} | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't this double
.toString
?But also: should we be trying to use the column formatting here? What if you have prices formatted with 2-digit decimals and you want to match all even-dollar values, with
contains '.00'
?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Getting access to formatting from here would be difficult.
I think you're right, I got carried away by the number case for dates. Deviating too much from what was agreed upon when we last went through filtering. Will revert the
contains
changes and focus on (1) datestartswith and (2) the lexeme bugThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK - certainly understand that this would be tough, and it's a weird edge case so I'm happy to ignore for now. Let's make an issue for it though, if it doesn't already exist. If a user is filtering as a string, they would expect the string used in the filter to be the one they see.