Dynamo Global Secondary Index QueryResult Mapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Globalization; | |
using System.Linq; | |
using System.Reflection; | |
using Amazon.DynamoDBv2.DataModel; | |
using Amazon.DynamoDBv2.Model; | |
namespace Helpers | |
{ | |
public interface IJsonSerializer | |
{ | |
string Serialize<T>(T item); | |
object Deserialize(string value, Type type); | |
} | |
public interface IQueryResultMapper | |
{ | |
T MapEntity<T>(Dictionary<string, AttributeValue> resultItem) where T : new(); | |
} | |
public class QueryResultMapper : IQueryResultMapper | |
{ | |
private readonly IJsonSerializer _serializer; | |
public QueryResultMapper(IJsonSerializer serializer) | |
{ | |
_serializer = serializer; | |
} | |
public T MapEntity<T>(Dictionary<string, AttributeValue> resultItem) where T : new() | |
{ | |
var type = typeof(T); | |
var ret = new T(); | |
var entityProperties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); | |
foreach (var property in entityProperties) | |
{ | |
var attributeName = GetAttributeName(property); | |
var attribute = GetAttribute(resultItem, attributeName); | |
if (attribute == null) continue; | |
var propertyType = property.PropertyType; | |
switch (Type.GetTypeCode(propertyType)) | |
{ | |
case TypeCode.String: | |
property.SetValue(ret, attribute.S, null); | |
break; | |
case TypeCode.Int32: | |
var intValue = ParseInt(attribute, attributeName); | |
property.SetValue(ret, intValue, null); | |
break; | |
case TypeCode.Boolean: | |
var booleanValue = ParseBoolean(attribute); | |
property.SetValue(ret, booleanValue, null); | |
break; | |
case TypeCode.DateTime: | |
var dateTimeValue = ParseDateTime(attribute, attributeName); | |
property.SetValue(ret, dateTimeValue, null); | |
break; | |
default: | |
var attributeValue = GetNonPrimitiveTypeValue(attribute); | |
if (attributeValue != null) | |
{ | |
var serializedItem = attributeValue is string | |
? attributeValue.ToString() | |
: _serializer.Serialize(attributeValue); | |
var deserializedItem = _serializer.Deserialize(serializedItem, propertyType); | |
if (deserializedItem != null) | |
{ | |
property.SetValue(ret, deserializedItem, null); | |
} | |
} | |
break; | |
} | |
} | |
return ret; | |
} | |
private static string GetAttributeName(PropertyInfo property) | |
{ | |
var attributeName = property.Name; | |
var dynamoDbProperty = property.GetCustomAttributes(typeof (DynamoDBPropertyAttribute), true).SingleOrDefault(); | |
if (dynamoDbProperty != null) | |
{ | |
var dynamoDbPropertyValue = (DynamoDBPropertyAttribute) dynamoDbProperty; | |
if (!string.IsNullOrWhiteSpace(dynamoDbPropertyValue.AttributeName)) | |
{ | |
attributeName = dynamoDbPropertyValue.AttributeName; | |
} | |
} | |
return attributeName; | |
} | |
private static object GetNonPrimitiveTypeValue(AttributeValue value) | |
{ | |
if (!string.IsNullOrWhiteSpace(value.S)) | |
{ | |
return value.S; | |
} | |
if (!string.IsNullOrWhiteSpace(value.N)) | |
{ | |
return value.N; | |
} | |
if (value.SS != null && value.SS.Any()) | |
{ | |
return value.SS; | |
} | |
if (value.NS != null && value.NS.Any()) | |
{ | |
return value.NS; | |
} | |
return null; | |
} | |
private static AttributeValue GetAttribute(IDictionary<string, AttributeValue> item, string attributeName) | |
{ | |
if (!item.ContainsKey(attributeName)) | |
{ | |
return null; | |
} | |
AttributeValue value; | |
return !item.TryGetValue(attributeName, out value) ? null : value; | |
} | |
private static int ParseInt(AttributeValue value, string attributeName) | |
{ | |
int output; | |
if (!int.TryParse(value.N, out output)) | |
{ | |
throw new ArithmeticException(string.Format(CultureInfo.InvariantCulture, | |
"[{0}]: Value '{1}' could not be cast to an integer", attributeName, value.N)); | |
} | |
return output; | |
} | |
private static DateTime ParseDateTime(AttributeValue value, string attributeName) | |
{ | |
DateTime output; | |
if (!DateTime.TryParse(value.S, out output)) | |
{ | |
throw new ArithmeticException(string.Format(CultureInfo.InvariantCulture, | |
"[{0}]: Value '{1}' could not be cast to a DateTime", attributeName, value.S)); | |
} | |
return output; | |
} | |
private static bool ParseBoolean(AttributeValue value) | |
{ | |
return value.N.Equals("1"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment