Skip to content

Commit cea3ee7

Browse files
hahn-kevmyieye
andauthored
Use newly created writing systems when updating the full text search table (#1789)
* create a test which simulates downloading a project from the server * when updating the entry search table, use any writing systems that were created in the same transaction/SaveChanges --------- Co-authored-by: Tim Haasdyk <tim_haasdyk@sil.org>
1 parent 492fe8b commit cea3ee7

4 files changed

Lines changed: 77 additions & 27 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using Microsoft.Extensions.Logging;
3+
4+
namespace LcmCrdt.Tests.Data;
5+
6+
public class DownloadProjectTests : IAsyncLifetime
7+
{
8+
private readonly RegressionTestHelper _helper = new("DownloadProject");
9+
private readonly MiniLcmApiFixture _apiFixture = MiniLcmApiFixture.Create(false);
10+
11+
public async Task InitializeAsync()
12+
{
13+
await _helper.InitializeAsync();
14+
await _apiFixture.InitializeAsync();
15+
}
16+
17+
public async Task DisposeAsync()
18+
{
19+
await _helper.DisposeAsync();
20+
await _apiFixture.DisposeAsync();
21+
}
22+
23+
[Fact]
24+
public async Task CanCreateANewProjectViaSync()
25+
{
26+
var remoteModel = _helper.Services.GetRequiredService<DataModel>();
27+
await _apiFixture.DataModel.SyncWith(remoteModel);
28+
}
29+
}

backend/FwLite/LcmCrdt.Tests/MiniLcmApiFixture.cs

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace LcmCrdt.Tests;
1111

1212
public class MiniLcmApiFixture : IAsyncLifetime
1313
{
14+
private readonly bool _seedWs = true;
1415
private AsyncServiceScope _services;
1516
private LcmCrdtDbContext? _crdtDbContext;
1617
public CrdtMiniLcmApi Api => (CrdtMiniLcmApi)_services.ServiceProvider.GetRequiredService<IMiniLcmApi>();
@@ -22,10 +23,21 @@ public T GetService<T>() where T : notnull
2223
return _services.ServiceProvider.GetRequiredService<T>();
2324
}
2425

26+
//must have an empty constructor for xunit
2527
public MiniLcmApiFixture()
2628
{
2729
}
2830

31+
public static MiniLcmApiFixture Create(bool seedWs = true)
32+
{
33+
return new MiniLcmApiFixture(seedWs);
34+
}
35+
36+
private MiniLcmApiFixture(bool seedWs = true)
37+
{
38+
_seedWs = seedWs;
39+
}
40+
2941
public async Task InitializeAsync()
3042
{
3143
var db = ":memory:";
@@ -53,26 +65,28 @@ public async Task InitializeAsync()
5365
await CrdtProjectsService.InitProjectDb(_crdtDbContext,
5466
new ProjectData("Sena 3", "sena-3", Guid.NewGuid(), null, Guid.NewGuid()));
5567
await _services.ServiceProvider.GetRequiredService<CurrentProjectService>().RefreshProjectData();
56-
57-
await Api.CreateWritingSystem(new WritingSystem()
58-
{
59-
Id = Guid.NewGuid(),
60-
WsId = "en",
61-
Name = "English",
62-
Abbreviation = "en",
63-
Font = "Arial",
64-
Exemplars = ["a", "b"],
65-
Type = WritingSystemType.Vernacular
66-
});
67-
await Api.CreateWritingSystem(new WritingSystem()
68+
if (_seedWs)
6869
{
69-
Id = Guid.NewGuid(),
70-
WsId = "en",
71-
Name = "English",
72-
Abbreviation = "en",
73-
Font = "Arial",
74-
Type = WritingSystemType.Analysis
75-
});
70+
await Api.CreateWritingSystem(new WritingSystem()
71+
{
72+
Id = Guid.NewGuid(),
73+
WsId = "en",
74+
Name = "English",
75+
Abbreviation = "en",
76+
Font = "Arial",
77+
Exemplars = ["a", "b"],
78+
Type = WritingSystemType.Vernacular
79+
});
80+
await Api.CreateWritingSystem(new WritingSystem()
81+
{
82+
Id = Guid.NewGuid(),
83+
WsId = "en",
84+
Name = "English",
85+
Abbreviation = "en",
86+
Font = "Arial",
87+
Type = WritingSystemType.Analysis
88+
});
89+
}
7690
}
7791

