Merge pull request #8936 from backstage/freben/healer
Clear parent entity hashes on deletion, to get healing behaviors back
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Now when entities are deleted, the parent entity state is updated such that it will "heal" accidental deletes on the next refresh round.
|
||||
@@ -72,6 +72,8 @@ describe('NextEntitiesCatalog', () => {
|
||||
target_entity_ref: stringifyEntityRef(entity),
|
||||
});
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
async function addEntityToSearch(knex: Knex, entity: Entity) {
|
||||
@@ -468,4 +470,69 @@ describe('NextEntitiesCatalog', () => {
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('removeEntityByUid', () => {
|
||||
it.each(databases.eachSupportedId())(
|
||||
'also clears parent hashes',
|
||||
async databaseId => {
|
||||
const { knex } = await createDatabase(databaseId);
|
||||
|
||||
const grandparent: Entity = {
|
||||
apiVersion: 'a',
|
||||
kind: 'k',
|
||||
metadata: { name: 'grandparent' },
|
||||
spec: {},
|
||||
};
|
||||
const parent1: Entity = {
|
||||
apiVersion: 'a',
|
||||
kind: 'k',
|
||||
metadata: { name: 'parent1' },
|
||||
spec: {},
|
||||
};
|
||||
const parent2: Entity = {
|
||||
apiVersion: 'a',
|
||||
kind: 'k',
|
||||
metadata: { name: 'parent2' },
|
||||
spec: {},
|
||||
};
|
||||
const root: Entity = {
|
||||
apiVersion: 'a',
|
||||
kind: 'k',
|
||||
metadata: { name: 'root' },
|
||||
spec: {},
|
||||
};
|
||||
const unrelated: Entity = {
|
||||
apiVersion: 'a',
|
||||
kind: 'k',
|
||||
metadata: { name: 'unrelated' },
|
||||
spec: {},
|
||||
};
|
||||
|
||||
await addEntity(knex, grandparent, [{ source: 's' }]);
|
||||
await addEntity(knex, parent1, [{ entity: grandparent }]);
|
||||
await addEntity(knex, parent2, [{ entity: grandparent }]);
|
||||
const uid = await addEntity(knex, root, [
|
||||
{ entity: parent1 },
|
||||
{ entity: parent2 },
|
||||
]);
|
||||
await addEntity(knex, unrelated, []);
|
||||
await knex('refresh_state').update({ result_hash: 'not-changed' });
|
||||
|
||||
const catalog = new NextEntitiesCatalog(knex);
|
||||
await catalog.removeEntityByUid(uid);
|
||||
|
||||
await expect(
|
||||
knex
|
||||
.from('refresh_state')
|
||||
.select('entity_ref', 'result_hash')
|
||||
.orderBy('entity_ref'),
|
||||
).resolves.toEqual([
|
||||
{ entity_ref: 'k:default/grandparent', result_hash: 'not-changed' },
|
||||
{ entity_ref: 'k:default/parent1', result_hash: 'child-was-deleted' },
|
||||
{ entity_ref: 'k:default/parent2', result_hash: 'child-was-deleted' },
|
||||
{ entity_ref: 'k:default/unrelated', result_hash: 'not-changed' },
|
||||
]);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -204,6 +204,29 @@ export class NextEntitiesCatalog implements EntitiesCatalog {
|
||||
}
|
||||
|
||||
async removeEntityByUid(uid: string): Promise<void> {
|
||||
// Clear the hashed state of the immediate parents of the deleted entity.
|
||||
// This makes sure that when they get reprocessed, their output is written
|
||||
// down again. The reason for wanting to do this, is that if the user
|
||||
// deletes entities that ARE still emitted by the parent, the parent
|
||||
// processing will still generate the same output hash as always, which
|
||||
// means it'll never try to write down the children again (it assumes that
|
||||
// they already exist). This means that without the code below, the database
|
||||
// never "heals" from accidental deletes.
|
||||
await this.database<DbRefreshStateRow>('refresh_state')
|
||||
.update({
|
||||
result_hash: 'child-was-deleted',
|
||||
})
|
||||
.whereIn('entity_ref', function parents(builder) {
|
||||
return builder
|
||||
.from<DbRefreshStateRow>('refresh_state')
|
||||
.innerJoin<DbRefreshStateReferencesRow>('refresh_state_references', {
|
||||
'refresh_state_references.target_entity_ref':
|
||||
'refresh_state.entity_ref',
|
||||
})
|
||||
.where('refresh_state.entity_id', '=', uid)
|
||||
.select('refresh_state_references.source_entity_ref');
|
||||
});
|
||||
|
||||
await this.database<DbRefreshStateRow>('refresh_state')
|
||||
.where('entity_id', uid)
|
||||
.delete();
|
||||
|
||||
Reference in New Issue
Block a user