using System.Collections.Immutable; using Connected.Caching; using Connected.Entities; using Connected.Entities.Storage; using Connected.Notifications; using Connected.Notifications.Events; using Connected.ServiceModel; using Connected.ServiceModel.Search; using Connected.Services; namespace Common.Notes; internal static class NoteOps { /// /// Deletes the note entity, its text and search entity from the storage. /// public class Delete : ServiceAction> { /// /// Create a new instance. /// public Delete(IStorageProvider storage, IEventService events) { Storage = storage; Events = events; } private IStorageProvider Storage { get; } private IEventService Events { get; } protected override async Task OnInvoke() { /* * First delete the entity. */ await Storage.Open().Update(Arguments.AsEntity(State.Deleted)); /* * Delete the note's text. */ await Storage.Open().Update(Arguments.AsEntity(State.Deleted)); /* * Delete search entry. */ await Storage.Open().Update(Arguments.AsEntity(State.Deleted)); } protected override async Task OnCommitted() { /* * We are triggering notify only for the entity, not for text and search transactions. * Note that we don't cache text and search entries. They are read from the storage every time * it is requested. */ await Events.Enqueue(this, typeof(NoteService), nameof(IServiceNotifications.Deleted), Arguments); } } /// /// Inserts a new note entity into storage. /// /// /// This class inserts a new entity into storage, then inserts text /// into table storage and the creates a search index entry. /// public sealed class Insert : ServiceFunction { public Insert(IStorageProvider storage, IEventService events) { Storage = storage; Events = events; } private IStorageProvider Storage { get; } private IEventService Events { get; } protected override async Task OnInvoke() { /* * This call inserts a new record into storage (database) and returns its id. */ var result = await Storage.Open().Update(Arguments.AsEntity(State.New)); /* * We'll be using a newly inserted id to create a new record in the table * storage for text. */ await Storage.Open().Update(Arguments.AsEntity(State.New, new { result.Id })); /* * And create entry in the search index. */ //await Storage.Open().Update(Arguments.AsEntity(State.New, new { result.Id })); return result.Id; } protected override async Task OnCommitted() { await Events.Enqueue(this, typeof(NoteService), nameof(IServiceNotifications.Inserted), new PrimaryKeyArgs { Id = Result }); } } public sealed class Update : ServiceAction { public Update(IStorageProvider storage, ICacheContext cache, IEventService events, INoteService notes) { Storage = storage; Cache = cache; Events = events; Notes = notes; } private IStorageProvider Storage { get; } private ICacheContext Cache { get; } private IEventService Events { get; } private INoteService Notes { get; } protected override async Task OnInvoke() { if (await Notes.Select(Arguments.Id) is not INote entity) return; await Storage.Open().Update(Arguments.AsEntity(State.Default), Arguments, async () => { await Cache.Remove(Note.EntityKey, Arguments.Id); return (await Notes.Select(Arguments.Id)) as Note; }); await Storage.Open().Update(Arguments.AsEntity(State.Default), Arguments, async () => { await Cache.Remove(NoteText.EntityKey, Arguments.Id); return (await Notes.SelectText(new SelectNoteTextArgs { Entity = entity.Entity, EntityId = entity.EntityId, Id = Arguments.Id })) as NoteText; }); await Storage.Open().Update(Arguments.AsEntity(State.Default)); } protected override async Task OnCommitted() { await Cache.Remove(Note.EntityKey, Arguments.Id); await Cache.Remove(NoteText.EntityKey, Arguments.Id); await Events.Enqueue(this, typeof(NoteService), nameof(IServiceNotifications.Updated), new PrimaryKeyArgs { Id = Arguments.Id }); } } public sealed class Query : ServiceFunction> { public Query(IStorageProvider provider) { Provider = provider; } private IStorageProvider Provider { get; } protected override async Task> OnInvoke() { return await (from dc in Provider.Open() select dc).AsEntities(); } } public sealed class Select : ServiceFunction, INote> { public Select(IStorageProvider provider, ICacheContext cache) { Provider = provider; Cache = cache; } private IStorageProvider Provider { get; } private ICacheContext Cache { get; } protected override Task OnInvoke() { return Cache.Get(Note.EntityKey, Arguments.Id, async (f) => { return await (from dc in Provider.Open() where dc.Id == Arguments.Id select dc).AsEntity(); }); } } public sealed class Search : ServiceFunction> { public Search(IStorageProvider storage) { Storage = storage; } private IStorageProvider Storage { get; } protected override async Task?> OnInvoke() { return await (from dc in Storage.Open() where dc.Text.Contains(Arguments.Text) select dc).AsEntities(); } } public sealed class QueryText : ServiceFunction> { public QueryText(IStorageProvider storage) { Storage = storage; } private IStorageProvider Storage { get; } protected override async Task?> OnInvoke() { return await (from dc in Storage.Open() where string.Equals(dc.Entity, Arguments.Entity, StringComparison.Ordinal) && Arguments.IdList.Any(f => f == dc.Id) select dc).AsEntities(); } } public sealed class SelectText : ServiceFunction { public SelectText(IStorageProvider provider) { Provider = provider; } private IStorageProvider Provider { get; } protected override async Task OnInvoke() { return await (from dc in Provider.Open() where string.Equals(dc.Entity, Arguments.Entity) && string.Equals(dc.EntityId, Arguments.EntityId) && dc.Id == Arguments.Id select dc).AsEntity(); } } }