Skip to content

Commit

Permalink
Actually use validators in MiniLCM API
Browse files Browse the repository at this point in the history
  • Loading branch information
rmunn committed Jan 7, 2025
1 parent 379d4d4 commit 3bcd237
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 6 deletions.
16 changes: 14 additions & 2 deletions backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ internal void CompleteExemplars(WritingSystems writingSystems)

public Task<WritingSystem> CreateWritingSystem(WritingSystemType type, WritingSystem writingSystem)
{
validators.ValidateAndThrow(writingSystem);
var exitingWs = type == WritingSystemType.Analysis ? Cache.ServiceLocator.WritingSystems.AnalysisWritingSystems : Cache.ServiceLocator.WritingSystems.VernacularWritingSystems;
if (exitingWs.Any(ws => ws.Id == writingSystem.WsId))
{
Expand Down Expand Up @@ -220,6 +221,7 @@ await Cache.DoUsingNewOrCurrentUOW("Update WritingSystem",

public async Task<WritingSystem> UpdateWritingSystem(WritingSystem before, WritingSystem after)
{
await validators.ValidateAndThrowAsync(after);
await Cache.DoUsingNewOrCurrentUOW("Update WritingSystem",
"Revert WritingSystem",
async () =>
Expand Down Expand Up @@ -248,6 +250,7 @@ public IAsyncEnumerable<PartOfSpeech> GetPartsOfSpeech()

public Task<PartOfSpeech> CreatePartOfSpeech(PartOfSpeech partOfSpeech)
{
validators.ValidateAndThrow(partOfSpeech);
IPartOfSpeech? lcmPartOfSpeech = null;
if (partOfSpeech.Id == default) partOfSpeech.Id = Guid.NewGuid();
UndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW("Create Part of Speech",
Expand Down Expand Up @@ -278,6 +281,7 @@ public Task<PartOfSpeech> UpdatePartOfSpeech(Guid id, UpdateObjectInput<PartOfSp

public async Task<PartOfSpeech> UpdatePartOfSpeech(PartOfSpeech before, PartOfSpeech after)
{
await validators.ValidateAndThrowAsync(after);
await PartOfSpeechSync.Sync(before, after, this);
return await GetPartOfSpeech(after.Id) ?? throw new NullReferenceException($"unable to find part of speech with id {after.Id}");
}
Expand Down Expand Up @@ -323,6 +327,7 @@ public IAsyncEnumerable<SemanticDomain> GetSemanticDomains()

public async Task<SemanticDomain> CreateSemanticDomain(SemanticDomain semanticDomain)
{
await validators.ValidateAndThrowAsync(semanticDomain);
if (semanticDomain.Id == Guid.Empty) semanticDomain.Id = Guid.NewGuid();
UndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW("Create Semantic Domain",
"Remove semantic domain",
Expand Down Expand Up @@ -355,6 +360,7 @@ public Task<SemanticDomain> UpdateSemanticDomain(Guid id, UpdateObjectInput<Sema

public async Task<SemanticDomain> UpdateSemanticDomain(SemanticDomain before, SemanticDomain after)
{
await validators.ValidateAndThrowAsync(after);
await SemanticDomainSync.Sync(before, after, this);
return await GetSemanticDomain(after.Id) ?? throw new NullReferenceException($"unable to find semantic domain with id {after.Id}");
}
Expand Down Expand Up @@ -396,7 +402,7 @@ private ComplexFormType ToComplexFormType(ILexEntryType t)

public async Task<ComplexFormType> CreateComplexFormType(ComplexFormType complexFormType)
{
await validators.ValidateAndThrow(complexFormType);
await validators.ValidateAndThrowAsync(complexFormType);
if (complexFormType.Id == default) complexFormType.Id = Guid.NewGuid();
UndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW("Create complex form type",
"Remove complex form type",
Expand Down Expand Up @@ -429,7 +435,7 @@ public Task<ComplexFormType> UpdateComplexFormType(Guid id, UpdateObjectInput<Co

public async Task<ComplexFormType> UpdateComplexFormType(ComplexFormType before, ComplexFormType after)
{
await validators.ValidateAndThrow(after);
await validators.ValidateAndThrowAsync(after);
await ComplexFormTypeSync.Sync(before, after, this);
return ToComplexFormType(ComplexFormTypesFlattened.Single(c => c.Guid == after.Id));
}
Expand Down Expand Up @@ -661,6 +667,7 @@ public IAsyncEnumerable<Entry> SearchEntries(string query, QueryOptions? options
public async Task<Entry> CreateEntry(Entry entry)
{
entry.Id = entry.Id == default ? Guid.NewGuid() : entry.Id;
await validators.ValidateAndThrowAsync(entry);
try
{
UndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW("Create Entry",
Expand Down Expand Up @@ -853,6 +860,7 @@ public Task<Entry> UpdateEntry(Guid id, UpdateObjectInput<Entry> update)

public async Task<Entry> UpdateEntry(Entry before, Entry after)
{
await validators.ValidateAndThrowAsync(after);
await Cache.DoUsingNewOrCurrentUOW("Update Entry",
"Revert entry",
async () =>
Expand Down Expand Up @@ -963,6 +971,7 @@ public Task<Sense> CreateSense(Guid entryId, Sense sense, BetweenPosition? betwe
if (sense.Id == default) sense.Id = Guid.NewGuid();
if (!EntriesRepository.TryGetObject(entryId, out var lexEntry))
throw new InvalidOperationException("Entry not found");
validators.ValidateAndThrow(sense);
UndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW("Create Sense",
"Remove sense",
Cache.ServiceLocator.ActionHandler,
Expand All @@ -987,6 +996,7 @@ public Task<Sense> UpdateSense(Guid entryId, Guid senseId, UpdateObjectInput<Sen

public async Task<Sense> UpdateSense(Guid entryId, Sense before, Sense after)
{
await validators.ValidateAndThrowAsync(after);
await Cache.DoUsingNewOrCurrentUOW("Update Sense",
"Revert Sense",
async () =>
Expand Down Expand Up @@ -1073,6 +1083,7 @@ public Task<ExampleSentence> CreateExampleSentence(Guid entryId, Guid senseId, E
if (exampleSentence.Id == default) exampleSentence.Id = Guid.NewGuid();
if (!SenseRepository.TryGetObject(senseId, out var lexSense))
throw new InvalidOperationException("Sense not found");
validators.ValidateAndThrow(exampleSentence);
UndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW("Create Example Sentence",
"Remove example sentence",
Cache.ServiceLocator.ActionHandler,
Expand Down Expand Up @@ -1103,6 +1114,7 @@ public async Task<ExampleSentence> UpdateExampleSentence(Guid entryId,
ExampleSentence before,
ExampleSentence after)
{
await validators.ValidateAndThrowAsync(after);
await Cache.DoUsingNewOrCurrentUOW("Update Example Sentence",
"Revert Example Sentence",
async () =>
Expand Down
16 changes: 14 additions & 2 deletions backend/FwLite/LcmCrdt/CrdtMiniLcmApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public async Task<WritingSystems> GetWritingSystems()

public async Task<WritingSystem> CreateWritingSystem(WritingSystemType type, WritingSystem writingSystem)
{
await validators.ValidateAndThrowAsync(writingSystem);
var entityId = Guid.NewGuid();
var wsCount = await WritingSystems.CountAsync(ws => ws.Type == type);
try
Expand All @@ -69,6 +70,7 @@ public async Task<WritingSystem> UpdateWritingSystem(WritingSystemId id, Writing

public async Task<WritingSystem> UpdateWritingSystem(WritingSystem before, WritingSystem after)
{
await validators.ValidateAndThrowAsync(after);
await WritingSystemSync.Sync(before, after, this);
return await GetWritingSystem(after.WsId, after.Type) ?? throw new NullReferenceException("unable to find writing system with id " + after.WsId);
}
Expand Down Expand Up @@ -101,6 +103,7 @@ public IAsyncEnumerable<PartOfSpeech> GetPartsOfSpeech()

public async Task<PartOfSpeech> CreatePartOfSpeech(PartOfSpeech partOfSpeech)
{
await validators.ValidateAndThrowAsync(partOfSpeech);
await dataModel.AddChange(ClientId, new CreatePartOfSpeechChange(partOfSpeech.Id, partOfSpeech.Name, partOfSpeech.Predefined));
return await GetPartOfSpeech(partOfSpeech.Id) ?? throw new NullReferenceException();
}
Expand All @@ -116,6 +119,7 @@ public async Task<PartOfSpeech> UpdatePartOfSpeech(Guid id, UpdateObjectInput<Pa

public async Task<PartOfSpeech> UpdatePartOfSpeech(PartOfSpeech before, PartOfSpeech after)
{
await validators.ValidateAndThrowAsync(after);
await PartOfSpeechSync.Sync(before, after, this);
return await GetPartOfSpeech(after.Id) ?? throw new NullReferenceException($"unable to find part of speech with id {after.Id}");
}
Expand All @@ -137,6 +141,7 @@ public async Task DeletePartOfSpeech(Guid id)

public async Task<MiniLcm.Models.SemanticDomain> CreateSemanticDomain(MiniLcm.Models.SemanticDomain semanticDomain)
{
await validators.ValidateAndThrowAsync(semanticDomain);
await dataModel.AddChange(ClientId, new CreateSemanticDomainChange(semanticDomain.Id, semanticDomain.Name, semanticDomain.Code, semanticDomain.Predefined));
return await GetSemanticDomain(semanticDomain.Id) ?? throw new NullReferenceException();
}
Expand All @@ -152,6 +157,7 @@ public async Task<SemanticDomain> UpdateSemanticDomain(Guid id, UpdateObjectInpu

public async Task<SemanticDomain> UpdateSemanticDomain(SemanticDomain before, SemanticDomain after)
{
await validators.ValidateAndThrowAsync(after);
await SemanticDomainSync.Sync(before, after, this);
return await GetSemanticDomain(after.Id) ?? throw new NullReferenceException($"unable to find semantic domain with id {after.Id}");
}
Expand All @@ -178,7 +184,7 @@ public IAsyncEnumerable<ComplexFormType> GetComplexFormTypes()

public async Task<ComplexFormType> CreateComplexFormType(ComplexFormType complexFormType)
{
await validators.ValidateAndThrow(complexFormType);
await validators.ValidateAndThrowAsync(complexFormType);
if (complexFormType.Id == default) complexFormType.Id = Guid.NewGuid();
await dataModel.AddChange(ClientId, new CreateComplexFormType(complexFormType.Id, complexFormType.Name));
return await ComplexFormTypes.SingleAsync(c => c.Id == complexFormType.Id);
Expand All @@ -192,7 +198,7 @@ public async Task<ComplexFormType> UpdateComplexFormType(Guid id, UpdateObjectIn

public async Task<ComplexFormType> UpdateComplexFormType(ComplexFormType before, ComplexFormType after)
{
await validators.ValidateAndThrow(after);
await validators.ValidateAndThrowAsync(after);
await ComplexFormTypeSync.Sync(before, after, this);
return await GetComplexFormType(after.Id) ?? throw new NullReferenceException($"unable to find complex form type with id {after.Id}");
}
Expand Down Expand Up @@ -362,6 +368,7 @@ private IEnumerable<IChange> CreateEntryChanges(Entry entry, Dictionary<Guid, Se

public async Task<Entry> CreateEntry(Entry entry)
{
await validators.ValidateAndThrowAsync(entry);
await dataModel.AddChanges(ClientId,
[
new CreateEntryChange(entry),
Expand Down Expand Up @@ -449,6 +456,7 @@ public async Task<Entry> UpdateEntry(Guid id,

public async Task<Entry> UpdateEntry(Entry before, Entry after)
{
await validators.ValidateAndThrowAsync(after);
await EntrySync.Sync(before, after, this);
return await GetEntry(after.Id) ?? throw new NullReferenceException("unable to find entry with id " + after.Id);
}
Expand Down Expand Up @@ -494,6 +502,7 @@ public async Task<Sense> CreateSense(Guid entryId, Sense sense, BetweenPosition?
throw new InvalidOperationException("Order should not be provided when creating a sense");

sense.Order = await OrderPicker.PickOrder(Senses.Where(s => s.EntryId == entryId), between);
await validators.ValidateAndThrowAsync(sense);
await dataModel.AddChanges(ClientId, await CreateSenseChanges(entryId, sense).ToArrayAsync());
return await dataModel.GetLatest<Sense>(sense.Id) ?? throw new NullReferenceException();
}
Expand All @@ -510,6 +519,7 @@ public async Task<Sense> UpdateSense(Guid entryId,

public async Task<Sense> UpdateSense(Guid entryId, Sense before, Sense after)
{
await validators.ValidateAndThrowAsync(after);
await SenseSync.Sync(entryId, before, after, this);
return await GetSense(entryId, after.Id) ?? throw new NullReferenceException("unable to find sense with id " + after.Id);
}
Expand Down Expand Up @@ -539,6 +549,7 @@ public async Task<ExampleSentence> CreateExampleSentence(Guid entryId,
Guid senseId,
ExampleSentence exampleSentence)
{
await validators.ValidateAndThrowAsync(exampleSentence);
await dataModel.AddChange(ClientId, new CreateExampleSentenceChange(exampleSentence, senseId));
return await dataModel.GetLatest<ExampleSentence>(exampleSentence.Id) ?? throw new NullReferenceException();
}
Expand Down Expand Up @@ -567,6 +578,7 @@ public async Task<ExampleSentence> UpdateExampleSentence(Guid entryId,
ExampleSentence before,
ExampleSentence after)
{
await validators.ValidateAndThrowAsync(after);
await ExampleSentenceSync.Sync(entryId, senseId, before, after, this);
return await GetExampleSentence(entryId, senseId, after.Id) ?? throw new NullReferenceException();
}
Expand Down
83 changes: 81 additions & 2 deletions backend/FwLite/MiniLcm/Validators/MiniLcmValidators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,85 @@

namespace MiniLcm.Validators;

public record MiniLcmValidators(IValidator<ComplexFormType> ComplexFormTypeValidator)
public record MiniLcmValidators(
IValidator<ComplexFormType> ComplexFormTypeValidator,
IValidator<Entry> EntryValidator,
IValidator<Sense> SenseValidator,
IValidator<ExampleSentence> ExampleSentenceValidator,
IValidator<WritingSystem> WritingSystemValidator,
IValidator<PartOfSpeech> PartOfSpeechValidator,
IValidator<SemanticDomain> SemanticDomainValidator)
{
public async Task ValidateAndThrow(ComplexFormType value)
public async Task ValidateAndThrowAsync(ComplexFormType value)
{
await ComplexFormTypeValidator.ValidateAndThrowAsync(value);
}

public async Task ValidateAndThrowAsync(Entry value)
{
await EntryValidator.ValidateAndThrowAsync(value);
}

public async Task ValidateAndThrowAsync(Sense value)
{
await SenseValidator.ValidateAndThrowAsync(value);
}

public async Task ValidateAndThrowAsync(ExampleSentence value)
{
await ExampleSentenceValidator.ValidateAndThrowAsync(value);
}

public async Task ValidateAndThrowAsync(WritingSystem value)
{
await WritingSystemValidator.ValidateAndThrowAsync(value);
}

public async Task ValidateAndThrowAsync(PartOfSpeech value)
{
await PartOfSpeechValidator.ValidateAndThrowAsync(value);
}

public async Task ValidateAndThrowAsync(SemanticDomain value)
{
await SemanticDomainValidator.ValidateAndThrowAsync(value);
}

public void ValidateAndThrow(ComplexFormType value)
{
ComplexFormTypeValidator.ValidateAndThrow(value);
}

public void ValidateAndThrow(Entry value)
{
EntryValidator.ValidateAndThrow(value);
}

public void ValidateAndThrow(Sense value)
{
SenseValidator.ValidateAndThrow(value);
}

public void ValidateAndThrow(ExampleSentence value)
{
ExampleSentenceValidator.ValidateAndThrow(value);
}

public void ValidateAndThrow(WritingSystem value)
{
WritingSystemValidator.ValidateAndThrow(value);
}

public void ValidateAndThrow(PartOfSpeech value)
{
PartOfSpeechValidator.ValidateAndThrow(value);
}

public void ValidateAndThrow(SemanticDomain value)
{
SemanticDomainValidator.ValidateAndThrow(value);
}

}

public static class MiniLcmValidatorsExtensions
Expand All @@ -18,6 +91,12 @@ public static IServiceCollection AddMiniLcmValidators(this IServiceCollection se
{
services.AddTransient<MiniLcmValidators>();
services.AddTransient<IValidator<ComplexFormType>, ComplexFormTypeValidator>();
services.AddTransient<IValidator<Entry>, EntryValidator>();
services.AddTransient<IValidator<Sense>, SenseValidator>();
services.AddTransient<IValidator<ExampleSentence>, ExampleSentenceValidator>();
services.AddTransient<IValidator<WritingSystem>, WritingSystemValidator>();

Check failure on line 97 in backend/FwLite/MiniLcm/Validators/MiniLcmValidators.cs

View workflow job for this annotation

GitHub Actions / Build FW Lite and run tests

The type or namespace name 'WritingSystemValidator' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 97 in backend/FwLite/MiniLcm/Validators/MiniLcmValidators.cs

View workflow job for this annotation

GitHub Actions / Build FwHeadless / publish-fw-headless

The type or namespace name 'WritingSystemValidator' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 97 in backend/FwLite/MiniLcm/Validators/MiniLcmValidators.cs

View workflow job for this annotation

GitHub Actions / Build FwHeadless / publish-fw-headless

The type or namespace name 'WritingSystemValidator' could not be found (are you missing a using directive or an assembly reference?)
services.AddTransient<IValidator<PartOfSpeech>, PartOfSpeechValidator>();

Check failure on line 98 in backend/FwLite/MiniLcm/Validators/MiniLcmValidators.cs

View workflow job for this annotation

GitHub Actions / Build FW Lite and run tests

The type or namespace name 'PartOfSpeechValidator' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 98 in backend/FwLite/MiniLcm/Validators/MiniLcmValidators.cs

View workflow job for this annotation

GitHub Actions / Build FwHeadless / publish-fw-headless

The type or namespace name 'PartOfSpeechValidator' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 98 in backend/FwLite/MiniLcm/Validators/MiniLcmValidators.cs

View workflow job for this annotation

GitHub Actions / Build FwHeadless / publish-fw-headless

The type or namespace name 'PartOfSpeechValidator' could not be found (are you missing a using directive or an assembly reference?)
services.AddTransient<IValidator<SemanticDomain>, SemanticDomainValidator>();
return services;
}
}

0 comments on commit 3bcd237

Please sign in to comment.