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

Add Update(before, after) API for senses #1267

Merged
merged 4 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 17 additions & 0 deletions backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@
}
await Cache.DoUsingNewOrCurrentUOW("Update WritingSystem",
"Revert WritingSystem",
async () =>

Check warning on line 209 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build FwHeadless / publish-fw-headless

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 209 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build FW Lite and run tests

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 209 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Linux

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 209 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Linux

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 209 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 209 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 209 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Windows

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 209 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Windows

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
var updateProxy = new UpdateWritingSystemProxy(lcmWritingSystem, this)
{
Expand Down Expand Up @@ -911,6 +911,12 @@
}
}

public Task<Sense?> GetSense(Guid entryId, Guid id)
{
var lcmSense = SenseRepository.GetObject(id);
return Task.FromResult(lcmSense is null ? null : FromLexSense(lcmSense));
}

public Task<Sense> CreateSense(Guid entryId, Sense sense)
{
if (sense.Id == default) sense.Id = Guid.NewGuid();
Expand Down Expand Up @@ -938,6 +944,17 @@
return Task.FromResult(FromLexSense(lexSense));
}

public async Task<Sense> UpdateSense(Guid entryId, Sense before, Sense after)
{
await Cache.DoUsingNewOrCurrentUOW("Update Sense",
"Revert Sense",
async () =>
{
await SenseSync.Sync(entryId, after, before, this);
});
return await GetSense(entryId, after.Id) ?? throw new NullReferenceException("unable to find sense with id " + after.Id);
}

public Task AddSemanticDomainToSense(Guid senseId, SemanticDomain semanticDomain)
{
UndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW("Add Semantic Domain to Sense",
Expand Down
2 changes: 1 addition & 1 deletion backend/FwLite/FwLiteProjectSync.Tests/UpdateDiffTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public async Task SenseDiffShouldUpdateAllFields()
var senseDiffToUpdate = await SenseSync.SenseDiffToUpdate(before, after);
ArgumentNullException.ThrowIfNull(senseDiffToUpdate);
senseDiffToUpdate.Apply(before);
before.Should().BeEquivalentTo(after, options => options.Excluding(x => x.Id).Excluding(x => x.EntryId).Excluding(x => x.DeletedAt).Excluding(x => x.ExampleSentences));
before.Should().BeEquivalentTo(after, options => options.Excluding(x => x.Id).Excluding(x => x.EntryId).Excluding(x => x.DeletedAt).Excluding(x => x.ExampleSentences).Excluding(x => x.SemanticDomains));
}

[Fact]
Expand Down
12 changes: 12 additions & 0 deletions backend/FwLite/FwLiteProjectSync/DryRunMiniLcmApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,11 @@ public async Task RemoveComplexFormType(Guid entryId, Guid complexFormTypeId)
await Task.CompletedTask;
}

public Task<Sense?> GetSense(Guid entryId, Guid id)
{
return api.GetSense(entryId, id);
}

