private static DynamoMetadataType ToMetadataType(Type type)
        {
            var alias = type.FirstAttribute <AliasAttribute>();
            var props = GetTableProperties(type);

            var metadata = new DynamoMetadataType
            {
                Type = type,
                Name = alias != null ? alias.Name : type.Name,
            };

            metadata.Fields = props.Map(p =>
                                        new DynamoMetadataField
            {
                Parent          = metadata,
                Type            = p.PropertyType,
                Name            = Converters.GetFieldName(p),
                DbType          = Converters.GetFieldType(p.PropertyType),
                IsAutoIncrement = p.HasAttribute <AutoIncrementAttribute>(),
                SetValueFn      = p.CreateSetter(),
                GetValueFn      = p.CreateGetter(),
            }).ToArray();

            return(metadata);
        }
        private List <T> ConvertBatchGetItemResponse <T>(DynamoMetadataType table, KeysAndAttributes getItems)
        {
            var to = new List <T>();

            var request = new BatchGetItemRequest(new Dictionary <string, KeysAndAttributes> {
                { table.Name, getItems }
            });

            var response = Exec(() => DynamoDb.BatchGetItem(request));

            if (response.Responses.TryGetValue(table.Name, out var results))
            {
                results.Each(x => to.Add(Converters.FromAttributeValues <T>(table, x)));
            }

            var i = 0;

            while (response.UnprocessedKeys.Count > 0)
            {
                response = Exec(() => DynamoDb.BatchGetItem(new BatchGetItemRequest(response.UnprocessedKeys)));
                if (response.Responses.TryGetValue(table.Name, out results))
                {
                    results.Each(x => to.Add(Converters.FromAttributeValues <T>(table, x)));
                }

                if (response.UnprocessedKeys.Count > 0)
                {
                    i.SleepBackOffMultiplier();
                }
            }

            return(to);
        }
        private static DynamoLocalIndex CreateLocalIndex(Type type, DynamoMetadataType metadata, string hashField, Type indexType)
        {
            var indexProps = indexType.GetPublicProperties();
            var indexProp  = indexProps.FirstOrDefault(x =>
                                                       x.HasAttribute <IndexAttribute>() || x.HasAttribute <DynamoDBRangeKeyAttribute>());

            if (indexProp == null)
            {
                throw new ArgumentException($"Missing [Index]. Could not infer Range Key in index '{indexType}'.");
            }

            var indexAlias = indexType.FirstAttribute <AliasAttribute>();
            var rangeKey   = metadata.GetField(indexProp.Name);

            if (rangeKey == null)
            {
                throw new ArgumentException($"Range Key '{indexProp.Name}' was not found on Table '{type.Name}'");
            }

            var indexProjection = indexType.FirstAttribute <ProjectionTypeAttribute>();
            var projectionType  = indexProjection?.ProjectionType ?? DynamoProjectionType.Include;

            return(new DynamoLocalIndex
            {
                IndexType = indexType,
                Name = indexAlias != null ? indexAlias.Name : indexType.Name,
                HashKey = metadata.HashKey,
                RangeKey = rangeKey,
                ProjectionType = projectionType,
                ProjectedFields = projectionType == DynamoProjectionType.Include
                    ? indexProps.Where(x => x.Name != hashField).Select(x => x.Name).ToArray()
                    : new string[0],
            });
        }
        private void PopulateMissingHashes <T>(DynamoMetadataType table, List <T> items)
        {
            var autoIncr = table.Fields.FirstOrDefault(x => x.IsAutoIncrement);

            if (autoIncr != null)
            {
                var seqRequiredPos = new List <int>();
                for (int i = 0; i < items.Count; i++)
                {
                    var item  = items[i];
                    var value = autoIncr.GetValue(item);
                    if (DynamoConverters.IsNumberDefault(value))
                    {
                        seqRequiredPos.Add(i);
                    }
                }
                if (seqRequiredPos.Count == 0)
                {
                    return;
                }

                var nextSequences = Sequences.GetNextSequences(table, seqRequiredPos.Count);
                for (int i = 0; i < nextSequences.Length; i++)
                {
                    var pos = seqRequiredPos[i];
                    autoIncr.SetValue(items[pos], nextSequences[i]);
                }
            }
        }
