From 64c0542c3e6733a34c73ae9aab393b212ebd47e3 Mon Sep 17 00:00:00 2001 From: Stephanie Yang Date: Tue, 1 Jun 2021 14:44:21 -0500 Subject: [PATCH 1/3] implement 'like' for query builder queries --- lattice/src/App/QueryBuilder/RowCall/helpers.ts | 1 + lattice/src/App/QueryBuilder/utils.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lattice/src/App/QueryBuilder/RowCall/helpers.ts b/lattice/src/App/QueryBuilder/RowCall/helpers.ts index 4068057ef..dd55cad7c 100644 --- a/lattice/src/App/QueryBuilder/RowCall/helpers.ts +++ b/lattice/src/App/QueryBuilder/RowCall/helpers.ts @@ -10,6 +10,7 @@ export const operators = { set: [ { label: 'is', value: '=' }, { label: 'is not', value: '!=' }, + { label: 'like', value: 'like' }, { label: 'CIDR', value: 'cidr' } ], timestamp: [ diff --git a/lattice/src/App/QueryBuilder/utils.ts b/lattice/src/App/QueryBuilder/utils.ts index a37bca045..d0adf3331 100644 --- a/lattice/src/App/QueryBuilder/utils.ts +++ b/lattice/src/App/QueryBuilder/utils.ts @@ -29,6 +29,8 @@ export const stringifyRowData = (rowData: RowGrouping[], operator?: Operator) => } catch (error) { return { error: true, query: error.message }; } + } else if (rowOperator === 'like') { + rowString = `UnionRows(Rows(field=${field}, like="%${value}%"))`; } else { rowString = ['set', 'timestamp'].includes(type) ? `Row(${field}${operator}"${value}")` From af83e611019170e099b226b76698f2723f5e7e10 Mon Sep 17 00:00:00 2001 From: Stephanie Yang Date: Wed, 2 Jun 2021 10:51:34 -0500 Subject: [PATCH 2/3] add tests --- lattice/src/App/QueryBuilder/QueryBuilder.tsx | 2 +- .../QueryBuilder/QueryBuilderContainer.tsx | 2 +- .../App/QueryBuilder/stringifyRowData.test.ts | 193 ++++++++++++++++++ .../{utils.ts => stringifyRowData.ts} | 0 ...formatByes.test.ts => formatBytes.test.ts} | 0 5 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 lattice/src/App/QueryBuilder/stringifyRowData.test.ts rename lattice/src/App/QueryBuilder/{utils.ts => stringifyRowData.ts} (100%) rename lattice/src/shared/utils/{formatByes.test.ts => formatBytes.test.ts} (100%) diff --git a/lattice/src/App/QueryBuilder/QueryBuilder.tsx b/lattice/src/App/QueryBuilder/QueryBuilder.tsx index fcad11f97..ef83a787b 100644 --- a/lattice/src/App/QueryBuilder/QueryBuilder.tsx +++ b/lattice/src/App/QueryBuilder/QueryBuilder.tsx @@ -30,7 +30,7 @@ import { ResultType } from 'App/Query/QueryContainer'; import { RowCall } from './RowCall'; import { SavedQueries } from './SavedQueries'; import { Select } from 'shared/Select'; -import { stringifyRowData } from './utils'; +import { stringifyRowData } from './stringifyRowData'; import css from './QueryBuilder.module.scss'; type QueryBuilderProps = { diff --git a/lattice/src/App/QueryBuilder/QueryBuilderContainer.tsx b/lattice/src/App/QueryBuilder/QueryBuilderContainer.tsx index 266aa9858..0456943ec 100644 --- a/lattice/src/App/QueryBuilder/QueryBuilderContainer.tsx +++ b/lattice/src/App/QueryBuilder/QueryBuilderContainer.tsx @@ -13,7 +13,7 @@ import { ResultType } from 'App/Query/QueryContainer'; import { queryPQL } from 'services/grpcServices'; import { grpc } from '@improbable-eng/grpc-web'; import { RowResponse } from 'proto/pilosa_pb'; -import { stringifyRowData } from './utils'; +import { stringifyRowData } from './stringifyRowData'; import css from './QueryBuilderContainer.module.scss'; let streamingResults: ResultType = { diff --git a/lattice/src/App/QueryBuilder/stringifyRowData.test.ts b/lattice/src/App/QueryBuilder/stringifyRowData.test.ts new file mode 100644 index 000000000..1be3f3539 --- /dev/null +++ b/lattice/src/App/QueryBuilder/stringifyRowData.test.ts @@ -0,0 +1,193 @@ +import { stringifyRowData } from './stringifyRowData'; + +describe('int types', () => { + it('stringifies = operator', () => { + expect(stringifyRowData([{ + row: [{ + "field": "fieldName", + "rowOperator": "=", + "value": "0", + "type": "int" + }] + }])).toEqual({ error: false, query: 'Row(fieldName=0)' }) + }); + + it('stringifies != operator', () => { + expect(stringifyRowData([{ + row: [{ + "field": "fieldName", + "rowOperator": "!=", + "value": "0", + "type": "int" + }] + }])).toEqual({ error: false, query: 'Not(Row(fieldName=0))' }) + }); + + it('stringifies > operator', () => { + expect(stringifyRowData([{ + row: [{ + "field": "fieldName", + "rowOperator": ">", + "value": "0", + "type": "int" + }] + }])).toEqual({ error: false, query: 'Row(fieldName>0)' }) + }); + + it('stringifies >= operator', () => { + expect(stringifyRowData([{ + row: [{ + "field": "fieldName", + "rowOperator": ">=", + "value": "0", + "type": "int" + }] + }])).toEqual({ error: false, query: 'Row(fieldName>=0)' }) + }); + + it('stringifies negated operatorations', () => { + expect(stringifyRowData([{ + row: [{ + "field": "fieldName", + "rowOperator": ">=", + "value": "0", + "type": "int" + }], + isNot: true + }])).toEqual({ error: false, query: 'Not(Row(fieldName>=0))' }) + }); +}) + +describe('set types', () => { + it('stringifies is operator', () => { + expect(stringifyRowData([{ + row: [{ + "field": "fieldName", + "rowOperator": "=", + "value": "value", + "type": "set" + }] + }])).toEqual({ error: false, query: 'Row(fieldName="value")' }) + }); + + it('stringifies is operator for multiple values', () => { + expect(stringifyRowData([{ + row: [{ + "field": "fieldName", + "rowOperator": "=", + "value": "one, two", + "type": "set" + }] + }])).toEqual({ error: false, query: 'Union(Row(fieldName="one"), Row(fieldName="two"))' }) + }); + + it('stringifies is not operator', () => { + expect(stringifyRowData([{ + row: [{ + "field": "fieldName", + "rowOperator": "!=", + "value": "value", + "type": "set" + }] + }])).toEqual({ error: false, query: 'Not(Row(fieldName="value"))' }) + }); + + it('stringifies is not operator for multiple values', () => { + expect(stringifyRowData([{ + row: [{ + "field": "fieldName", + "rowOperator": "!=", + "value": "one, two", + "type": "set" + }] + }])).toEqual({ error: false, query: 'Not(Union(Row(fieldName="one"), Row(fieldName="two")))' }) + }); + + it('stringifies like operator', () => { + expect(stringifyRowData([{ + row: [{ + "field": "fieldName", + "rowOperator": "like", + "value": "value", + "type": "set" + }] + }])).toEqual({ error: false, query: 'UnionRows(Rows(field=fieldName, like="%value%"))' }) + }); + + it('stringifies CIDR operator', () => { + expect(stringifyRowData([{ + row: [{ + "field": "fieldName", + "rowOperator": "cidr", + "value": "10.164.124.33/30", + "type": "set" + }] + }])).toEqual({ error: false, query: 'Union(Row(fieldName="10.164.124.32"), Row(fieldName="10.164.124.33"), Row(fieldName="10.164.124.34"), Row(fieldName="10.164.124.35"))' }) + }); + + it('stringifies negated operatorations', () => { + expect(stringifyRowData([{ + row: [{ + "field": "fieldName", + "rowOperator": "like", + "value": "value", + "type": "set" + }], + isNot: true + }])).toEqual({ error: false, query: 'Not(UnionRows(Rows(field=fieldName, like="%value%")))' }) + }); +}); + +describe('mixed types', () => { + it('stringifies multiple and-ed rows', () => { + expect(stringifyRowData([{ + row: [{ + "field": "stringType", + "rowOperator": "like", + "value": "value", + "type": "set" + }, { + "field": "intType", + "rowOperator": "=", + "value": "0", + "type": "int" + }], + operator: "and" + }])).toEqual({ error: false, query: 'Intersect(UnionRows(Rows(field=stringType, like="%value%")), Row(intType=0))' }) + }); + + it('stringifies multiple or-ed rows', () => { + expect(stringifyRowData([{ + row: [{ + "field": "stringType", + "rowOperator": "like", + "value": "value", + "type": "set" + }, { + "field": "intType", + "rowOperator": "=", + "value": "0", + "type": "int" + }], + operator: "or" + }])).toEqual({ error: false, query: 'Union(UnionRows(Rows(field=stringType, like="%value%")), Row(intType=0))' }) + }); + + it('stringifies negated multiple rows', () => { + expect(stringifyRowData([{ + row: [{ + "field": "stringType", + "rowOperator": "like", + "value": "value", + "type": "set" + }, { + "field": "intType", + "rowOperator": "=", + "value": "0", + "type": "int" + }], + operator: "or", + isNot: true + }])).toEqual({ error: false, query: 'Not(Union(UnionRows(Rows(field=stringType, like="%value%")), Row(intType=0)))' }) + }); +}) diff --git a/lattice/src/App/QueryBuilder/utils.ts b/lattice/src/App/QueryBuilder/stringifyRowData.ts similarity index 100% rename from lattice/src/App/QueryBuilder/utils.ts rename to lattice/src/App/QueryBuilder/stringifyRowData.ts diff --git a/lattice/src/shared/utils/formatByes.test.ts b/lattice/src/shared/utils/formatBytes.test.ts similarity index 100% rename from lattice/src/shared/utils/formatByes.test.ts rename to lattice/src/shared/utils/formatBytes.test.ts From 732040dc80d786382818bcfe9e40106a7839a5e2 Mon Sep 17 00:00:00 2001 From: Stephanie Yang Date: Mon, 7 Jun 2021 12:41:00 -0500 Subject: [PATCH 3/3] update like to wrap between % if no wildcard is given --- .../src/App/QueryBuilder/stringifyRowData.test.ts | 13 ++++++++++++- lattice/src/App/QueryBuilder/stringifyRowData.ts | 6 +++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lattice/src/App/QueryBuilder/stringifyRowData.test.ts b/lattice/src/App/QueryBuilder/stringifyRowData.test.ts index 1be3f3539..4ace4d7a9 100644 --- a/lattice/src/App/QueryBuilder/stringifyRowData.test.ts +++ b/lattice/src/App/QueryBuilder/stringifyRowData.test.ts @@ -103,7 +103,18 @@ describe('set types', () => { }])).toEqual({ error: false, query: 'Not(Union(Row(fieldName="one"), Row(fieldName="two")))' }) }); - it('stringifies like operator', () => { + it('stringifies like operator with a wildcard', () => { + expect(stringifyRowData([{ + row: [{ + "field": "fieldName", + "rowOperator": "like", + "value": "value%", + "type": "set" + }] + }])).toEqual({ error: false, query: 'UnionRows(Rows(field=fieldName, like="value%"))' }) + }); + + it('stringifies like operator without a wildcard', () => { expect(stringifyRowData([{ row: [{ "field": "fieldName", diff --git a/lattice/src/App/QueryBuilder/stringifyRowData.ts b/lattice/src/App/QueryBuilder/stringifyRowData.ts index d0adf3331..c03ea9da4 100644 --- a/lattice/src/App/QueryBuilder/stringifyRowData.ts +++ b/lattice/src/App/QueryBuilder/stringifyRowData.ts @@ -30,7 +30,11 @@ export const stringifyRowData = (rowData: RowGrouping[], operator?: Operator) => return { error: true, query: error.message }; } } else if (rowOperator === 'like') { - rowString = `UnionRows(Rows(field=${field}, like="%${value}%"))`; + if (value.includes('%')) { + rowString = `UnionRows(Rows(field=${field}, like="${value}"))`; + } else { + rowString = `UnionRows(Rows(field=${field}, like="%${value}%"))`; + } } else { rowString = ['set', 'timestamp'].includes(type) ? `Row(${field}${operator}"${value}")`