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.
Connected.Common/Common.Notes/NoteOps.cs

241 lines
6.7 KiB

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
{
/// <summary>
/// Deletes the note entity, its text and search entity from the storage.
/// </summary>
public class Delete : ServiceAction<PrimaryKeyArgs<long>>
{
/// <summary>
/// Create a new <see cref="Delete"/> instance.
/// </summary>
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<Note>().Update(Arguments.AsEntity<Note>(State.Deleted));
/*
* Delete the note's text.
*/
await Storage.Open<NoteText>().Update(Arguments.AsEntity<NoteText>(State.Deleted));
/*
* Delete search entry.
*/
await Storage.Open<NoteSearch>().Update(Arguments.AsEntity<NoteSearch>(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<long>.Deleted), Arguments);
}
}
/// <summary>
/// Inserts a new note entity into storage.
/// </summary>
/// <remarks>
/// This class inserts a new <see cref="INote"/> entity into storage, then inserts text
/// into table storage and the creates a search index entry.
/// </remarks>
public sealed class Insert : ServiceFunction<InsertNoteArgs, long>
{
public Insert(IStorageProvider storage, IEventService events)
{
Storage = storage;
Events = events;
}
private IStorageProvider Storage { get; }
private IEventService Events { get; }
protected override async Task<long> OnInvoke()
{
/*
* This call inserts a new record into storage (database) and returns its id.
*/
var result = await Storage.Open<Note>().Update(Arguments.AsEntity<Note>(State.New));
/*
* We'll be using a newly inserted id to create a new record in the table
* storage for text.
*/
await Storage.Open<NoteText>().Update(Arguments.AsEntity<NoteText>(State.New, new { result.Id }));
/*
* And create entry in the search index.
*/
//await Storage.Open<NoteSearch>().Update(Arguments.AsEntity<NoteSearch>(State.New, new { result.Id }));
return result.Id;
}
protected override async Task OnCommitted()
{
await Events.Enqueue(this, typeof(NoteService), nameof(IServiceNotifications<long>.Inserted), new PrimaryKeyArgs<long> { Id = Result });
}
}
public sealed class Update : ServiceAction<UpdateNoteArgs>
{
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<Note>().Update(Arguments.AsEntity<Note>(State.Default), Arguments, async () =>
{
await Cache.Remove(Note.EntityKey, Arguments.Id);
return (await Notes.Select(Arguments.Id)) as Note;
});
await Storage.Open<NoteText>().Update(Arguments.AsEntity<NoteText>(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<NoteSearch>().Update(Arguments.AsEntity<NoteSearch>(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<long>.Updated), new PrimaryKeyArgs<long> { Id = Arguments.Id });
}
}
public sealed class Query : ServiceFunction<NoteArgs, ImmutableList<INote>>
{
public Query(IStorageProvider provider)
{
Provider = provider;
}
private IStorageProvider Provider { get; }
protected override async Task<ImmutableList<INote>> OnInvoke()
{
return await (from dc in Provider.Open<Note>() select dc).AsEntities<INote>();
}
}
public sealed class Select : ServiceFunction<PrimaryKeyArgs<long>, INote>
{
public Select(IStorageProvider provider, ICacheContext cache)
{
Provider = provider;
Cache = cache;
}
private IStorageProvider Provider { get; }
private ICacheContext Cache { get; }
protected override Task<INote?> OnInvoke()
{
return Cache.Get<INote>(Note.EntityKey, Arguments.Id,
async (f) =>
{
return await (from dc in Provider.Open<Note>() where dc.Id == Arguments.Id select dc).AsEntity();
});
}
}
public sealed class Search : ServiceFunction<SearchArgs, ImmutableList<INoteSearch>>
{
public Search(IStorageProvider storage)
{
Storage = storage;
}
private IStorageProvider Storage { get; }
protected override async Task<ImmutableList<INoteSearch>?> OnInvoke()
{
return await (from dc in Storage.Open<NoteSearch>()
where dc.Text.Contains(Arguments.Text)
select dc).AsEntities<INoteSearch>();
}
}
public sealed class QueryText : ServiceFunction<QueryNoteTextArgs, ImmutableList<INoteText>>
{
public QueryText(IStorageProvider storage)
{
Storage = storage;
}
private IStorageProvider Storage { get; }
protected override async Task<ImmutableList<INoteText>?> OnInvoke()
{
return await (from dc in Storage.Open<NoteText>()
where string.Equals(dc.Entity, Arguments.Entity, StringComparison.Ordinal)
&& Arguments.IdList.Any(f => f == dc.Id)
select dc).AsEntities<INoteText>();
}
}
public sealed class SelectText : ServiceFunction<SelectNoteTextArgs, INoteText>
{
public SelectText(IStorageProvider provider)
{
Provider = provider;
}
private IStorageProvider Provider { get; }
protected override async Task<INoteText?> OnInvoke()
{
return await (from dc in Provider.Open<NoteText>()
where string.Equals(dc.Entity, Arguments.Entity)
&& string.Equals(dc.EntityId, Arguments.EntityId)
&& dc.Id == Arguments.Id
select dc).AsEntity();
}
}
}