Beispiel #5
0
 public DynamoDbQueryDataSource(QueryDataContext context, IPocoDynamo dynamo, bool allowScans = true)
     : base(context)
 {
     this.db         = dynamo;
     this.modelDef   = db.GetTableMetadata <T>();
     isGlobalIndex   = typeof(T).IsGlobalIndex();
     this.allowScans = allowScans;
 }
        private T ConvertGetItemResponse <T>(GetItemRequest request, DynamoMetadataType table)
        {
            var response = Exec(() => DynamoDb.GetItem(request), rethrowExceptions: throwNotFoundExceptions);

            if (!response.IsItemSet)
            {
                return(default(T));
            }
            var attributeValues = response.Item;

            return(Converters.FromAttributeValues <T>(table, attributeValues));
        }
Beispiel #7
0
        private static object ApplyFieldBehavior(IPocoDynamo db, DynamoMetadataType type, DynamoMetadataField field, object instance, object value)
        {
            if (type == null || field == null || !field.IsAutoIncrement)
            {
                return(value);
            }

            var needsId = IsNumberDefault(value);

            if (!needsId)
            {
                return(value);
            }

            var nextId = db.Sequences.Increment(type.Name);

            return(field.SetValue(instance, nextId));
        }
        private Task CreateTableAsync(DynamoMetadataType table)
        {
            var request = ToCreateTableRequest(table);

            try
            {
                return(ExecAsync(() => DynamoDb.CreateTableAsync(request)));
            }
            catch (AmazonDynamoDBException ex)
            {
                if (ex.ErrorCode == DynamoErrors.AlreadyExists)
                {
                    return(PclExportClient.EmptyTask);
                }

                throw;
            }
        }
        private static DynamoGlobalIndex CreateGlobalIndex(Type type, DynamoMetadataType metadata, Type indexType)
        {
            var indexProps = indexType.GetPublicProperties();

            Converters.GetHashAndRangeKeyFields(indexType, indexProps, out var indexHash, out var indexRange);

            var hashKey = metadata.GetField(indexHash.Name);

            if (hashKey == null)
            {
                throw new ArgumentException($"Hash Key '{indexHash.Name}' was not found on Table '{type.Name}'");
            }

            if (indexRange == null)
            {
                indexRange = indexProps.FirstOrDefault(x => x.HasAttribute <IndexAttribute>());
            }

            var rangeKey = indexRange != null
                ? metadata.GetField(indexRange.Name)
                : null;

            var indexAlias = indexType.FirstAttribute <AliasAttribute>();

            var indexProvision = indexType.FirstAttribute <ProvisionedThroughputAttribute>();

            var indexProjection = indexType.FirstAttribute <ProjectionTypeAttribute>();
            var projectionType  = indexProjection?.ProjectionType ?? DynamoProjectionType.Include;

            return(new DynamoGlobalIndex
            {
                IndexType = indexType,
                Name = indexAlias != null ? indexAlias.Name : indexType.Name,
                HashKey = hashKey,
                RangeKey = rangeKey,
                ProjectionType = projectionType,
                ProjectedFields = projectionType == DynamoProjectionType.Include
                    ? indexProps.Where(x => x.Name != indexHash.Name).Select(x => x.Name).ToArray()
                    : new string[0],
                ReadCapacityUnits = indexProvision?.ReadCapacityUnits ?? metadata.ReadCapacityUnits,
                WriteCapacityUnits = indexProvision?.WriteCapacityUnits ?? metadata.WriteCapacityUnits,
            });
        }
        private void ExecBatchWriteItemResponse <T>(DynamoMetadataType table, List <WriteRequest> deleteItems)
        {
            var request = new BatchWriteItemRequest(new Dictionary <string, List <WriteRequest> >
            {
                { table.Name, deleteItems }
            });

            var response = Exec(() => DynamoDb.BatchWriteItem(request));

            var i = 0;

            while (response.UnprocessedItems.Count > 0)
            {
                response = Exec(() => DynamoDb.BatchWriteItem(new BatchWriteItemRequest(response.UnprocessedItems)));

                if (response.UnprocessedItems.Count > 0)
                {
                    i.SleepBackOffMultiplier();
                }
            }
        }
        private void CreateTable(DynamoMetadataType table)
        {
            var request = ToCreateTableRequest(table);

            Exec(() =>
            {
                try
                {
                    DynamoDb.CreateTable(request);
                }
                catch (AmazonDynamoDBException ex)
                {
                    if (ex.ErrorCode == DynamoErrors.AlreadyExists ||
                        ex.Message == "Cannot create preexisting table")
                    {
                        return;
                    }

                    throw;
                }
            });
        }
