public static IList BuildIEnumerable(DeserializationContext context, Type type, JEnumerable<JToken> elements, IEnumerable<TypeMapping> typeMappings, int nestingLevel)
        {
            typeMappings = typeMappings.ToArray();
            var itemType = type.GetGenericArguments().Single();
            var listType = typeof(List<>).MakeGenericType(itemType);
            var list = (IList)Activator.CreateInstance(listType);

            foreach (var element in elements)
            {
                if (itemType.IsPrimitive)
                {
                    var value = element as JValue;
                    if (value != null)
                    {
                        list.Add(Convert.ChangeType(value.Value, itemType));
                    }
                }
                else if (itemType == typeof (string))
                {
                    list.Add(element.AsString());
                }
                else
                {
                    var item = CreateAndMap(context, itemType, element, typeMappings, nestingLevel + 1);
                    list.Add(item);
                }
            }

            return list;
        }
 public static Dictionary<string, PropertyInfo> ApplyPropertyCasing(DeserializationContext context, Dictionary<string, PropertyInfo> properties)
 {
     if (context.JsonContractResolver is CamelCasePropertyNamesContractResolver)
     {
         var camel = new Func<string, string>(name => string.Format("{0}{1}", name.Substring(0,1).ToLowerInvariant(), name.Substring(1, name.Length-1)));
         return properties.Select(x => new { Key = camel(x.Key), x.Value }).ToDictionary(x => x.Key, x => x.Value);
     }
     return properties;
 }
        public static IDictionary BuildDictionary(DeserializationContext context, Type type, JEnumerable<JToken> elements, IEnumerable<TypeMapping> typeMappings, int nestingLevel)
        {
            typeMappings = typeMappings.ToArray();
            var dict = (IDictionary)Activator.CreateInstance(type);
            var valueType = type.GetGenericArguments()[1];
            foreach (JProperty child in elements)
            {
                var key = child.Name;
                var item = CreateAndMap(context, valueType, child.Value, typeMappings, nestingLevel + 1);
                dict.Add(key, item);
            }

            return dict;
        }
 static bool TryJsonConverters(DeserializationContext context, Type type, JToken element, out object instance)
 {
     instance = null;
     if (context.JsonConverters == null) return false;
     var converter = context.JsonConverters.FirstOrDefault(c => c.CanConvert(type));
     if (converter == null) return false;
     using (var reader = element.CreateReader())
     {
         reader.Read();
         instance = converter.ReadJson(reader, type, null, null);
         return true;
     }
 }
        public static object CreateAndMap(DeserializationContext context, Type type, JToken element, IEnumerable<TypeMapping> typeMappings, int nestingLevel)
        {
            if (element.Type == JTokenType.Null)
                return null;

            object instance;
            typeMappings = typeMappings.ToArray();

            Type genericTypeDefinition = null;

            if (type.IsGenericType)
            {
                genericTypeDefinition = type.GetGenericTypeDefinition();
                if (genericTypeDefinition == typeof (Nullable<>))
                {
                    type = type.GetGenericArguments()[0];
                    genericTypeDefinition = null;
                }
            }

            if (genericTypeDefinition != null)
            {
                if (genericTypeDefinition == typeof(Dictionary<,>))
                {
                    instance = BuildDictionary(context, type, element.Children(), typeMappings, nestingLevel + 1);
                }
                else if (genericTypeDefinition == typeof(List<>))
                {
                    instance = BuildList(context, type, element.Children(), typeMappings, nestingLevel + 1);
                }
                else if (genericTypeDefinition == typeof(IEnumerable<>))
                {
                    instance = BuildIEnumerable(context, type, element.Children(), typeMappings, nestingLevel + 1);
                }
                else if (type == typeof (string))
                {
                    instance = (string) element;
                }
                else
                {
                    var mapping = typeMappings.FirstOrDefault(m => m.ShouldTriggerForPropertyType(nestingLevel, type));
                    if (mapping != null)
                        instance = MutateObject(context, element, typeMappings, nestingLevel, mapping, type);
                    else
                    {
                        instance = Activator.CreateInstance(type);
                        Map(context, instance, element, typeMappings, nestingLevel);
                    }
                }
            }
            else if (type == typeof(byte[]))
            {
                instance = Convert.FromBase64String(element.Value<string>());
            }
            else if (type.BaseType == typeof(Array)) //One Dimensional Only
            {
                var underlyingType = type.GetElementType();
                var arrayType = typeof(ArrayList);
                instance = BuildArray(context, arrayType, underlyingType, element.Children(), typeMappings, nestingLevel + 1);
            }
            else if (type == typeof(string))
            {
                instance = element.ToString();
            }
            else if (TryJsonConverters(context, type, element, out instance))
            {
            }
            else if (type.IsValueType)
            {
                if (type == typeof(Guid))
                {
                    instance = Guid.Parse(element.ToString());
                }
                else if (type.BaseType == typeof(Enum))
                {
                    instance = Enum.Parse(type, element.ToString(), false);
                }
                else
                {
                    instance = Convert.ChangeType(element.ToString(), type);
                }
            }
            else
            {
                try
                {
                    instance = Activator.CreateInstance(type);
                }
                catch (MissingMethodException ex)
                {
                    throw new DeserializationException(
                        string.Format("We expected a default public constructor on {0} so that we could create instances of it to deserialize data into, however this constructor does not exist or is inaccessible.", type.Name),
                        ex);
                }
                Map(context, instance, element, typeMappings, nestingLevel);
            }
            return instance;
        }
        public static void SetPropertyValue(DeserializationContext context, object targetObject, PropertyInfo propertyInfo, JToken value, IEnumerable<TypeMapping> typeMappings, int nestingLevel)
        {
            if (value == null || value.Type == JTokenType.Null)
                return;

            var coercedValue = CoerceValue(context, propertyInfo, value, typeMappings, nestingLevel);
            propertyInfo.SetValue(targetObject, coercedValue, null);
        }
        public IEnumerable <TResult> Deserialize(string content, bool isHttp)
        {
            try
            {
                var context = new DeserializationContext
                {
                    Culture              = culture,
                    JsonConverters       = Enumerable.Reverse(client.JsonConverters ?? new List <JsonConverter>(0)).ToArray(),
                    JsonContractResolver = client.JsonContractResolver
                };

                if (isHttp)
                {
                    content = CommonDeserializerMethods.RemoveResultsFromJson(content);
                }
                content = CommonDeserializerMethods.ReplaceAllDateInstancesWithNeoDates(content);

                var reader = new JsonTextReader(new StringReader(content))
                {
                    DateParseHandling = DateParseHandling.None
                };

                // Force the deserialization to happen now, not later, as there's
                // not much value to deferred execution here and we'd like to know
                // about any errors now
                return(inTransaction
                    ? FullDeserializationFromTransactionResponse(reader, context, isHttp).ToArray()
                    : DeserializeFromRoot(content, reader, context, isHttp).ToArray());
            }
            catch (Exception ex)
            {
                // we want the NeoException to be thrown
                if (ex is NeoException)
                {
                    throw;
                }

                const string messageTemplate =
                    @"Neo4j returned a valid response, however Neo4jClient was unable to deserialize into the object structure you supplied.

First, try and review the exception below to work out what broke.

If it's not obvious, you can ask for help at http://stackoverflow.com/questions/tagged/neo4jclient

Include the full text of this exception, including this message, the stack trace, and all of the inner exception details.

Include the full type definition of {0}.

Include this raw JSON, with any sensitive values replaced with non-sensitive equivalents:

{1}";
                var message = string.Format(messageTemplate, typeof(TResult).FullName, content);

                // If it's a specifc scenario that we're blowing up about, put this front and centre in the message
                if (ex is DeserializationException deserializationException)
                {
                    message = $"{deserializationException.Message}{Environment.NewLine}{Environment.NewLine}----{Environment.NewLine}{Environment.NewLine}{message}";
                }

                throw new ArgumentException(message, nameof(content), ex);
            }
        }
        static Dictionary<string, PropertyInfo> GetPropertiesForType(DeserializationContext context, Type objType)
        {
            Dictionary<string, PropertyInfo> result;
            if (PropertyInfoCache.TryGetValue(objType, out result))
                return result;

            lock (PropertyInfoCacheLock)
            {
                if (PropertyInfoCache.TryGetValue(objType, out result))
                    return result;

                var camelCase = (context.JsonContractResolver is CamelCasePropertyNamesContractResolver);
                var camel = new Func<string, string>(name => string.Format("{0}{1}", name.Substring(0, 1).ToLowerInvariant(), name.Length > 1 ? name.Substring(1, name.Length - 1) : string.Empty));

                var properties = objType
                    .GetProperties()
                    .Where(p => p.CanWrite)
                    .Select(p =>
                    {
                        var attributes =
                            (JsonPropertyAttribute[])p.GetCustomAttributes(typeof(JsonPropertyAttribute), true);
                        return new
                        {
                            Name = attributes.Any() && attributes.Single().PropertyName != null ? attributes.Single().PropertyName : camelCase ? camel(p.Name) : p.Name, //only camelcase if json property doesn't exist
                            Property = p
                        };
                    });

                return properties.ToDictionary(p => p.Name, p => p.Property);
            }
        }
