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