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); }
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); }
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); }
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); }
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)); }
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)); }
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); }
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)); }
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); } } } }