Exemple #9
0
        IEnumerable <TResult> DeserializeFromRoot(string content, JsonTextReader reader, DeserializationContext context)
        {
            var root = JToken.ReadFrom(reader).Root;

            if (!(root is JObject))
            {
                throw new InvalidOperationException("Root expected to be a JSON object.");
            }
            return(DeserializeResultSet(root, context));
        }
Exemple #10
0
        private IEnumerable <TResult> FullDeserializationFromTransactionResponse(JsonTextReader reader, DeserializationContext context)
        {
            var root = JToken.ReadFrom(reader).Root as JObject;

            // discarding all the results but the first
            // (this won't affect the library because as of now there is no way of executing
            // multiple statements in the same batch within a transaction and returning the results)
            var resultSet = GetRootResultInTransaction(root);

            if (resultSet == null)
            {
                throw new InvalidOperationException(
                          @"`results` array should have one result set.
This means no query was emitted, so a method that doesn't care about getting results should have been called."
                          );
            }
            return(DeserializeResultSet(resultSet, context));
        }
Exemple #11
0
        IEnumerable <TResult> DeserializeResultSet(JToken resultRoot, DeserializationContext context)
        {
            var columnsArray = (JArray)resultRoot["columns"];
            var columnNames  = columnsArray
                               .Children()
                               .Select(c => c.AsString())
                               .ToArray();

            var jsonTypeMappings = new List <TypeMapping>
            {
                new TypeMapping
                {
                    ShouldTriggerForPropertyType = (nestingLevel, type) =>
                                                   type.GetTypeInfo().IsGenericType&&
                                                   type.GetGenericTypeDefinition() == typeof(Node <>),
                    DetermineTypeToParseJsonIntoBasedOnPropertyType = t =>
                    {
                        var nodeType = t.GetGenericArguments();
                        return(typeof(NodeApiResponse <>).MakeGenericType(nodeType));
                    },
                    MutationCallback = n => n.GetType().GetMethod("ToNode").Invoke(n, new object[] { client })
                },
                new TypeMapping
                {
                    ShouldTriggerForPropertyType = (nestingLevel, type) =>
                                                   type.GetTypeInfo().IsGenericType&&
                                                   type.GetGenericTypeDefinition() == typeof(RelationshipInstance <>),
                    DetermineTypeToParseJsonIntoBasedOnPropertyType = t =>
                    {
                        var relationshipType = t.GetGenericArguments();
                        return(typeof(RelationshipApiResponse <>).MakeGenericType(relationshipType));
                    },
                    MutationCallback = n => n.GetType().GetMethod("ToRelationshipInstance").Invoke(n, new object[] { client })
                }
            };

            switch (resultMode)
            {
            case CypherResultMode.Set:
                return(ParseInSingleColumnMode(context, resultRoot, columnNames, jsonTypeMappings.ToArray()));

            case CypherResultMode.Projection:
                // if we are in transaction and we have an object we dont need a mutation
                if (!inTransaction && !inBolt)
                {
                    jsonTypeMappings.Add(new TypeMapping
                    {
                        ShouldTriggerForPropertyType = (nestingLevel, type) =>
                                                       nestingLevel == 0 && type.GetTypeInfo().IsClass,
                        DetermineTypeToParseJsonIntoBasedOnPropertyType = t =>
                                                                          typeof(NodeOrRelationshipApiResponse <>).MakeGenericType(new[] { t }),
                        MutationCallback = n =>
                                           n.GetType().GetProperty("Data").GetGetMethod().Invoke(n, new object[0])
                    });
                }
                return(ParseInProjectionMode(context, resultRoot, columnNames, jsonTypeMappings.ToArray()));

            default:
                throw new NotSupportedException(string.Format("Unrecognised result mode of {0}.", resultMode));
            }
        }
