using System.Collections.Immutable;
using Connected;
using Connected.Entities;
using Connected.Entities.Storage;
using Connected.Globalization.Languages;
using Connected.Notifications.Events;
using Connected.ServiceModel;
using Connected.Services;
namespace Common.Globalization;
///
/// Queries all records except those marked as deleting.
///
internal sealed class QueryLanguages : ServiceFunction?>
{
public QueryLanguages(ILanguageCache cache)
{
Cache = cache;
}
private ILanguageCache Cache { get; }
protected override async Task?> OnInvoke()
{
/*
* Filter records to return only currently valid record. Those with
* deleting state should never be returned to any client.
*/
return await (from dc in Cache
select dc).AsEntities();
}
}
///
/// Queries the records for the specified set of ids.
///
internal sealed class LookupLanguages : ServiceFunction, ImmutableList>
{
public LookupLanguages(ILanguageCache cache)
{
Cache = cache;
}
private ILanguageCache Cache { get; }
protected override async Task?> OnInvoke()
{
if (Arguments?.IdList is null)
return default;
return await (from dc in Cache
where Arguments.IdList.Any(f => f == dc.Id)
select dc).AsEntities();
}
}
///
/// Returns first with matches the provided mapping.
///
internal sealed class ResolveLanguage : ServiceFunction
{
public ResolveLanguage(ILanguageCache cache)
{
Cache = cache;
}
private ILanguageCache Cache { get; }
protected override Task OnInvoke()
{
return Task.FromResult(Cache.Select(Arguments.Mapping));
}
}
///
/// Returns with the specified id or null
/// if the record for the specified id does not exist.
///
internal sealed class SelectLanguage : ServiceFunction, ILanguage?>
{
public SelectLanguage(ILanguageCache cache)
{
Cache = cache;
}
private ILanguageCache Cache { get; }
protected override async Task OnInvoke()
{
return await (from dc in Cache
where dc.Id == Arguments.Id
select dc).AsEntity();
}
}
///
/// Returns with the specified name and rate or null if
/// the record with the specified arguments does not exist.
///
internal sealed class SelectLanguageByName : ServiceFunction
{
public SelectLanguageByName(ILanguageCache cache)
{
Cache = cache;
}
private ILanguageCache Cache { get; }
protected override async Task OnInvoke()
{
return await (from dc in Cache
where string.Equals(dc.Name, Arguments.Name, StringComparison.OrdinalIgnoreCase)
select dc).AsEntity();
}
}
///
/// Inserts a new and returns its Id.
///
internal sealed class InsertLanguage : ServiceFunction
{
public InsertLanguage(ILanguageService languageService, IStorageProvider storage, IEventService events, ILanguageCache cache)
{
LanguageService = languageService;
Storage = storage;
Events = events;
Cache = cache;
}
///
/// We need this service to call a distribute event.
///
private ILanguageService LanguageService { get; }
private IStorageProvider Storage { get; }
private IEventService Events { get; }
private ILanguageCache Cache { get; }
protected override async Task OnInvoke()
{
/*
* First, create a new entity from the passed arguments and mark its state as new. This will
* signal the DatabaseContext to perform an insert operation when calling the Update.
*/
var entity = Arguments.AsEntity(State.New);
/*
* Call update on the DatabaseContext. This call will return a new ILanguage of the inserted
* entity.
*/
var result = await Storage.Open().Update(entity);
/*
* Return a newly inserted id to the caller.
*/
return result.Id;
}
protected override async Task OnCommitted()
{
await Cache.Refresh(Result);
/*
* If ILanguageServer is our implementation (and should be) it's a IServerNotificationsTriggers
* for sure.
*/
await Events.Enqueue(this, LanguageService, ServiceEvents.Inserted, Result);
}
}
internal sealed class DeleteLanguage : ServiceAction>
{
public DeleteLanguage(ILanguageService languageService, IStorageProvider storage, ILanguageCache cache, IEventService events)
{
LanguageService = languageService;
Storage = storage;
Cache = cache;
Events = events;
}
private ILanguageService LanguageService { get; }
private IStorageProvider Storage { get; }
private ILanguageCache Cache { get; }
private IEventService Events { get; }
protected override async Task OnInvoke()
{
var entity = new Language { Id = Arguments.Id, State = State.Deleted };
await Storage.Open().Update(entity);
}
protected override async Task OnCommitted()
{
await Cache.Remove(Arguments.Id);
await Events.Enqueue(this, LanguageService, ServiceEvents.Deleted, Arguments.Id);
}
}
///
/// Updates entity.
///
internal sealed class UpdateLanguage : ServiceAction
{
public UpdateLanguage(ILanguageService languageService, IStorageProvider storage, ILanguageCache cache, IEventService events)
{
LanguageService = languageService;
Storage = storage;
Cache = cache;
Events = events;
}
private ILanguageService LanguageService { get; }
private IStorageProvider Storage { get; }
private ILanguageCache Cache { get; }
private IEventService Events { get; }
protected override async Task OnInvoke()
{
/*
* Updating Concurrency entity requires a bit more logic. Since Concurrency entity
* guarantees data consistency we must use a retry logic in case of
* Concurrency failure. We'll call Update method with reload lambda function.
*/
await Storage.Open().Update(await Load(), Arguments, async () =>
{
/*
* Remove entry from the cache to ensure it will be loaded from the database
* next time.
*/
await Cache.Refresh(Arguments.Id);
return await Load();
});
}
private async Task Load() => await (from dc in Cache where dc.Id == Arguments.Id select dc).AsEntity();
protected override async Task OnCommitted()
{
/*
* Once the update is complete remove the entity from the cache because its concurrency
* state is not valid enymore.
*/
await Cache.Remove(Arguments.Id);
/*
* Now trigger the distributed event notifying the update has completed.
*/
await Events.Enqueue(this, LanguageService, ServiceEvents.Updated, Arguments.Id);
}
}