/// <inheritdoc />
        // triggered by GET /articles/1/relationships/{relationshipName}
        public virtual async Task <TResource> GetRelationshipAsync(TId id, string relationshipName)
        {
            _traceWriter.LogMethodStart(new { id, relationshipName });
            if (relationshipName == null)
            {
                throw new ArgumentNullException(nameof(relationshipName));
            }

            AssertRelationshipExists(relationshipName);

            _hookExecutor?.BeforeRead <TResource>(ResourcePipeline.GetRelationship, id.ToString());

            var secondaryLayer = _queryLayerComposer.Compose(_request.SecondaryResource);

            secondaryLayer.Projection = _queryLayerComposer.GetSecondaryProjectionForRelationshipEndpoint(_request.SecondaryResource);
            secondaryLayer.Include    = null;

            var primaryLayer = _queryLayerComposer.WrapLayerForSecondaryEndpoint(secondaryLayer, _request.PrimaryResource, id, _request.Relationship);

            var primaryResources = await _repository.GetAsync(primaryLayer);

            var primaryResource = primaryResources.SingleOrDefault();

            AssertPrimaryResourceExists(primaryResource);

            if (_hookExecutor != null)
            {
                _hookExecutor.AfterRead(AsList(primaryResource), ResourcePipeline.GetRelationship);
                primaryResource = _hookExecutor.OnReturn(AsList(primaryResource), ResourcePipeline.GetRelationship).Single();
            }

            return(primaryResource);
        }
Example #2
0
        /// <inheritdoc />
        public virtual async Task <object> GetSecondaryAsync(TId id, string relationshipName, CancellationToken cancellationToken)
        {
            _traceWriter.LogMethodStart(new
            {
                id,
                relationshipName
            });

            AssertHasRelationship(_request.Relationship, relationshipName);

            _hookExecutor.BeforeReadSingle <TResource, TId>(id, ResourcePipeline.GetRelationship);

            QueryLayer secondaryLayer = _queryLayerComposer.ComposeFromConstraints(_request.SecondaryResource);
            QueryLayer primaryLayer   = _queryLayerComposer.WrapLayerForSecondaryEndpoint(secondaryLayer, _request.PrimaryResource, id, _request.Relationship);

            IReadOnlyCollection <TResource> primaryResources = await _repositoryAccessor.GetAsync <TResource>(primaryLayer, cancellationToken);

            TResource primaryResource = primaryResources.SingleOrDefault();

            AssertPrimaryResourceExists(primaryResource);

            _hookExecutor.AfterReadSingle(primaryResource, ResourcePipeline.GetRelationship);

            object secondaryResourceOrResources = _request.Relationship.GetValue(primaryResource);

            if (secondaryResourceOrResources is ICollection secondaryResources && secondaryLayer.Pagination?.PageSize?.Value == secondaryResources.Count)
            {
                _paginationContext.IsPageFull = true;
            }

            return(_hookExecutor.OnReturnRelationship(secondaryResourceOrResources));
        }
Example #3
0
        /// <inheritdoc />
        public virtual async Task <object> GetSecondaryAsync(TId id, string relationshipName, CancellationToken cancellationToken)
        {
            _traceWriter.LogMethodStart(new
            {
                id,
                relationshipName
            });

            AssertHasRelationship(_request.Relationship, relationshipName);

            _hookExecutor.BeforeReadSingle <TResource, TId>(id, ResourcePipeline.GetRelationship);

            QueryLayer secondaryLayer = _queryLayerComposer.ComposeFromConstraints(_request.SecondaryResource);
            QueryLayer primaryLayer   = _queryLayerComposer.WrapLayerForSecondaryEndpoint(secondaryLayer, _request.PrimaryResource, id, _request.Relationship);

            if (_request.IsCollection && _options.IncludeTotalResourceCount)
            {
                // TODO: Consider support for pagination links on secondary resource collection. This requires to call Count() on the inverse relationship (which may not exist).
                // For /blogs/1/articles we need to execute Count(Articles.Where(article => article.Blog.Id == 1 && article.Blog.existingFilter))) to determine TotalResourceCount.
                // This also means we need to invoke ResourceRepository<Article>.CountAsync() from ResourceService<Blog>.
                // And we should call BlogResourceDefinition.OnApplyFilter to filter out soft-deleted blogs and translate from equals('IsDeleted','false') to equals('Blog.IsDeleted','false')
            }

            IReadOnlyCollection <TResource> primaryResources = await _repositoryAccessor.GetAsync <TResource>(primaryLayer, cancellationToken);

            TResource primaryResource = primaryResources.SingleOrDefault();

            AssertPrimaryResourceExists(primaryResource);

            _hookExecutor.AfterReadSingle(primaryResource, ResourcePipeline.GetRelationship);

            object secondaryResourceOrResources = _request.Relationship.GetValue(primaryResource);

            if (secondaryResourceOrResources is ICollection secondaryResources && secondaryLayer.Pagination?.PageSize?.Value == secondaryResources.Count)
            {
                _paginationContext.IsPageFull = true;
            }

            return(_hookExecutor.OnReturnRelationship(secondaryResourceOrResources));
        }