Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minilcm diff API #1181

Merged
merged 43 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
63a7a80
refactor diff code out of the sync service
hahn-kev Oct 17, 2024
f39073f
change terminiology
hahn-kev Oct 17, 2024
99a8524
write test trying to sync changes between an entrys components
hahn-kev Oct 17, 2024
0a01487
implement Component API
hahn-kev Oct 17, 2024
33eb096
implement semantic domain API
hahn-kev Oct 17, 2024
c111134
GitButler WIP Commit
gitbutler-client Oct 18, 2024
5947210
Merge branch 'develop' into Prep-diff-apis
hahn-kev Oct 21, 2024
a411b00
being making API to update an entry by simply passing it in
hahn-kev Oct 22, 2024
e03f1e7
add logging from MiniLcmApiFixture to xunit
hahn-kev Oct 22, 2024
f889baa
comment out version stuff and make a 2 entry update api for now
hahn-kev Oct 22, 2024
a4fb38c
Merge branch 'develop' into Prep-diff-apis
hahn-kev Oct 29, 2024
804c8fa
remove version from entry
hahn-kev Oct 29, 2024
2ccf0e2
fix some test bugs related to complex forms getting deleted and then …
hahn-kev Oct 29, 2024
f2c3eac
use locking to prevent a race condition from calling Project loader i…
hahn-kev Oct 29, 2024
6228935
support syncing Entry.ComplexForms in addition to Components
hahn-kev Oct 29, 2024
80fb4c3
define AddComplexFormType and RemoveComplexFormType on MiniLcmApi
hahn-kev Oct 29, 2024
90c44b4
preseed complex form types in crdt projects
hahn-kev Oct 29, 2024
be5fa9e
implement syncing entry complex form types
hahn-kev Oct 29, 2024
9d4611e
make complex form type a record
hahn-kev Oct 30, 2024
f783ca1
test creating an entry with a generated entry
hahn-kev Oct 30, 2024
f04794e
write sync tests for a generated entry, fix bugs
hahn-kev Oct 30, 2024
fb05ae7
update harmony to include the new `BeforeSaveObject` option
hahn-kev Oct 30, 2024
2a4e139
add version to miniLcm models using CrdtConfig.BeforeSaveObject
hahn-kev Oct 30, 2024
2c4119d
fix bug trying to use Commit.DateTime in a query
hahn-kev Oct 30, 2024
8d7f5a6
implement UpdateEntry(Entry entry) on FwDataMiniLcmApi, then fix bugs
hahn-kev Oct 30, 2024
356679d
remove unused fields
hahn-kev Oct 30, 2024
e402294
use the version to check for changes having been invalidated rather t…
hahn-kev Oct 30, 2024
ce07b24
minor fix suggestions
hahn-kev Oct 31, 2024
b900c5e
test CreateComplexFormComponent, fix a bug when there's more than one…
hahn-kev Oct 31, 2024
df91f0e
write test demonstrating update entry not supporting sense changes
hahn-kev Oct 31, 2024
883984e
attempt to use get at commit api when updating an entry
hahn-kev Nov 1, 2024
950f127
Merge branch 'develop' into minilcm-diff-apis
hahn-kev Nov 5, 2024
a90266c
always using DoUsingNewOrCurrentUOW as we've got a lot of recursive c…
hahn-kev Nov 5, 2024
0a8fbef
simplify basic api tests to not special case different handling of en…
hahn-kev Nov 5, 2024
9650ad5
allow defining copy which returns the correct type instead of IObject…
hahn-kev Nov 5, 2024
11054f9
change use of GetEntitySnapshotAtTime to GetAtTime
hahn-kev Nov 5, 2024
18cb5ee
exclude version from more tests
hahn-kev Nov 5, 2024
57fe76c
change UpdateEntry to use before and after instead of depending on Ve…
hahn-kev Nov 5, 2024
96c14b7
Merge branch 'develop' into minilcm-diff-apis
hahn-kev Nov 11, 2024
bb428cb
remove version property
hahn-kev Nov 11, 2024
c8e042f
fix test issue due to parts of speech and domains not being created w…
hahn-kev Nov 11, 2024
a4b97c6
Merge branch 'refs/heads/develop' into minilcm-diff-apis
hahn-kev Nov 12, 2024
9a315be
exclude Semantic domain predefined due to it always being true in fwdata
hahn-kev Nov 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions .idea/.idea.LexBox/.idea/dataSources.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using FwDataMiniLcmBridge.Tests.Fixtures;
using FwDataMiniLcmBridge.Api;
using FwDataMiniLcmBridge.Tests.Fixtures;
using MiniLcm.Models;

