public void Applies_cascading_settings_for_relationship_links(LinkTypes linksInRelationshipAttribute, LinkTypes linksInResourceContext,
                                                                      LinkTypes linksInOptions, LinkTypes expected)
        {
            // Arrange
            var exampleResourceContext = new ResourceContext
            {
                PublicName        = nameof(ExampleResource),
                ResourceType      = typeof(ExampleResource),
                RelationshipLinks = linksInResourceContext
            };

            var options = new JsonApiOptions
            {
                RelationshipLinks = linksInOptions
            };

            var request                   = new JsonApiRequest();
            var paginationContext         = new PaginationContext();
            var resourceGraph             = new ResourceGraph(exampleResourceContext.AsArray());
            var httpContextAccessor       = new FakeHttpContextAccessor();
            var linkGenerator             = new FakeLinkGenerator();
            var controllerResourceMapping = new FakeControllerResourceMapping();

            var linkBuilder = new LinkBuilder(options, request, paginationContext, resourceGraph, httpContextAccessor, linkGenerator,
                                              controllerResourceMapping);

            var relationship = new HasOneAttribute
            {
                Links = linksInRelationshipAttribute
            };

            // Act
            RelationshipLinks relationshipLinks = linkBuilder.GetRelationshipLinks(relationship, new ExampleResource());

            // Assert
            if (expected == LinkTypes.None)
            {
                relationshipLinks.Should().BeNull();
            }
            else
            {
                if (expected.HasFlag(LinkTypes.Self))
                {
                    relationshipLinks.Self.Should().NotBeNull();
                }
                else
                {
                    relationshipLinks.Self.Should().BeNull();
                }

                if (expected.HasFlag(LinkTypes.Related))
                {
                    relationshipLinks.Related.Should().NotBeNull();
                }
                else
                {
                    relationshipLinks.Related.Should().BeNull();
                }
            }
        }
Example #2
0
        /// <inheritdoc />
        public RelationshipLinks GetRelationshipLinks(RelationshipAttribute relationship, IIdentifiable parent)
        {
            if (relationship == null)
            {
                throw new ArgumentNullException(nameof(relationship));
            }
            if (parent == null)
            {
                throw new ArgumentNullException(nameof(parent));
            }

            var parentResourceContext = _provider.GetResourceContext(parent.GetType());
            var childNavigation       = relationship.PublicName;
            RelationshipLinks links   = null;

            if (ShouldAddRelationshipLink(parentResourceContext, relationship, LinkTypes.Related))
            {
                links = new RelationshipLinks {
                    Related = GetRelatedRelationshipLink(parentResourceContext.PublicName, parent.StringId, childNavigation)
                };
            }

            if (ShouldAddRelationshipLink(parentResourceContext, relationship, LinkTypes.Self))
            {
                links ??= new RelationshipLinks();
                links.Self = GetSelfRelationshipLink(parentResourceContext.PublicName, parent.StringId, childNavigation);
            }

            return(links);
        }