Exemple #12
0
        IEnumerable <TResult> DeserializeInternal(string content)
        {
            var context = new DeserializationContext
            {
                Culture              = culture,
                JsonConverters       = Enumerable.Reverse(client.JsonConverters ?? new List <JsonConverter>(0)).ToArray(),
                JsonContractResolver = client.JsonContractResolver
            };

            content = CommonDeserializerMethods.ReplaceAllDateInstacesWithNeoDates(content);

            var reader = new JsonTextReader(new StringReader(content))
            {
                DateParseHandling = DateParseHandling.None
            };
            var root = JToken.ReadFrom(reader).Root;

            var columnsArray = (JArray)root["columns"];
            var columnNames  = columnsArray
                               .Children()
                               .Select(c => c.AsString())
                               .ToArray();

            var jsonTypeMappings = new List <TypeMapping>
            {
                new TypeMapping
                {
                    ShouldTriggerForPropertyType = (nestingLevel, type) =>
                                                   type.GetTypeInfo().IsGenericType&&
                                                   type.GetGenericTypeDefinition() == typeof(Node <>),
                    DetermineTypeToParseJsonIntoBasedOnPropertyType = t =>
                    {
                        var nodeType = t.GetGenericArguments();
                        return(typeof(NodeApiResponse <>).MakeGenericType(nodeType));
                    },
                    MutationCallback = n => n.GetType().GetMethod("ToNode").Invoke(n, new object[] { client })
                },
                new TypeMapping
                {
                    ShouldTriggerForPropertyType = (nestingLevel, type) =>
                                                   type.GetTypeInfo().IsGenericType&&
                                                   type.GetGenericTypeDefinition() == typeof(RelationshipInstance <>),
                    DetermineTypeToParseJsonIntoBasedOnPropertyType = t =>
                    {
                        var relationshipType = t.GetGenericArguments();
                        return(typeof(RelationshipApiResponse <>).MakeGenericType(relationshipType));
                    },
                    MutationCallback = n => n.GetType().GetMethod("ToRelationshipInstance").Invoke(n, new object[] { client })
                }
            };

            switch (resultMode)
            {
            case CypherResultMode.Set:
                return(ParseInSingleColumnMode(context, root, columnNames, jsonTypeMappings.ToArray()));

            case CypherResultMode.Projection:
                jsonTypeMappings.Add(new TypeMapping
                {
                    ShouldTriggerForPropertyType = (nestingLevel, type) =>
                                                   nestingLevel == 0 && type.GetTypeInfo().IsClass,
                    DetermineTypeToParseJsonIntoBasedOnPropertyType = t =>
                                                                      typeof(NodeOrRelationshipApiResponse <>).MakeGenericType(new[] { t }),
                    MutationCallback = n =>
                                       n.GetType().GetProperty("Data").GetGetMethod().Invoke(n, new object[0])
                });
                return(ParseInProjectionMode(context, root, columnNames, jsonTypeMappings.ToArray()));

            default:
                throw new NotSupportedException(string.Format("Unrecognised result mode of {0}.", resultMode));
            }
        }
        public static object CreateAndMap(DeserializationContext context, Type type, JToken element, IEnumerable <TypeMapping> typeMappings, int nestingLevel)
        {
            if (element.Type == JTokenType.Null)
            {
                return(null);
            }

            object instance;

            typeMappings = typeMappings.ToArray();

            Type genericTypeDefinition = null;
            var  typeInfo = type.GetTypeInfo();

            if (typeInfo.IsGenericType)
            {
                genericTypeDefinition = type.GetGenericTypeDefinition();
                if (genericTypeDefinition == typeof(Nullable <>))
                {
                    type = type.GetGenericArguments()[0];
                    genericTypeDefinition = null;
                }
            }

            if (genericTypeDefinition != null)
            {
                if (genericTypeDefinition == typeof(Dictionary <,>))
                {
                    instance = BuildDictionary(context, type, element.Children(), typeMappings, nestingLevel + 1);
                }
                else if (genericTypeDefinition == typeof(List <>))
                {
                    instance = BuildList(context, type, element.Children(), typeMappings, nestingLevel + 1);
                }
                else if (genericTypeDefinition == typeof(IEnumerable <>))
                {
                    instance = BuildIEnumerable(context, type, element.Children(), typeMappings, nestingLevel + 1);
                }
                else if (type == typeof(string))
                {
                    instance = (string)element;
                }
                else
                {
                    var mapping = typeMappings.FirstOrDefault(m => m.ShouldTriggerForPropertyType(nestingLevel, type));
                    if (mapping != null)
                    {
                        instance = MutateObject(context, element, typeMappings, nestingLevel, mapping, type);
                    }
                    else
                    {
                        instance = Activator.CreateInstance(type);
                        Map(context, instance, element, typeMappings, nestingLevel);
                    }
                }
            }
            else if (type == typeof(byte[]))
            {
                instance = Convert.FromBase64String(element.Value <string>());
            }
            else if (typeInfo.BaseType == typeof(Array)) //One Dimensional Only
            {
                var underlyingType = type.GetElementType();
                var arrayType      = typeof(ArrayList);
                instance = BuildArray(context, arrayType, underlyingType, element.Children(), typeMappings, nestingLevel + 1);
            }
            else if (type == typeof(string))
            {
                instance = element.ToString();
            }
            else if (TryJsonConverters(context, type, element, out instance))
            {
            }
            else if (typeInfo.IsValueType)
            {
                if (type == typeof(Guid))
                {
                    instance = Guid.Parse(element.ToString());
                }
                else if (typeInfo.BaseType == typeof(Enum))
                {
                    instance = Enum.Parse(type, element.ToString(), false);
                }
                else
                {
                    instance = Convert.ChangeType(element.ToString(), type);
                }
            }
            else
            {
                try
                {
                    instance = Activator.CreateInstance(type);
                }
                catch (MissingMethodException ex)
                {
                    throw new DeserializationException(
                              $"We expected a default public constructor on {type.Name} so that we could create instances of it to deserialize data into, however this constructor does not exist or is inaccessible.",
                              ex);
                }
                Map(context, instance, element, typeMappings, nestingLevel);
            }
            return(instance);
        }
        public static object CoerceValue(DeserializationContext context, PropertyInfo propertyInfo, JToken value, IEnumerable <TypeMapping> typeMappings, int nestingLevel)
        {
            if (value == null || value.Type == JTokenType.Null)
            {
                return(null);
            }

            var propertyType = propertyInfo.PropertyType;
            var typeInfo     = propertyType.GetTypeInfo();

            if (TryJsonConverters(context, propertyType, value, out var jsonConversionResult))
            {
                return(jsonConversionResult);
            }

            Type genericTypeDef = null;

            if (typeInfo.IsGenericType)
            {
                genericTypeDef = propertyType.GetGenericTypeDefinition();

                if (genericTypeDef == typeof(Nullable <>))
                {
                    propertyType   = propertyType.GetGenericArguments()[0];
                    genericTypeDef = null;
                }
            }

            typeMappings = typeMappings.ToArray();
            if (typeInfo.IsPrimitive)
            {
                // no primitives can contain quotes so we can safely remove them
                // allows converting a json value like {"index": "1"} to an int
                object tmpVal = value.AsString().Replace("\"", string.Empty);
                tmpVal = Convert.ChangeType(tmpVal, propertyType);
                return(tmpVal);
            }

            if (typeInfo.IsEnum)
            {
                var raw       = value.AsString();
                var converted = Enum.Parse(propertyType, raw, false);
                return(converted);
            }

            if (propertyType == typeof(Uri))
            {
                var raw = value.AsString();
                var uri = new Uri(raw, UriKind.RelativeOrAbsolute);
                return(uri);
            }

            if (propertyType == typeof(string))
            {
                var raw = value.AsString();
                return(raw);
            }

            if (propertyType == typeof(DateTime))
            {
                return(ParseDateTime(value));
            }

            if (propertyType == typeof(DateTimeOffset))
            {
                var dateTimeOffset = ParseDateTimeOffset(value);
                return(dateTimeOffset);
            }

            if (propertyType == typeof(Decimal))
            {
                var dec = Convert.ToDecimal(((JValue)value).Value);
                return(dec);
            }

            if (propertyType == typeof(TimeSpan))
            {
                var valueString = value.ToString();
                var timeSpan    = TimeSpan.Parse(valueString);
                return(timeSpan);
            }

            if (propertyType == typeof(Guid))
            {
                var raw  = value.AsString();
                var guid = string.IsNullOrEmpty(raw) ? Guid.Empty : new Guid(raw);
                return(guid);
            }

            if (propertyType == typeof(byte[]))
            {
                return(Convert.FromBase64String(value.Value <string>()));
            }

            if (genericTypeDef == typeof(List <>))
            {
                var list = BuildList(context, propertyType, value.Children(), typeMappings, nestingLevel + 1);
                return(list);
            }

            if (genericTypeDef == typeof(Dictionary <,>))
            {
                var keyType = propertyType.GetGenericArguments()[0];

                // only supports Dict<string, T>()
                if (keyType != typeof(string))
                {
                    throw new NotSupportedException("Value coercion only supports dictionaries with a key of type System.String");
                }

                var dict = BuildDictionary(context, propertyType, value.Children(), typeMappings, nestingLevel + 1);
                return(dict);
            }

            // nested objects
            var mapping = typeMappings.FirstOrDefault(m => m.ShouldTriggerForPropertyType(nestingLevel, propertyType));
            var item    = mapping != null?MutateObject(context, value, typeMappings, nestingLevel, mapping, propertyType) : CreateAndMap(context, propertyType, value, typeMappings, nestingLevel + 1);

            return(item);
        }
 static object MutateObject(DeserializationContext context, JToken value, IEnumerable<TypeMapping> typeMappings, int nestingLevel,
                            TypeMapping mapping, Type propertyType)
 {
     var newType = mapping.DetermineTypeToParseJsonIntoBasedOnPropertyType(propertyType);
     var rawItem = CreateAndMap(context, newType, value, typeMappings, nestingLevel + 1);
     var item = mapping.MutationCallback(rawItem);
     return item;
 }
