using Raven.Client.Documents;
using Raven.Client.Documents.Indexes;
using Raven.Client.Documents.Linq;
using Raven.Client.Documents.Session;
namespace zero.Stores;
public partial class StoreOperations : IStoreOperations
{
///
public virtual Task IsAllowedAsChild(T model, string parentId) where T : ZeroIdEntity, ISupportsTrees, new()
{
return Task.FromResult(true);
}
///
public async Task GetHierarchy(string id)
where T : ZeroIdEntity, ISupportsTrees, new()
where TIndex : ZeroTreeHierarchyIndex, new()
{
ZeroTreeHierarchyIndexResult result = await Session.Query()
.ProjectInto()
.Include(x => x.Path)
.Include(x => x.Id)
.FirstOrDefaultAsync(x => x.Id == id);
if (result == null)
{
return Array.Empty();
}
List ids = result.Path ?? new();
ids.Add(id);
return (await Session.LoadAsync(ids)).Select(x => x.Value).ToArray();
}
///
public async Task> LoadChildren(string parentId, int pageNumber, int pageSize, Func, IQueryable> querySelector = default) where T : ZeroIdEntity, ISupportsTrees, new()
{
IRavenQueryable queryable = Session.Query().Where(x => x.ParentId == parentId).Statistics(out QueryStatistics statistics);
querySelector ??= x => x.OrderBy(x => x.Sort);
List result = await querySelector(queryable).Paging(pageNumber, pageSize).ToListAsync();
return new Paged(result, statistics.TotalResults, pageNumber, pageSize);
}
///
public async Task> LoadChildren(string parentId, int pageNumber, int pageSize, Func, IQueryable> querySelector = default)
where T : ZeroIdEntity, ISupportsTrees, new()
where TIndex : AbstractCommonApiForIndexes, new()
{
IRavenQueryable queryable = Session.Query().Where(x => x.ParentId == parentId).Statistics(out QueryStatistics statistics);
querySelector ??= x => x.OrderBy(x => x.Sort);
var query = querySelector(queryable).Paging(pageNumber, pageSize);
List result = await query.ToListAsync();
return new Paged(result, statistics.TotalResults, pageNumber, pageSize);
}
///
public async Task> Move(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, ISupportsTrees, new()
{
T model = await Load(id);
T parent = await Load(newParentId);
if (model == null || (!newParentId.IsNullOrEmpty() && parent == null))
{
return Result.Fail("@errors.idnotfound");
}
if (isParentAllowed != null && !await isParentAllowed(model, newParentId))
{
return Result.Fail("@errors.treeentity.parentnotallowed");
}
model.ParentId = parent?.Id;
return await Update(model);
}
///
public Task> Copy(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, ISupportsTrees, new() => Copy(id, newParentId, false, isParentAllowed);
///
public Task> CopyWithDescendants(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, ISupportsTrees, new() => Copy(id, newParentId, true, isParentAllowed);
///
/// Copies an entity (with optional descendants) to a new location
///
protected async Task> Copy(string id, string newParentId, bool includeDescendants, Func> isParentAllowed = null) where T : ZeroIdEntity, ISupportsTrees, new()
{
T model = ObjectCopycat.Clone(await Load(id));
T parent = await Load(newParentId);
if (model == null || (!newParentId.IsNullOrEmpty() && parent == null))
{
return Result.Fail("@errors.idnotfound");
}
string baseId = model.Id;
string originalParentId = model.ParentId;
// update new page properties
model.Id = null;
model.ParentId = parent?.Id;
if (model is ZeroEntity zeroEntity)
{
zeroEntity.IsActive = false;
zeroEntity.CreatedDate = DateTime.Now;
// update page name in case they are on the same level
string name = zeroEntity.Name;
if (originalParentId == parent?.Id || await Session.Query().AnyAsync(x => x.Name == name && x.ParentId == newParentId))
{
zeroEntity.Name += " (copy #" + IdGenerator.Create(4) + ")";
}
}
// check if new parent is allowed
if (isParentAllowed != null && !await isParentAllowed(model, newParentId))
{
return Result.Fail("@errors.treeentity.parentnotallowed");
}
Result result = await Create(model);
// recursive function to store descendants
if (includeDescendants)
{
List children = await Session.Query().Where(x => x.ParentId == baseId).ToListAsync();
foreach (T child in children)
{
await Copy(child.Id, model.Id, true, isParentAllowed);
}
}
return result;
}
///
public async Task> DeleteWithDescendants(T model) where T : ZeroIdEntity, ISupportsTrees, new()
{
List pages = await GetDescendantsAndSelf(model);
if (pages.Count < 1)
{
return Result.Fail("@errors.ondelete.idnotfound");
}
await this.Delete(pages.ToArray());
return Result.Success(pages.Select(x => x.Id).ToArray());
}
///
/// Get an entity with all its descendants
///
async Task> GetDescendantsAndSelf(T model) where T : ZeroIdEntity, ISupportsTrees, new()
{
List items = new() { model };
async Task AddChildren(T parent)
{
string parentId = parent.Id;
List children = await Session.Query().Where(x => x.ParentId == parentId).ToListAsync();
items.AddRange(children);
foreach (T child in children)
{
await AddChildren(child);
}
}
await AddChildren(model);
return items;
}
}