1
0

fix(filters): parse labels and projects correctly when using in filter operator

This commit is contained in:
kolaente 2024-03-11 15:16:39 +01:00
parent 3896c680d3
commit 0529f30e77
No known key found for this signature in database
GPG Key ID: F40E70337AB24C9B
2 changed files with 118 additions and 64 deletions

View File

@ -37,10 +37,7 @@ describe('Filter Transformation', () => {
expect(transformed).toBe('labels = 1') expect(transformed).toBe('labels = 1')
}) })
it('should correctly resolve multiple labels', () => { const multipleDummyResolver = (title: string) => {
const transformed = transformFilterStringForApi(
'labels = lorem && dueDate = now && labels = ipsum',
(title: string) => {
switch (title) { switch (title) {
case 'lorem': case 'lorem':
return 1 return 1
@ -49,13 +46,28 @@ describe('Filter Transformation', () => {
default: default:
return null return null
} }
}, }
it('should correctly resolve multiple labels', () => {
const transformed = transformFilterStringForApi(
'labels = lorem && dueDate = now && labels = ipsum',
multipleDummyResolver,
nullTitleToIdResolver, 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', () => { it('should correctly resolve projects', () => {
const transformed = transformFilterStringForApi( const transformed = transformFilterStringForApi(
'project = lorem', 'project = lorem',
@ -70,20 +82,21 @@ describe('Filter Transformation', () => {
const transformed = transformFilterStringForApi( const transformed = transformFilterStringForApi(
'project = lorem && dueDate = now || project = ipsum', 'project = lorem && dueDate = now || project = ipsum',
nullTitleToIdResolver, nullTitleToIdResolver,
(title: string) => { multipleDummyResolver,
switch (title) {
case 'lorem':
return 1
case 'ipsum':
return 2
default:
return null
}
},
) )
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')
})
}) })
describe('To API', () => { describe('To API', () => {
@ -105,10 +118,7 @@ describe('Filter Transformation', () => {
expect(transformed).toBe('labels = lorem') expect(transformed).toBe('labels = lorem')
}) })
it('should correctly resolve multiple labels', () => { const multipleIdToTitleResolver = (id: number) => {
const transformed = transformFilterStringFromApi(
'labels = 1 && due_date = now && labels = 2',
(id: number) => {
switch (id) { switch (id) {
case 1: case 1:
return 'lorem' return 'lorem'
@ -117,13 +127,28 @@ describe('Filter Transformation', () => {
default: default:
return null return null
} }
}, }
it('should correctly resolve multiple labels', () => {
const transformed = transformFilterStringFromApi(
'labels = 1 && due_date = now && labels = 2',
multipleIdToTitleResolver,
nullIdToTitleResolver, 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', () => { it('should correctly resolve projects', () => {
const transformed = transformFilterStringFromApi( const transformed = transformFilterStringFromApi(
'project = 1', 'project = 1',
@ -136,21 +161,22 @@ describe('Filter Transformation', () => {
it('should correctly resolve multiple projects', () => { it('should correctly resolve multiple projects', () => {
const transformed = transformFilterStringFromApi( const transformed = transformFilterStringFromApi(
'project = lorem && due_date = now || project = ipsum', 'project = 1 && due_date = now || project = 2',
nullIdToTitleResolver, nullIdToTitleResolver,
(id: number) => { multipleIdToTitleResolver,
switch (id) {
case 1:
return 'lorem'
case 2:
return 'ipsum'
default:
return null
}
},
) )
expect(transformed).toBe('project = lorem && dueDate = now || project = ipsum') 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')
})
}) })
}) })

View File

@ -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 { function getFieldPattern(field: string): RegExp {
return new RegExp('(' + field + '\\s*' + FILTER_OPERATORS_REGEX + '\\s*)([\'"]?)([^\'"&|()]+\\1?)?', 'ig') return new RegExp('(' + field + '\\s*' + FILTER_OPERATORS_REGEX + '\\s*)([\'"]?)([^\'"&|()]+\\1?)?', 'ig')
@ -80,10 +80,17 @@ export function transformFilterStringForApi(
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const [matched, prefix, operator, space, keyword] = match const [matched, prefix, operator, space, keyword] = match
if (keyword) { if (keyword) {
const labelId = labelResolver(keyword.trim()) let keywords = [keyword.trim()]
if (labelId !== null) { if (operator === 'in' || operator === '?=') {
filter = filter.replace(keyword, String(labelId)) 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 // eslint-disable-next-line @typescript-eslint/no-unused-vars
const [matched, prefix, operator, space, keyword] = match const [matched, prefix, operator, space, keyword] = match
if (keyword) { if (keyword) {
const projectId = projectResolver(keyword.trim()) let keywords = [keyword.trim()]
if (projectId !== null) { if (operator === 'in' || operator === '?=') {
filter = filter.replace(keyword, String(projectId)) keywords = keyword.trim().split(',').map(k => k.trim())
} }
keywords.forEach(k => {
const projectId = projectResolver(k)
if (projectId !== null) {
filter = filter.replace(k, String(projectId))
}
})
} }
} }
}) })
@ -136,10 +150,17 @@ export function transformFilterStringFromApi(
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const [matched, prefix, operator, space, keyword] = match const [matched, prefix, operator, space, keyword] = match
if (keyword) { if (keyword) {
const labelTitle = labelResolver(Number(keyword.trim())) let keywords = [keyword.trim()]
if (labelTitle !== null) { if (operator === 'in' || operator === '?=') {
filter = filter.replace(keyword, labelTitle) 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 // eslint-disable-next-line @typescript-eslint/no-unused-vars
const [matched, prefix, operator, space, keyword] = match const [matched, prefix, operator, space, keyword] = match
if (keyword) { if (keyword) {
const project = projectResolver(Number(keyword.trim())) let keywords = [keyword.trim()]
if (project !== null) { if (operator === 'in' || operator === '?=') {
filter = filter.replace(keyword, project) keywords = keyword.trim().split(',').map(k => k.trim())
} }
keywords.forEach(k => {
const project = projectResolver(parseInt(k))
if (project !== null) {
filter = filter.replace(k, project)
}
})
} }
} }
}) })