Skip to content

Commit 58041f2

Browse files
authored
Constraint violation issue (#1629)
* make a helper script to download sqlite db files * update LcmDebugger with a fake sync source to facilitate debugging issues * update Harmony to fix constraint violation issue on sync
1 parent a19f124 commit 58041f2

File tree

5 files changed

+105
-28
lines changed

5 files changed

+105
-28
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using System.Text.Json;
3+
using SIL.Harmony;
4+
using SIL.Harmony.Changes;
5+
using SIL.Harmony.Core;
6+
7+
namespace LcmDebugger;
8+
9+
internal class FakeCommit : Commit
10+
{
11+
[SetsRequiredMembers]
12+
public FakeCommit(Guid id, HybridDateTime hybridDateTime) : base(id, "", NullParentHash, hybridDateTime)
13+
{
14+
HybridDateTime = hybridDateTime;
15+
SetParentHash(NullParentHash);
16+
}
17+
}
18+
19+
/// <summary>
20+
///
21+
/// </summary>
22+
/// <param name="commits"></param>
23+
/// <param name="currentSyncState">when null it will just report to the client that it has the same sync state, that way the client doesn't try to push any changes</param>
24+
public class FakeSyncSource(Commit[] commits, SyncState? currentSyncState = null) : ISyncable
25+
{
26+
public static FakeSyncSource FromSingleChangeJson(
27+
[StringSyntax(StringSyntaxAttribute.Json)] string json,
28+
DateTimeOffset commitDate,
29+
JsonSerializerOptions? options = null)
30+
{
31+
var change = JsonSerializer.Deserialize<ChangeEntity<IChange>>(json, options);
32+
ArgumentNullException.ThrowIfNull(change);
33+
return new FakeSyncSource([new FakeCommit(change.CommitId, new HybridDateTime(commitDate, 0))
34+
{
35+
ClientId = Guid.NewGuid(),
36+
ChangeEntities = [change]
37+
}]);
38+
}
39+
40+
public static FakeSyncSource FromJsonFile(string path, JsonSerializerOptions? options = null)
41+
{
42+
var changes = JsonSerializer.Deserialize<ChangesResult<Commit>>(File.OpenRead(path), options);
43+
ArgumentNullException.ThrowIfNull(changes);
44+
return new FakeSyncSource(changes.MissingFromClient, changes.ServerSyncState);
45+
}
46+
47+
public Task AddRangeFromSync(IEnumerable<Commit> commits)
48+
{
49+
return Task.CompletedTask;
50+
}
51+
52+
public Task<SyncState> GetSyncState()
53+
{
54+
return Task.FromResult(new SyncState([]));
55+
}
56+
57+
public Task<ChangesResult<Commit>> GetChanges(SyncState otherHeads)
58+
{
59+
return Task.FromResult(new ChangesResult<Commit>(commits, currentSyncState ?? otherHeads));
60+
}
61+
62+
public Task<SyncResults> SyncWith(ISyncable remoteModel)
63+
{
64+
throw new NotImplementedException();
65+
}
66+
67+
public Task SyncMany(ISyncable[] remotes)
68+
{
69+
throw new NotImplementedException();
70+
}
71+
72+
public ValueTask<bool> ShouldSync()
73+
{
74+
return new ValueTask<bool>(true);
75+
}
76+
}

backend/FwLite/LcmDebugger/LcmDebugger.csproj

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
<OutputType>Exe</OutputType>
44
</PropertyGroup>
55
<ItemGroup>
6-
<ProjectReference Include="..\..\FwLite\FwDataMiniLcmBridge\FwDataMiniLcmBridge.csproj" />
7-
<ProjectReference Include="..\..\FwLite\FwLiteProjectSync\FwLiteProjectSync.csproj" />
6+
<ProjectReference Include="..\..\FwLite\FwDataMiniLcmBridge\FwDataMiniLcmBridge.csproj"/>
7+
<ProjectReference Include="..\..\FwLite\FwLiteProjectSync\FwLiteProjectSync.csproj"/>
8+
<ProjectReference Include="..\FwLiteShared\FwLiteShared.csproj"/>
9+
<ProjectReference Include="..\LcmCrdt\LcmCrdt.csproj"/>
810
</ItemGroup>
911
<ItemGroup>
10-
<PackageReference Include="Microsoft.Extensions.Hosting" />
12+
<PackageReference Include="Microsoft.Extensions.Hosting"/>
1113
</ItemGroup>
1214
</Project>

backend/FwLite/LcmDebugger/Program.cs

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44
using FwDataMiniLcmBridge;
55
using FwLiteProjectSync;
66
using LcmCrdt;
7-
using LexCore.Exceptions;
7+
using LcmDebugger;
88
using Microsoft.Extensions.DependencyInjection;
99
using Microsoft.Extensions.Hosting;
10+
using Microsoft.Extensions.Logging;
1011
using Microsoft.Extensions.Options;
12+
using MiniLcm.Exceptions;
1113
using Refit;
1214
using SIL.Harmony;
1315
using SIL.Harmony.Core;
14-
using Microsoft.Extensions.Logging;
1516

1617
var builder = Host.CreateApplicationBuilder();
1718
//slows down import to log all sql.
@@ -22,31 +23,19 @@
2223

2324
using var app = builder.Build();
2425

25-
var fieldWorksProjectList = app.Services.GetRequiredService<FieldWorksProjectList>();
26-
var fwDataProject = fieldWorksProjectList.GetProject("petit-test-train-flex") ?? throw new InvalidOperationException("Could not find project");
27-
28-
var importService = app.Services.GetRequiredService<MiniLcmImport>();
29-
await importService.Import(fwDataProject);
3026
await using var scope = app.Services.CreateAsyncScope();
3127

3228
var crdtProjectsService = app.Services.GetRequiredService<CrdtProjectsService>();
33-
var crdtProject = crdtProjectsService.GetProject(fwDataProject.Name);
34-
if (crdtProject is null) throw new NotFoundException("project", "crdt");
35-
var crdtApi = await crdtProjectsService.OpenProject(crdtProject, scope.ServiceProvider);
36-
var dataModel = scope.ServiceProvider.GetRequiredService<DataModel>();
37-
JsonSerializerOptions options = new(JsonSerializerDefaults.Web)
29+
var crdtApi = await crdtProjectsService.OpenProject(
30+
new CrdtProject("test", "sbe-flex - Copy.sqlite"),
31+
scope.ServiceProvider);
32+
var dbContext = scope.ServiceProvider.GetRequiredService<LcmCrdtDbContext>();
33+
var jsonOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web)
3834
{
3935
TypeInfoResolver = scope.ServiceProvider.GetRequiredService<IOptions<CrdtConfig>>().Value
4036
.MakeLcmCrdtExternalJsonTypeResolver()
4137
};
42-
var (commits, _) = await dataModel.GetChanges(new SyncState([]));
43-
await using var f = File.Create("commits.json");
44-
await JsonSerializer.SerializeAsync(f, commits, options);
45-
46-
var fwDataFactory = app.Services.GetRequiredService<FwDataFactory>();
47-
// var miniLcmApi = fwDataFactory.GetFwDataMiniLcmApi(fwDataProject, false);
48-
// var entries = await miniLcmApi.GetEntries().ToArrayAsync();
49-
// var entries = miniLcmApi.GetEntries(new(Filter: new() { GridifyFilter = "LexemeForm[sbe]=ta" })).ToArrayAsync();
50-
// var entry = Utils.GetLexEntry(app.Services, fwDataProject, new Guid("{018d71a9-12c2-4129-be8a-35fe246afda2}"));
51-
52-
fwDataFactory.Dispose();
38+
await using var transaction = await dbContext.Database.BeginTransactionAsync();
39+
var dataModel = scope.ServiceProvider.GetRequiredService<DataModel>();
40+
await dataModel.SyncWith(FakeSyncSource.FromJsonFile("changes.json", jsonOptions));
41+
await transaction.RollbackAsync();

deployment/Taskfile.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,17 @@ tasks:
8888
prod-db-forward:
8989
cmds:
9090
- kubectl port-forward service/db 5435:5432 -n languagedepot --context aws-prod
91-
91+
download-sqlite-file:
92+
desc: 'example: `task download-sqlite-file id="<project id here>" code="<project code here>" context="dallas-stage"` the namespace can also be set'
93+
requires:
94+
vars: [id, code]
95+
vars:
96+
context: '{{.context| default "docker-desktop"}}'
97+
namespace: '{{.namespace| default "languagedepot"}}'
98+
pod:
99+
sh: kubectl get pods -l app=fw-headless -o jsonpath='{.items[0].metadata.name}' --context {{.context}} --namespace {{.namespace}}
100+
cmds:
101+
- kubectl cp {{.pod}}:/var/lib/fw-headless/projects/{{.code}}-{{.id}}/crdt.sqlite ./{{.code}}.sqlite --context {{.context}} --namespace {{.namespace}}
92102

93103
diff-staging:
94104
dir: ./staging

0 commit comments

Comments
 (0)