public Task<Sense> CreateSense(Guid entryId, Sense sense)
{
DryRunRecords.Add(new DryRunRecord(nameof(CreateSense), $"Create sense {sense.Gloss}"));
Expand All @@ -206,6 +211,13 @@ public async Task<Sense> UpdateSense(Guid entryId, Guid senseId, UpdateObjectInp
return sense;
}

public async Task<Sense> UpdateSense(Guid entryId, Sense before, Sense after)
{
DryRunRecords.Add(new DryRunRecord(nameof(UpdateSense),
$"Update sense {after.Id}"));
return await GetSense(entryId, after.Id) ?? throw new NullReferenceException($"unable to find sense with id {after.Id}");
}

public Task DeleteSense(Guid entryId, Guid senseId)
{
DryRunRecords.Add(new DryRunRecord(nameof(DeleteSense), $"Delete sense {senseId}"));
Expand Down
16 changes: 16 additions & 0 deletions backend/FwLite/LcmCrdt/CrdtMiniLcmApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

namespace LcmCrdt;

public class CrdtMiniLcmApi(DataModel dataModel, CurrentProjectService projectService, LcmCrdtDbContext dbContext, MiniLcmValidators validators) : IMiniLcmApi

Check warning on line 19 in backend/FwLite/LcmCrdt/CrdtMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build FwHeadless / publish-fw-headless

Parameter 'dbContext' is unread.

Check warning on line 19 in backend/FwLite/LcmCrdt/CrdtMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build FW Lite and run tests

Parameter 'dbContext' is unread.

Check warning on line 19 in backend/FwLite/LcmCrdt/CrdtMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Linux

Parameter 'dbContext' is unread.

Check warning on line 19 in backend/FwLite/LcmCrdt/CrdtMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Linux

Parameter 'dbContext' is unread.

Check warning on line 19 in backend/FwLite/LcmCrdt/CrdtMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

Parameter 'dbContext' is unread.

Check warning on line 19 in backend/FwLite/LcmCrdt/CrdtMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

Parameter 'dbContext' is unread.

Check warning on line 19 in backend/FwLite/LcmCrdt/CrdtMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Windows

Parameter 'dbContext' is unread.

Check warning on line 19 in backend/FwLite/LcmCrdt/CrdtMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Windows

Parameter 'dbContext' is unread.
{
private Guid ClientId { get; } = projectService.ProjectData.ClientId;
public ProjectData ProjectData => projectService.ProjectData;
Expand Down Expand Up @@ -366,7 +366,7 @@
]);
return await GetEntry(entry.Id) ?? throw new NullReferenceException();

async IAsyncEnumerable<AddEntryComponentChange> ToComplexFormComponents(IList<ComplexFormComponent> complexFormComponents)

Check warning on line 369 in backend/FwLite/LcmCrdt/CrdtMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Windows

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
foreach (var complexFormComponent in complexFormComponents)
{
Expand Down Expand Up @@ -464,6 +464,16 @@
}
}

public async Task<Sense?> GetSense(Guid entryId, Guid id)
{
var entry = await Entries.AsTracking(false)
.LoadWith(e => e.Senses)
.ThenLoad(s => s.ExampleSentences)
.AsQueryable()
.SingleOrDefaultAsync(e => e.Id == entryId);
return entry?.Senses.FirstOrDefault(s => s.Id == id);
}

public async Task<Sense> CreateSense(Guid entryId, Sense sense)
{
await dataModel.AddChanges(ClientId, await CreateSenseChanges(entryId, sense).ToArrayAsync());
Expand All @@ -480,6 +490,12 @@
return await dataModel.GetLatest<Sense>(senseId) ?? throw new NullReferenceException();
}

public async Task<Sense> UpdateSense(Guid entryId, Sense before, Sense after)
{
await SenseSync.Sync(entryId, after, before, this);
return await GetSense(entryId, after.Id) ?? throw new NullReferenceException("unable to find sense with id " + after.Id);
}

public async Task DeleteSense(Guid entryId, Guid senseId)
{
await dataModel.AddChange(ClientId, new DeleteChange<Sense>(senseId));
Expand Down
1 change: 1 addition & 0 deletions backend/FwLite/MiniLcm/IMiniLcmReadApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public interface IMiniLcmReadApi
IAsyncEnumerable<Entry> GetEntries(QueryOptions? options = null);
IAsyncEnumerable<Entry> SearchEntries(string query, QueryOptions? options = null);
Task<Entry?> GetEntry(Guid id);
Task<Sense?> GetSense(Guid entryId, Guid id);
Task<PartOfSpeech?> GetPartOfSpeech(Guid id);
Task<SemanticDomain?> GetSemanticDomain(Guid id);
Task<ExampleSentence?> GetExampleSentence(Guid entryId, Guid senseId, Guid id);
Expand Down
1 change: 1 addition & 0 deletions backend/FwLite/MiniLcm/IMiniLcmWriteApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Task<WritingSystem> UpdateWritingSystem(WritingSystemId id,
#region Sense
Task<Sense> CreateSense(Guid entryId, Sense sense);
Task<Sense> UpdateSense(Guid entryId, Guid senseId, UpdateObjectInput<Sense> update);
Task<Sense> UpdateSense(Guid entryId, Sense before, Sense after);
Task DeleteSense(Guid entryId, Guid senseId);
Task AddSemanticDomainToSense(Guid senseId, SemanticDomain semanticDomain);
Task RemoveSemanticDomainFromSense(Guid senseId, Guid semanticDomainId);
Expand Down
37 changes: 18 additions & 19 deletions backend/FwLite/MiniLcm/SyncHelpers/SenseSync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,28 @@
afterSense.ExampleSentences,
beforeSense.ExampleSentences,
api);
changes += await DiffCollection.Diff(api,
beforeSense.SemanticDomains,
afterSense.SemanticDomains,
async (api, domain) =>
{
await api.AddSemanticDomainToSense(beforeSense.Id, domain);
return 1;
},
async (api, beforeDomain) =>
{
await api.RemoveSemanticDomainFromSense(beforeSense.Id, beforeDomain.Id);
return 1;
},
(_, beforeDomain, afterDomain) =>
{
//do nothing, semantic domains are not editable here
return Task.FromResult(0);
});
return changes + (updateObjectInput is null ? 0 : 1);
}

