Example #1
0
        private JToken SerializeRelationshipData(ResourceGraphNode node, ResourceGraphRelationship relationship)
        {
            // check if the relationship property exists on the underlying model and if not bail with null
            // NOTE: this logic refers to https://github.com/joukevandermaas/saule/issues/159
            if (node.SourceObject.GetType().GetProperty(relationship.Relationship.PropertyName) == null)
            {
                return(null);
            }

            if (relationship.Relationship.Kind == RelationshipKind.BelongsTo)
            {
                if (relationship.SourceObject == null)
                {
                    return(JValue.CreateNull());
                }

                return(JObject.FromObject(new ResourceGraphNodeKey(relationship.SourceObject, relationship.Relationship.RelatedResource)));
            }

            if (relationship.Relationship.Kind == RelationshipKind.HasMany)
            {
                var content = new JArray();

                foreach (var sourceObject in (IEnumerable)relationship.SourceObject ?? new JArray())
                {
                    content.Add(JObject.FromObject(new ResourceGraphNodeKey(sourceObject, relationship.Relationship.RelatedResource)));
                }

                return(content);
            }

            return(null);
        }
Example #2
0
        private JObject SerializeNode(ResourceGraphNode node, bool isCollection)
        {
            var response = new JObject
            {
                ["type"] = node.Key.Type,
                ["id"]   = JToken.FromObject(node.Key.Id)
            };

            if (isCollection)
            {
                var self = _urlBuilder.BuildCanonicalPath(node.Resource, node.Key.Id.ToString());

                if (!string.IsNullOrEmpty(self) && node.Resource.LinkType.HasFlag(LinkType.Self))
                {
                    response["links"] = AddUrl(new JObject(), "self", self);
                }
            }

            var attributes = SerializeAttributes(node);

            if (attributes != null)
            {
                response["attributes"] = attributes;
            }

            var relationships = SerializeRelationships(node);

            if (relationships != null)
            {
                response["relationships"] = relationships;
            }

            return(response);
        }
Example #3
0
        private JObject SerializeRelationships(ResourceGraphNode node, FieldsetProperty fieldset)
        {
            if (!node.Relationships.Any())
            {
                return(null);
            }

            var response = new JObject();

            foreach (var kv in node.Relationships)
            {
                if (fieldset != null && !fieldset.Fields.Contains(kv.Value.Relationship.Name.ToComparablePropertyName()))
                {
                    continue;
                }

                var relationship = kv.Value.Relationship;

                var item = new JObject();

                var data = SerializeRelationshipData(node, kv.Value);

                var relationshipId = default(string);

                if (data != null &&
                    relationship.Kind == RelationshipKind.BelongsTo &&
                    kv.Value.SourceObject != null)
                {
                    relationshipId = (string)data["id"];
                }

                var links   = new JObject();
                var self    = _urlBuilder.BuildRelationshipPath(node.Resource, node.Key.Id.ToString(), relationship);
                var related = _urlBuilder.BuildRelationshipPath(node.Resource, node.Key.Id.ToString(), relationship, relationshipId);

                if (!string.IsNullOrEmpty(self) && relationship.LinkType.HasFlag(LinkType.Self))
                {
                    AddUrl(links, "self", self);
                }

                if (!string.IsNullOrEmpty(related) && relationship.LinkType.HasFlag(LinkType.Related))
                {
                    AddUrl(links, "related", related);
                }

                if (links.HasValues)
                {
                    item["links"] = links;
                }

                if (data != null && kv.Value != null)
                {
                    item["data"] = data;
                }

                response[_propertyNameConverter.ToJsonPropertyName(kv.Key)] = item;
            }

            return(response);
        }
Example #4
0
        private JObject SerializeRelationships(ResourceGraphNode node)
        {
            if (node.Relationships.Count == 0)
            {
                return(null);
            }

            var response = new JObject();

            foreach (var kv in node.Relationships)
            {
                var relationship = kv.Value.Relationship;

                var item = new JObject();

                var data = SerializeRelationshipData(node, kv.Value);

                var relationshipId = default(string);

                if (data != null &&
                    relationship.Kind == RelationshipKind.BelongsTo &&
                    kv.Value.SourceObject != null)
                {
                    relationshipId = (string)data["id"];
                }

                var links   = new JObject();
                var self    = _urlBuilder.BuildRelationshipPath(node.Resource, node.Key.Id.ToString(), relationship);
                var related = _urlBuilder.BuildRelationshipPath(node.Resource, node.Key.Id.ToString(), relationship, relationshipId);

                if (!string.IsNullOrEmpty(self) && relationship.LinkType.HasFlag(LinkType.Self))
                {
                    AddUrl(links, "self", self);
                }

                if (!string.IsNullOrEmpty(related) && relationship.LinkType.HasFlag(LinkType.Related))
                {
                    AddUrl(links, "related", related);
                }

                if (links.HasValues)
                {
                    item["links"] = links;
                }

                if (data != null)
                {
                    item["data"] = data;
                }

                response[kv.Key] = item;
            }

            return(response);
        }
Example #5
0
        private JObject SerializeAttributes(ResourceGraphNode node)
        {
            var attributeHash = node.Resource.Attributes
                                .Where(a =>
                                       node.SourceObject.IncludesProperty(a.PropertyName))
                                .Select(a =>
                                        new
            {
                Key   = a.Name,
                Value = node.SourceObject.GetValueOfProperty(a.PropertyName)
            })
                                .ToDictionary(
                kvp => kvp.Key,
                kvp => kvp.Value);

            return(JObject.FromObject(attributeHash, _serializer));
        }