Beispiel #12
0
 public static T ConvertTo <T>(this DynamoMetadataType table,
                               Dictionary <string, AttributeValue> attributeValues)
 {
     return(DynamoMetadata.Converters.FromAttributeValues <T>(table, attributeValues));
 }
Beispiel #13
0
 public virtual Dictionary <string, AttributeValue> ToAttributeKeyValue(IPocoDynamo db, DynamoMetadataType table, DynamoId id)
 {
     using (AwsClientUtils.GetJsScope())
     {
         return(new Dictionary <string, AttributeValue> {
             { table.HashKey.Name, ToAttributeValue(db, table.HashKey.Type, table.HashKey.DbType, id.Hash) },
             { table.RangeKey.Name, ToAttributeValue(db, table.RangeKey.Type, table.RangeKey.DbType, id.Range) },
         });
     }
 }
        private static DynamoMetadataType ToMetadataTable(Type type)
        {
            var alias = type.FirstAttribute <AliasAttribute>();
            var props = GetTableProperties(type);

            Converters.GetHashAndRangeKeyFields(type, props, out var hash, out var range);

            var provision = type.FirstAttribute <ProvisionedThroughputAttribute>();

            // If its a generic type, the type name will contain illegal characters (not accepted as DynamoDB table name)
            // so, remove the Tilde and make the type name unique to the runtime type of the generic
            string genericTypeNameAlias = null;

            if (type.IsGenericType)
            {
                var indexOfTilde = type.Name.IndexOf("`", StringComparison.Ordinal);
                indexOfTilde         = indexOfTilde < 1 ? type.Name.Length - 1 : indexOfTilde;
                genericTypeNameAlias = type.Name.Substring(0, indexOfTilde) + type.GetGenericArguments().Select(t => t.Name).Join();
            }

            var metadata = new DynamoMetadataType
            {
                Type               = type,
                IsTable            = true,
                Name               = alias != null ? alias.Name : genericTypeNameAlias ?? type.Name,
                ReadCapacityUnits  = provision?.ReadCapacityUnits,
                WriteCapacityUnits = provision?.WriteCapacityUnits,
            };

            metadata.Fields = props.Map(p =>
                                        new DynamoMetadataField
            {
                Parent           = metadata,
                Type             = p.PropertyType,
                Name             = Converters.GetFieldName(p),
                DbType           = Converters.GetFieldType(p.PropertyType),
                IsHashKey        = p == hash,
                IsRangeKey       = p == range,
                ExcludeNullValue = p.HasAttribute <IndexAttribute>() || p.HasAttribute <ExcludeNullValueAttribute>(),
                IsAutoIncrement  = p.HasAttribute <AutoIncrementAttribute>(),
                SetValueFn       = p.CreateSetter(),
                GetValueFn       = p.CreateGetter(),
            }).ToArray();

            metadata.HashKey  = metadata.Fields.FirstOrDefault(x => x.IsHashKey);
            metadata.RangeKey = metadata.Fields.FirstOrDefault(x => x.IsRangeKey);

            if (metadata.HashKey == null)
            {
                throw new ArgumentException($"Could not infer Hash Key in Table '{type.Name}'");
            }

            var    hashField = metadata.HashKey.Name;
            string indexName = null;

            metadata.LocalIndexes = props.Where(x => x.HasAttribute <IndexAttribute>()).Map(x =>
            {
                var indexProjection = x.FirstAttribute <ProjectionTypeAttribute>();
                var projectionType  = indexProjection?.ProjectionType ?? DynamoProjectionType.Include;
                indexName           = metadata.Name.ToIndexName(IndexType.Local, x.Name, metadata.HashKey.Name);
                return(new DynamoLocalIndex
                {
                    Name = indexName,
                    HashKey = metadata.HashKey,
                    RangeKey = metadata.GetField(x.Name),
                    ProjectionType = DynamoProjectionType.All,
                    ProjectedFields = new string[] { "" }
                });
            });

            metadata.GlobalIndexes = props.Where(x => x.HasAttribute <GlobalSecondaryIndexHashKeyAttribute>()).Map(x =>
            {
                var indexProjection = x.FirstAttribute <ProjectionTypeAttribute>();
                var globalSecondaryIndexHashKeyAttribute = x.GetCustomAttribute <GlobalSecondaryIndexHashKeyAttribute>();
                var rangeKey     = globalSecondaryIndexHashKeyAttribute.RangeKey;
                bool hasRangeKey = !string.IsNullOrEmpty(rangeKey);
                //string indexName = (hasRangeKey) ? $"{metadata.Name}-GSI-{x.Name}-{rangeKey}-Index" : $"{metadata.Name}-GSI-{x.Name}-Index";
                indexName       = metadata.Name.ToIndexName(IndexType.Global, x.Name, null, rangeKey);
                var dynamoIndex = new DynamoGlobalIndex
                {
                    Name            = indexName,
                    HashKey         = metadata.GetField(x.Name),
                    RangeKey        = metadata.GetField(rangeKey),
                    ProjectionType  = DynamoProjectionType.All,
                    ProjectedFields = new string[] { "" }
                };
                if (hasRangeKey)
                {
                    dynamoIndex.RangeKey = metadata.GetField(rangeKey);
                }
                return(dynamoIndex);
            });

            var references = type.AllAttributes <ReferencesAttribute>();

            foreach (var attr in references)
            {
                var localIndex = attr.Type.GetTypeWithGenericInterfaceOf(typeof(ILocalIndex <>));
                if (localIndex != null)
                {
                    metadata.LocalIndexes.Add(CreateLocalIndex(type, metadata, hashField, attr.Type));
                }

                var globalIndex = attr.Type.GetTypeWithGenericInterfaceOf(typeof(IGlobalIndex <>));
                if (globalIndex != null)
                {
                    metadata.GlobalIndexes.Add(CreateGlobalIndex(type, metadata, attr.Type));
                }
            }

            return(metadata);
        }