public static async Task<UpdateObjectInput<Sense>?> SenseDiffToUpdate(Sense beforeSense, Sense afterSense)

Check warning on line 41 in backend/FwLite/MiniLcm/SyncHelpers/SenseSync.cs

View workflow job for this annotation

GitHub Actions / Build API / publish-api

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 41 in backend/FwLite/MiniLcm/SyncHelpers/SenseSync.cs

View workflow job for this annotation

GitHub Actions / Build FwHeadless / publish-fw-headless

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 41 in backend/FwLite/MiniLcm/SyncHelpers/SenseSync.cs

View workflow job for this annotation

GitHub Actions / Build FW Lite and run tests

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 41 in backend/FwLite/MiniLcm/SyncHelpers/SenseSync.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Linux

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 41 in backend/FwLite/MiniLcm/SyncHelpers/SenseSync.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Linux

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 41 in backend/FwLite/MiniLcm/SyncHelpers/SenseSync.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 41 in backend/FwLite/MiniLcm/SyncHelpers/SenseSync.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 41 in backend/FwLite/MiniLcm/SyncHelpers/SenseSync.cs

View workflow job for this annotation

GitHub Actions / GHA integration tests / execute

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 41 in backend/FwLite/MiniLcm/SyncHelpers/SenseSync.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Windows

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 41 in backend/FwLite/MiniLcm/SyncHelpers/SenseSync.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Windows

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
JsonPatchDocument<Sense> patchDocument = new();
patchDocument.Operations.AddRange(
Expand All @@ -38,25 +56,6 @@
patchDocument.Replace(sense => sense.PartOfSpeechId, afterSense.PartOfSpeechId);
}

await DiffCollection.Diff(null!,
beforeSense.SemanticDomains,
afterSense.SemanticDomains,
(_, domain) =>
{
patchDocument.Add(sense => sense.SemanticDomains, domain);
return Task.FromResult(1);
},
(_, beforeDomain) =>
{
patchDocument.Remove(sense => sense.SemanticDomains,
beforeSense.SemanticDomains.IndexOf(beforeDomain));
return Task.FromResult(1);
},
(_, beforeDomain, afterDomain) =>
{
//do nothing, semantic domains are not editable here
return Task.FromResult(0);
});
if (patchDocument.Operations.Count == 0) return null;
return new UpdateObjectInput<Sense>(patchDocument);
}
Expand Down
14 changes: 14 additions & 0 deletions backend/LfClassicData/LfClassicMiniLcmApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ public IAsyncEnumerable<ComplexFormType> GetComplexFormTypes()
return AsyncEnumerable.Empty<ComplexFormType>();
}

public Task<ComplexFormType?> GetComplexFormType(Guid id)
{
return Task.FromResult<ComplexFormType?>(null);
}

public async Task<WritingSystems> GetWritingSystems()
{
var inputSystems = await systemDbContext.Projects.AsQueryable()
Expand Down Expand Up @@ -315,6 +320,15 @@ private static SemanticDomain ToSemanticDomain(Entities.OptionListItem item)
return ToEntry(entry);
}

public async Task<Sense?> GetSense(Guid entryId, Guid id)
{
var entry = await Entries.Find(e => e.Guid == entryId).FirstOrDefaultAsync();
if (entry is null) return null;
var sense = entry.Senses?.FirstOrDefault(s => s?.Guid == id);
if (sense is null) return null;
return ToSense(entryId, sense);
}

public async Task<ExampleSentence?> GetExampleSentence(Guid entryId, Guid senseId, Guid id)
{
var entry = await Entries.Find(e => e.Guid == entryId).FirstOrDefaultAsync();
Expand Down
Loading