Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Dynamo Global Secondary Index QueryResult Mapper
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