Beispiel #15
0
        public virtual Dictionary <string, AttributeValue> ToAttributeKeyValue(IPocoDynamo db, DynamoMetadataType table, object hash, object range)
        {
            using (AwsClientUtils.GetJsScope())
            {
                var to = new Dictionary <string, AttributeValue> {
                    { table.HashKey.Name, ToAttributeValue(db, table.HashKey.Type, table.HashKey.DbType, hash) },
                };

                if (range != null)
                {
                    to[table.RangeKey.Name] = ToAttributeValue(db, table.RangeKey.Type, table.RangeKey.DbType, range);
                }

                return(to);
            }
        }
Beispiel #16
0
        public virtual Dictionary <string, AttributeValue> ToAttributeKey(IPocoDynamo db, DynamoMetadataType table, object instance)
        {
            using (AwsClientUtils.GetJsScope())
            {
                var field = table.HashKey;
                var to    = new Dictionary <string, AttributeValue> {
                    { field.Name, ToAttributeValue(db, field.Type, field.DbType, field.GetValue(instance)) },
                };

                if (table.RangeKey != null)
                {
                    field          = table.RangeKey;
                    to[field.Name] = ToAttributeValue(db, field.Type, field.DbType, field.GetValue(instance));
                }

                return(to);
            }
        }
Beispiel #17
0
        public virtual Dictionary <string, AttributeValue> ToAttributeValues(IPocoDynamo db, object instance, DynamoMetadataType table)
        {
            var ret = ToAttributeValuesFn?.Invoke(instance, table);

            if (ret != null)
            {
                return(ret);
            }

            using (AwsClientUtils.GetJsScope())
            {
                var to = new Dictionary <string, AttributeValue>();

                foreach (var field in table.Fields)
                {
                    var value = field.GetValue(instance);

                    value = ApplyFieldBehavior(db, table, field, instance, value);

                    if (value == null)
                    {
                        if (DynamoConfig.ExcludeNullValues || field.ExcludeNullValue)
                        {
                            continue;
                        }
                    }

                    to[field.Name] = ToAttributeValue(db, field.Type, field.DbType, value);
                }

                return(to);
            }
        }
