-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: correct filter application in queries (#90)
- Loading branch information
Showing
5 changed files
with
98 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { addLabelToQuery, removeLabelFromQuery } from './modifyQuery'; | ||
|
||
describe('modifyQuery', () => { | ||
describe('addLabelToQuery', () => { | ||
it('should add a label to the query with the specified operator', () => { | ||
const query = 'foo: bar'; | ||
const key = 'baz'; | ||
const value = 'qux'; | ||
const operator = 'AND'; | ||
const result = addLabelToQuery(query, key, value, operator); | ||
expect(result).toBe('foo: bar AND baz:"qux"'); | ||
}); | ||
|
||
it('should add a label to the query and retain pipes', () => { | ||
const query = 'foo: bar | pipe1 | pipe2'; | ||
const key = 'baz'; | ||
const value = 'qux'; | ||
const operator = 'AND'; | ||
const result = addLabelToQuery(query, key, value, operator); | ||
expect(result).toBe('foo: bar AND baz:"qux" | pipe1 | pipe2'); | ||
}); | ||
}); | ||
|
||
describe('removeLabelFromQuery', () => { | ||
it('should remove a label from the query', () => { | ||
const query = 'foo: bar AND baz:"qux"'; | ||
const key = 'baz'; | ||
const value = 'qux'; | ||
const result = removeLabelFromQuery(query, key, value); | ||
expect(result).toBe('foo: bar'); | ||
}); | ||
|
||
it('should remove a label from the query and retain pipes', () => { | ||
const query = 'foo: bar AND baz:"qux" | pipe1 | pipe2'; | ||
const key = 'baz'; | ||
const value = 'qux'; | ||
const result = removeLabelFromQuery(query, key, value); | ||
expect(result).toBe('foo: bar | pipe1 | pipe2'); | ||
}); | ||
|
||
it('should handle nested filters correctly', () => { | ||
const query = 'foo: bar AND (baz:"qux" OR quux:"corge")'; | ||
const key = 'baz'; | ||
const value = 'qux'; | ||
const result = removeLabelFromQuery(query, key, value); | ||
expect(result).toBe('foo: bar AND (quux:"corge")'); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,54 @@ | ||
export function queryHasFilter(query: string, key: string, value: string): boolean { | ||
return query.includes(`${key}:${value}`) | ||
import { buildVisualQueryFromString, splitExpression } from "./components/QueryEditor/QueryBuilder/utils/parseFromString"; | ||
import { parseVisualQueryToString } from "./components/QueryEditor/QueryBuilder/utils/parseToString"; | ||
import { FilterVisualQuery } from "./types"; | ||
|
||
const getKeyValue = (key: string, value: string): string => { | ||
return `${key}:"${value}"` | ||
} | ||
|
||
export const removeLabelFromQuery = (query: string, key: string, value: string): string => { | ||
const operators = ['AND', 'NOT'] | ||
const parts = query.split(' ') | ||
const index = parts.findIndex((part) => part.includes(`${key}:${value}`)) | ||
const newParts = removeAtIndexAndBefore(parts, index, operators.includes(parts[index - 1])) | ||
return newParts.join(' ') | ||
export function queryHasFilter(query: string, key: string, value: string): boolean { | ||
return query.includes(getKeyValue(key, value)) | ||
} | ||
|
||
export const addLabelToQuery = (query: string, key: string, value: string, operator: string): string => { | ||
return `${query} ${operator} ${key}:${value}` | ||
const [filters, ...pipes] = splitExpression(query) | ||
const insertPart = `${operator} ${getKeyValue(key, value)}` | ||
const pipesPart = pipes?.length ? `| ${pipes.join(' | ')}` : '' | ||
return (`${filters} ${insertPart} ${pipesPart}`).trim() | ||
} | ||
|
||
const removeAtIndexAndBefore = (arr: string[], index: number, removeBefore: boolean): string[] => { | ||
if (index < 0 || index >= arr.length) { | ||
return arr; | ||
export const removeLabelFromQuery = (query: string, key: string, value: string): string => { | ||
const { query: { filters, pipes }, errors } = buildVisualQueryFromString(query); | ||
if (errors.length) { | ||
console.error(errors.join('\n')); | ||
return query; | ||
} | ||
|
||
if (removeBefore) { | ||
const isStart = index === 0; | ||
arr.splice(isStart ? index : index - 1, isStart ? 1 : 2); | ||
} else { | ||
arr.splice(index, 1); | ||
const keyValue = getKeyValue(key, value); | ||
recursiveRemove(filters, keyValue) | ||
return parseVisualQueryToString({ filters, pipes }) | ||
} | ||
|
||
const recursiveRemove = (filters: FilterVisualQuery, keyValue: string): boolean => { | ||
const { values, operators } = filters; | ||
let removed = false; | ||
|
||
for (let i = values.length - 1; i >= 0; i--) { | ||
const val = values[i]; | ||
const isString = typeof val === 'string' | ||
const isFilterObject = typeof val === 'object' && 'values' in val | ||
|
||
if (isString && val === keyValue) { | ||
// If the string matches keyValue, delete it and the operator | ||
values.splice(i, 1); | ||
(i > 0 && i - 1 < operators.length) && operators.splice(i - 1, 1); | ||
removed = true; | ||
} else if (isFilterObject) { | ||
// If it is an object of type FilterVisualQuery, recursively check it | ||
const wasRemoved = recursiveRemove(val, keyValue); | ||
removed = wasRemoved || removed; | ||
} | ||
} | ||
|
||
return arr; | ||
return removed; | ||
} |