Merge pull request #29368 from tylerd-canva/catalog-backend-sortField-distinct

Fix for duplicate results in queryEntities when using an orderField
This commit is contained in:
Fredrik Adelöw
2025-04-08 10:42:21 +02:00
committed by GitHub
3 changed files with 87 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
Fix for duplicate results in `queryEntities` when providing an `orderField` parameter
@@ -1970,6 +1970,87 @@ describe('DefaultEntitiesCatalog', () => {
).resolves.toEqual(['BB']);
},
);
it.each(databases.eachSupportedId())(
'should not return duplicate entities when using orderField, %p',
async databaseId => {
await createDatabase(databaseId);
// Create a few test entities with different names to sort by
const entities = [
{
apiVersion: 'a',
kind: 'k',
metadata: {
name: 'a-entity',
title: 'A Test Entity',
uid: 'uid-a',
},
spec: {},
},
{
apiVersion: 'a',
kind: 'k',
metadata: {
name: 'b-entity',
title: 'B Test Entity',
uid: 'uid-b',
},
spec: {},
},
{
apiVersion: 'a',
kind: 'k',
metadata: {
name: 'c-entity',
title: 'C Test Entity',
uid: 'uid-c',
},
spec: {},
},
];
await Promise.all(entities.map(e => addEntityToSearch(e)));
// Manually insert duplicate search entries for the same entities
// I'm not sure exactly how this happens but I have seen it in the real world
await knex<DbSearchRow>('search').insert([
{
entity_id: 'uid-a',
key: 'metadata.title',
value: 'a test entity',
original_value: 'A Test Entity',
},
{
entity_id: 'uid-b',
key: 'metadata.title',
value: 'b test entity',
original_value: 'B Test Entity',
},
]);
const catalog = new DefaultEntitiesCatalog({
database: knex,
logger: mockServices.logger.mock(),
stitcher,
});
// Query with orderField
const response = await catalog.queryEntities({
orderFields: [{ field: 'metadata.title', order: 'asc' }],
credentials: mockCredentials.none(),
});
const resultEntities = entitiesResponseToObjects(response.items);
// Ensure we get exactly 3 entities back, sorted, with no duplicates
expect(resultEntities.map(e => e!.metadata.name)).toEqual([
'a-entity',
'b-entity',
'c-entity',
]);
},
);
});
describe('removeEntityByUid', () => {
@@ -285,6 +285,7 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog {
if (sortField) {
inner
.distinct()
.leftOuterJoin('search', qb =>
qb
.on('search.entity_id', 'final_entities.entity_id')