Example #3
0
        /// <inheritdoc />
        public RelationshipLinks GetRelationshipLinks(RelationshipAttribute relationship, IIdentifiable parent)
        {
            ArgumentGuard.NotNull(relationship, nameof(relationship));
            ArgumentGuard.NotNull(parent, nameof(parent));

            ResourceContext   parentResourceContext = _provider.GetResourceContext(parent.GetType());
            string            childNavigation       = relationship.PublicName;
            RelationshipLinks links = null;

            if (ShouldAddRelationshipLink(parentResourceContext, relationship, LinkTypes.Related))
            {
                links = new RelationshipLinks
                {
                    Related = GetRelatedRelationshipLink(parentResourceContext.PublicName, parent.StringId, childNavigation)
                };
            }

            if (ShouldAddRelationshipLink(parentResourceContext, relationship, LinkTypes.Self))
            {
                links ??= new RelationshipLinks();
                links.Self = GetSelfRelationshipLink(parentResourceContext.PublicName, parent.StringId, childNavigation);
            }

            return(links);
        }
        protected ResponseSerializer <T> GetResponseSerializer <T>(IEnumerable <IEnumerable <RelationshipAttribute> > inclusionChains = null,
                                                                   Dictionary <string, object> metaDict = null, TopLevelLinks topLinks = null, ResourceLinks resourceLinks = null,
                                                                   RelationshipLinks relationshipLinks  = null)
            where T : class, IIdentifiable
        {
            IMetaBuilder meta = GetMetaBuilder(metaDict);
            ILinkBuilder link = GetLinkBuilder(topLinks, resourceLinks, relationshipLinks);
            IEnumerable <IQueryConstraintProvider> includeConstraints = GetIncludeConstraints(inclusionChains);
            IIncludedResourceObjectBuilder         includedBuilder    = GetIncludedBuilder();
            IFieldsToSerialize fieldsToSerialize = GetSerializableFields();

            var resourceObjectBuilder = new ResponseResourceObjectBuilder(link, includedBuilder, includeConstraints, ResourceGraph,
                                                                          GetResourceDefinitionAccessor(), GetSerializerSettingsProvider());

            return(new ResponseSerializer <T>(meta, link, includedBuilder, fieldsToSerialize, resourceObjectBuilder, new JsonApiOptions()));
        }
 public SerializerTestsSetup()
 {
     _dummyTopLevelLinks = new TopLevelLinks
     {
         Self  = "http://www.dummy.com/dummy-self-link",
         Next  = "http://www.dummy.com/dummy-next-link",
         Prev  = "http://www.dummy.com/dummy-prev-link",
         First = "http://www.dummy.com/dummy-first-link",
         Last  = "http://www.dummy.com/dummy-last-link"
     };
     _dummyResourceLinks = new ResourceLinks
     {
         Self = "http://www.dummy.com/dummy-resource-self-link"
     };
     _dummyRelationshipLinks = new RelationshipLinks
     {
         Related = "http://www.dummy.com/dummy-relationship-related-link",
         Self    = "http://www.dummy.com/dummy-relationship-self-link"
     };
 }
Example #6
0
        /// <inheritdoc/>
        public RelationshipLinks GetRelationshipLinks(RelationshipAttribute relationship, IIdentifiable parent)
        {
            var parentResourceContext = _provider.GetResourceContext(parent.GetType());
            var childNavigation       = relationship.PublicRelationshipName;
            RelationshipLinks links   = null;

            if (ShouldAddRelationshipLink(parentResourceContext, relationship, Link.Related))
            {
                links = new RelationshipLinks {
                    Related = GetRelatedRelationshipLink(parentResourceContext.ResourceName, parent.StringId, childNavigation)
                };
            }

            if (ShouldAddRelationshipLink(parentResourceContext, relationship, Link.Self))
            {
                links ??= new RelationshipLinks();
                links.Self = GetSelfRelationshipLink(parentResourceContext.ResourceName, parent.StringId, childNavigation);
            }

            return(links);
        }
Example #7
0
        /// <summary>
        /// Builds the values of the relationships object on a resource object. The server serializer only populates the "data" member when the relationship is
        /// included, and adds links unless these are turned off. This means that if a relationship is not included and links are turned off, the entry would be
        /// completely empty, ie { }, which is not conform JSON:API spec. In that case we return null which will omit the entry from the output.
        /// </summary>
        protected override RelationshipEntry GetRelationshipData(RelationshipAttribute relationship, IIdentifiable resource)
        {
            ArgumentGuard.NotNull(relationship, nameof(relationship));
            ArgumentGuard.NotNull(resource, nameof(resource));

            RelationshipEntry relationshipEntry = null;
            IReadOnlyCollection <IReadOnlyCollection <RelationshipAttribute> > relationshipChains = GetInclusionChainsStartingWith(relationship);

            if (Equals(relationship, _requestRelationship) || relationshipChains.Any())
            {
                relationshipEntry = base.GetRelationshipData(relationship, resource);

                if (relationshipChains.Any() && relationshipEntry.HasResource)
                {
                    foreach (IReadOnlyCollection <RelationshipAttribute> chain in relationshipChains)
                    {
                        // traverses (recursively) and extracts all (nested) related resources for the current inclusion chain.
                        _includedBuilder.IncludeRelationshipChain(chain, resource);
                    }
                }
            }

            if (!IsRelationshipInSparseFieldSet(relationship))
            {
                return(null);
            }

            RelationshipLinks links = _linkBuilder.GetRelationshipLinks(relationship, resource);

            if (links != null)
            {
                // if relationshipLinks should be built for this entry, populate the "links" field.
                relationshipEntry ??= new RelationshipEntry();
                relationshipEntry.Links = links;
            }

            // if neither "links" nor "data" was populated, return null, which will omit this entry from the output.
            // (see the NullValueHandling settings on <see cref="ResourceObject"/>)
            return(relationshipEntry);
        }
