|
|
|
|
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 Connected.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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|