/// <summary>
        /// The <see cref="ToAttributeValue(object,Type,DynamoSerializerOptions)"/> method converts an instance to a DynamoDB attribute value.
        /// </summary>
        /// <param name="value">The value to convert.</param>
        /// <param name="targetType">The source value type.</param>
        /// <param name="options">The serialization options.</param>
        /// <returns>A DynamoDB attribute value, or <c>null</c> if the instance state cannot be represented in DynamoDB.</returns>
        public override AttributeValue ToAttributeValue(object value, Type targetType, DynamoSerializerOptions options)
        {
            var mapObject = new Dictionary <string, AttributeValue>();

            foreach (var property in targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy))
            {
                var propertyAttributes = property.GetCustomAttributes();

                // check if this object property should be ignored
                if (!(propertyAttributes.OfType <DynamoPropertyIgnoreAttribute>().SingleOrDefault() is null))
                {
                    continue;
                }

                var propertyValue = property.GetValue(value);
                if (!(propertyValue is null) || !options.IgnoreNullValues)
                {
                    var attributeValue = DynamoSerializer.Serialize(propertyValue, options);
                    if (!(attributeValue is null))
                    {
                        // check if this object property has a custom name
                        var name = propertyAttributes.OfType <DynamoPropertyNameAttribute>().SingleOrDefault()?.Name ?? property.Name;
                        mapObject.Add(name, attributeValue);
                    }
                }
            }
            return(new AttributeValue {
                M = mapObject,
                IsMSet = true
            });
        }
        /// <summary>
        /// The <see cref="FromMap(Dictionary{string,AttributeValue},Type,DynamoSerializerOptions)"/> method converts a DynamoDB M attribute value to the type of the converter.
        /// </summary>
        /// <param name="value">The DynamoDB attribute value to convert.</param>
        /// <param name="targetType">The expected return type.</param>
        /// <param name="options">The deserialization options.</param>
        /// <returns>An instance of type <paramref name="targetType"/>.</returns>
        public override object?FromMap(Dictionary <string, AttributeValue> value, Type targetType, DynamoSerializerOptions options)
        {
            // create instance and set properties on it
            var result = Activator.CreateInstance(targetType) ?? throw new ApplicationException("Activator.CreateInstance() returned null");

            foreach (var property in targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy))
            {
                var propertyAttributes = property.GetCustomAttributes();

                // check if this object property should be ignored
                if (!(propertyAttributes.OfType <DynamoPropertyIgnoreAttribute>().SingleOrDefault() is null))
                {
                    continue;
                }

                // check if this object property has a custom name
                var name = propertyAttributes.OfType <DynamoPropertyNameAttribute>().SingleOrDefault()?.Name ?? property.Name;
                if (value.TryGetValue(name, out var attribute))
                {
                    property.SetValue(result, DynamoSerializer.Deserialize(attribute, property.PropertyType, options));
                }
                else
                {
                    property.SetValue(result, DynamoSerializer.Deserialize(attribute: null, property.PropertyType, options));
                }
            }
            return(result);
        }
        /// <summary>
        /// The <see cref="ToAttributeValue(object,Type,DynamoSerializerOptions)"/> method converts an instance to a DynamoDB attribute value.
        /// </summary>
        /// <param name="value">The value to convert.</param>
        /// <param name="targetType">The source value type.</param>
        /// <param name="options">The serialization options.</param>
        /// <returns>A DynamoDB attribute value, or <c>null</c> if the instance state cannot be represented in DynamoDB.</returns>
        public override AttributeValue ToAttributeValue(object value, Type targetType, DynamoSerializerOptions options)
        {
            var mapDictionary = new Dictionary <string, AttributeValue>();

            foreach (DictionaryEntry?entry in (IDictionary)value)
            {
                if (entry is null)
                {
                    continue;
                }
                var entryValue = entry?.Value;
                if (!(entryValue is null) || !options.IgnoreNullValues)
                {
                    var entryKey = entry?.Key as string;
                    if (entryKey is null)
                    {
                        throw new DynamoSerializationException("null key is not supported");
                    }
                    var attributeValue = DynamoSerializer.Serialize(entryValue, options);
                    if (attributeValue != null)
                    {
                        mapDictionary.Add(entryKey, attributeValue);
                    }
                }
            }
            return(new AttributeValue {
                M = mapDictionary,
                IsMSet = true
            });
        }
        /// <summary>
        /// The <see cref="FromMap(Dictionary{string,AttributeValue},Type,DynamoSerializerOptions)"/> method converts a DynamoDB M attribute value to the type of the converter.
        /// </summary>
        /// <param name="value">The DynamoDB attribute value to convert.</param>
        /// <param name="targetType">The expected return type.</param>
        /// <param name="options">The deserialization options.</param>
        /// <returns>An instance of type <paramref name="targetType"/>.</returns>
        public override object?FromMap(Dictionary <string, AttributeValue> value, Type targetType, DynamoSerializerOptions options)
        {
            if (targetType.IsAssignableFrom(typeof(Dictionary <string, object>)))
            {
                return(value.ToDictionary(kv => kv.Key, kv => DynamoSerializer.Deserialize(kv.Value, typeof(object), options)));
            }

            // check if item type can be determined via `IDictionary<string, T>` inheritance
            var itemType = GetDictionaryItemType(targetType);

            // determine if a concrete type needs to be identified
            Type mapType = targetType;

            if (targetType.IsInterface)
            {
                if (!(itemType is null))
                {
                    mapType = typeof(Dictionary <,>).MakeGenericType(new[] { typeof(string), itemType });
                }
                else
                {
                    mapType = typeof(Dictionary <string, object>);
                }
                if (targetType.IsAssignableFrom(mapType))
                {
                    throw new DynamoSerializationException($"incompatible target type for M attribute value (given: {targetType.FullName})");
                }
            }
        /// <summary>
        /// The <see cref="FromList(List{AttributeValue},Type,DynamoSerializerOptions)"/> method converts a DynamoDB L attribute value to the type of the converter.
        /// </summary>
        /// <param name="value">The DynamoDB attribute value to convert.</param>
        /// <param name="targetType">The expected return type.</param>
        /// <param name="options">The deserialization options.</param>
        /// <returns>An instance of type <paramref name="targetType"/>.</returns>
        public override object?FromList(List <AttributeValue> value, Type targetType, DynamoSerializerOptions options)
        {
            if (targetType.IsAssignableFrom(typeof(List <object>)))
            {
                // NOTE (2021-06-23, bjorg): this covers the case where targetype is `IList`

                // return List<object>
                return(value.Select(item => DynamoSerializer.Deserialize(item, targetType: null, options)).ToList());
            }

            // check if item type can be determined via `IList<T>` inheritance
            var itemType = GetListItemType(targetType);

            // determine if a concrete type needs to be identified
            Type listType = targetType;

            if (targetType.IsInterface)
            {
                if (itemType != null)
                {
                    // create `List<T>`
                    listType = typeof(List <>).MakeGenericType(new[] { itemType });
                }
                else
                {
                    // create `ArrayList`
                    listType = typeof(ArrayList);
                }
                if (!targetType.IsAssignableFrom(listType))
                {
                    throw new DynamoSerializationException($"incompatible target type for L attribute value (given: {targetType.FullName})");
                }
            }

            // check if we can use the `IList` interface to add items to the list instance
            if (typeof(IList).IsAssignableFrom(listType))
            {
                var result = (IList)(Activator.CreateInstance(listType) ?? throw new ApplicationException("Activator.CreateInstance() returned null"));
                foreach (var item in value)
                {
                    result.Add(DynamoSerializer.Deserialize(item, itemType, options));
                }
                return(result);
            }
            else
            {
                // use `dynamic` to invoke the appropriate typed `Add()` method
                dynamic result = Activator.CreateInstance(listType) ?? throw new ApplicationException("Activator.CreateInstance() returned null");
                foreach (var item in value)
                {
                    result.Add(DynamoSerializer.Deserialize(item, itemType, options));
                }
                return(result);
            }
        }
        /// <summary>
        /// The <see cref="ToAttributeValue(object,Type,DynamoSerializerOptions)"/> method converts an instance to a DynamoDB attribute value.
        /// </summary>
        /// <param name="value">The value to convert.</param>
        /// <param name="targetType">The source value type.</param>
        /// <param name="options">The serialization options.</param>
        /// <returns>A DynamoDB attribute value, or <c>null</c> if the instance state cannot be represented in DynamoDB.</returns>
        public override AttributeValue ToAttributeValue(object value, Type targetType, DynamoSerializerOptions options)
        {
            var list = new List <AttributeValue>();

            foreach (var item in (IEnumerable)value)
            {
                var attributeValue = DynamoSerializer.Serialize(item, options);
                list.Add(attributeValue ?? new AttributeValue {
                    NULL = true
                });
            }
            return(new AttributeValue {
                L = list,
                IsLSet = true
            });
        }
Пример #7
0
        internal Dictionary <string, AttributeValue> SerializeItem <TRecord>(TRecord record, DynamoPrimaryKey <TRecord> primaryKey)
            where TRecord : class
        {
            var attributes = DynamoSerializer.Serialize(record, SerializerOptions)?.M;

            if (attributes is null)
            {
                throw new ArgumentException("cannot serialize null record", nameof(record));
            }

            // add type details
            attributes["_t"] = new AttributeValue(Options.GetShortTypeName(typeof(TRecord)));

            // add modified details
            attributes["_m"] = new AttributeValue {
                N = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(CultureInfo.InvariantCulture)
            };

            // add primary key details
            attributes[primaryKey.PKName] = new AttributeValue(primaryKey.PKValue);
            attributes[primaryKey.SKName] = new AttributeValue(primaryKey.SKValue);
            return(attributes);
        }
Пример #8
0
 private object?DeserializeItem(Dictionary <string, AttributeValue> item, Type?type)
 => DynamoSerializer.Deserialize(item, type, SerializerOptions);
Пример #9
0
 internal TRecord?DeserializeItem <TRecord>(Dictionary <string, AttributeValue> item)
     where TRecord : class
 => DynamoSerializer.Deserialize <TRecord>(item, SerializerOptions);