Merge pull request #17539 from backstage/fix/query-entities-and-filters
queryEntities: fix filters clashing with pagination clause
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Fixed a bug in the `queryEntities` endpoint that was causing filtered entities to be included in cursor requests.
|
||||
@@ -1418,6 +1418,87 @@ describe('DefaultEntitiesCatalog', () => {
|
||||
},
|
||||
);
|
||||
|
||||
it.each(databases.eachSupportedId())(
|
||||
'should exclude filtered entities when paginating, %p',
|
||||
async databaseId => {
|
||||
await createDatabase(databaseId);
|
||||
|
||||
await Promise.all([
|
||||
addEntityToSearch(entityFrom('AA', { uid: '1', kind: 'included' })),
|
||||
addEntityToSearch(
|
||||
entityFrom('AA', {
|
||||
namespace: 'namespace2',
|
||||
kind: 'included',
|
||||
uid: '2',
|
||||
}),
|
||||
),
|
||||
addEntityToSearch(
|
||||
entityFrom('AA', {
|
||||
namespace: 'ns',
|
||||
kind: 'excluded',
|
||||
uid: '3',
|
||||
}),
|
||||
),
|
||||
addEntityToSearch(
|
||||
entityFrom('AA', {
|
||||
namespace: 'namespace3',
|
||||
uid: '4',
|
||||
kind: 'included',
|
||||
}),
|
||||
),
|
||||
addEntityToSearch(
|
||||
entityFrom('AA', {
|
||||
namespace: 'namespace4',
|
||||
uid: '5',
|
||||
kind: 'included',
|
||||
}),
|
||||
),
|
||||
addEntityToSearch(entityFrom('CC', { uid: '6', kind: 'included' })),
|
||||
addEntityToSearch(entityFrom('DD', { uid: '7', kind: 'included' })),
|
||||
]);
|
||||
|
||||
const catalog = new DefaultEntitiesCatalog({
|
||||
database: knex,
|
||||
logger: getVoidLogger(),
|
||||
stitcher,
|
||||
});
|
||||
|
||||
const limit = 2;
|
||||
|
||||
// initial request
|
||||
const request1: QueryEntitiesInitialRequest = {
|
||||
limit,
|
||||
filter: {
|
||||
key: 'kind',
|
||||
values: ['included'],
|
||||
},
|
||||
orderFields: [{ field: 'metadata.name', order: 'asc' }],
|
||||
};
|
||||
const response1 = await catalog.queryEntities(request1);
|
||||
expect(response1.items).toMatchObject([
|
||||
entityFrom('AA', { uid: '1', kind: 'included' }),
|
||||
entityFrom('AA', { uid: '2', kind: 'included' }),
|
||||
]);
|
||||
expect(response1.pageInfo.nextCursor).toBeDefined();
|
||||
expect(response1.pageInfo.prevCursor).toBeUndefined();
|
||||
expect(response1.totalItems).toBe(6);
|
||||
|
||||
// second request (forward)
|
||||
const request2: QueryEntitiesCursorRequest = {
|
||||
cursor: response1.pageInfo.nextCursor!,
|
||||
limit,
|
||||
};
|
||||
const response2 = await catalog.queryEntities(request2);
|
||||
expect(response2.items).toMatchObject([
|
||||
entityFrom('AA', { uid: '4', kind: 'included' }),
|
||||
entityFrom('AA', { uid: '5', kind: 'included' }),
|
||||
]);
|
||||
expect(response2.pageInfo.nextCursor).toBeDefined();
|
||||
expect(response2.pageInfo.prevCursor).toBeDefined();
|
||||
expect(response2.totalItems).toBe(6);
|
||||
},
|
||||
);
|
||||
|
||||
it.each(databases.eachSupportedId())(
|
||||
'should paginate results without sort fields, %p',
|
||||
async databaseId => {
|
||||
@@ -1754,11 +1835,12 @@ function entityFrom(
|
||||
uid,
|
||||
namespace,
|
||||
title,
|
||||
}: { uid?: string; namespace?: string; title?: string } = {},
|
||||
kind = 'k',
|
||||
}: { uid?: string; namespace?: string; title?: string; kind?: string } = {},
|
||||
) {
|
||||
return {
|
||||
apiVersion: 'a',
|
||||
kind: 'k',
|
||||
kind,
|
||||
metadata: {
|
||||
name,
|
||||
...(!!namespace && { namespace }),
|
||||
|
||||
@@ -413,17 +413,18 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog {
|
||||
const isOrderingDescending = sortField.order === 'desc';
|
||||
|
||||
if (prevItemOrderFieldValue) {
|
||||
dbQuery.andWhere(
|
||||
'value',
|
||||
isFetchingBackwards !== isOrderingDescending ? '<' : '>',
|
||||
prevItemOrderFieldValue,
|
||||
);
|
||||
dbQuery.orWhere(function nested() {
|
||||
this.where('value', '=', prevItemOrderFieldValue).andWhere(
|
||||
'search.entity_id',
|
||||
dbQuery.andWhere(function nested() {
|
||||
this.where(
|
||||
'value',
|
||||
isFetchingBackwards !== isOrderingDescending ? '<' : '>',
|
||||
prevItemUid,
|
||||
);
|
||||
prevItemOrderFieldValue,
|
||||
)
|
||||
.orWhere('value', '=', prevItemOrderFieldValue)
|
||||
.andWhere(
|
||||
'search.entity_id',
|
||||
isFetchingBackwards !== isOrderingDescending ? '<' : '>',
|
||||
prevItemUid,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user