Merge pull request #25170 from backstage/freben/location-by-entity
fix getLocationByEntity
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user