namespace FwDataMiniLcmBridge.Tests.MiniLcmTests;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using FwDataMiniLcmBridge.Tests.Fixtures;

namespace FwDataMiniLcmBridge.Tests.MiniLcmTests;

[Collection(ProjectLoaderFixture.Name)]
public class UpdateEntryTests(ProjectLoaderFixture fixture) : UpdateEntryTestsBase
{
protected override Task<IMiniLcmApi> NewApi()
{
return Task.FromResult<IMiniLcmApi>(fixture.NewProjectApi("update-entry-test", "en", "en"));
}
}
22 changes: 17 additions & 5 deletions backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,12 @@ public async Task<Entry> CreateEntry(Entry entry)
CreateSense(lexEntry, sense);
}

//form types should be created before components, otherwise the form type "unspecified" will be added
foreach (var complexFormType in entry.ComplexFormTypes)
{
AddComplexFormType(lexEntry, complexFormType.Id);
}

foreach (var component in entry.Components)
{
AddComplexFormComponent(lexEntry, component);
Expand All @@ -585,11 +591,6 @@ public async Task<Entry> CreateEntry(Entry entry)
var complexLexEntry = EntriesRepository.GetObject(complexForm.ComplexFormEntryId);
AddComplexFormComponent(complexLexEntry, complexForm);
}

foreach (var complexFormType in entry.ComplexFormTypes)
{
AddComplexFormType(lexEntry, complexFormType.Id);
}
});

return await GetEntry(entry.Id) ?? throw new InvalidOperationException("Entry was not created");
Expand Down Expand Up @@ -738,6 +739,17 @@ public Task<Entry> UpdateEntry(Guid id, UpdateObjectInput<Entry> update)
return Task.FromResult(FromLexEntry(lexEntry));
}

public async Task<Entry> UpdateEntry(Entry before, Entry after)
{
await Cache.DoUsingNewOrCurrentUOW("Update Entry",
"Revert entry",
async () =>
{
await EntrySync.Sync(after, before, this);
});
return await GetEntry(after.Id) ?? throw new NullReferenceException("unable to find entry with id " + after.Id);
}

