fix batch fetch by ref with filtering

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
Fredrik Adelöw
2023-02-25 11:43:07 +01:00
parent 107ae5220e
commit f093ce83d5
4 changed files with 70 additions and 5 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
Fix a bug where the batch fetch by ref endpoint did not work in conjunction with filtering (e.g. if authorization was enabled).
+3 -1
View File
@@ -98,7 +98,9 @@ export interface EntitiesBatchRequest {
*/
entityRefs: string[];
/**
* Any additional filters to apply in the selection of the entities.
* Any additional filters to apply in the selection of the entities. Entities
* that do not match the filter result in a null entry in the response, as if
* they did not exist.
*/
filter?: EntityFilter;
/**
@@ -87,6 +87,9 @@ describe('DefaultEntitiesCatalog', () => {
});
}
const search = await buildEntitySearch(id, entity);
await knex<DbSearchRow>('search').insert(search);
return id;
}
@@ -721,6 +724,51 @@ describe('DefaultEntitiesCatalog', () => {
},
60_000,
);
it.each(databases.eachSupportedId())(
'queries for entities by ref, including filtering, %p',
async databaseId => {
await createDatabase(databaseId);
await addEntity(
{
apiVersion: 'a',
kind: 'k',
metadata: { name: 'one' },
spec: {},
relations: [],
},
[],
);
await addEntity(
{
apiVersion: 'a',
kind: 'k',
metadata: { name: 'two' },
spec: { owner: 'me' },
relations: [],
},
[],
);
const catalog = new DefaultEntitiesCatalog({
database: knex,
logger: getVoidLogger(),
stitcher,
});
const { items } = await catalog.entitiesBatch({
entityRefs: ['k:default/two', 'k:default/one'],
filter: { key: 'spec.owner', values: ['me'] },
});
expect(items.map(e => e && stringifyEntityRef(e))).toEqual([
'k:default/two',
null,
]);
},
60_000,
);
});
describe('queryEntities', () => {
@@ -309,17 +309,27 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog {
for (const chunk of lodashChunk(request.entityRefs, 200)) {
let query = this.database<DbFinalEntitiesRow>('final_entities')
.innerJoin<DbRefreshStateRow>('refresh_state', {
'refresh_state.entity_id': 'final_entities.entity_id',
})
.innerJoin<DbRefreshStateRow>(
'refresh_state',
'refresh_state.entity_id',
'final_entities.entity_id',
)
.select({
entityRef: 'refresh_state.entity_ref',
entity: 'final_entities.final_entity',
})
.whereIn('refresh_state.entity_ref', chunk);
if (request?.filter) {
query = parseFilter(request.filter, query, this.database);
query = parseFilter(
request.filter,
query,
this.database,
false,
'refresh_state.entity_id',
);
}
for (const row of await query) {
lookup.set(row.entityRef, row.entity ? JSON.parse(row.entity) : null);
}