Exemplo n.º 1
0
        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);
            }
        }
Exemplo n.º 2
0
        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
                });
            }
        }
Exemplo n.º 3
0
        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
                });
            }
        }
Exemplo n.º 4
0
        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
                });
            }
        }
Exemplo n.º 5
0
        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);
            }
        }
Exemplo n.º 6
0
        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
                });
            }
        }
Exemplo n.º 7
0
        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
                });
            }
        }
Exemplo n.º 8
0
        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());
            }
        }
Exemplo n.º 9
0
        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);
        }
Exemplo n.º 10
0
        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));
        }
Exemplo n.º 11
0
        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);
            }
        }
Exemplo n.º 12
0
        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
                });
            }
        }
Exemplo n.º 13
0
        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
                });
            }
        }