private static bool TryToPrimitiveList(Type type, object value, bool canReturnPrimitive, out DynamoDBEntry output)
        {
            Type elementType;

            if (!EntityUtils.ImplementsInterface(type, typeof(ICollection <>)) ||
                !EntityUtils.IsPrimitive(elementType = type.GetGenericArguments()[0]))
            {
                output = null;
                return(false);
            }

            IEnumerable enumerable = value as IEnumerable;

            Primitive primitive;

            // Strings are collections of chars, don't treat them as collections
            if (enumerable == null || value is string)
            {
                if (canReturnPrimitive &&
                    value.GetType().IsAssignableFrom(elementType) &&
                    TryToPrimitive(elementType, value, out primitive))
                {
                    output = primitive;
                    return(true);
                }

                output = null;
                return(false);
            }

            PrimitiveList     primitiveList = new PrimitiveList();
            DynamoDBEntryType?listType      = null;

            foreach (var item in enumerable)
            {
                if (TryToPrimitive(elementType, item, out primitive))
                {
                    if (listType.HasValue && listType.Value != primitive.Type)
                    {
                        throw new InvalidOperationException("List cannot contain a mix of different types");
                    }
                    listType = primitive.Type;

                    primitiveList.Entries.Add(primitive);
                }
                else
                {
                    output = null;
                    return(false);
                }
            }
            primitiveList.Type = listType.GetValueOrDefault(DynamoDBEntryType.String);

            output = primitiveList;
            return(true);
        }
        private static bool TryToPrimitiveList(Type type, object value, bool canReturnPrimitive, out DynamoDBEntry output)
        {
            Type elementType;

            if (!EntityUtils.ImplementsInterface(type, typeof(ICollection <>)) ||
                !EntityUtils.IsPrimitive(elementType = type.GetGenericArguments()[0]))
            {
                output = null;
                return(false);
            }

            PrimitiveList primitiveList = new PrimitiveList();
            ICollection   collection    = value as ICollection;

            Primitive primitive;

            if (collection == null)
            {
                if (canReturnPrimitive &&
                    value.GetType().IsAssignableFrom(elementType) &&
                    TryToPrimitive(elementType, value, out primitive))
                {
                    output = primitive;
                    return(true);
                }

                output = null;
                return(false);
            }

            bool?isNumeric = null;

            foreach (var item in collection)
            {
                if (TryToPrimitive(elementType, item, out primitive))
                {
                    if (isNumeric.HasValue && isNumeric.Value != primitive.SaveAsNumeric)
                    {
                        throw new InvalidOperationException("List cannot contain a mix of numerics and non-numerics");
                    }
                    isNumeric = primitive.SaveAsNumeric;

                    primitiveList.Entries.Add(primitive);
                }
                else
                {
                    output = null;
                    return(false);
                }
            }
            primitiveList.SaveAsNumeric = isNumeric.HasValue ? isNumeric.Value : false;

            output = primitiveList;
            return(true);
        }
        // PrimitiveList <--> List
        private static bool TryFromPrimitiveList(Type targetType, PrimitiveList value, out object output)
        {
            Type elementType;

            if ((!EntityUtils.ImplementsInterface(targetType, typeof(ICollection <>)) &&
                 !EntityUtils.ImplementsInterface(targetType, typeof(IList))) ||
                !EntityUtils.CanInstantiate(targetType) ||
                !EntityUtils.IsPrimitive(elementType = targetType.GetGenericArguments()[0]))
            {
                output = null;
                return(false);
            }

            var   collection        = EntityUtils.Instantiate(targetType);
            IList ilist             = collection as IList;
            bool  useIListInterface = ilist != null;

            MethodInfo collectionAdd = null;

            if (!useIListInterface)
            {
                collectionAdd = targetType.GetMethod("Add");
            }

            foreach (Primitive primitive in value.Entries)
            {
                object primitiveValue;
                if (TryFromPrimitive(elementType, primitive, out primitiveValue))
                {
                    if (useIListInterface)
                    {
                        ilist.Add(primitiveValue);
                    }
                    else
                    {
                        collectionAdd.Invoke(collection, new object[] { primitiveValue });
                    }
                }
                else
                {
                    output = null;
                    return(false);
                }
            }

            output = collection;
            return(true);
        }