Exemple #16
0
        // ReSharper disable UnusedParameter.Local
        IEnumerable <TResult> ParseInSingleColumnMode(DeserializationContext context, JToken root, string[] columnNames, TypeMapping[] jsonTypeMappings)
        // ReSharper restore UnusedParameter.Local
        {
            if (columnNames.Count() != 1)
            {
                throw new InvalidOperationException("The deserializer is running in single column mode, but the response included multiple columns which indicates a projection instead. If using the fluent Cypher interface, use the overload of Return that takes a lambda or object instead of single string. (The overload with a single string is for an identity, not raw query text: we can't map the columns back out if you just supply raw query text.)");
            }

            var resultType = typeof(TResult);
            var isResultTypeANodeOrRelationshipInstance = resultType.GetTypeInfo().IsGenericType&&
                                                          (resultType.GetGenericTypeDefinition() == typeof(Node <>) ||
                                                           resultType.GetGenericTypeDefinition() == typeof(RelationshipInstance <>));
            var mapping = jsonTypeMappings.SingleOrDefault(m => m.ShouldTriggerForPropertyType(0, resultType));
            var newType = mapping == null ? resultType : mapping.DetermineTypeToParseJsonIntoBasedOnPropertyType(resultType);

            var dataArray = (JArray)root["data"];
            var rows      = dataArray.Children();

            var dataPropertyNameInTransaction = resultFormat == CypherResultFormat.Rest ? "rest" : "row";
            var results = rows.Select(row =>
            {
                if (inTransaction)
                {
                    var rowObject = row as JObject;
                    if (rowObject == null)
                    {
                        throw new InvalidOperationException("Expected the row to be a JSON object, but it wasn't.");
                    }

                    JToken rowProperty;
                    if (!rowObject.TryGetValue(dataPropertyNameInTransaction, out rowProperty))
                    {
                        throw new InvalidOperationException("There is no row property in the JSON object.");
                    }
                    row = rowProperty;
                }

                if (!(row is JArray))
                {
                    // no transaction mode and the row is not an array
                    throw new InvalidOperationException("Expected the row to be a JSON array of values, but it wasn't.");
                }
                var rowAsArray = (JArray)row;
                if (rowAsArray.Count != 1)
                {
                    throw new InvalidOperationException(string.Format("Expected the row to only have a single array value, but it had {0}.", rowAsArray.Count));
                }

                var elementToParse = row[0];
                if (elementToParse is JObject)
                {
                    var propertyNames = ((JObject)elementToParse)
                                        .Properties()
                                        .Select(p => p.Name)
                                        .ToArray();
                    var dataElementLooksLikeANodeOrRelationshipInstance =
                        new[] { "data", "self", "traverse", "properties" }.All(propertyNames.Contains);
                    if (!isResultTypeANodeOrRelationshipInstance &&
                        dataElementLooksLikeANodeOrRelationshipInstance)
                    {
                        elementToParse = elementToParse["data"];
                    }
                }

                var parsed = CommonDeserializerMethods.CreateAndMap(context, newType, elementToParse, jsonTypeMappings, 0);
                return((TResult)(mapping == null ? parsed : mapping.MutationCallback(parsed)));
            });

            return(results);
        }
        public static void Map(DeserializationContext context, object targetObject, JToken parentJsonToken, IEnumerable<TypeMapping> typeMappings, int nestingLevel)
        {
            typeMappings = typeMappings.ToArray();
            var objType = targetObject.GetType();
            var props = GetPropertiesForType(context, objType);
            IDictionary<string, JToken> dictionary = parentJsonToken as JObject;
            if (dictionary != null && props.Keys.All(dictionary.ContainsKey) == false && dictionary.ContainsKey("data")) {
               parentJsonToken = parentJsonToken["data"];
            }

            foreach (var propertyName in props.Keys)
            {
                var propertyInfo = props[propertyName];
                JToken jsonToken;
                try
                {
                    jsonToken = parentJsonToken[propertyName];
                }
                catch (InvalidOperationException ex)
                {
                    throw new InvalidOperationException(string.Format("While trying to map some JSON into an object of type {0}, we failed to find an expected property ({1}) in the JSON at path {2}.\r\n\r\nThe JSON block for this token was:\r\n\r\n{3}",
                        objType.FullName,
                        propertyName,
                        parentJsonToken.Path,
                        parentJsonToken),
                        ex);
                }
                SetPropertyValue(context, targetObject, propertyInfo, jsonToken, typeMappings, nestingLevel);
            }
        }
