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

Make Sense.PartOfSpeech an object instead of a string #1350

Merged
merged 31 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d1e54aa
Backend changes to make PartOfSpeech an object
rmunn Jan 7, 2025
e92c76c
Mark FwLiteProjectSync tests as integration tests
rmunn Jan 7, 2025
7385dfe
Fix a couple of tests broken by PoS type change
rmunn Jan 7, 2025
1788d74
Better use of Task.WhenAll
rmunn Jan 7, 2025
c5f358d
Fix failing integration tests
rmunn Jan 7, 2025
a62cb9a
Fix up part of speech creation in AutoFaker
rmunn Jan 8, 2025
7cdd697
don't store PartOfSpeech objects in CreateSenseChange
hahn-kev Jan 8, 2025
329a9c5
load part of speech when loading senses
hahn-kev Jan 8, 2025
9d60316
ensure EntryReadyForCreation always creates a part of speech when eit…
hahn-kev Jan 8, 2025
6fbbf4c
fix UpdateSensePartOfSpeech as now `PartOfSpeech` gets used when crea…
hahn-kev Jan 8, 2025
64029e3
When part of speech GUID not found, should throw
rmunn Jan 8, 2025
affd25b
Better implementation of GetPartOfSpeech
rmunn Jan 8, 2025
bb0eec4
Address various review comments
rmunn Jan 8, 2025
879f2d0
Change to frontend generated type for PartOfSpeech
rmunn Jan 8, 2025
73a17b9
Update entry-data.ts and utils.ts to use IPartOfSpeech
rmunn Jan 8, 2025
a36d2a2
More part of speech frontend changes
rmunn Jan 8, 2025
261d8cb
Fix old typo in function
rmunn Jan 8, 2025
24c1c61
Update test sena-3 data with new partOfSpeech objects
rmunn Jan 9, 2025
a6b8b02
Add other parts of speech found in Sena-3 test data
rmunn Jan 9, 2025
f652112
Get CanCreateEntry_AutoFaker test passing
rmunn Jan 9, 2025
9b96ec5
Consistent exceptions between FwData and CRDT APIs
rmunn Jan 9, 2025
b333bc1
VerifyDbModel test now expects PartOfSpeech object
rmunn Jan 10, 2025
e4521c5
Fix SenseDiffShouldUpdateAllFields test
rmunn Jan 10, 2025
93bc1b5
Can now validate PartOfSpeech GUIDs safely
rmunn Jan 10, 2025
4890857
Add validation check for PartOfSpeechId
rmunn Jan 10, 2025
46135af
fix test which was trying to use a PartOfSpeech before it was created
hahn-kev Jan 14, 2025
e515f4a
handle deleted semantic domains and part of speech in CreateSenseChange
hahn-kev Jan 14, 2025
f761055
Merge branch 'develop' into feat/crdt-part-of-speech-object-in-senses
hahn-kev Jan 14, 2025
e65013c
changed code converting senses to avoid a cache stampede
hahn-kev Jan 15, 2025
45e7453
Merge branch 'develop' into feat/crdt-part-of-speech-object-in-senses
rmunn Jan 15, 2025
1e14f4c
Add FwLite DB migration for part of speech object
rmunn Jan 15, 2025
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
9 changes: 6 additions & 3 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 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.
{
var updateProxy = new UpdateWritingSystemProxy(lcmWritingSystem, this)
{
Expand Down Expand Up @@ -568,14 +568,15 @@
private Sense FromLexSense(ILexSense sense)
{
var enWs = GetWritingSystemHandle("en");
var pos = sense.MorphoSyntaxAnalysisRA?.GetPartOfSpeech();
var s = new Sense
{
Id = sense.Guid,
EntryId = sense.Entry.Guid,
Gloss = FromLcmMultiString(sense.Gloss),
Definition = FromLcmMultiString(sense.Definition),
PartOfSpeech = sense.MorphoSyntaxAnalysisRA?.GetPartOfSpeech()?.Name.get_String(enWs).Text ?? "",
PartOfSpeechId = sense.MorphoSyntaxAnalysisRA?.GetPartOfSpeech()?.Guid,
PartOfSpeech = pos is null ? null : FromLcmPartOfSpeech(pos),
PartOfSpeechId = pos?.Guid,
SemanticDomains = sense.SemanticDomainsRC.Select(FromLcmSemanticDomain).ToList(),
ExampleSentences = sense.ExamplesOS.Select(sentence => FromLexExampleSentence(sense.Guid, sentence)).ToList()
};
Expand Down Expand Up @@ -887,8 +888,10 @@
var lexSense = LexSenseFactory.Create(sense.Id);
InsertSense(lexEntry, lexSense, between);
var msa = new SandboxGenericMSA() { MsaType = lexSense.GetDesiredMsaType() };
if (sense.PartOfSpeechId.HasValue && PartOfSpeechRepository.TryGetObject(sense.PartOfSpeechId.Value, out var pos))
if (sense.PartOfSpeechId.HasValue)
{
var found = PartOfSpeechRepository.TryGetObject(sense.PartOfSpeechId.Value, out var pos);
if (!found) throw new InvalidOperationException($"Part of speech must exist when creating a sense (could not find GUID {sense.PartOfSpeechId.Value})");
msa.MainPOS = pos;
}
lexSense.SandboxMSA = msa;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public override MultiString Gloss
set => throw new NotImplementedException();
}

public override string PartOfSpeech
public override PartOfSpeech? PartOfSpeech
{
get => throw new NotImplementedException();
set { }
Expand Down
7 changes: 7 additions & 0 deletions backend/FwLite/FwLiteProjectSync.Tests/Sena3SyncTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ private async Task WorkaroundMissingWritingSystems()
}

[Fact]
[Trait("Category", "Integration")]
public async Task DryRunImport_MakesNoChanges()
{
await WorkaroundMissingWritingSystems();
Expand All @@ -87,6 +88,7 @@ public async Task DryRunImport_MakesNoChanges()
}

[Fact]
[Trait("Category", "Integration")]
public async Task DryRunImport_MakesTheSameChangesAsImport()
{
var dryRunSyncResult = await _syncService.SyncDryRun(_crdtApi, _fwDataApi);
Expand All @@ -95,6 +97,7 @@ public async Task DryRunImport_MakesTheSameChangesAsImport()
}

[Fact]
[Trait("Category", "Integration")]
public async Task DryRunSync_MakesNoChanges()
{
await BypassImport();
Expand All @@ -107,6 +110,7 @@ public async Task DryRunSync_MakesNoChanges()

[Fact]
[Trait("Category", "Slow")]
[Trait("Category", "Integration")]
public async Task DryRunSync_MakesTheSameChangesAsSync()
{
//syncing requires querying entries, which fails if there are no writing systems, so we import those first
Expand All @@ -121,6 +125,7 @@ public async Task DryRunSync_MakesTheSameChangesAsSync()
}

[Fact]
[Trait("Category", "Integration")]
public async Task FirstSena3SyncJustDoesAnSync()
{
_fwDataApi.EntryCount.Should().BeGreaterThan(1000,
Expand All @@ -138,6 +143,7 @@ public async Task FirstSena3SyncJustDoesAnSync()

[Fact]
[Trait("Category", "Slow")]
[Trait("Category", "Integration")]
public async Task SyncWithoutImport_CrdtShouldMatchFwdata()
{
await BypassImport();
Expand All @@ -153,6 +159,7 @@ public async Task SyncWithoutImport_CrdtShouldMatchFwdata()
}

[Fact]
[Trait("Category", "Integration")]
public async Task SecondSena3SyncDoesNothing()
{
await _syncService.Sync(_crdtApi, _fwDataApi);
Expand Down
12 changes: 10 additions & 2 deletions backend/FwLite/FwLiteProjectSync.Tests/SyncTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,14 @@ public async Task PartsOfSpeechSyncInEntries()
await fwdataApi.CreatePartOfSpeech(noun);
// Note we do *not* call crdtApi.CreatePartOfSpeech(noun);

var verb = new PartOfSpeech()
{
Id = new Guid("86ff66f6-0774-407a-a0dc-3eeaf873daf7"),
Name = { { "en", "verb" } },
Predefined = true,
};
await crdtApi.CreatePartOfSpeech(verb);

await fwdataApi.CreateEntry(new Entry()
{
LexemeForm = { { "en", "Pear" } },
Expand All @@ -311,10 +319,10 @@ await fwdataApi.CreateEntry(new Entry()
});
await crdtApi.CreateEntry(new Entry()
{
LexemeForm = { { "en", "Banana" } },
LexemeForm = { { "en", "Eat" } },
Senses =
[
new Sense() { Gloss = { { "en", "Banana" } }, PartOfSpeechId = noun.Id }
new Sense() { Gloss = { { "en", "Eat" } }, PartOfSpeechId = verb.Id }
]
});
await _syncService.Sync(crdtApi, fwdataApi);
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 @@ -42,7 +42,7 @@ public void SenseDiffShouldUpdateAllFields()
var senseDiffToUpdate = 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).Excluding(x => x.SemanticDomains));
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).Excluding(x => x.PartOfSpeech));
}

[Fact]
Expand Down
9 changes: 0 additions & 9 deletions backend/FwLite/LcmCrdt.Tests/Changes/JsonPatchChangeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,4 @@ public void NewChangeIPatchDoc_ThrowsForRemoveAtIndex()
var act = () => new JsonPatchChange<Entry>(Guid.NewGuid(), patch);
act.Should().Throw<NotSupportedException>();
}

[Fact]
public void NewPatchDoc_ThrowsForIndexBasedPath()
{
var patch = new JsonPatchDocument<Entry>();
patch.Replace(entry => entry.Senses[0].PartOfSpeech, "noun");
var act = () => new JsonPatchChange<Entry>(Guid.NewGuid(), patch);
act.Should().Throw<NotSupportedException>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -202,21 +202,23 @@
Annotations:
Relational:ColumnType: jsonb
Order (double) Required
PartOfSpeech (string) Required
PartOfSpeechId (Guid?)
PartOfSpeechId (Guid?) FK Index
SemanticDomains (IList<SemanticDomain>) Required
Annotations:
Relational:ColumnType: jsonb
SnapshotId (no field, Guid?) Shadow FK Index
Navigations:
ExampleSentences (List<ExampleSentence>) Collection ToDependent ExampleSentence
PartOfSpeech (PartOfSpeech) ToPrincipal PartOfSpeech
Keys:
Id PK
Foreign keys:
Sense {'EntryId'} -> Entry {'Id'} Required Cascade ToDependent: Senses
Sense {'PartOfSpeechId'} -> PartOfSpeech {'Id'} ClientSetNull ToPrincipal: PartOfSpeech
Sense {'SnapshotId'} -> ObjectSnapshot {'Id'} Unique SetNull
Indexes:
EntryId
PartOfSpeechId
SnapshotId Unique
Annotations:
DiscriminatorProperty:
Expand Down
20 changes: 13 additions & 7 deletions backend/FwLite/LcmCrdt.Tests/JsonPatchSenseRewriteTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,20 @@ public class JsonPatchSenseRewriteTests
{
private JsonPatchDocument<MiniLcm.Models.Sense> _patchDocument = new() { Options = new JsonSerializerOptions(JsonSerializerDefaults.Web) };

private Sense _sense = new Sense()
private Sense _sense = MakeSense("test");

private static Sense MakeSense(string name)
{
Id = Guid.NewGuid(),
EntryId = Guid.NewGuid(),
PartOfSpeechId = Guid.NewGuid(),
PartOfSpeech = "test",
SemanticDomains = [new SemanticDomain() { Id = Guid.NewGuid(), Code = "test", Name = new MultiString() }],
};
var pos = new PartOfSpeech() { Id = Guid.NewGuid(), Name = {{ "en", name }} };
return new Sense()
{
Id = Guid.NewGuid(),
EntryId = Guid.NewGuid(),
PartOfSpeech = pos,
PartOfSpeechId = pos.Id,
SemanticDomains = [new SemanticDomain() { Id = Guid.NewGuid(), Code = "test", Name = new MultiString() }],
};
}

[Fact]
public void RewritePartOfSpeechChangesIntoSetPartOfSpeechChange()
Expand Down
10 changes: 4 additions & 6 deletions backend/FwLite/LcmCrdt/Changes/CreateSenseChange.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using LcmCrdt.Utils;
using SIL.Harmony;
using SIL.Harmony.Changes;
using SIL.Harmony.Entities;
Expand All @@ -15,8 +16,7 @@ public CreateSenseChange(Sense sense, Guid entryId) : base(sense.Id == Guid.Empt
Definition = sense.Definition;
SemanticDomains = sense.SemanticDomains;
Gloss = sense.Gloss;
PartOfSpeech = sense.PartOfSpeech;
PartOfSpeechId = sense.PartOfSpeechId;
PartOfSpeechId = sense.PartOfSpeech?.Id ?? sense.PartOfSpeechId;
}

[JsonConstructor]
Expand All @@ -29,7 +29,6 @@ private CreateSenseChange(Guid entityId, Guid entryId) : base(entityId)
public double Order { get; set; }
public MultiString? Definition { get; set; }
public MultiString? Gloss { get; set; }
public string? PartOfSpeech { get; set; }
public Guid? PartOfSpeechId { get; set; }
public IList<SemanticDomain>? SemanticDomains { get; set; }

Expand All @@ -42,9 +41,8 @@ public override async ValueTask<Sense> NewEntity(Commit commit, ChangeContext co
Order = Order,
Definition = Definition ?? new MultiString(),
Gloss = Gloss ?? new MultiString(),
PartOfSpeech = PartOfSpeech ?? string.Empty,
PartOfSpeechId = PartOfSpeechId,
SemanticDomains = SemanticDomains ?? [],
PartOfSpeechId = await context.DeletedAsNull(PartOfSpeechId),
SemanticDomains = await context.FilterDeleted(SemanticDomains ?? []).ToArrayAsync(),
DeletedAt = await context.IsObjectDeleted(EntryId) ? commit.DateTime : (DateTime?)null
};
}
Expand Down
5 changes: 2 additions & 3 deletions backend/FwLite/LcmCrdt/Changes/SetPartOfSpeechChange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,17 @@ public override async ValueTask ApplyChange(Sense entity, ChangeContext context)
if (PartOfSpeechId is null)
{
entity.PartOfSpeechId = null;
entity.PartOfSpeech = string.Empty;
return;
}

var partOfSpeech = await context.GetCurrent<PartOfSpeech>(PartOfSpeechId.Value);
if (partOfSpeech is null or { DeletedAt: not null })
{
entity.PartOfSpeechId = null;
entity.PartOfSpeech = string.Empty;
entity.PartOfSpeech = null;
return;
}
entity.PartOfSpeechId = partOfSpeech.Id;
entity.PartOfSpeech = partOfSpeech.Name["en"];
entity.PartOfSpeech = partOfSpeech;
rmunn marked this conversation as resolved.
Show resolved Hide resolved
}
}
22 changes: 8 additions & 14 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 / 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 Android

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 @@ -276,6 +276,7 @@
queryable = queryable
.LoadWith(e => e.Senses)
.ThenLoad(s => s.ExampleSentences)
.LoadWith(e => e.Senses).ThenLoad(s => s.PartOfSpeech)
.LoadWith(e => e.ComplexForms)
.LoadWith(e => e.Components)
.AsQueryable()
Expand All @@ -295,6 +296,7 @@
var entry = await Entries.AsTracking(false)
.LoadWith(e => e.Senses)
.ThenLoad(s => s.ExampleSentences)
.LoadWith(e => e.Senses).ThenLoad(s => s.PartOfSpeech)
.LoadWith(e => e.ComplexForms)
.LoadWith(e => e.Components)
.AsQueryable()
Expand All @@ -321,16 +323,15 @@
public async Task BulkCreateEntries(IAsyncEnumerable<Entry> entries)
{
var semanticDomains = await SemanticDomains.ToDictionaryAsync(sd => sd.Id, sd => sd);
var partsOfSpeech = await PartsOfSpeech.ToDictionaryAsync(p => p.Id, p => p);
await dataModel.AddChanges(ClientId,
entries.ToBlockingEnumerable()
.SelectMany(entry => CreateEntryChanges(entry, semanticDomains, partsOfSpeech))
.SelectMany(entry => CreateEntryChanges(entry, semanticDomains))
//force entries to be created first, this avoids issues where references are created before the entry is created
.OrderBy(c => c is CreateEntryChange ? 0 : 1)
);
}

