Merge pull request #3159 from omnivore-app/fix/nested-labels

feat: wildcard search for labels and nested labels
This commit is contained in:
Hongbo Wu
2023-11-23 21:44:44 +08:00
committed by GitHub
2 changed files with 105 additions and 11 deletions

View File

@ -171,22 +171,61 @@ const buildWhereClause = (
if (includeLabels && includeLabels.length > 0) {
includeLabels.forEach((includeLabel, i) => {
const param = `includeLabels_${i}`
queryBuilder.andWhere(
`lower(array_cat(library_item.label_names, library_item.highlight_labels)::text)::text[] && ARRAY[:...${param}]::text[]`,
{
[param]: includeLabel.labels,
}
const hasWildcard = includeLabel.labels.some((label) =>
label.includes('*')
)
if (hasWildcard) {
queryBuilder.andWhere(
new Brackets((qb) => {
includeLabel.labels.forEach((label, j) => {
const param = `includeLabels_${i}_${j}`
qb.orWhere(
`array_to_string(array_cat(library_item.label_names, library_item.highlight_labels)::text[], ',') ILIKE :${param}`,
{
[param]: label.replace(/\*/g, '%'),
}
)
})
})
)
} else {
queryBuilder.andWhere(
`lower(array_cat(library_item.label_names, library_item.highlight_labels)::text)::text[] && ARRAY[:...${param}]::text[]`,
{
[param]: includeLabel.labels,
}
)
}
})
}
if (excludeLabels && excludeLabels.length > 0) {
queryBuilder.andWhere(
'NOT lower(array_cat(library_item.label_names, library_item.highlight_labels)::text)::text[] && ARRAY[:...excludeLabels]::text[]',
{
excludeLabels: excludeLabels.flatMap((filter) => filter.labels),
}
)
const labels = excludeLabels.flatMap((filter) => filter.labels)
const hasWildcard = labels.some((label) => label.includes('*'))
if (hasWildcard) {
queryBuilder.andWhere(
new Brackets((qb) => {
labels.forEach((label, i) => {
const param = `excludeLabels_${i}`
qb.andWhere(
`array_to_string(array_cat(library_item.label_names, library_item.highlight_labels)::text[], ',') NOT ILIKE :${param}`,
{
[param]: label.replace(/\*/g, '%'),
}
)
})
})
)
} else {
queryBuilder.andWhere(
'NOT lower(array_cat(library_item.label_names, library_item.highlight_labels)::text)::text[] && ARRAY[:...excludeLabels]::text[]',
{
excludeLabels: labels,
}
)
}
}
}

View File

@ -1208,6 +1208,61 @@ describe('Article API', () => {
})
})
context('when wildcard search for labels', () => {
let items: LibraryItem[] = []
let labelIds: string[]
before(async () => {
keyword = 'label:test/*'
// Create some test items
const label1 = await createLabel('test/one', '', user.id)
const label2 = await createLabel('test/two', '', user.id)
labelIds = [label1.id, label2.id]
items = await createLibraryItems(
[
{
user,
title: 'test title wildcard',
readableContent: '<p>test wildcard</p>',
slug: 'test slug wildcard',
originalUrl: `${url}/wildcard`,
},
{
user,
title: 'test title wildcard 1',
readableContent: '<p>test wildcard</p>',
slug: 'test slug wildcard 1',
originalUrl: `${url}/wildcard_1`,
},
{
user,
title: 'test title wildcard 2',
readableContent: '<p>test wildcard</p>',
slug: 'test slug wildcard 2',
originalUrl: `${url}/wildcard_2`,
},
],
user.id
)
await saveLabelsInLibraryItem([label1], items[0].id, user.id)
await saveLabelsInLibraryItem([label2], items[1].id, user.id)
})
after(async () => {
await deleteLabels(labelIds, user.id)
await deleteLibraryItems(items, user.id)
})
it('returns library items with label test/one and test/two', async () => {
const res = await graphqlRequest(query, authToken).expect(200)
expect(res.body.data.search.pageInfo.totalCount).to.eq(2)
expect(res.body.data.search.edges[0].node.id).to.eq(items[0].id)
expect(res.body.data.search.edges[1].node.id).to.eq(items[1].id)
})
})
context('when type:file label:test is in the query', () => {
let items: LibraryItem[] = []
let label: Label