Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 29 additions & 13 deletions Amazon.DynamoDB/DataModel/EntityUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,32 +74,48 @@ public static void ValidateVersionType(Type memberType)

public static DynamoDBTableAttribute GetTableAttribute(Type type)
{
DynamoDBTableAttribute tableAttribute = GetAttribute(type) as DynamoDBTableAttribute;
DynamoDBTableAttribute tableAttribute = null;
int count =0;

foreach (var attribute in GetAttributes(type))
{
if (!(attribute is DynamoDBTableAttribute))
continue;

count++;
if(count > 1)
throw new Exception("There can only be one TableAttribute per table.");

tableAttribute = attribute as DynamoDBTableAttribute;
}

if (tableAttribute == null)
return null;
return tableAttribute;
}

public static DynamoDBAttribute GetAttribute(Type targetType)
public static DynamoDBAttribute[] GetAttributes(Type targetType)
{
if (targetType == null) throw new ArgumentNullException("targetType");
object[] attributes = targetType.GetCustomAttributes(typeof(DynamoDBAttribute), true);
return GetSingleDDBAttribute(attributes);
var attributes = targetType.GetCustomAttributes(typeof(DynamoDBAttribute), true);
return GetAttributes(attributes);
}
public static DynamoDBAttribute GetAttribute(MemberInfo targetMemberInfo)

public static DynamoDBAttribute[] GetAttributes(MemberInfo targetMemberInfo)
{
if (targetMemberInfo == null) throw new ArgumentNullException("targetMemberInfo");
object[] attributes = targetMemberInfo.GetCustomAttributes(typeof(DynamoDBAttribute), true);
return GetSingleDDBAttribute(attributes);
var attributes = targetMemberInfo.GetCustomAttributes(typeof(DynamoDBAttribute), true);
return GetAttributes(attributes);
}

public static DynamoDBAttribute GetSingleDDBAttribute(object[] attributes)
private static DynamoDBAttribute[] GetAttributes(object[] attributes)
{
if (attributes.Length == 0)
return null;
if (attributes.Length == 1)
return (attributes[0] as DynamoDBAttribute);
throw new InvalidOperationException("Cannot have multiple DynamoDBAttributes on a single member");
var result = new DynamoDBAttribute[attributes.Length];

for (int x = 0; x < attributes.Length; x++ )
result[x] = attributes[x] as DynamoDBAttribute;

return result;
}

#endregion
Expand Down
102 changes: 67 additions & 35 deletions Amazon.DynamoDB/DataModel/InternalModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ internal static ItemStorageConfig CreateStorageConfig(Type type)

ItemStorageConfig config = new ItemStorageConfig();

DynamoDBTableAttribute tableAttribute = EntityUtils.GetTableAttribute(type);
var 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");
Expand All @@ -174,22 +174,52 @@ internal static ItemStorageConfig CreateStorageConfig(Type type)
// 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;
var attributes = EntityUtils.GetAttributes(member);

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

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

bool ignoreAttiribute = false;
DynamoDBPropertyAttribute propertyAttribute = null;
DynamoDBHashKeyAttribute hashKeyAttribute = null;
DynamoDBRangeKeyAttribute rangeKeyAttribute = null;
DynamoDBVersionAttribute versionAttribute = null;

foreach (var attribute in attributes)
{
Member = member,
MemberType = memberType,
};
// filter out ignored properties
if (attribute is DynamoDBIgnoreAttribute)
{
ignoreAttiribute = true;
continue;
}

if (attribute is DynamoDBVersionAttribute)
versionAttribute = attribute as DynamoDBVersionAttribute;

if (attribute is DynamoDBPropertyAttribute)
propertyAttribute = attribute as DynamoDBPropertyAttribute;

if (attribute is DynamoDBVersionAttribute)
if (attribute is DynamoDBHashKeyAttribute)
hashKeyAttribute = attribute as DynamoDBHashKeyAttribute;

if (attribute is DynamoDBRangeKeyAttribute)
rangeKeyAttribute = attribute as DynamoDBRangeKeyAttribute;
}

if (ignoreAttiribute)
continue;

//TODO: test for valid attribute combinations

if (versionAttribute != null)
{
EntityUtils.ValidateVersionType(memberType); // no conversion is possible, so type must be a nullable primitive

Expand All @@ -200,46 +230,48 @@ internal static ItemStorageConfig CreateStorageConfig(Type type)
propertyStorage.IsVersion = true;
}

DynamoDBPropertyAttribute propertyAttribute = attribute as DynamoDBPropertyAttribute;
if (propertyAttribute != null)
if (hashKeyAttribute != null)
{
if (!string.IsNullOrEmpty(propertyAttribute.AttributeName))
attributeName = GetAccurateCase(config, propertyAttribute.AttributeName);
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");

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

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");
if (rangeKeyAttribute != null)
{
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;
}
config.RangeKeyPropertyName = propertyName;
propertyStorage.IsRangeKey = true;
}

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

if (propertyAttribute.Converter != null)
{
if (!EntityUtils.CanInstantiate(propertyAttribute.Converter) || !EntityUtils.ImplementsInterface(propertyAttribute.Converter, typeof(IPropertyConverter)))
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.Converter =
EntityUtils.Instantiate(propertyAttribute.Converter) as IPropertyConverter;
}
}

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

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