7892
ITestOutputHelper? _outputHelper;

backend/FwLite/LcmCrdt/FullTextSearch/EntrySearchService.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,16 @@ public async Task UpdateEntrySearchTable(Entry entry)
144144

145145
public async Task UpdateEntrySearchTable(IEnumerable<Entry> entries)
146146
{
147-
await UpdateEntrySearchTable(entries, dbContext);
147+
await UpdateEntrySearchTable(entries, [], dbContext);
148148
}
149149

150-
public static async Task UpdateEntrySearchTable(IEnumerable<Entry> entries, LcmCrdtDbContext dbContext)
150+
public static async Task UpdateEntrySearchTable(IEnumerable<Entry> entries, IEnumerable<WritingSystem> newWritingSystems, LcmCrdtDbContext dbContext)
151151
{
152-
var writingSystems = await dbContext.WritingSystems.OrderBy(ws => ws.Order).ToArrayAsync();
152+
WritingSystem[] writingSystems = [
153+
..dbContext.WritingSystems,
154+
..newWritingSystems
155+
];
156+
Array.Sort(writingSystems, (ws1, ws2) => ws1.Order.CompareTo(ws2.Order));
153157
await dbContext.GetTable<EntrySearchRecord>()
154158
.BulkCopyAsync(entries.Select(entry => ToEntrySearchRecord(entry, writingSystems)));
155159
}

backend/FwLite/LcmCrdt/FullTextSearch/UpdateEntrySearchTableInterceptor.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ private async Task UpdateSearchTableOnSave(DbContext? dbContext)
2929
{
3030
if (dbContext is null) return;
3131
List<Entry> toUpdate = [];
32+
var newWritingSystems = dbContext.ChangeTracker.Entries()
33+
.Where(e => e.Entity is WritingSystem && e.State == EntityState.Added)
34+
.Select(e => (WritingSystem)e.Entity).ToList();
3235
foreach (var group in dbContext.ChangeTracker.Entries()
3336
.Where(e => e is { State: EntityState.Added or EntityState.Modified, Entity: Entry or Sense })
3437
.GroupBy(e =>
@@ -42,13 +45,13 @@ private async Task UpdateSearchTableOnSave(DbContext? dbContext)
4245
};
4346
}))
4447
{
45-
toUpdate.Add(await ForUpdate(group, dbContext));
48+
toUpdate.Add(await ForUpdate(group, group.Key, dbContext));
4649
}
4750
if (toUpdate is []) return;
48-
await EntrySearchService.UpdateEntrySearchTable(toUpdate, (LcmCrdtDbContext)dbContext);
51+
await EntrySearchService.UpdateEntrySearchTable(toUpdate, newWritingSystems, (LcmCrdtDbContext)dbContext);
4952
}
5053

51-
private async Task<Entry> ForUpdate(IGrouping<Guid, EntityEntry> group, DbContext dbContext)
54+
private async Task<Entry> ForUpdate(IEnumerable<EntityEntry> group, Guid entryId, DbContext dbContext)
5255
{
5356
var entities = group.ToArray();
5457
//scope created so the entry variables don't collide
@@ -61,11 +64,11 @@ private async Task<Entry> ForUpdate(IGrouping<Guid, EntityEntry> group, DbContex
6164

6265
var fullEntry = await dbContext.Set<Entry>()
6366
.Include(e => e.Senses)
64-
.FirstOrDefaultAsync(e => e.Id == group.Key);
67+
.FirstOrDefaultAsync(e => e.Id == entryId);
6568
if (fullEntry is null)
6669
{
6770
//null when a new entry is added along with some senses
68-
fullEntry = new Entry() { Id = group.Key };
71+
fullEntry = new Entry() { Id = entryId };
6972
}
7073

7174
foreach (var entity in entities)

0 commit comments

Comments
 (0)