Beispiel #18
0
        public virtual Dictionary <string, AttributeValueUpdate> ToNonDefaultAttributeValueUpdates(IPocoDynamo db, object instance, DynamoMetadataType table)
        {
            using (AwsClientUtils.GetJsScope())
            {
                var to = new Dictionary <string, AttributeValueUpdate>();
                foreach (var field in table.Fields)
                {
                    if (field.IsHashKey || field.IsRangeKey)
                    {
                        continue;
                    }

                    var value = field.GetValue(instance);

                    if (value == null)
                    {
                        continue;
                    }

                    to[field.Name] = new AttributeValueUpdate(ToAttributeValue(db, field.Type, field.DbType, value), DynamoAttributeAction.Put);
                }
                return(to);
            }
        }
Beispiel #19
0
 public static bool CreateTableIfMissing(this IPocoDynamo db, DynamoMetadataType table)
 {
     return(db.CreateMissingTables(new[] { table }));
 }
        protected virtual CreateTableRequest ToCreateTableRequest(DynamoMetadataType table)
        {
            var props = table.Type.GetSerializableProperties();

            if (props.Length == 0)
            {
                throw new NotSupportedException($"{table.Name} does not have any serializable properties");
            }

            var keySchema = new List <KeySchemaElement> {
                new KeySchemaElement(table.HashKey.Name, KeyType.HASH),
            };
            var attrDefinitions = new List <AttributeDefinition> {
                new AttributeDefinition(table.HashKey.Name, table.HashKey.DbType),
            };

            if (table.RangeKey != null)
            {
                keySchema.Add(new KeySchemaElement(table.RangeKey.Name, KeyType.RANGE));
                attrDefinitions.Add(new AttributeDefinition(table.RangeKey.Name, table.RangeKey.DbType));
            }

            var to = new CreateTableRequest
            {
                TableName             = table.Name,
                KeySchema             = keySchema,
                AttributeDefinitions  = attrDefinitions,
                ProvisionedThroughput = new ProvisionedThroughput
                {
                    ReadCapacityUnits  = table.ReadCapacityUnits ?? ReadCapacityUnits,
                    WriteCapacityUnits = table.WriteCapacityUnits ?? WriteCapacityUnits,
                }
            };

            if (!table.LocalIndexes.IsEmpty())
            {
                to.LocalSecondaryIndexes = table.LocalIndexes.Map(x => new LocalSecondaryIndex
                {
                    IndexName  = x.Name,
                    KeySchema  = x.ToKeySchemas(),
                    Projection = new Projection
                    {
                        ProjectionType   = ProjectionType.ALL,
                        NonKeyAttributes = new List <string>()
                    },
                });

                table.LocalIndexes.Each(x =>
                {
                    if (x.RangeKey != null && attrDefinitions.All(a => a.AttributeName != x.RangeKey.Name))
                    {
                        attrDefinitions.Add(new AttributeDefinition(x.RangeKey.Name, x.RangeKey.DbType));
                    }
                });
            }
            if (!table.GlobalIndexes.IsEmpty())
            {
                to.GlobalSecondaryIndexes = table.GlobalIndexes.Map(x => new GlobalSecondaryIndex
                {
                    IndexName  = x.Name,
                    KeySchema  = x.ToKeySchemas(),
                    Projection = new Projection
                    {
                        ProjectionType   = ProjectionType.ALL,
                        NonKeyAttributes = new List <string>(),
                    },
                    ProvisionedThroughput = new ProvisionedThroughput
                    {
                        ReadCapacityUnits  = x.ReadCapacityUnits ?? ReadCapacityUnits,
                        WriteCapacityUnits = x.WriteCapacityUnits ?? WriteCapacityUnits,
                    }
                });

                table.GlobalIndexes.Each(x =>
                {
                    if (x.HashKey != null && attrDefinitions.All(a => a.AttributeName != x.HashKey.Name))
                    {
                        attrDefinitions.Add(new AttributeDefinition(x.HashKey.Name, x.HashKey.DbType));
                    }
                    if (x.RangeKey != null && attrDefinitions.All(a => a.AttributeName != x.RangeKey.Name))
                    {
                        attrDefinitions.Add(new AttributeDefinition(x.RangeKey.Name, x.RangeKey.DbType));
                    }
                });
            }


            return(to);
        }