public Task DeleteEntry(Guid id)
{
UndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW("Delete Entry",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace FwDataMiniLcmBridge.Api;

public class VersionInvalidException(string type, Exception? innerException = null) : Exception(
$"version of {type} is invalid, it has been changed since this version was fetched",
innerException);
20 changes: 15 additions & 5 deletions backend/FwLite/FwDataMiniLcmBridge/LcmUtils/ProjectLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class ProjectLoader(IOptions<FwDataBridgeConfig> config) : IProjectLoader
{
protected string TemplatesFolder => config.Value.TemplatesFolder;
private static bool _init;
private static readonly object _initLock = new();

public static void Init()
{
Expand All @@ -34,13 +35,22 @@ public static void Init()
return;
}

Icu.Wrapper.Init();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
lock (_initLock)
{
Debug.Assert(Icu.Wrapper.IcuVersion == "72.1.0.3");
if (_init)
{
return;
}

Icu.Wrapper.Init();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Debug.Assert(Icu.Wrapper.IcuVersion == "72.1.0.3");
}

Sldr.Initialize();
_init = true;
}
Sldr.Initialize();
_init = true;
}

public virtual LcmCache LoadCache(FwDataProject project)
Expand Down
108 changes: 108 additions & 0 deletions backend/FwLite/FwLiteProjectSync.Tests/EntrySyncTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using FluentAssertions.Equivalency;
using FwLiteProjectSync.Tests.Fixtures;
using MiniLcm.Models;
using MiniLcm.SyncHelpers;
using MiniLcm.Tests.AutoFakerHelpers;
using Soenneker.Utils.AutoBogus;

namespace FwLiteProjectSync.Tests;

public class EntrySyncTests : IClassFixture<SyncFixture>
{
private readonly AutoFaker _autoFaker = new(builder => builder.WithOverride(new MultiStringOverride()).WithOverride(new ObjectWithIdOverride()));
public EntrySyncTests(SyncFixture fixture)
{
_fixture = fixture;
}

private readonly SyncFixture _fixture;

[Fact]
public async Task CanSyncRandomEntries()
{
var createdEntry = await _fixture.CrdtApi.CreateEntry(await _autoFaker.EntryReadyForCreation(_fixture.CrdtApi));
var after = await _autoFaker.EntryReadyForCreation(_fixture.CrdtApi, entryId: createdEntry.Id);
await EntrySync.Sync(after, createdEntry, _fixture.CrdtApi);
var actual = await _fixture.CrdtApi.GetEntry(after.Id);
actual.Should().NotBeNull();
actual.Should().BeEquivalentTo(after, options => options);
}

[Fact]
public async Task CanChangeComplexFormVisSync_Components()
{
var component1 = await _fixture.CrdtApi.CreateEntry(new() { LexemeForm = { { "en", "component1" } } });
var component2 = await _fixture.CrdtApi.CreateEntry(new() { LexemeForm = { { "en", "component2" } } });
var complexFormId = Guid.NewGuid();
var complexForm = await _fixture.CrdtApi.CreateEntry(new()
{
Id = complexFormId,
LexemeForm = { { "en", "complex form" } },
Components =
[
new ComplexFormComponent()
{
ComponentEntryId = component1.Id,
ComponentHeadword = component1.Headword(),
ComplexFormEntryId = complexFormId,
ComplexFormHeadword = "complex form"
}
]
});
Entry after = (Entry) complexForm.Copy();
after.Components[0].ComponentEntryId = component2.Id;
after.Components[0].ComponentHeadword = component2.Headword();

await EntrySync.Sync(after, complexForm, _fixture.CrdtApi);

var actual = await _fixture.CrdtApi.GetEntry(after.Id);
actual.Should().NotBeNull();
actual.Should().BeEquivalentTo(after, options => options);
}

[Fact]
public async Task CanChangeComplexFormViaSync_ComplexForms()
{
var complexForm1 = await _fixture.CrdtApi.CreateEntry(new() { LexemeForm = { { "en", "complexForm1" } } });
var complexForm2 = await _fixture.CrdtApi.CreateEntry(new() { LexemeForm = { { "en", "complexForm2" } } });
var componentId = Guid.NewGuid();
var component = await _fixture.CrdtApi.CreateEntry(new()
{
Id = componentId,
LexemeForm = { { "en", "component" } },
ComplexForms =
[
new ComplexFormComponent()
{
ComponentEntryId = componentId,
ComponentHeadword = "component",
ComplexFormEntryId = complexForm1.Id,
ComplexFormHeadword = complexForm1.Headword()
}
]
});
Entry after = (Entry) component.Copy();
hahn-kev marked this conversation as resolved.
Show resolved Hide resolved
after.ComplexForms[0].ComplexFormEntryId = complexForm2.Id;
after.ComplexForms[0].ComplexFormHeadword = complexForm2.Headword();

await EntrySync.Sync(after, component, _fixture.CrdtApi);

var actual = await _fixture.CrdtApi.GetEntry(after.Id);
actual.Should().NotBeNull();
actual.Should().BeEquivalentTo(after, options => options);
}

[Fact]
public async Task CanChangeComplexFormTypeViaSync()
{
var entry = await _fixture.CrdtApi.CreateEntry(new() { LexemeForm = { { "en", "complexForm1" } } });
var complexFormType = await _fixture.CrdtApi.GetComplexFormTypes().FirstAsync();
var after = (Entry) entry.Copy();
after.ComplexFormTypes = [complexFormType];
await EntrySync.Sync(after, entry, _fixture.CrdtApi);

var actual = await _fixture.CrdtApi.GetEntry(after.Id);
actual.Should().NotBeNull();
actual.Should().BeEquivalentTo(after, options => options);
}
}
3 changes: 2 additions & 1 deletion backend/FwLite/FwLiteProjectSync.Tests/SyncTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using FwLiteProjectSync.Tests.Fixtures;
using FluentAssertions.Equivalency;
using FwLiteProjectSync.Tests.Fixtures;
using LcmCrdt;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
Expand Down
1 change: 1 addition & 0 deletions backend/FwLite/FwLiteProjectSync.Tests/UpdateDiffTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using FwLiteProjectSync.Tests.Fixtures;
using MiniLcm.Models;
using MiniLcm.SyncHelpers;
using MiniLcm.Tests.AutoFakerHelpers;
using Soenneker.Utils.AutoBogus;
using Soenneker.Utils.AutoBogus.Config;

Expand Down
6 changes: 6 additions & 0 deletions backend/FwLite/FwLiteProjectSync/DryRunMiniLcmApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
DryRunRecords.Add(new DryRunRecord(nameof(UpdateWritingSystem),
$"Update writing system {type}, changes: {update.Summarize()}"));
var ws = await api.GetWritingSystems();
return (type switch

Check warning on line 30 in backend/FwLite/FwLiteProjectSync/DryRunMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build FwHeadless / publish-fw-headless

The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(MiniLcm.Models.WritingSystemType)2' is not covered.

Check warning on line 30 in backend/FwLite/FwLiteProjectSync/DryRunMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build FW Lite and run tests

The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(MiniLcm.Models.WritingSystemType)2' is not covered.

Check warning on line 30 in backend/FwLite/FwLiteProjectSync/DryRunMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Linux

The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(MiniLcm.Models.WritingSystemType)2' is not covered.

Check warning on line 30 in backend/FwLite/FwLiteProjectSync/DryRunMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Linux

The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(MiniLcm.Models.WritingSystemType)2' is not covered.

Check warning on line 30 in backend/FwLite/FwLiteProjectSync/DryRunMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(MiniLcm.Models.WritingSystemType)2' is not covered.

Check warning on line 30 in backend/FwLite/FwLiteProjectSync/DryRunMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(MiniLcm.Models.WritingSystemType)2' is not covered.

Check warning on line 30 in backend/FwLite/FwLiteProjectSync/DryRunMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Windows

The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(MiniLcm.Models.WritingSystemType)2' is not covered.

Check warning on line 30 in backend/FwLite/FwLiteProjectSync/DryRunMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Windows

The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(MiniLcm.Models.WritingSystemType)2' is not covered.
{
WritingSystemType.Vernacular => ws.Vernacular,
WritingSystemType.Analysis => ws.Analysis
Expand Down Expand Up @@ -130,6 +130,12 @@
return GetEntry(id)!;
}

public Task<Entry> UpdateEntry(Entry before, Entry after)
{
DryRunRecords.Add(new DryRunRecord(nameof(UpdateEntry), $"Update entry {after.Id}"));
return Task.FromResult(after);
}

public Task DeleteEntry(Guid id)
{
DryRunRecords.Add(new DryRunRecord(nameof(DeleteEntry), $"Delete entry {id}"));
Expand Down
Loading
Loading