Skip to content

Commit

Permalink
Implement UpdateWritingSystem(before, after)
Browse files Browse the repository at this point in the history
Note that FwDataMiniLcmApi hasn't implemented the UpdateWritingSystem
overload with (id, type, update), which is the (before, after) method
is going to end up calling. So that still needs to happen.
  • Loading branch information
rmunn committed Nov 15, 2024
1 parent 10a107f commit 4409d47
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 2 deletions.
18 changes: 17 additions & 1 deletion backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ private WritingSystem FromLcmWritingSystem(CoreWritingSystemDefinition ws, int i
};
}

public Task<WritingSystem> GetWritingSystem(WritingSystemId id, WritingSystemType type)
{
throw new NotImplementedException();
}

internal void CompleteExemplars(WritingSystems writingSystems)
{
var wsExemplars = writingSystems.Vernacular.Concat(writingSystems.Analysis)
Expand Down Expand Up @@ -185,7 +190,18 @@ public Task<WritingSystem> CreateWritingSystem(WritingSystemType type, WritingSy

public Task<WritingSystem> UpdateWritingSystem(WritingSystemId id, WritingSystemType type, UpdateObjectInput<WritingSystem> update)
{
throw new NotImplementedException();
throw new NotImplementedException(); // TODO: This needs to be implemented now, because UpdateWritingSystem(before, after) needs to call this
}

public async Task<WritingSystem> UpdateWritingSystem(WritingSystem before, WritingSystem after)
{
await Cache.DoUsingNewOrCurrentUOW("Update WritingSystem",
"Revert WritingSystem",
async () =>
{
await WritingSystemSync.Sync(after, before, this);
});
return await GetWritingSystem(after.WsId, after.Type) ?? throw new NullReferenceException("unable to find writing system with id " + after.Id);
}

public IAsyncEnumerable<PartOfSpeech> GetPartsOfSpeech()
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 @@ -34,6 +34,12 @@ public async Task<WritingSystem> UpdateWritingSystem(WritingSystemId id,
}).First(w => w.WsId == id);
}

public Task<WritingSystem> UpdateWritingSystem(WritingSystem before, WritingSystem after)
{
DryRunRecords.Add(new DryRunRecord(nameof(UpdateEntry), $"Update {after.Type} writing system {after.Id}"));
return Task.FromResult(after);
}

