Merge pull request #25170 from backstage/freben/location-by-entity

fix getLocationByEntity
This commit is contained in:
Ben Lambert
2024-06-12 21:41:42 +02:00
committed by GitHub
3 changed files with 78 additions and 12 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
Fix bug in `getLocationByEntity`
@@ -15,8 +15,15 @@
*/
import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils';
import { ANNOTATION_ORIGIN_LOCATION } from '@backstage/catalog-model';
import { v4 as uuid } from 'uuid';
import { applyDatabaseMigrations } from '../../database/migrations';
import {
DbFinalEntitiesRow,
DbLocationsRow,
DbRefreshStateRow,
DbSearchRow,
} from '../../database/tables';
import { DefaultLocationStore } from './DefaultLocationStore';
jest.setTimeout(60_000);
@@ -30,7 +37,7 @@ describe('DefaultLocationStore', () => {
const connection = { applyMutation: jest.fn(), refresh: jest.fn() };
const store = new DefaultLocationStore(knex);
await store.connect(connection);
return { store, connection };
return { store, connection, knex };
}
it.each(databases.eachSupportedId())(
@@ -172,4 +179,59 @@ describe('DefaultLocationStore', () => {
},
);
});
describe('getLocationByEntity', () => {
it.each(databases.eachSupportedId())(
'loads correctly, %p',
async databaseId => {
const { store, knex } = await createLocationStore(databaseId);
const entityId = uuid();
const locationId = uuid();
await knex<DbRefreshStateRow>('refresh_state').insert({
entity_id: entityId,
entity_ref: 'k:ns/n',
unprocessed_entity: '{}',
errors: '[]',
next_update_at: new Date(),
last_discovery_at: new Date(),
});
await knex<DbFinalEntitiesRow>('final_entities').insert({
entity_id: entityId,
final_entity: '{}',
hash: 'hash',
last_updated_at: new Date(),
stitch_ticket: '',
});
await knex<DbSearchRow>('search').insert({
entity_id: entityId,
key: `metadata.annotations.${ANNOTATION_ORIGIN_LOCATION}`,
value: `url:https://example.com`,
});
await knex<DbLocationsRow>('locations').insert({
id: locationId,
type: 'url',
target: 'https://example.com',
});
await expect(
store.getLocationByEntity({ kind: 'k', namespace: 'ns', name: 'n' }),
).resolves.toEqual({
id: locationId,
type: 'url',
target: 'https://example.com',
});
await expect(
store.getLocationByEntity({ kind: 'k', namespace: 'ns', name: 'n2' }),
).rejects.toMatchInlineSnapshot(
`[NotFoundError: found no entity for ref k:ns/n2]`,
);
},
);
});
});
@@ -124,41 +124,40 @@ export class DefaultLocationStore implements LocationStore, EntityProvider {
async getLocationByEntity(entityRef: CompoundEntityRef): Promise<Location> {
const entityRefString = stringifyEntityRef(entityRef);
const [entity] = await this.db<DbRefreshStateRow>('refresh_state')
const [entityRow] = await this.db<DbRefreshStateRow>('refresh_state')
.where({ entity_ref: entityRefString })
.select('entity_id')
.limit(1);
if (!entity) {
if (!entityRow) {
throw new NotFoundError(`found no entity for ref ${entityRefString}`);
}
const [locationKeyValue] = await this.db<DbSearchRow>('search')
const [searchRow] = await this.db<DbSearchRow>('search')
.where({
entity_id: entity.entity_id,
entity_id: entityRow.entity_id,
key: `metadata.annotations.${ANNOTATION_ORIGIN_LOCATION}`,
})
.select('value')
.limit(1);
if (!locationKeyValue) {
if (!searchRow?.value) {
throw new NotFoundError(
`found no origin annotation for ref ${entityRefString}`,
);
}
const { type, target } = parseLocationRef(entityRefString);
// const kind, target = split[0], split[1];
const [location] = await this.db<DbLocationsRow>('locations')
const { type, target } = parseLocationRef(searchRow.value);
const [locationRow] = await this.db<DbLocationsRow>('locations')
.where({ type, target })
.select()
.limit(1);
// select * from locations where type = 'split(prev)[0]'
if (!location) {
if (!locationRow) {
throw new NotFoundError(
`Found no location with type ${type} and target ${target}`,
);
}
return location;
return locationRow;
}
private get connection(): EntityProviderConnection {