/// <summary>
        /// Converts a single resource into a serialized <see cref="Document" />.
        /// </summary>
        /// <remarks>
        /// This method is internal instead of private for easier testability.
        /// </remarks>
        internal string SerializeSingle(IIdentifiable resource)
        {
            if (resource != null && _fieldsToSerialize.ShouldSerialize)
            {
                _resourceDefinitionAccessor.OnSerialize(resource);
            }

            IReadOnlyCollection <AttrAttribute>         attributes    = _fieldsToSerialize.GetAttributes(_primaryResourceType);
            IReadOnlyCollection <RelationshipAttribute> relationships = _fieldsToSerialize.GetRelationships(_primaryResourceType);

            Document       document       = Build(resource, attributes, relationships);
            ResourceObject resourceObject = document.SingleData;

            if (resourceObject != null)
            {
                resourceObject.Links = _linkBuilder.GetResourceLinks(resourceObject.Type, resourceObject.Id);
            }

            AddTopLevelObjects(document);

            return(SerializeObject(document, _options.SerializerSettings, serializer =>
            {
                serializer.NullValueHandling = NullValueHandling.Include;
            }));
        }
        private AtomicResultObject SerializeOperation(OperationContainer operation)
        {
            ResourceObject resourceObject = null;

            if (operation != null)
            {
                _request.CopyFrom(operation.Request);
                _fieldsToSerialize.ResetCache();
                _evaluatedIncludeCache.Set(null);

                _resourceDefinitionAccessor.OnSerialize(operation.Resource);

                Type resourceType = operation.Resource.GetType();
                IReadOnlyCollection <AttrAttribute>         attributes    = _fieldsToSerialize.GetAttributes(resourceType);
                IReadOnlyCollection <RelationshipAttribute> relationships = _fieldsToSerialize.GetRelationships(resourceType);

                resourceObject = ResourceObjectBuilder.Build(operation.Resource, attributes, relationships);
            }

            if (resourceObject != null)
            {
                resourceObject.Links = _linkBuilder.GetResourceLinks(resourceObject.Type, resourceObject.Id);
            }

            return(new AtomicResultObject
            {
                Data = resourceObject
            });
        }
        private void ProcessRelationship(IIdentifiable parent, IList <RelationshipAttribute> inclusionChain)
        {
            ResourceObject resourceObject = TryGetBuiltResourceObjectFor(parent);

            if (resourceObject == null)
            {
                _resourceDefinitionAccessor.OnSerialize(parent);

                resourceObject = BuildCachedResourceObjectFor(parent);
            }

            if (!inclusionChain.Any())
            {
                return;
            }

            RelationshipAttribute        nextRelationship = inclusionChain.First();
            List <RelationshipAttribute> chainRemainder   = inclusionChain.ToList();

            chainRemainder.RemoveAt(0);

            string nextRelationshipName = nextRelationship.PublicName;
            IDictionary <string, RelationshipEntry> relationshipsObject = resourceObject.Relationships;

            // add the relationship entry in the relationship object.
            if (!relationshipsObject.TryGetValue(nextRelationshipName, out RelationshipEntry relationshipEntry))
            {
                relationshipEntry = GetRelationshipData(nextRelationship, parent);
                relationshipsObject[nextRelationshipName] = relationshipEntry;
            }

            relationshipEntry.Data = GetRelatedResourceLinkage(nextRelationship, parent);

            if (relationshipEntry.HasResource)
            {
                // if the relationship is set, continue parsing the chain.
                object related = nextRelationship.GetValue(parent);
                ProcessChain(related, chainRemainder);
            }
        }