private IEnumerable<IChange> CreateEntryChanges(Entry entry, Dictionary<Guid, SemanticDomain> semanticDomains, Dictionary<Guid, PartOfSpeech> partsOfSpeech)
private IEnumerable<IChange> CreateEntryChanges(Entry entry, Dictionary<Guid, SemanticDomain> semanticDomains)
{
yield return new CreateEntryChange(entry);

Expand All @@ -350,11 +351,6 @@
.Select(sd => semanticDomains.TryGetValue(sd.Id, out var selectedSd) ? selectedSd : null)
.OfType<MiniLcm.Models.SemanticDomain>()
.ToList();
if (sense.PartOfSpeechId is not null && partsOfSpeech.TryGetValue(sense.PartOfSpeechId.Value, out var partOfSpeech))
{
sense.PartOfSpeechId = partOfSpeech.Id;
sense.PartOfSpeech = partOfSpeech.Name["en"] ?? string.Empty;
}
sense.Order = senseOrder++;
yield return new CreateSenseChange(sense, entry.Id);
var exampleOrder = 1;
Expand Down Expand Up @@ -385,7 +381,7 @@
]);
return await GetEntry(entry.Id) ?? throw new NullReferenceException();

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

Check warning on line 384 in backend/FwLite/LcmCrdt/CrdtMiniLcmApi.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 384 in backend/FwLite/LcmCrdt/CrdtMiniLcmApi.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 384 in backend/FwLite/LcmCrdt/CrdtMiniLcmApi.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 384 in backend/FwLite/LcmCrdt/CrdtMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Android

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 384 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 @@ -469,12 +465,6 @@
sense.SemanticDomains = await SemanticDomains
.Where(sd => sense.SemanticDomains.Select(s => s.Id).Contains(sd.Id))
.ToListAsync();
if (sense.PartOfSpeechId is not null)
{
var partOfSpeech = await PartsOfSpeech.FirstOrDefaultAsync(p => p.Id == sense.PartOfSpeechId);
sense.PartOfSpeechId = partOfSpeech?.Id;
sense.PartOfSpeech = partOfSpeech?.Name["en"] ?? string.Empty;
}