Example #8
0
        public static Dictionary <string, IRelationship> CreateRelationships(object objectGraph, string parentId, IResourceMapping resourceMapping, Context context)
        {
            var relationships = new Dictionary <string, IRelationship>();

            foreach (var linkMapping in resourceMapping.Relationships)
            {
                var relationshipName = linkMapping.RelationshipName;
                var rel      = new Relationship();
                var relLinks = new RelationshipLinks();

                // Generating "self" link
                if (linkMapping.SelfUrlTemplate != null)
                {
                    relLinks.Self = GetUrlFromTemplate(context, linkMapping.SelfUrlTemplate, parentId);
                }

                if (!linkMapping.IsCollection)
                {
                    string relatedId       = null;
                    object relatedInstance = null;
                    if (linkMapping.RelatedResource != null)
                    {
                        relatedInstance = linkMapping.RelatedResource(objectGraph);
                        if (relatedInstance != null)
                        {
                            relatedId = linkMapping.ResourceMapping.IdGetter(relatedInstance).ToString();
                        }
                    }
                    if (linkMapping.RelatedResourceId != null && relatedId == null)
                    {
                        var id = linkMapping.RelatedResourceId(objectGraph);
                        if (id != null)
                        {
                            relatedId = id.ToString();
                        }
                    }

                    // Generating "related" link for to-one relationships
                    if (linkMapping.RelatedUrlTemplate != null && relatedId != null)
                    {
                        relLinks.Related = GetUrlFromTemplate(context, linkMapping.RelatedUrlTemplate, parentId, relatedId.ToString());
                    }


                    if (linkMapping.InclusionRule != ResourceInclusionRules.ForceOmit)
                    {
                        // Generating resource linkage for to-one relationships
                        if (relatedInstance != null)
                        {
                            rel.Data = new SingleResourceIdentifier
                            {
                                Id   = relatedId,
                                Type = context.Configuration.GetMapping(relatedInstance.GetType()).ResourceType // This allows polymorphic (subtyped) resources to be fully represented
                            }
                        }
                        ;
                        else if (relatedId == null || linkMapping.InclusionRule == ResourceInclusionRules.ForceInclude)
                        {
                            rel.Data = new NullResourceIdentifier(); // two-state null case, see NullResourceIdentifier summary
                        }
                    }
                }
                else
                {
                    // Generating "related" link for to-many relationships
                    if (linkMapping.RelatedUrlTemplate != null)
                    {
                        relLinks.Related = GetUrlFromTemplate(context, linkMapping.RelatedUrlTemplate, parentId);
                    }

                    IEnumerable relatedInstance = null;
                    if (linkMapping.RelatedResource != null)
                    {
                        relatedInstance = (IEnumerable)linkMapping.RelatedResource(objectGraph);
                    }

                    // Generating resource linkage for to-many relationships
                    if (linkMapping.InclusionRule == ResourceInclusionRules.ForceInclude && relatedInstance == null)
                    {
                        rel.Data = new MultipleResourceIdentifiers();
                    }
                    if (linkMapping.InclusionRule != ResourceInclusionRules.ForceOmit && relatedInstance != null)
                    {
                        var idGetter    = linkMapping.ResourceMapping.IdGetter;
                        var identifiers = relatedInstance
                                          .Cast <object>()
                                          .Select(o => new SingleResourceIdentifier
                        {
                            Id   = idGetter(o).ToString(),
                            Type = context.Configuration.GetMapping(o.GetType()).ResourceType     // This allows polymorphic (subtyped) resources to be fully represented
                        });
                        rel.Data = new MultipleResourceIdentifiers(identifiers);
                    }

                    // If data is present, count meta attribute is added for convenience
                    if (rel.Data != null)
                    {
                        rel.Meta = new Dictionary <string, string> {
                            { MetaCountAttribute, ((MultipleResourceIdentifiers)rel.Data).Count.ToString() }
                        }
                    }
                    ;
                }

                if (relLinks.Self != null || relLinks.Related != null)
                {
                    rel.Links = relLinks;
                }

                if (rel.Data != null || rel.Links != null)
                {
                    relationships.Add(relationshipName, rel);
                }
            }
            return(relationships.Any() ? relationships : null);
        }
        protected ILinkBuilder GetLinkBuilder(TopLevelLinks top = null, ResourceLinks resource = null, RelationshipLinks relationship = null)
        {
            var mock = new Mock <ILinkBuilder>();

            mock.Setup(m => m.GetTopLevelLinks()).Returns(top);
            mock.Setup(m => m.GetResourceLinks(It.IsAny <string>(), It.IsAny <string>())).Returns(resource);
            mock.Setup(m => m.GetRelationshipLinks(It.IsAny <RelationshipAttribute>(), It.IsAny <IIdentifiable>())).Returns(relationship);
            return(mock.Object);
        }
        protected ResponseResourceObjectBuilder GetResponseResourceObjectBuilder(List <List <RelationshipAttribute> > inclusionChains = null, ResourceLinks resourceLinks = null, RelationshipLinks relationshipLinks = null)
        {
            var link = GetLinkBuilder(null, resourceLinks, relationshipLinks);
            var includeConstraints = GetIncludeConstraints(inclusionChains);
            var includedBuilder    = GetIncludedBuilder();

            return(new ResponseResourceObjectBuilder(link, includedBuilder, includeConstraints, _resourceGraph, GetSerializerSettingsProvider()));
        }
