ent
ent copied to clipboard
Delete actions do not call `removeInboundEdge` on field edges
Ents with a field edge get that edge created automatically (and removed automatically when unset) through their builder. This is done in the getEditedFields
method of the builder, as defined in the builder template (specifically line 291):
https://github.com/lolopinto/ent/blob/47372cfd6c0376753c805a2249ed3428866077b7/internal/tscode/builder.tmpl#L276-L295
The generated code ends up looking something like this:
private async getEditedFields(): Promise<Map<string, any>> {
const input = this.input;
const result = new Map<string, any>();
const addField = function (key: string, value: any) {
if (value !== undefined) {
result.set(key, value);
}
};
addField('competitionEventID', input.competitionEventId);
if (input.competitionEventId !== undefined) {
if (input.competitionEventId) {
this.orchestrator.addInboundEdge(
input.competitionEventId,
EdgeType.CompetitionEventToEntries,
NodeType.CompetitionEvent,
);
}
if (
this.existingEnt &&
this.existingEnt.competitionEventId &&
this.existingEnt.competitionEventId !== input.competitionEventId
) {
this.orchestrator.removeInboundEdge(
this.existingEnt.competitionEventId,
EdgeType.CompetitionEventToEntries,
);
}
}
return $result;
}
This method is passed into the Orchestrator in the constructor of the builder like this:
this.orchestrator = new Orchestrator({
viewer,
operation: this.operation,
tableName: 'generic_competition_entries',
key: 'id',
loaderOptions: GenericCompetitionEntry.loaderOptions(),
builder: this,
action,
schema,
editedFields: () => this.getEditedFields.apply(this), // <--- Right here
updateInput,
fieldInfo: genericCompetitionEntryLoaderInfo.fieldInfo,
...opts,
});
This works great for insert/update operations, but fails with delete actions. This is because the delete action always defines getInput
as
getInput(): GenericCompetitionEntryInput {
return {};
}
So the checks in getEditedFields
always fail. I think the simplest way to get around this is to just add a check for this.operation === WriteOperation.Delete
to always call removeInboundEdge
even when input
is empty. Thus changing the call to look like this:
private async getEditedFields(): Promise<Map<string, any>> {
const input = this.input;
const result = new Map<string, any>();
const addField = function (key: string, value: any) {
if (value !== undefined) {
result.set(key, value);
}
};
addField('competitionEventID', input.competitionEventId);
- if (input.competitionEventId !== undefined) {
+ if (
+ input.competitionEventId !== undefined ||
+ this.operation === WriteOperation.Delete
+ ) {
if (input.competitionEventId) {
this.orchestrator.addInboundEdge(
input.competitionEventId,
EdgeType.CompetitionEventToEntries,
NodeType.CompetitionEvent,
);
}
if (
this.existingEnt &&
this.existingEnt.competitionEventId &&
this.existingEnt.competitionEventId !== input.competitionEventId
) {
this.orchestrator.removeInboundEdge(
this.existingEnt.competitionEventId,
EdgeType.CompetitionEventToEntries,
);
}
}
return $result;
}
This bug doesn't have much effect since the ents are deleted so fetching edges doesn't return deleted ents, but when you try to do something like event.queryEntries().queryRawCount()
, that only fetches over the edge table, which will now return a bad count.