Example #6
0
        private JObject SerializeAttributes(ResourceGraphNode node, FieldsetProperty fieldset)
        {
            var attributeHash = node.Resource.Attributes
                                .Where(a =>
                                       node.SourceObject.IncludesProperty(_propertyNameConverter.ToModelPropertyName(a.InternalName)) && fieldset.Fields.Contains(a.InternalName.ToComparablePropertyName()))
                                .Select(a =>
                                        new
            {
                Key   = _propertyNameConverter.ToJsonPropertyName(a.InternalName),
                Value = node.SourceObject.GetValueOfProperty(_propertyNameConverter.ToModelPropertyName(a.InternalName))
            })
                                .ToDictionary(
                kvp => kvp.Key,
                kvp => kvp.Value);

            return(JObject.FromObject(attributeHash, _serializer));
        }
Example #7
0
        private JObject SerializeNode(ResourceGraphNode node, bool isCollection)
        {
            var response = new JObject
            {
                ["type"] = node.Key.Type,
                ["id"]   = JToken.FromObject(node.Key.Id)
            };

            if (isCollection)
            {
                var self = _urlBuilder.BuildCanonicalPath(node.Resource, node.Key.Id.ToString());

                if (!string.IsNullOrEmpty(self) && node.Resource.LinkType.HasFlag(LinkType.Self))
                {
                    response["links"] = AddUrl(new JObject(), "self", self);
                }
            }

            JObject attributes = null;

            if (_fieldsetContext != null && _fieldsetContext.Properties.Count(property => property.Type == node.Key.Type) > 0)
            {
                FieldsetProperty fieldset = _fieldsetContext.Properties.Where(property => property.Type == node.Key.Type).First();
                attributes = SerializeAttributes(node, fieldset);
            }
            else
            {
                attributes = SerializeAttributes(node);
            }

            if (attributes != null)
            {
                response["attributes"] = attributes;
            }

            var relationships = SerializeRelationships(node);

            if (relationships != null)
            {
                response["relationships"] = relationships;
            }

            return(response);
        }
Example #8
0
        private JObject SerializeAttributes(ResourceGraphNode node, FieldsetProperty fieldset)
        {
            // The source serializer uses a SourceContractResolver to ensure that we only serialize the properties needed
            var serializedSourceObject = JObject.FromObject(node.SourceObject, _sourceSerializer);
            var attributeHash          = node.Resource.Attributes
                                         .Where(a =>
                                                node.SourceObject.IncludesProperty(_propertyNameConverter.ToModelPropertyName(a.InternalName)) && fieldset.Fields.Contains(a.InternalName.ToComparablePropertyName()))
                                         .Select(a =>
                                                 new
            {
                Key   = _propertyNameConverter.ToJsonPropertyName(a.InternalName),
                Value = serializedSourceObject.SelectToken(_propertyNameConverter.ToJsonPropertyName(a.InternalName)) ??
                        serializedSourceObject.SelectToken(a.PropertyName)
            })
                                         .ToDictionary(
                kvp => kvp.Key,
                kvp => kvp.Value);

            return(JObject.FromObject(attributeHash, _serializer));
        }
Example #9
0
        private void Build(
            object obj,
            ApiResource resource,
            ResourceGraphPathSet includePaths,
            int depth,
            string propertyName = null)
        {
            if (obj == null)
            {
                // end of the line - obj will be a leaf node in our graph
                return;
            }

            if (obj.IsCollectionType())
            {
                foreach (var o in (IEnumerable)obj)
                {
                    Build(o, resource, includePaths, depth);
                }

                return;
            }

            // keys (type & id pair) uniquely identifier each resource in a compount document
            var key          = new ResourceGraphNodeKey(obj, resource);
            var existingNode = _nodes.ContainsKey(key) ? _nodes[key] : null;

            if (existingNode == null)
            {
                // this is the first time we have seen this node
                existingNode = new ResourceGraphNode(obj, resource, includePaths, depth, propertyName);
            }
            else if (!existingNode.IncludePaths.Equals(includePaths))
            {
                /*
                 * We've seen this node before but this time it's include paths are different
                 * to those we are currently applying.This is usually because a resource
                 * is present at two or more distinct locations within an object graph.
                 *
                 * We must combine our current include paths with those of the already built node
                 * and rebuild to capture any new relationships to include.
                 */

                includePaths = existingNode.IncludePaths.Union(includePaths);
                existingNode = new ResourceGraphNode(obj, resource, includePaths, depth, propertyName);
            }
            else if (existingNode.GraphDepth > depth)
            {
                /*
                 * We've seen this node before but this time we're closer to the root node.
                 * We must update it's depth to the new lower value so we can later on identify
                 * nodes that should be serialized into the data section.
                 */

                existingNode.GraphDepth = depth;
                return;
            }
            else
            {
                return;
            }

            _nodes[key] = existingNode;

            foreach (var r in resource.Relationships
                     .Where(r => includePaths.MatchesProperty(r.PropertyName)))
            {
                // Build a new set of include paths with the relationship property as the root
                var childIncludes = includePaths.PathSetForChildProperty(r.PropertyName);

                if (r.Kind == RelationshipKind.HasMany)
                {
                    var collection = (IEnumerable)obj.GetValueOfProperty(r.PropertyName);

                    if (collection != null)
                    {
                        foreach (var o in collection)
                        {
                            // Add the relationship member to the graph
                            Build(o, r.RelatedResource, childIncludes, depth + 1, r.PropertyName);
                        }
                    }
                }
                else
                {
                    var o = obj.GetValueOfProperty(r.PropertyName);
                    if (o != null)
                    {
                        // Add the relationship member to the graph
                        Build(o, r.RelatedResource, childIncludes, depth + 1, r.PropertyName);
                    }
                }
            }
        }