yield return new CreateSenseChange(sense, entryId);
var exampleOrder = 1;
Expand All @@ -490,6 +480,7 @@
var entry = await Entries.AsTracking(false)
.LoadWith(e => e.Senses)
.ThenLoad(s => s.ExampleSentences)
.LoadWith(e => e.Senses).ThenLoad(s => s.PartOfSpeech)
.AsQueryable()
.SingleOrDefaultAsync(e => e.Id == entryId);
var sense = entry?.Senses.FirstOrDefault(s => s.Id == id);
Expand All @@ -500,6 +491,9 @@
public async Task<Sense> CreateSense(Guid entryId, Sense sense, BetweenPosition? between = null)
{
await validators.ValidateAndThrow(sense);
if (sense.PartOfSpeechId.HasValue && await GetPartOfSpeech(sense.PartOfSpeechId.Value) is null)
throw new InvalidOperationException($"Part of speech must exist when creating a sense (could not find GUID {sense.PartOfSpeechId.Value})");

sense.Order = await OrderPicker.PickOrder(Senses.Where(s => s.EntryId == entryId), between);
await dataModel.AddChanges(ClientId, await CreateSenseChanges(entryId, sense).ToArrayAsync());
return await dataModel.GetLatest<Sense>(sense.Id) ?? throw new NullReferenceException();
Expand Down
Loading
Loading