Example #11
0
        protected ResponseSerializer <T> GetResponseSerializer <T>(List <List <RelationshipAttribute> > inclusionChains = null, Dictionary <string, object> metaDict = null, TopLevelLinks topLinks = null, ResourceLinks resourceLinks = null, RelationshipLinks relationshipLinks = null) where T : class, IIdentifiable
        {
            var meta              = GetMetaBuilder <T>(metaDict);
            var link              = GetLinkBuilder(topLinks, resourceLinks, relationshipLinks);
            var included          = GetIncludedRelationships(inclusionChains);
            var includedBuilder   = GetIncludedBuilder();
            var fieldsToSerialize = GetSerializableFields();
            ResponseResourceObjectBuilder resourceObjectBuilder = new ResponseResourceObjectBuilder(link, includedBuilder, included, _resourceGraph, GetSerializerSettingsProvider());

            return(new ResponseSerializer <T>(meta, link, includedBuilder, fieldsToSerialize, resourceObjectBuilder, new JsonApiOptions()));
        }
        protected ResponseResourceObjectBuilder GetResponseResourceObjectBuilder(IEnumerable <IEnumerable <RelationshipAttribute> > inclusionChains = null,
                                                                                 ResourceLinks resourceLinks = null, RelationshipLinks relationshipLinks = null)
        {
            ILinkBuilder link = GetLinkBuilder(null, resourceLinks, relationshipLinks);
            IEnumerable <IQueryConstraintProvider> includeConstraints = GetIncludeConstraints(inclusionChains);
            IIncludedResourceObjectBuilder         includedBuilder    = GetIncludedBuilder();

            return(new ResponseResourceObjectBuilder(link, includedBuilder, includeConstraints, ResourceGraph, GetResourceDefinitionAccessor(),
                                                     GetSerializerSettingsProvider()));
        }