public IAsyncEnumerable<PartOfSpeech> GetPartsOfSpeech()
{
return api.GetPartsOfSpeech();
Expand Down
6 changes: 6 additions & 0 deletions backend/FwLite/LcmCrdt/CrdtMiniLcmApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ public async Task<WritingSystem> UpdateWritingSystem(WritingSystemId id, Writing
return await dataModel.GetLatest<WritingSystem>(ws.Id) ?? throw new NullReferenceException();
}

public async Task<WritingSystem> UpdateWritingSystem(WritingSystem before, WritingSystem after)
{
await WritingSystemSync.Sync(after, before, this);
return await GetWritingSystem(after.WsId, after.Type) ?? throw new NullReferenceException("unable to find writing system with id " + after.WsId);
}

private WritingSystem? _defaultVernacularWs;
private WritingSystem? _defaultAnalysisWs;
private async Task<WritingSystem?> GetWritingSystem(WritingSystemId id, WritingSystemType type)
Expand Down
3 changes: 2 additions & 1 deletion backend/FwLite/MiniLcm/IMiniLcmWriteApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ public interface IMiniLcmWriteApi
Task<WritingSystem> UpdateWritingSystem(WritingSystemId id,
WritingSystemType type,
UpdateObjectInput<WritingSystem> update);

Task<WritingSystem> UpdateWritingSystem(WritingSystem before, WritingSystem after);
// Note there's no Task DeleteWritingSystem(Guid id) because deleting writing systems needs careful consideration, as it can cause a massive cascade of data deletion

#region PartOfSpeech
Task<PartOfSpeech> CreatePartOfSpeech(PartOfSpeech partOfSpeech);
Expand Down
16 changes: 16 additions & 0 deletions backend/FwLite/MiniLcm/SyncHelpers/SimpleStringDiff.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using SystemTextJsonPatch.Operations;

namespace MiniLcm.SyncHelpers;

public static class SimpleStringDiff
{
public static IEnumerable<Operation<T>> GetStringDiff<T>(string path,
string before,
string after) where T : class
{
if (before == after) yield break;
if (after is null) yield return new Operation<T>("remove", $"/{path}", null);
else if (before is null) yield return new Operation<T>("add", $"/{path}", null);
else yield return new Operation<T>("replace", $"/{path}", null, after);
}
}
59 changes: 59 additions & 0 deletions backend/FwLite/MiniLcm/SyncHelpers/WritingSystemSync.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using MiniLcm;
using MiniLcm.Models;
using MiniLcm.SyncHelpers;
using SystemTextJsonPatch;

public static class WritingSystemSync
{
public static async Task<int> Sync(WritingSystem[] currentWritingSystems,
WritingSystem[] previousWritingSystems,
IMiniLcmApi api)
{
return await DiffCollection.Diff(api,
previousWritingSystems,
currentWritingSystems,
ws => ws.Id,
async (api, currentWs) =>
{
await api.CreateWritingSystem(currentWs.Type, currentWs);
return 1;
},
async (api, previousWs) =>

Check warning on line 21 in backend/FwLite/MiniLcm/SyncHelpers/WritingSystemSync.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 21 in backend/FwLite/MiniLcm/SyncHelpers/WritingSystemSync.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 21 in backend/FwLite/MiniLcm/SyncHelpers/WritingSystemSync.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 21 in backend/FwLite/MiniLcm/SyncHelpers/WritingSystemSync.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 21 in backend/FwLite/MiniLcm/SyncHelpers/WritingSystemSync.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 21 in backend/FwLite/MiniLcm/SyncHelpers/WritingSystemSync.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 21 in backend/FwLite/MiniLcm/SyncHelpers/WritingSystemSync.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 21 in backend/FwLite/MiniLcm/SyncHelpers/WritingSystemSync.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.
{
// await api.DeleteWritingSystem(previousWs.Id); // Deleting writing systems is dangerous as it causes cascading data deletion. Needs careful thought.
// TODO: should we throw an exception?
return 0;
},
async (api, previousWs, currentWs) =>
{
return await Sync(currentWs, previousWs, api);
});
}

public static async Task<int> Sync(WritingSystem afterWs, WritingSystem beforeWs, IMiniLcmApi api)
{
var updateObjectInput = WritingSystemDiffToUpdate(beforeWs, afterWs);
if (updateObjectInput is not null) await api.UpdateWritingSystem(afterWs.WsId, afterWs.Type, updateObjectInput);
return updateObjectInput is null ? 0 : 1;
}

public static UpdateObjectInput<WritingSystem>? WritingSystemDiffToUpdate(WritingSystem previousWritingSystem, WritingSystem currentWritingSystem)
{
JsonPatchDocument<WritingSystem> patchDocument = new();
patchDocument.Operations.AddRange(SimpleStringDiff.GetStringDiff<WritingSystem>(nameof(WritingSystem.WsId),
previousWritingSystem.WsId,
currentWritingSystem.WsId));
patchDocument.Operations.AddRange(SimpleStringDiff.GetStringDiff<WritingSystem>(nameof(WritingSystem.Name),
previousWritingSystem.Name,
currentWritingSystem.Name));
patchDocument.Operations.AddRange(SimpleStringDiff.GetStringDiff<WritingSystem>(nameof(WritingSystem.Abbreviation),
previousWritingSystem.Abbreviation,
currentWritingSystem.Abbreviation));
patchDocument.Operations.AddRange(SimpleStringDiff.GetStringDiff<WritingSystem>(nameof(WritingSystem.Font),
previousWritingSystem.Font,
currentWritingSystem.Font));
// TODO: Exemplars, Order, and do we need DeletedAt?
if (patchDocument.Operations.Count == 0) return null;
return new UpdateObjectInput<WritingSystem>(patchDocument);
}
}

0 comments on commit 4409d47

Please sign in to comment.