using FluentValidation.Results;
using Raven.Client.Documents.Indexes;
using Raven.Client.Documents.Linq;
using System.Security.Claims;
namespace zero.Stores;
public partial class StoreOperations :
IStoreOperations,
ISharedStoreOperations,
IStoreOperationsWithInactive,
ISharedStoreOperationsWithInactive
{
///
public IZeroDocumentSession Session => Context.Store.Session(_overrideDatabase ?? Config.Database);
///
public StoreConfig Config { get; set; }
protected record OperationOptions(bool IncludeInactive);
protected IZeroContext Context { get; private set; }
protected IInterceptors Interceptors { get; private set; }
protected FlavorOptions Flavors { get; private set; }
string _overrideDatabase = null;
public StoreOperations(IStoreContext context, StoreConfig config = null)
{
Context = context.Context;
Interceptors = context.Interceptors;
Flavors = context.Options.For();
Config = config ?? new();
}
///
public async Task GenerateId(T model) where T : ZeroIdEntity
{
IZeroDocumentSession session = Session;
return await session.Advanced.DocumentStore.Conventions.GenerateDocumentIdAsync(session.Advanced.DocumentStore.Database, model);
}
///
public T AutoSetIds(T model)
{
return IdGenerator.Autofill(model);
}
///
public T PrepareForSave(T model) where T : ZeroIdEntity
{
// set IDs
AutoSetIds(model);
if (model is ZeroEntity zeroModel)
{
// get current user
string userId = Context.BackofficeUser.FindFirstValue(Constants.Auth.Claims.UserId);
// set default properties
if (zeroModel.CreatedDate == default)
{
zeroModel.CreatedDate = DateTimeOffset.Now;
}
if (zeroModel.CreatedById.IsNullOrEmpty())
{
zeroModel.CreatedById = userId;
}
if (zeroModel.LanguageId.IsNullOrEmpty())
{
zeroModel.LanguageId ??= "languages.1-A"; // TODO correct language id
}
// update name alias and last modified
zeroModel.Alias = Safenames.Alias(zeroModel.Name);
zeroModel.LastModifiedById = userId;
zeroModel.LastModifiedDate = DateTimeOffset.Now;
zeroModel.CreatedById ??= userId;
zeroModel.Hash ??= IdGenerator.Create();
}
if (model is IAlwaysActive activeModel)
{
activeModel.IsActive = true;
}
return model;
}
///
/// Do only return the model when it is set to active or inactive entities are included with IncludeInactive()
///
protected virtual T WhenActive(T model) where T : ZeroIdEntity, new()
{
return model != null && (Config.IncludeInactive || model is IAlwaysActive || model is not ZeroEntity || (model as ZeroEntity).IsActive) ? model : default;
}
}
public interface IStoreOperations
{
///
/// Access to the current session
///
IZeroDocumentSession Session { get; }
///
/// Configure operations
///
StoreConfig Config { get; set; }
///
/// Get new instance of an entity (with an optional flavor)
///
Task Empty(string flavorAlias = null) where T : ZeroIdEntity, ISupportsFlavors, new();
///
/// Get new instance of an entity with a specific flavor
///
/// Optional alias. If left out the default flavor is used (if configured)
Task Empty(string flavorAlias = null)
where T : ZeroIdEntity, ISupportsFlavors, new()
where TFlavor : T, new();
///
/// Generate model Id by using configured document store conventions
///
Task GenerateId(T model) where T : ZeroIdEntity;
///
/// Generate values for all properties (incl. nested) which contain the [GenerateId] attribute
///
T AutoSetIds(T model);
///
/// Automatically fill base properties of a ZeroEntity
///
T PrepareForSave(T model) where T : ZeroIdEntity;
///
/// Check if any items exist in this collection (with optional query)
///
Task Any(Func, IQueryable> querySelector = default) where T : ZeroIdEntity, new();
///
/// Get an entity by Id
///
Task Load(string id, string changeVector = null) where T : ZeroIdEntity, new();
///
/// Get entities by ids
///
Task> Load(IEnumerable ids) where T : ZeroIdEntity, new();
///
/// Get entities by query
///
Task> Load(int pageNumber, int pageSize, Func, IQueryable> expression = default) where T : ZeroIdEntity, new();
///
/// Get entities by query (by using the specified index)
///
Task> Load(int pageNumber, int pageSize, Func, IQueryable> expression = default) where T : ZeroIdEntity, new() where TIndex : AbstractCommonApiForIndexes, new();
///
/// Get all entities from this collection.
/// Warning: Don't use this method for large collections. Stream the results instead.
///
Task> LoadAll() where T : ZeroIdEntity, new();
///
/// Stream the collection
///
IAsyncEnumerable Stream(Func, IQueryable> expression) where T : ZeroIdEntity, new();
///
/// Get the change vector for a model
///
string GetChangeToken(T model) where T : ZeroIdEntity, new();
///
/// Creates an entity with an optional validator
///
Task> Create(T model, Func> validate = null) where T : ZeroIdEntity, new();
///
/// Updates an entity with an optional validator
///
Task> Update(T model, Func> validate = null) where T : ZeroIdEntity, new();
///
Task>> Sort(string[] sortedIds) where T : ZeroIdEntity, ISupportsSorting, new();
///
/// Deletes an entity
///
Task> Delete(T model) where T : ZeroIdEntity, new();
///
/// Loads all children for an entity
///
Task> LoadChildren(string parentId, int pageNumber, int pageSize, Func, IQueryable> querySelector = default) where T : ZeroIdEntity, ISupportsTrees, new();
///
/// Get descendants by query (by using the specified index)
///
Task> LoadChildren(string parentId, int pageNumber, int pageSize, Func, IQueryable> querySelector = default) where T : ZeroIdEntity, ISupportsTrees, new() where TIndex : AbstractCommonApiForIndexes, new();
///
/// Get tree hierarchy for an entity
///
Task GetHierarchy(string id) where T : ZeroIdEntity, ISupportsTrees, new() where TIndex : ZeroTreeHierarchyIndex, new();
///
/// Move an entity to a new parent
///
Task> Move(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, ISupportsTrees, new();
///
/// Copies an entity to a new location
///
Task> Copy(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, ISupportsTrees, new();
///
/// Copies an entity with descendants to a new location
///
Task> CopyWithDescendants(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, ISupportsTrees, new();
///
/// Deletes an entity with all descendents
///
Task> DeleteWithDescendants(T model) where T : ZeroIdEntity, ISupportsTrees, new();
}
public interface ISharedStoreOperations : IStoreOperations { }
public interface IStoreOperationsWithInactive : IStoreOperations { }
public interface ISharedStoreOperationsWithInactive : IStoreOperations { }