public async Task <ClassifierGroup> Handle(GetClassifierGroup request, CancellationToken cancellationToken) { var typeCode = request.TypeCode ?? throw new ArgumentNullException(nameof(request.TypeCode)); var type = await _classifierTypeService.Get(typeCode, cancellationToken); using (var db = _dbContextFactory.Create()) { if (type.HierarchyType == HierarchyType.Groups) { var tree = await db.GetTable <DbClassifierTree>() .SingleAsync(x => x.TypeUid == type.Uid && x.Uid == request.TreeUid, cancellationToken); var item = await db.GetTable <DbClassifierGroup>() .SingleAsync(x => x.TreeUid == tree.Uid && x.Uid == request.Uid, cancellationToken); return(new ClassifierGroup { Uid = item.Uid, TreeUid = item.TreeUid, ParentUid = item.ParentUid, Code = item.Code, Name = item.Name }); } throw new InvalidOperationException("Groups not supported for classifiers with hierarchy type " + type.HierarchyType); } }
public async Task <ApiResult> Handle(DeleteClassifierTree request, CancellationToken cancellationToken) { if (request.UserUid == Guid.Empty) { throw new InvalidOperationException("User is required."); } var type = await _classifierTypeService.Get(request.TypeCode, cancellationToken); using (var scope = _unitOfWorkFactory.Create()) { int affected; using (var db = _dbContextFactory.Create()) { // todo: return error when trying to remove default tree affected = await db.GetTable <DbClassifierTree>() .Where(x => x.TypeUid == type.Uid && request.Uids.Contains(x.Uid) && x.Code != ClassifierTree.DefaultCode) .DeleteAsync(cancellationToken); } scope.Commit(); return(new ApiResult { AffectedRows = affected }); } }
public async Task <ApiResult> Handle(UpdateClassifierTree request, CancellationToken cancellationToken) { if (request.UserUid == Guid.Empty) { throw new InvalidOperationException("User is required."); } var item = request.Item ?? throw new ArgumentNullException(nameof(request.Item)); var type = await _classifierTypeService.Get(request.TypeCode, cancellationToken); using (var scope = _unitOfWorkFactory.Create()) { int affected; using (var db = _dbContextFactory.Create()) { affected = await db.GetTable <DbClassifierTree>() .Where(x => x.TypeUid == type.Uid && x.Uid == item.Uid) .Set(x => x.Code, item.Code) // todo: do not update default tree code (?) .Set(x => x.Name, item.Name) .UpdateAsync(cancellationToken); } scope.Commit(); return(new ApiResult { AffectedRows = affected }); } }
public async Task <ApiResult> Handle(InsertClassifierTree request, CancellationToken cancellationToken) { if (request.UserUid == Guid.Empty) { throw new InvalidOperationException("User is required."); } var item = request.Item ?? throw new ArgumentNullException(nameof(request.Item)); var type = await _classifierTypeService.Get(request.TypeCode, cancellationToken); using (var scope = _unitOfWorkFactory.Create()) { var itemUid = Guid.NewGuid(); using (var db = _dbContextFactory.Create()) { // todo: company + modification data // insert classifier tree await db.GetTable <DbClassifierTree>() .Value(x => x.Uid, itemUid) .Value(x => x.TypeUid, type.Uid) .Value(x => x.Code, item.Code) .Value(x => x.Name, item.Name) .InsertAsync(cancellationToken); scope.Commit(); } return(new ApiResult { Uid = itemUid }); } }
public async Task <SearchResult <Classifier> > Search(ClassifierSearchRequest request, CancellationToken cancellationToken) { var type = await _classifierTypeService.Get(request.TypeCode, cancellationToken); using (var db = _dbContextFactory.Create()) { var result = await SearchInternal(db, type, request, cancellationToken); // search in data by Uid is not effective - O(n), but ok for small collections if (request.FocusUid.HasValue && result.Rows.Any(x => x.Uid == request.FocusUid) == false) { // todo: add test var focus = await SearchInternal(db, type, new ClassifierSearchRequest { Uid = request.FocusUid, SkipPaging = true }, cancellationToken); for (var i = focus.Rows.Count - 1; i >= 0; i--) { result.Rows.Insert(0, focus.Rows[i]); } } // todo: preload fields for multiple items or (?) store fields in the same table? if (request.IncludeFields) { var metadata = await _metadataService.GetMetadata(type, cancellationToken); foreach (var item in result.Rows) { var fields = await _fieldDataRepository.Search(new FieldDataSearchRequest { Metadata = metadata, EntityTypeCode = Classifier.TypeCode, // ReSharper disable once PossibleInvalidOperationException EntityUids = new[] { item.Uid.Value } }, cancellationToken); item.Fields = fields.Rows.SingleOrDefault(); } } return(result); } }
public async Task <ApiResult> Handle(InsertClassifierGroup request, CancellationToken cancellationToken) { if (request.UserUid == Guid.Empty) { throw new InvalidOperationException("User is required."); } var item = request.Item ?? throw new ArgumentNullException(nameof(request.Item)); var type = await _classifierTypeService.Get(request.TypeCode, cancellationToken); using (var scope = _unitOfWorkFactory.Create()) { var itemUid = Guid.NewGuid(); // todo: validation and limits using (var db = _dbContextFactory.Create()) { var tree = await db.GetTable <DbClassifierTree>() .SingleAsync(x => x.TypeUid == type.Uid && x.Uid == request.TreeUid, cancellationToken); var validator = new ClassifierGroupValidator(db); if (await validator.ValidateInsert(item, cancellationToken) == false) { return(new ApiResult { Success = false, Errors = validator.Errors }); } await db.GetTable <DbClassifierGroup>() .Value(x => x.Uid, itemUid) .Value(x => x.TreeUid, tree.Uid) // todo: validate parent belongs to the same tree .Value(x => x.ParentUid, item.ParentUid) .Value(x => x.Code, item.Code) .Value(x => x.Name, item.Name) .InsertAsync(cancellationToken); var closureTable = new ClosureTableHandler(db, type); if (await closureTable.Insert(itemUid, item.ParentUid, cancellationToken) == false) { return(new ApiResult { Success = false, Errors = closureTable.Errors }); } } scope.Commit(); return(new ApiResult { Uid = itemUid }); } }
public async Task <ApiResult> Handle(UpdateClassifierGroup request, CancellationToken cancellationToken) { if (request.UserUid == Guid.Empty) { throw new InvalidOperationException("User is required."); } var item = request.Item ?? throw new ArgumentNullException(nameof(request.Item)); // todo: validate required fields var type = await _classifierTypeService.Get(request.TypeCode, cancellationToken); using (var scope = _unitOfWorkFactory.Create()) { int affected; using (var db = _dbContextFactory.Create()) { /*var tree = await db.GetTable<DbClassifierTree>() * .SingleAsync(x => x.TypeUid == type.Uid && x.Code == request.TreeCode, cancellationToken);*/ var validator = new ClassifierGroupValidator(db); if (await validator.ValidateUpdate(item, cancellationToken) == false) { return(new ApiResult { Success = false, Errors = validator.Errors }); } var closureTable = new ClosureTableHandler(db, type); if (await closureTable.Update(item.Uid, item.ParentUid, cancellationToken) == false) { return(new ApiResult { Success = false, Errors = closureTable.Errors }); } affected = await db.GetTable <DbClassifierGroup>() .Where(x => x.Uid == item.Uid) .Set(x => x.ParentUid, item.ParentUid) .Set(x => x.Code, item.Code) .Set(x => x.Name, item.Name) .UpdateAsync(cancellationToken); } scope.Commit(); return(new ApiResult { AffectedRows = affected }); } }
public async Task <ApiResult> Handle(InsertClassifierLink request, CancellationToken cancellationToken) { if (request.UserUid == Guid.Empty) { throw new InvalidOperationException("User is required."); } var type = await _classifierTypeService.Get(request.TypeCode, cancellationToken); using (var scope = _unitOfWorkFactory.Create()) { using (var db = _dbContextFactory.Create()) { // todo: validate group and item belongs to the same type if (type.HierarchyType != HierarchyType.Groups) { throw new InvalidOperationException("Invalid classifier hierarchy type for groups operations."); } // delete other links in same hierarchy await( from link in db.GetTable <DbClassifierLink>().Where(x => x.ItemUid == request.ItemUid) join allGroups in db.GetTable <DbClassifierGroup>() on link.GroupUid equals allGroups.Uid join newGroup in db.GetTable <DbClassifierGroup>().Where(x => x.Uid == request.GroupUid) on allGroups.TreeUid equals newGroup.TreeUid select link ).DeleteAsync(cancellationToken); await db.GetTable <DbClassifierLink>() .Value(x => x.GroupUid, request.GroupUid) .Value(x => x.ItemUid, request.ItemUid) .InsertAsync(cancellationToken); } scope.Commit(); return(new ApiResult()); } }
public async Task <SearchResult <ClassifierGroup> > Handle(GetClassifierGroupList request, CancellationToken cancellationToken) { if (request == null) { throw new ArgumentNullException(nameof(request)); } var type = await _classifierTypeService.Get(request.TypeCode, cancellationToken); using (var db = _dbContextFactory.Create()) { if (type.HierarchyType == HierarchyType.Groups) { var tree = request.TreeUid != null ? await _classifierTreeService.GetClassifierTree(/*request.CompanyUid,*/ request.TypeCode, request.TreeUid.Value, cancellationToken) : await _classifierTreeService.GetClassifierTree(/*request.CompanyUid,*/ request.TypeCode, request.TreeCode, cancellationToken); if (request.FocusUid != null) { return(await GetGroupsByFocus(db, type, tree, request, cancellationToken)); } return(await GetGroupsByParent(db, type, tree, request.ParentUid, request, true)); } if (type.HierarchyType == HierarchyType.Items) { if (request.FocusUid != null) { return(await GetItemsByFocus(db, type, request, cancellationToken)); } return(await GetItemsByParent(db, type, request.ParentUid, request, true)); } } return(null); }
public async Task <DataView> Handle(GetClassifierMetadata request, CancellationToken cancellationToken) { if (request.ViewId == "ClassifierType/Tabs") { return(GetClassifierTypeTabs()); } if (request.ViewId == "NumeratorEntity/Form") { return(GetNumeratorEntityForm()); } var typeCode = request.TypeCode ?? throw new ArgumentNullException(nameof(request.TypeCode)); var type = await _classifierTypeService.Get(typeCode, cancellationToken); if (request.ViewId == "Classifier/Tabs") { return(GetClassifierTabs(type)); } return(await GetClassifierForm(type, cancellationToken)); }
public async Task <ApiResult> Handle(DeleteClassifierLink request, CancellationToken cancellationToken) { if (request.UserUid == Guid.Empty) { throw new InvalidOperationException("User is required."); } var type = await _classifierTypeService.Get(request.TypeCode, cancellationToken); using (var scope = _unitOfWorkFactory.Create()) { int affected; ApiResultError error = null; using (var db = _dbContextFactory.Create()) { // todo: validate group and item belongs to type if (type.HierarchyType != HierarchyType.Groups) { throw new InvalidOperationException("Invalid classifier hierarchy type for groups operations."); } affected = await db.GetTable <DbClassifierLink>() .Where(x => x.GroupUid == request.GroupUid && x.ItemUid == request.ItemUid) .DeleteAsync(cancellationToken); if (affected > 0) { var root = await GetRoot(db, request.GroupUid, cancellationToken); if (root.Code == ClassifierTree.DefaultCode) { // todo: move to ClassifierGroupService await db.GetTable <DbClassifierLink>() .Value(x => x.GroupUid, root.Uid) .Value(x => x.ItemUid, request.ItemUid) .InsertAsync(cancellationToken); error = new ApiResultError { Messages = new[] { "All items should be linked to default hierarchy. Relinked item to root." } }; } } } scope.Commit(); var result = new ApiResult { AffectedRows = affected }; if (error != null) { result.Errors = new List <ApiResultError> { error }; } return(result); } }
public async Task <SearchResult <ClassifierLink> > Handle(GetClassifierLinkList request, CancellationToken cancellationToken) { if (request == null) { throw new ArgumentNullException(nameof(request)); } var type = await _classifierTypeService.Get(request.TypeCode, cancellationToken); if (type.HierarchyType != HierarchyType.Groups) { throw new InvalidOperationException("Invalid classifier hierarchy type for groups operations."); } using (var db = _dbContextFactory.Create()) { IQueryable <DbClassifierLink> query = db.GetTable <DbClassifierLink>(); if (request.GroupUid.HasValue) { query = query.Where(x => x.GroupUid == request.GroupUid); } if (request.ItemUid.HasValue) { query = query.Where(x => x.ItemUid == request.ItemUid); } var joined = from link in query join @group in db.GetTable <DbClassifierGroup>() on link.GroupUid equals @group.Uid join tree in db.GetTable <DbClassifierTree>() on @group.TreeUid equals tree.Uid join item in db.GetTable <DbClassifier>() on link.ItemUid equals item.Uid select new { Tree = tree, Group = @group, Item = item }; // todo: order by default hierarchy first, then by group name // todo: fix QueryableExtensions.GetMemberName and write tests request.SortColumn = "Group.Name"; var data = await joined .Apply(request, x => x.Group.Name) .Select(x => new ClassifierLink { Tree = new ClassifierTree { Uid = x.Tree.Uid, Code = x.Tree.Code, Name = x.Tree.Name }, Group = new ClassifierGroup { Uid = x.Group.Uid, Code = x.Group.Code, Name = x.Group.Name }, Item = new Classifier { Type = type.Code, Uid = x.Item.Uid, Code = x.Item.Code, Name = x.Item.Name } }) .ToListAsync(cancellationToken); return(new SearchResult <ClassifierLink> { TotalCount = query.GetTotalCount(request), Rows = data }); } }
public async Task <ApiResult> Handle(DeleteClassifierGroup request, CancellationToken cancellationToken) { if (request.UserUid == Guid.Empty) { throw new InvalidOperationException("User is required."); } var type = await _classifierTypeService.Get(request.TypeCode, cancellationToken); using (var scope = _unitOfWorkFactory.Create()) { var result = 0; using (var db = _dbContextFactory.Create()) { if (type.HierarchyType == HierarchyType.Groups) { var closureTable = new ClosureTableHandler(db, type); /*var tree = await db.GetTable<DbClassifierTree>() * .SingleAsync(x => x.TypeUid == type.Uid && x.Code == request.TreeCode, cancellationToken);*/ var group = await db.GetTable <DbClassifierGroup>() .SingleAsync(x => /*x.TypeUid == type.Uid &&*/ x.Uid == request.Uid, cancellationToken); // todo: remove next two todos or move to delete tree delete operation ??? // todo: validate - do not delete root group (if children exists - or children become roots) // todo: validate - do not delete or change code for default root (why needed default root code?) await closureTable.Delete(group.Uid, group.ParentUid, cancellationToken); // reset parent of groups await db.GetTable <DbClassifierGroup>() .Where(x => x.ParentUid == group.Uid) .Set(x => x.ParentUid, group.ParentUid) .UpdateAsync(cancellationToken); // reset parent of items if (group.ParentUid != null) { await db.GetTable <DbClassifierLink>() .Where(x => x.GroupUid == group.Uid) .Set(x => x.GroupUid, group.ParentUid) .UpdateAsync(cancellationToken); } else { await db.GetTable <DbClassifierLink>() .Where(x => x.GroupUid == group.Uid) .DeleteAsync(cancellationToken); } result = await db.GetTable <DbClassifierGroup>() .Where(x => x.Uid == group.Uid) .DeleteAsync(cancellationToken); } } scope.Commit(); return(new ApiResult { AffectedRows = result }); } }