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 { }