fix(filters): parse labels and projects correctly when using in
filter operator
This commit is contained in:
parent
3896c680d3
commit
0529f30e77
@ -17,7 +17,7 @@ describe('Filter Transformation', () => {
|
||||
'assignees': 'assignees',
|
||||
'labels': 'labels',
|
||||
}
|
||||
|
||||
|
||||
describe('For api', () => {
|
||||
for (const c in fieldCases) {
|
||||
it('should transform all filter params for ' + c + ' to snake_case', () => {
|
||||
@ -37,23 +37,35 @@ describe('Filter Transformation', () => {
|
||||
expect(transformed).toBe('labels = 1')
|
||||
})
|
||||
|
||||
const multipleDummyResolver = (title: string) => {
|
||||
switch (title) {
|
||||
case 'lorem':
|
||||
return 1
|
||||
case 'ipsum':
|
||||
return 2
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
it('should correctly resolve multiple labels', () => {
|
||||
const transformed = transformFilterStringForApi(
|
||||
'labels = lorem && dueDate = now && labels = ipsum',
|
||||
(title: string) => {
|
||||
switch (title) {
|
||||
case 'lorem':
|
||||
return 1
|
||||
case 'ipsum':
|
||||
return 2
|
||||
default:
|
||||
return null
|
||||
}
|
||||
},
|
||||
multipleDummyResolver,
|
||||
nullTitleToIdResolver,
|
||||
)
|
||||
|
||||
expect(transformed).toBe('labels = 1&& due_date = now && labels = 2')
|
||||
expect(transformed).toBe('labels = 1 && due_date = now && labels = 2')
|
||||
})
|
||||
|
||||
it('should correctly resolve multiple labels with an in clause', () => {
|
||||
const transformed = transformFilterStringForApi(
|
||||
'labels in lorem, ipsum && dueDate = now',
|
||||
multipleDummyResolver,
|
||||
nullTitleToIdResolver,
|
||||
)
|
||||
|
||||
expect(transformed).toBe('labels in 1, 2 && due_date = now')
|
||||
})
|
||||
|
||||
it('should correctly resolve projects', () => {
|
||||
@ -70,19 +82,20 @@ describe('Filter Transformation', () => {
|
||||
const transformed = transformFilterStringForApi(
|
||||
'project = lorem && dueDate = now || project = ipsum',
|
||||
nullTitleToIdResolver,
|
||||
(title: string) => {
|
||||
switch (title) {
|
||||
case 'lorem':
|
||||
return 1
|
||||
case 'ipsum':
|
||||
return 2
|
||||
default:
|
||||
return null
|
||||
}
|
||||
},
|
||||
multipleDummyResolver,
|
||||
)
|
||||
|
||||
expect(transformed).toBe('project = 1&& due_date = now || project = 2')
|
||||
expect(transformed).toBe('project = 1 && due_date = now || project = 2')
|
||||
})
|
||||
|
||||
it('should correctly resolve multiple projects with in', () => {
|
||||
const transformed = transformFilterStringForApi(
|
||||
'project in lorem, ipsum',
|
||||
nullTitleToIdResolver,
|
||||
multipleDummyResolver,
|
||||
)
|
||||
|
||||
expect(transformed).toBe('project in 1, 2')
|
||||
})
|
||||
})
|
||||
|
||||
@ -104,24 +117,36 @@ describe('Filter Transformation', () => {
|
||||
|
||||
expect(transformed).toBe('labels = lorem')
|
||||
})
|
||||
|
||||
|
||||
const multipleIdToTitleResolver = (id: number) => {
|
||||
switch (id) {
|
||||
case 1:
|
||||
return 'lorem'
|
||||
case 2:
|
||||
return 'ipsum'
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
it('should correctly resolve multiple labels', () => {
|
||||
const transformed = transformFilterStringFromApi(
|
||||
'labels = 1 && due_date = now && labels = 2',
|
||||
(id: number) => {
|
||||
switch (id) {
|
||||
case 1:
|
||||
return 'lorem'
|
||||
case 2:
|
||||
return 'ipsum'
|
||||
default:
|
||||
return null
|
||||
}
|
||||
},
|
||||
multipleIdToTitleResolver,
|
||||
nullIdToTitleResolver,
|
||||
)
|
||||
|
||||
expect(transformed).toBe('labels = lorem&& dueDate = now && labels = ipsum')
|
||||
expect(transformed).toBe('labels = lorem && dueDate = now && labels = ipsum')
|
||||
})
|
||||
|
||||
it('should correctly resolve multiple labels in', () => {
|
||||
const transformed = transformFilterStringFromApi(
|
||||
'labels in 1, 2',
|
||||
multipleIdToTitleResolver,
|
||||
nullIdToTitleResolver,
|
||||
)
|
||||
|
||||
expect(transformed).toBe('labels in lorem, ipsum')
|
||||
})
|
||||
|
||||
it('should correctly resolve projects', () => {
|
||||
@ -136,21 +161,22 @@ describe('Filter Transformation', () => {
|
||||
|
||||
it('should correctly resolve multiple projects', () => {
|
||||
const transformed = transformFilterStringFromApi(
|
||||
'project = lorem && due_date = now || project = ipsum',
|
||||
'project = 1 && due_date = now || project = 2',
|
||||
nullIdToTitleResolver,
|
||||
(id: number) => {
|
||||
switch (id) {
|
||||
case 1:
|
||||
return 'lorem'
|
||||
case 2:
|
||||
return 'ipsum'
|
||||
default:
|
||||
return null
|
||||
}
|
||||
},
|
||||
multipleIdToTitleResolver,
|
||||
)
|
||||
|
||||
expect(transformed).toBe('project = lorem && dueDate = now || project = ipsum')
|
||||
})
|
||||
|
||||
it('should correctly resolve multiple projects in', () => {
|
||||
const transformed = transformFilterStringFromApi(
|
||||
'project in 1, 2',
|
||||
nullIdToTitleResolver,
|
||||
multipleIdToTitleResolver,
|
||||
)
|
||||
|
||||
expect(transformed).toBe('project in lorem, ipsum')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -55,7 +55,7 @@ export const FILTER_JOIN_OPERATOR = [
|
||||
')',
|
||||
]
|
||||
|
||||
export const FILTER_OPERATORS_REGEX = '(<|>|<=|>=|=|!=)'
|
||||
export const FILTER_OPERATORS_REGEX = '(<|>|<=|>=|=|!=|in)'
|
||||
|
||||
function getFieldPattern(field: string): RegExp {
|
||||
return new RegExp('(' + field + '\\s*' + FILTER_OPERATORS_REGEX + '\\s*)([\'"]?)([^\'"&|()]+\\1?)?', 'ig')
|
||||
@ -66,11 +66,11 @@ export function transformFilterStringForApi(
|
||||
labelResolver: (title: string) => number | null,
|
||||
projectResolver: (title: string) => number | null,
|
||||
): string {
|
||||
|
||||
|
||||
if (filter.trim() === '') {
|
||||
return ''
|
||||
}
|
||||
|
||||
|
||||
// Transform labels to ids
|
||||
LABEL_FIELDS.forEach(field => {
|
||||
const pattern = getFieldPattern(field)
|
||||
@ -80,10 +80,17 @@ export function transformFilterStringForApi(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [matched, prefix, operator, space, keyword] = match
|
||||
if (keyword) {
|
||||
const labelId = labelResolver(keyword.trim())
|
||||
if (labelId !== null) {
|
||||
filter = filter.replace(keyword, String(labelId))
|
||||
let keywords = [keyword.trim()]
|
||||
if (operator === 'in' || operator === '?=') {
|
||||
keywords = keyword.trim().split(',').map(k => k.trim())
|
||||
}
|
||||
|
||||
keywords.forEach(k => {
|
||||
const labelId = labelResolver(k)
|
||||
if (labelId !== null) {
|
||||
filter = filter.replace(k, String(labelId))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -96,10 +103,17 @@ export function transformFilterStringForApi(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [matched, prefix, operator, space, keyword] = match
|
||||
if (keyword) {
|
||||
const projectId = projectResolver(keyword.trim())
|
||||
if (projectId !== null) {
|
||||
filter = filter.replace(keyword, String(projectId))
|
||||
let keywords = [keyword.trim()]
|
||||
if (operator === 'in' || operator === '?=') {
|
||||
keywords = keyword.trim().split(',').map(k => k.trim())
|
||||
}
|
||||
|
||||
keywords.forEach(k => {
|
||||
const projectId = projectResolver(k)
|
||||
if (projectId !== null) {
|
||||
filter = filter.replace(k, String(projectId))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -117,16 +131,16 @@ export function transformFilterStringFromApi(
|
||||
labelResolver: (id: number) => string | null,
|
||||
projectResolver: (id: number) => string | null,
|
||||
): string {
|
||||
|
||||
|
||||
if (filter.trim() === '') {
|
||||
return ''
|
||||
}
|
||||
|
||||
|
||||
// Transform all attributes from snake case
|
||||
AVAILABLE_FILTER_FIELDS.forEach(f => {
|
||||
filter = filter.replace(snakeCase(f), f)
|
||||
})
|
||||
|
||||
|
||||
// Transform labels to their titles
|
||||
LABEL_FIELDS.forEach(field => {
|
||||
const pattern = getFieldPattern(field)
|
||||
@ -136,10 +150,17 @@ export function transformFilterStringFromApi(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [matched, prefix, operator, space, keyword] = match
|
||||
if (keyword) {
|
||||
const labelTitle = labelResolver(Number(keyword.trim()))
|
||||
if (labelTitle !== null) {
|
||||
filter = filter.replace(keyword, labelTitle)
|
||||
let keywords = [keyword.trim()]
|
||||
if (operator === 'in' || operator === '?=') {
|
||||
keywords = keyword.trim().split(',').map(k => k.trim())
|
||||
}
|
||||
|
||||
keywords.forEach(k => {
|
||||
const labelTitle = labelResolver(parseInt(k))
|
||||
if (labelTitle !== null) {
|
||||
filter = filter.replace(k, labelTitle)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -153,10 +174,17 @@ export function transformFilterStringFromApi(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [matched, prefix, operator, space, keyword] = match
|
||||
if (keyword) {
|
||||
const project = projectResolver(Number(keyword.trim()))
|
||||
if (project !== null) {
|
||||
filter = filter.replace(keyword, project)
|
||||
let keywords = [keyword.trim()]
|
||||
if (operator === 'in' || operator === '?=') {
|
||||
keywords = keyword.trim().split(',').map(k => k.trim())
|
||||
}
|
||||
|
||||
keywords.forEach(k => {
|
||||
const project = projectResolver(parseInt(k))
|
||||
if (project !== null) {
|
||||
filter = filter.replace(k, project)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user