Beispiel #4
0
        internal static ItemStorageConfig CreateStorageConfig(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            ItemStorageConfig config = new ItemStorageConfig();

            DynamoDBTableAttribute tableAttribute = EntityUtils.GetTableAttribute(type);

            if (tableAttribute == null || string.IsNullOrEmpty(tableAttribute.TableName))
            {
                throw new InvalidOperationException("No DynamoDBTableAttribute on type");
            }

            if (string.IsNullOrEmpty(tableAttribute.TableName))
            {
                throw new InvalidOperationException("DynamoDBTableAttribute.Table is empty or null");
            }
            config.TableName = tableAttribute.TableName;
            config.LowerCamelCaseProperties = tableAttribute.LowerCamelCaseProperties;

            foreach (var member in type.GetMembers())
            {
                // filter out non-fields and non-properties
                if (!(member is FieldInfo || member is PropertyInfo))
                {
                    continue;
                }

                // filter out properties that aren't both read and write
                if (!EntityUtils.IsReadWrite(member))
                {
                    continue;
                }

                DynamoDBAttribute attribute = EntityUtils.GetAttribute(member);

                // filter out ignored properties
                if (attribute is DynamoDBIgnoreAttribute)
                {
                    continue;
                }

                Type   memberType    = EntityUtils.GetType(member);
                string attributeName = GetAccurateCase(config, member.Name);
                string propertyName  = member.Name;

                PropertyStorage propertyStorage = new PropertyStorage
                {
                    Member     = member,
                    MemberType = memberType,
                };

                if (attribute is DynamoDBVersionAttribute)
                {
                    EntityUtils.ValidateVersionType(memberType);    // no conversion is possible, so type must be a nullable primitive

                    if (!string.IsNullOrEmpty(config.VersionPropertyName))
                    {
                        throw new InvalidOperationException("Multiple version attributes defined");
                    }

                    config.VersionPropertyName = propertyName;
                    propertyStorage.IsVersion  = true;
                }

                DynamoDBPropertyAttribute propertyAttribute = attribute as DynamoDBPropertyAttribute;
                if (propertyAttribute != null)
                {
                    if (!string.IsNullOrEmpty(propertyAttribute.AttributeName))
                    {
                        attributeName = GetAccurateCase(config, propertyAttribute.AttributeName);
                    }

                    if (propertyAttribute is DynamoDBHashKeyAttribute)
                    {
                        if (propertyAttribute.Converter == null && !EntityUtils.IsPrimitive(memberType))
                        {
                            throw new InvalidOperationException("Hash key " + propertyName + " must be of primitive type");
                        }
                        if (!string.IsNullOrEmpty(config.HashKeyPropertyName))
                        {
                            throw new InvalidOperationException("Multiple hash keys defined");
                        }

                        config.HashKeyPropertyName = propertyName;
                        propertyStorage.IsHashKey  = true;
                    }
                    if (propertyAttribute is DynamoDBRangeKeyAttribute)
                    {
                        if (propertyAttribute.Converter == null && !EntityUtils.IsPrimitive(memberType))
                        {
                            throw new InvalidOperationException("Range key " + propertyName + " must be of primitive type");
                        }
                        if (!string.IsNullOrEmpty(config.RangeKeyPropertyName))
                        {
                            throw new InvalidOperationException("Multiple range keys defined");
                        }

                        config.RangeKeyPropertyName = propertyName;
                        propertyStorage.IsRangeKey  = true;
                    }


                    if (propertyAttribute.Converter != null)
                    {
                        if (!EntityUtils.CanInstantiate(propertyAttribute.Converter) || !EntityUtils.ImplementsInterface(propertyAttribute.Converter, typeof(IPropertyConverter)))
                        {
                            throw new InvalidOperationException("Converter for " + propertyName + " must be instantiable with no parameters and must implement IPropertyConverter");
                        }

                        propertyStorage.Converter = EntityUtils.Instantiate(propertyAttribute.Converter) as IPropertyConverter;
                    }
                }

                propertyStorage.PropertyName  = propertyName;
                propertyStorage.AttributeName = attributeName;

                config.AttributesToGet.Add(attributeName);
                config.AddPropertyStorage(propertyStorage);
            }

            if (string.IsNullOrEmpty(config.HashKeyPropertyName))
            {
                throw new InvalidOperationException("No hash key configured on type");
            }

            return(config);
        }