Skip to content

Commit 1ac7462

Browse files
authored
Unify behavior of adding and updating projected entities (#58)
* Add failing tests demonstrating inconsistency of add vs update * Tweak work-antonym relationship * Prevent persisting an Antonym that does not match AntonymId * Stop marking whole entity graph as added * PR feedback * Rename AddAntonymReferenceChange, because it sets a single object. It does not add to a collection. * Fix test logic
1 parent 0a9068e commit 1ac7462

File tree

7 files changed

+307
-20
lines changed

7 files changed

+307
-20
lines changed

src/SIL.Harmony.Sample/Changes/NewWordChange.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ public class NewWordChange(Guid entityId, string text, string? note = null, Guid
1212

1313
public override async ValueTask<Word> NewEntity(Commit commit, IChangeContext context)
1414
{
15-
var antonymShouldBeNull = AntonymId is null || (await context.IsObjectDeleted(AntonymId.Value));
16-
return (new Word { Text = Text, Note = Note, Id = EntityId, AntonymId = antonymShouldBeNull ? null : AntonymId });
15+
var antonym = AntonymId is null ? null : await context.GetCurrent<Word>(AntonymId.Value);
16+
antonym = antonym is { DeletedAt: null } ? antonym : null;
17+
return new Word { Text = Text, Note = Note, Id = EntityId, Antonym = antonym, AntonymId = antonym?.Id };
1718
}
1819
}

src/SIL.Harmony.Sample/Changes/AddAntonymReferenceChange.cs renamed to src/SIL.Harmony.Sample/Changes/SetAntonymReferenceChange.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,22 @@
44

55
namespace SIL.Harmony.Sample.Changes;
66

7-
public class AddAntonymReferenceChange(Guid entityId, Guid antonymId)
8-
: EditChange<Word>(entityId), ISelfNamedType<AddAntonymReferenceChange>
7+
public class SetAntonymReferenceChange(Guid entityId, Guid antonymId, bool setObject = true)
8+
: EditChange<Word>(entityId), ISelfNamedType<SetAntonymReferenceChange>
99
{
1010
public Guid AntonymId { get; set; } = antonymId;
11+
public bool SetObject { get; set; } = setObject;
1112

1213
public override async ValueTask ApplyChange(Word entity, IChangeContext context)
1314
{
1415
//if the word being referenced was deleted before this change was applied (could happen after a sync)
1516
//then we don't want to apply the change
1617
//if the change was already applied,
1718
//then this reference is removed via Word.RemoveReference after the change which deletes the Antonym, see SnapshotWorker.MarkDeleted
18-
if (!await context.IsObjectDeleted(AntonymId))
19-
entity.AntonymId = AntonymId;
19+
var antonym = await context.GetCurrent<Word>(AntonymId);
20+
if (antonym is null or { DeletedAt: not null }) return;
21+
22+
entity.Antonym = SetObject ? antonym : null;
23+
entity.AntonymId = AntonymId;
2024
}
2125
}

src/SIL.Harmony.Sample/CrdtSampleKernel.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public static IServiceCollection AddCrdtDataSample(this IServiceCollection servi
4343
.Add<EditExampleChange>()
4444
.Add<SetWordTextChange>()
4545
.Add<SetWordNoteChange>()
46-
.Add<AddAntonymReferenceChange>()
46+
.Add<SetAntonymReferenceChange>()
4747
.Add<AddWordImageChange>()
4848
.Add<SetOrderChange<Definition>>()
4949
.Add<SetDefinitionPartOfSpeechChange>()
@@ -60,6 +60,10 @@ public static IServiceCollection AddCrdtDataSample(this IServiceCollection servi
6060
builder.HasMany(w => w.Tags)
6161
.WithMany()
6262
.UsingEntity<WordTag>();
63+
builder.HasOne((w) => w.Antonym)
64+
.WithMany()
65+
.HasForeignKey(w => w.AntonymId)
66+
.OnDelete(DeleteBehavior.SetNull);
6367
})
6468
.Add<Definition>(builder =>
6569
{
@@ -81,4 +85,4 @@ public static IServiceCollection AddCrdtDataSample(this IServiceCollection servi
8185
});
8286
return services;
8387
}
84-
}
88+
}

src/SIL.Harmony.Sample/Models/Word.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public class Word : IObjectBase<Word>
99

1010
public Guid Id { get; init; }
1111
public DateTimeOffset? DeletedAt { get; set; }
12+
public Word? Antonym { get; set; }
1213
public Guid? AntonymId { get; set; }
1314
public Guid? ImageResourceId { get; set; }
1415
public List<Tag> Tags { get; set; } = new();
@@ -26,7 +27,11 @@ IEnumerable<Guid> Refs()
2627

2728
public void RemoveReference(Guid id, CommitBase commit)
2829
{
29-
if (AntonymId == id) AntonymId = null;
30+
if (AntonymId == id)
31+
{
32+
AntonymId = null;
33+
Antonym = null;
34+
}
3035
}
3136

3237
public IObjectBase Copy()
@@ -36,6 +41,7 @@ public IObjectBase Copy()
3641
Id = Id,
3742
Text = Text,
3843
Note = Note,
44+
Antonym = Antonym,
3945
AntonymId = AntonymId,
4046
DeletedAt = DeletedAt,
4147
ImageResourceId = ImageResourceId,
@@ -46,7 +52,7 @@ public IObjectBase Copy()
4652
public override string ToString()
4753
{
4854
return
49-
$"{nameof(Text)}: {Text}, {nameof(Id)}: {Id}, {nameof(Note)}: {Note}, {nameof(DeletedAt)}: {DeletedAt}, {nameof(AntonymId)}: {AntonymId}, {nameof(ImageResourceId)}: {ImageResourceId}" +
55+
$"{nameof(Text)}: {Text}, {nameof(Id)}: {Id}, {nameof(Note)}: {Note}, {nameof(DeletedAt)}: {DeletedAt}, {nameof(Antonym)}: {Antonym}, {nameof(AntonymId)}: {AntonymId}, {nameof(ImageResourceId)}: {ImageResourceId}" +
5056
$", {nameof(Tags)}: {string.Join(", ", Tags.Select(t => t.Text))}";
5157
}
52-
}
58+
}

0 commit comments

Comments
 (0)