Skip to content

Commit 0fbc8a4

Browse files
myieyeclaude
andcommitted
Tolerate complex form parent already deleted during FwData sync
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent ff6ac34 commit 0fbc8a4

2 files changed

Lines changed: 23 additions & 1 deletion

File tree

backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1093,7 +1093,8 @@ public Task DeleteComplexFormComponent(ComplexFormComponent complexFormComponent
10931093
Cache.ServiceLocator.ActionHandler,
10941094
() =>
10951095
{
1096-
var lexEntry = EntriesRepository.GetObject(complexFormComponent.ComplexFormEntryId);
1096+
//complex form entry has been deleted, so this component relationship is gone already
1097+
if (!EntriesRepository.TryGetObject(complexFormComponent.ComplexFormEntryId, out var lexEntry)) return;
10971098
RemoveComplexFormComponent(lexEntry, complexFormComponent);
10981099
});
10991100
return Task.CompletedTask;

backend/FwLite/FwLiteProjectSync.Tests/EntrySyncTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,27 @@ public async Task FwDataApiDoesNotUpdateMorphType()
168168
actual.Should().NotBeNull();
169169
actual.MorphType.Should().Be(MorphTypeKind.BoundStem);
170170
}
171+
172+
[Fact]
173+
public async Task SyncFull_RemovingComplexFormWhoseParentWasDeleted_DoesNotThrow()
174+
{
175+
var component = await Api.CreateEntry(new() { Id = Guid.NewGuid(), LexemeForm = { { "en", "component" } } });
176+
var complexForm = new Entry { Id = Guid.NewGuid(), LexemeForm = { { "en", "complexForm" } } };
177+
complexForm.Components = [ComplexFormComponent.FromEntries(complexForm, component)];
178+
await Api.CreateEntry(complexForm);
179+
180+
var before = await Api.GetEntry(component.Id);
181+
before!.ComplexForms.Should().ContainSingle();
182+
183+
// Deleting the parent already drops the relationship; the sync then redundantly removes it from the surviving component, which used to throw because the parent was gone.
184+
await Api.DeleteEntry(complexForm.Id);
185+
var after = before.Copy();
186+
after.ComplexForms.Clear();
187+
188+
await EntrySync.SyncFull(before, after, Api);
189+
190+
(await Api.GetEntry(component.Id)).Should().NotBeNull();
191+
}
171192
}
172193

173194
public abstract class EntrySyncTestsBase(ExtraWritingSystemsSyncFixture fixture) : IClassFixture<ExtraWritingSystemsSyncFixture>, IAsyncLifetime

0 commit comments

Comments
 (0)