You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
235 lines
6.8 KiB
235 lines
6.8 KiB
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;
|
|
|
|
/// <summary>
|
|
/// Queries all <see cref="ILanguage"/> records except those marked as deleting.
|
|
/// </summary>
|
|
internal sealed class QueryLanguages : ServiceFunction<IDto, ImmutableList<ILanguage>?>
|
|
{
|
|
public QueryLanguages(ILanguageCache cache)
|
|
{
|
|
Cache = cache;
|
|
}
|
|
|
|
private ILanguageCache Cache { get; }
|
|
protected override async Task<ImmutableList<ILanguage>?> 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<ILanguage>();
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Queries the <see cref="ILanguage"/> records for the specified set of ids.
|
|
/// </summary>
|
|
internal sealed class LookupLanguages : ServiceFunction<PrimaryKeyListArgs<int>, ImmutableList<ILanguage>>
|
|
{
|
|
public LookupLanguages(ILanguageCache cache)
|
|
{
|
|
Cache = cache;
|
|
}
|
|
|
|
private ILanguageCache Cache { get; }
|
|
protected override async Task<ImmutableList<ILanguage>?> 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<ILanguage>();
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Returns first <see cref="ILanguage"/> with matches the provided mapping.
|
|
/// </summary>
|
|
internal sealed class ResolveLanguage : ServiceFunction<LanguageResolveArgs, ILanguage?>
|
|
{
|
|
public ResolveLanguage(ILanguageCache cache)
|
|
{
|
|
Cache = cache;
|
|
}
|
|
|
|
private ILanguageCache Cache { get; }
|
|
protected override Task<ILanguage?> OnInvoke()
|
|
{
|
|
return Task.FromResult<ILanguage?>(Cache.Select(Arguments.Mapping));
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Returns <see cref="ILanguage"/> with the specified id or null
|
|
/// if the record for the specified id does not exist.
|
|
/// </summary>
|
|
internal sealed class SelectLanguage : ServiceFunction<PrimaryKeyArgs<int>, ILanguage?>
|
|
{
|
|
public SelectLanguage(ILanguageCache cache)
|
|
{
|
|
Cache = cache;
|
|
}
|
|
|
|
private ILanguageCache Cache { get; }
|
|
protected override async Task<ILanguage?> OnInvoke()
|
|
{
|
|
return await (from dc in Cache
|
|
where dc.Id == Arguments.Id
|
|
select dc).AsEntity();
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Returns <see cref="ILanguage"/> with the specified name and rate or null if
|
|
/// the record with the specified arguments does not exist.
|
|
/// </summary>
|
|
internal sealed class SelectLanguageByName : ServiceFunction<NameArgs, ILanguage?>
|
|
{
|
|
public SelectLanguageByName(ILanguageCache cache)
|
|
{
|
|
Cache = cache;
|
|
}
|
|
|
|
private ILanguageCache Cache { get; }
|
|
|
|
protected override async Task<ILanguage?> OnInvoke()
|
|
{
|
|
return await (from dc in Cache
|
|
where string.Equals(dc.Name, Arguments.Name, StringComparison.OrdinalIgnoreCase)
|
|
select dc).AsEntity();
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Inserts a new <see cref="ILanguage"/> and returns its Id.
|
|
/// </summary>
|
|
internal sealed class InsertLanguage : ServiceFunction<LanguageInsertArgs, int>
|
|
{
|
|
public InsertLanguage(ILanguageService languageService, IStorageProvider storage, IEventService events, ILanguageCache cache)
|
|
{
|
|
LanguageService = languageService;
|
|
Storage = storage;
|
|
Events = events;
|
|
Cache = cache;
|
|
}
|
|
/// <summary>
|
|
/// We need this service to call a distribute event.
|
|
/// </summary>
|
|
private ILanguageService LanguageService { get; }
|
|
private IStorageProvider Storage { get; }
|
|
private IEventService Events { get; }
|
|
private ILanguageCache Cache { get; }
|
|
|
|
protected override async Task<int> 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<Language>(State.New);
|
|
/*
|
|
* Call update on the DatabaseContext. This call will return a new ILanguage of the inserted
|
|
* entity.
|
|
*/
|
|
var result = await Storage.Open<Language>().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<PrimaryKeyArgs<int>>
|
|
{
|
|
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<Language>().Update(entity);
|
|
}
|
|
|
|
protected override async Task OnCommitted()
|
|
{
|
|
await Cache.Remove(Arguments.Id);
|
|
await Events.Enqueue(this, LanguageService, ServiceEvents.Deleted, Arguments.Id);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Updates <see cref="ILanguage"/> entity.
|
|
/// </summary>
|
|
internal sealed class UpdateLanguage : ServiceAction<LanguageUpdateArgs>
|
|
{
|
|
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<Language>().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<Language> 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);
|
|
}
|
|
}
|