Exemple #18
0
        IEnumerable <TResult> ParseInProjectionMode(DeserializationContext context, JToken root, string[] columnNames, TypeMapping[] jsonTypeMappings)
        {
            var properties           = typeof(TResult).GetProperties();
            var propertiesDictionary = properties
                                       .ToDictionary(p => p.Name);


            Func <JToken, TResult> getRow = null;

            var columnsWhichDontHaveSettableProperties = columnNames.Where(c => !propertiesDictionary.ContainsKey(c) || !propertiesDictionary[c].CanWrite).ToArray();

            if (columnsWhichDontHaveSettableProperties.Any())
            {
                // See if there is a constructor that is compatible with all property types,
                // which is the case for anonymous types...
                var ctor = typeof(TResult).GetConstructors().FirstOrDefault(info =>
                {
                    var parameters = info.GetParameters();
                    if (parameters.Length != columnNames.Length)
                    {
                        return(false);
                    }

                    for (var i = 0; i < parameters.Length; i++)
                    {
                        var property = propertiesDictionary[columnNames[i]];
                        if (!parameters[i].ParameterType.IsAssignableFrom(property.PropertyType))
                        {
                            return(false);
                        }
                    }
                    return(true);
                });

                if (ctor != null)
                {
                    getRow = token => ReadProjectionRowUsingCtor(context, token, propertiesDictionary, columnNames, jsonTypeMappings, ctor);
                }

                if (getRow == null)
                {
                    // wasn't able to build TResult via constructor
                    var columnsWhichDontHaveSettablePropertiesCommaSeparated = string.Join(", ", columnsWhichDontHaveSettableProperties);
                    throw new ArgumentException(string.Format(
                                                    "The query response contains columns {0} however {1} does not contain publically settable properties to receive this data.",
                                                    columnsWhichDontHaveSettablePropertiesCommaSeparated,
                                                    typeof(TResult).FullName),
                                                "columnNames");
                }
            }
            else
            {
                getRow = token => ReadProjectionRowUsingProperties(context, token, propertiesDictionary, columnNames, jsonTypeMappings);
            }

            var dataArray = (JArray)root["data"];
            var rows      = dataArray.Children();

            var dataPropertyNameInTransaction = resultFormat == CypherResultFormat.Rest ? "rest" : "row";

            return(inTransaction ? rows.Select(row => row[dataPropertyNameInTransaction]).Select(getRow) : rows.Select(getRow));
        }
        public static object CoerceValue(DeserializationContext context, PropertyInfo propertyInfo, JToken value, IEnumerable<TypeMapping> typeMappings, int nestingLevel)
        {
            if (value == null || value.Type == JTokenType.Null)
                return null;

            var propertyType = propertyInfo.PropertyType;
            object jsonConversionResult;
            if (TryJsonConverters(context, propertyType, value, out jsonConversionResult))
                return jsonConversionResult;
            
            Type genericTypeDef = null;

            if (propertyType.IsGenericType)
            {
                genericTypeDef = propertyType.GetGenericTypeDefinition();

                if (genericTypeDef == typeof(Nullable<>))
                {
                    propertyType = propertyType.GetGenericArguments()[0];
                    genericTypeDef = null;
                }
            }

            typeMappings = typeMappings.ToArray();
            if (propertyType.IsPrimitive)
            {
                // no primitives can contain quotes so we can safely remove them
                // allows converting a json value like {"index": "1"} to an int
                object tmpVal = value.AsString().Replace("\"", string.Empty);
                tmpVal = Convert.ChangeType(tmpVal, propertyType);
                return tmpVal;
            }

            if (propertyType.IsEnum)
            {
                var raw = value.AsString();
                var converted = Enum.Parse(propertyType, raw, false);
                return converted;
            }

            if (propertyType == typeof(Uri))
            {
                var raw = value.AsString();
                var uri = new Uri(raw, UriKind.RelativeOrAbsolute);
                return uri;
            }

            if (propertyType == typeof(string))
            {
                var raw = value.AsString();
                return raw;
            }

            if (propertyType == typeof(DateTime))
            {
                return ParseDateTime(value);
            }

            if (propertyType == typeof(DateTimeOffset))
            {
                var dateTimeOffset = ParseDateTimeOffset(value);
                if (dateTimeOffset.HasValue)
                    return dateTimeOffset.Value;
                return null;
            }

            if (propertyType == typeof(Decimal))
            {
                var dec = Convert.ToDecimal(((JValue) value).Value);
                return dec;
            }

            if (propertyType == typeof(TimeSpan))
            {
                var valueString = value.ToString();
                var timeSpan = TimeSpan.Parse(valueString);
                return timeSpan;
            }

            if (propertyType == typeof(Guid))
            {
                var raw = value.AsString();
                var guid = string.IsNullOrEmpty(raw) ? Guid.Empty : new Guid(raw);
                return guid;
            }

            if (propertyType == typeof(byte[]))
            {
                return Convert.FromBase64String(value.Value<string>());
            }

            if (genericTypeDef == typeof(List<>))
            {
                var list = BuildList(context, propertyType, value.Children(), typeMappings, nestingLevel + 1);
                return list;
            }

            if (genericTypeDef == typeof(Dictionary<,>))
            {
                var keyType = propertyType.GetGenericArguments()[0];

                // only supports Dict<string, T>()
                if (keyType != typeof (string))
                {
                    throw new NotSupportedException("Value coersion only supports dictionaries with a key of type System.String");
                }

                var dict = BuildDictionary(context, propertyType, value.Children(), typeMappings, nestingLevel + 1);
                return dict;
            }

            // nested objects
            var mapping = typeMappings.FirstOrDefault(m => m.ShouldTriggerForPropertyType(nestingLevel, propertyType));
            var item = mapping != null ? MutateObject(context, value, typeMappings, nestingLevel, mapping, propertyType) : CreateAndMap(context, propertyType, value, typeMappings, nestingLevel + 1);
            return item;
        }
        private IEnumerable <TResult> DeserializeResultSet(JToken resultRoot, DeserializationContext context, bool isHttp)
        {
            var columnsArray = isHttp ? (JArray)resultRoot.SelectToken("$.results[0].columns") : (JArray)resultRoot["columns"];

            if (columnsArray == null) //This is a hack prior to shifting the Bolt deserialization entirely away from this.
            {
                columnsArray = !isHttp ? (JArray)resultRoot.SelectToken("$.results[0].columns") : (JArray)resultRoot["columns"];
            }
            var columnNames = columnsArray
                              .Children()
                              .Select(c => c.AsString())
                              .ToArray();

            var jsonTypeMappings = new List <TypeMapping>
            {
                new TypeMapping
                {
                    ShouldTriggerForPropertyType = (nestingLevel, type) =>
                                                   type.GetTypeInfo().IsGenericType&&
                                                   type.GetGenericTypeDefinition() == typeof(Node <>),
                    DetermineTypeToParseJsonIntoBasedOnPropertyType = t =>
                    {
                        var nodeType = t.GetGenericArguments();
                        return(typeof(NodeApiResponse <>).MakeGenericType(nodeType));
                    },
                    MutationCallback = n => n.GetType().GetMethod("ToNode").Invoke(n, new object[] { client })
                },
                new TypeMapping
                {
                    ShouldTriggerForPropertyType = (nestingLevel, type) =>
                                                   type.GetTypeInfo().IsGenericType&&
                                                   type.GetGenericTypeDefinition() == typeof(RelationshipInstance <>),
                    DetermineTypeToParseJsonIntoBasedOnPropertyType = t =>
                    {
                        var relationshipType = t.GetGenericArguments();
                        return(typeof(RelationshipApiResponse <>).MakeGenericType(relationshipType));
                    },
                    MutationCallback = n => n.GetType().GetMethod("ToRelationshipInstance").Invoke(n, new object[] { client })
                }
            };

            switch (resultMode)
            {
            case CypherResultMode.Set:
                return(ParseInSingleColumnMode(context, resultRoot, columnNames, jsonTypeMappings.ToArray(), isHttp));

            case CypherResultMode.Projection:
                // if we are in transaction and we have an object we dont need a mutation
                if (!inTransaction && !inBolt)
                {
                    // jsonTypeMappings.Add(new TypeMapping
                    // {
                    //     ShouldTriggerForPropertyType = (nestingLevel, type) =>
                    //         nestingLevel == 0 && type.GetTypeInfo().IsClass,
                    //     DetermineTypeToParseJsonIntoBasedOnPropertyType = t =>
                    //         typeof(NodeOrRelationshipApiResponse<>).MakeGenericType(new[] { t }),
                    //     MutationCallback = n =>
                    //         n.GetType().GetProperty("Data").GetGetMethod().Invoke(n, new object[0])
                    // });
                }
                return(ParseInProjectionMode(context, resultRoot, columnNames, jsonTypeMappings.ToArray(), isHttp));

            default:
                throw new NotSupportedException($"Unrecognised result mode of {resultMode}.");
            }
        }