Exemple #1
0
 protected DictionaryDdbConverterBase(DynamoDbContextMetadata metadata)
 {
     KeyConverter           = metadata.GetOrAddConverter <TKey>();
     ValueConverter         = metadata.GetOrAddConverter <TValue>();
     KeyDictionaryConverter = KeyConverter as IDictionaryKeyConverter <TKey> ??
                              throw new DdbException($"{KeyConverter.GetType().Name} must implement IDictionaryKeyConverter in order to store value as a dictionary key.");
 }
        public void Setup()
        {
            var metadata = new DynamoDbContextMetadata(Array.Empty <DdbConverter>());

            _properties = new DdbClassInfo(typeof(MediumStringFieldsEntity), metadata, new ObjectDdbConverter <MediumStringFieldsEntity>(metadata)).Properties.OfType <DdbPropertyInfo <string> >().ToArray();
            _entity     = new MediumStringFieldsEntity();
        }
        public static Document ToDocument <T>(this T entity, DynamoDbContextMetadata metadata) where T : class
        {
            var classInfo = metadata.GetOrAddClassInfo(typeof(T));

            var document = new Document(classInfo.Properties.Length);

            foreach (var property in classInfo.Properties)
            {
                property.SetDocumentValue(entity, document);
            }

            return(document);
        }
        public static T ToObject <T>(this Document document, DynamoDbContextMetadata metadata) where T : class
        {
            var classInfo = metadata.GetOrAddClassInfo(typeof(T));

            var entity = classInfo.Constructor !();

            foreach (var pair in document)
            {
                if (!classInfo.AttributesMap.TryGetValue(pair.Key, out var propertyInfo) || pair.Value.IsNull)
                {
                    continue;
                }

                propertyInfo.SetValue(entity, pair.Value);
            }

            return((T)entity);
        }
Exemple #5
0
 internal abstract DdbPropertyInfo CreateDdbPropertyInfo(PropertyInfo propertyInfo, string attributeName, DynamoDbAttributeType attributeType, DynamoDbContextMetadata dynamoDbContextMetadata);
Exemple #6
0
        public DdbEntityReadStack(int defaultStackLength, DynamoDbContextMetadata metadata) : this()
        {
            _previous = ArrayPool <DdbEntityReadStackFrame> .Shared.Rent(defaultStackLength);

            Metadata = metadata;
        }
Exemple #7
0
 public override DdbConverter CreateConverter(Type typeToConvert, DynamoDbContextMetadata metadata) => new AttributeValueDdbConverter();
Exemple #8
0
        public DdbPropertyInfo(PropertyInfo propertyInfo, string attributeName, DynamoDbAttributeType attributeType, DdbConverter <T> converter, DynamoDbContextMetadata metadata) : base(propertyInfo, attributeName, attributeType)
        {
            Converter = converter;

            Get = EmitMemberAccessor.CreatePropertyGetter <T>(propertyInfo);
            Set = propertyInfo.SetMethod != null?EmitMemberAccessor.CreatePropertySetter <T>(propertyInfo) : null;

            RuntimeClassInfo = metadata.GetOrAddClassInfo(propertyInfo.PropertyType, converter);
        }
Exemple #9
0
 public static ValueTask WriteEntityAsync(this DdbWriter writer, object entity,
                                          DynamoDbContextMetadata metadata) => WriteEntityAsync(writer, metadata.GetOrAddClassInfo(entity.GetType()), entity);
Exemple #10
0
        public DdbClassInfo(Type type, DynamoDbContextMetadata metadata, DdbConverter converter)
        {
            Type = type;

            var properties     = new Dictionary <string, DdbPropertyInfo>();
            var jsonProperties = new JsonReaderDictionary <DdbPropertyInfo>();

            ConverterBase = converter;
            ConverterType = converter.GetType();
            ClassType     = ConverterBase.ClassType;

            switch (ClassType)
            {
            case DdbClassType.Object:
            {
                for (var currentType = type; currentType != null; currentType = currentType.BaseType)
                {
                    const BindingFlags bindingFlags =
                        BindingFlags.Instance |
                        BindingFlags.Public |
                        BindingFlags.NonPublic |
                        BindingFlags.DeclaredOnly;

                    foreach (PropertyInfo propertyInfo in currentType.GetProperties(bindingFlags))
                    {
                        var attribute = propertyInfo.GetCustomAttribute <DynamoDbPropertyAttribute>();
                        if (attribute == null)
                        {
                            continue;
                        }

                        if (properties.ContainsKey(attribute.Name))
                        {
                            continue;
                        }

                        var propertyConverter = metadata.GetOrAddConverter(propertyInfo.PropertyType, attribute.DdbConverterType);

                        var ddbPropertyInfo = propertyConverter.CreateDdbPropertyInfo(propertyInfo, attribute.Name, attribute.AttributeType, metadata);
                        properties.Add(attribute.Name, ddbPropertyInfo);
                        jsonProperties.Add(attribute.Name, ddbPropertyInfo);

                        switch (attribute.AttributeType)
                        {
                        case DynamoDbAttributeType.PartitionKey:
                            if (PartitionKey != null)
                            {
                                throw new DdbException($"An entity {Type.FullName} contains multiple partition key attributes");
                            }
                            PartitionKey = ddbPropertyInfo;
                            break;

                        case DynamoDbAttributeType.SortKey:
                            if (SortKey != null)
                            {
                                throw new DdbException($"An entity {Type.FullName} contains multiple sort key attributes");
                            }
                            SortKey = ddbPropertyInfo;
                            break;
                        }

                        if (Version == null && propertyInfo.GetCustomAttribute <DynamoDbVersionAttribute>() != null)
                        {
                            Version = ddbPropertyInfo;
                        }
                    }

                    TableName ??= currentType.GetCustomAttribute <DynamoDbTableAttribute>()?.TableName;
                }
                Constructor = EmitMemberAccessor.CreateConstructor(type) ?? throw new InvalidOperationException($"Can't generate constructor delegate for type '{type}'.");

                break;
            }

            case DdbClassType.Enumerable:
            case DdbClassType.Dictionary:
            {
                ElementType      = ConverterBase.ElementType;
                ElementClassInfo = metadata.GetOrAddClassInfo(ElementType !);
                break;
            }
            }


            AttributesMap  = properties;
            PropertiesMap  = properties.Values.ToDictionary(x => x.PropertyInfo.Name);
            JsonProperties = jsonProperties;
            Properties     = properties.Values.ToArray();
        }
Exemple #11
0
        public static async ValueTask <ReadResult <TEntity> > ReadAsync <TEntity>(Stream utf8Json, DdbClassInfo classInfo, DynamoDbContextMetadata metadata, bool returnCrc, int defaultBufferSize = DefaultBufferSize, CancellationToken cancellationToken = default)
            where TEntity : class
        {
            var readerState = new JsonReaderState();

            var readStack = new DdbEntityReadStack(DdbEntityReadStack.DefaultStackLength, metadata);

            try
            {
                readStack.GetCurrent().ClassInfo ??= classInfo;

                var buffer = ArrayPool <byte> .Shared.Rent(defaultBufferSize);

                var clearMax = 0;

                try
                {
                    var  bytesInBuffer = 0;
                    uint crc           = 0;
                    var  isFirstBlock  = true;

                    while (true)
                    {
                        var isFinalBlock = false;

                        while (true)
                        {
                            var bytesRead = await utf8Json.ReadAsync(new Memory <byte>(buffer, bytesInBuffer, buffer.Length - bytesInBuffer), cancellationToken).ConfigureAwait(false);

                            if (bytesRead == 0)
                            {
                                isFinalBlock = true;
                                break;
                            }

                            if (returnCrc)
                            {
                                crc = Crc32Algorithm.Append(crc, buffer, bytesInBuffer, bytesRead);
                            }

                            bytesInBuffer += bytesRead;

                            if (bytesInBuffer == buffer.Length)
                            {
                                break;
                            }
                        }

                        if (bytesInBuffer > clearMax)
                        {
                            clearMax = bytesInBuffer;
                        }

                        readStack.UseFastPath  = isFirstBlock && isFinalBlock;
                        readStack.Buffer       = buffer;
                        readStack.BufferStart  = 0;
                        readStack.BufferLength = bytesInBuffer;
                        ReadCore <TEntity>(ref readerState, isFinalBlock, new ReadOnlySpan <byte>(buffer, 0, bytesInBuffer), ref readStack);

                        var bytesConsumed = (int)readStack.BytesConsumed;
                        bytesInBuffer -= bytesConsumed;

                        if (isFinalBlock)
                        {
                            break;
                        }

                        // Check if we need to shift or expand the buffer because there wasn't enough data to complete deserialization.
                        if ((uint)bytesInBuffer > ((uint)buffer.Length / 2))
                        {
                            // We have less than half the buffer available, double the buffer size.
                            byte[] dest = ArrayPool <byte> .Shared.Rent((buffer.Length < (int.MaxValue / 2))?buffer.Length * 2 : int.MaxValue);

                            // Copy the unprocessed data to the new buffer while shifting the processed bytes.
                            Buffer.BlockCopy(buffer, bytesConsumed, dest, 0, bytesInBuffer);

                            new Span <byte>(buffer, 0, clearMax).Clear();
                            ArrayPool <byte> .Shared.Return(buffer);

                            clearMax = bytesInBuffer;
                            buffer   = dest;
                        }
                        else if (bytesInBuffer != 0)
                        {
                            // Shift the processed bytes to the beginning of buffer to make more room.
                            Buffer.BlockCopy(buffer, bytesConsumed, buffer, 0, bytesInBuffer);
                        }

                        isFirstBlock = false;
                    }

                    return(new ReadResult <TEntity>((TEntity)readStack.GetCurrent().ReturnValue !, crc));
                }
                finally
                {
                    new Span <byte>(buffer, 0, clearMax).Clear();
                    ArrayPool <byte> .Shared.Return(buffer);
                }
            }
            finally
            {
                readStack.Dispose();
            }
        }
Exemple #12
0
 public NumberSetDdbConverter(DynamoDbContextMetadata metadata) : base(metadata)
 {
 }
 public JsonBatchGetItemUnprocessedKeysConverter(DynamoDbContextMetadata metadata) : base(metadata)
 {
     ValueConverter = (DdbConverter <TableBatchGetItemRequest>)metadata.GetOrAddConverter(typeof(TableBatchGetItemRequest),
                                                                                          typeof(JsonObjectDdbConverter <TableBatchGetItemRequest>));
 }
 public JsonIReadOnlyDictionaryDdbConverter(DynamoDbContextMetadata metadata)
 {
     _keyConverter  = metadata.GetOrAddConverter <TKey>();
     ValueConverter = metadata.GetOrAddConverter <TValue>();
 }
        public JsonBatchGetItemResponsesConverter(DynamoDbContextMetadata metadata) : base(metadata)
        {
            var entityType = typeof(TValue).GenericTypeArguments[0];

            ValueConverter = (DdbConverter <TValue>)metadata.GetOrAddConverter(typeof(TValue), typeof(JsonListDdbConverter <>).MakeGenericType(entityType));
        }
        internal sealed override DdbPropertyInfo CreateDdbPropertyInfo(PropertyInfo propertyInfo, string attributeName, DynamoDbAttributeType attributeType, DynamoDbContextMetadata dynamoDbContextMetadata)
        {
            Debug.Fail("We should never get here.");

            throw new InvalidOperationException();
        }
 public abstract DdbConverter CreateConverter(Type typeToConvert, DynamoDbContextMetadata metadata);
 public ObjectDdbConverter(DynamoDbContextMetadata metadata)
 {
     _metadata = metadata;
 }
Exemple #19
0
 public SdkEnumHashSetConverter(DynamoDbContextMetadata metadata) : base(metadata.GetOrAddConverter <TEnum>())
 {
 }
 public DdbExpressionVisitor(DynamoDbContextMetadata metadata)
 {
     _metadata = metadata;
 }
Exemple #21
0
 public DictionaryDdbConverter(DynamoDbContextMetadata metadata) : base(metadata)
 {
 }
Exemple #22
0
        public static async ValueTask ProcessErrorAsync(DynamoDbContextMetadata metadata, HttpResponseMessage response, CancellationToken cancellationToken = default)
        {
            try
            {
                await using var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);

                if (response.StatusCode == HttpStatusCode.ServiceUnavailable)
                {
                    throw new ServiceUnavailableException("DynamoDB is currently unavailable. (This should be a temporary state.)");
                }

                var recyclableStream = DynamoDbHttpContent.MemoryStreamManager.GetStream();

                try
                {
                    await responseStream.CopyToAsync(recyclableStream, cancellationToken).ConfigureAwait(false);

                    recyclableStream.Position = 0;
                    var error = await JsonSerializer.DeserializeAsync <Error>(recyclableStream, SerializerOptions, cancellationToken).ConfigureAwait(false);

                    recyclableStream.Position = 0;

                    switch (response.StatusCode)
                    {
                    case HttpStatusCode.BadRequest:
                        var type           = error.Type;
                        var exceptionStart = error.Type?.LastIndexOf('#') ?? -1;
                        if (exceptionStart != -1)
                        {
                            type = error.Type !.Substring(exceptionStart + 1);
                        }

                        if (type == "TransactionCanceledException")
                        {
                            var classInfo = metadata.GetOrAddClassInfo(typeof(TransactionCancelledResponse), typeof(JsonObjectDdbConverter <TransactionCancelledResponse>));
                            var transactionCancelledResponse = await EntityDdbJsonReader
                                                               .ReadAsync <TransactionCancelledResponse>(recyclableStream, classInfo, metadata, false, cancellationToken : cancellationToken)
                                                               .ConfigureAwait(false);

                            throw new TransactionCanceledException(transactionCancelledResponse.Value !.CancellationReasons, error.Message);
                        }

                        throw type switch
                              {
                                  "AccessDeniedException" => new AccessDeniedException(error.Message),
                                  "ConditionalCheckFailedException" => new ConditionalCheckFailedException(error.Message),
                                  "IncompleteSignatureException" => new IncompleteSignatureException(error.Message),
                                  "ItemCollectionSizeLimitExceededException" => new ItemCollectionSizeLimitExceededException(error.Message),
                                  "LimitExceededException" => new LimitExceededException(error.Message),
                                  "MissingAuthenticationTokenException" => new MissingAuthenticationTokenException(error.Message),
                                  "ProvisionedThroughputExceededException" => new ProvisionedThroughputExceededException(error.Message),
                                  "RequestLimitExceeded" => new RequestLimitExceededException(error.Message),
                                  "ResourceInUseException" => new ResourceInUseException(error.Message),
                                  "ResourceNotFoundException" => new ResourceNotFoundException(error.Message),
                                  "ThrottlingException" => new ThrottlingException(error.Message),
                                  "UnrecognizedClientException" => new UnrecognizedClientException(error.Message),
                                  "ValidationException" => new ValidationException(error.Message),
                                  "IdempotentParameterMismatchException" => new IdempotentParameterMismatchException(error.Message),
                                  "TransactionInProgressException" => new TransactionInProgressException(error.Message),
                                  _ => new DdbException(error.Message ?? type ?? string.Empty)
                              };

                    case HttpStatusCode.InternalServerError:
                        throw new InternalServerErrorException(error.Message);

                    default:
                        throw new DdbException(error.Message);
                    }
                }
                finally
                {
                    await recyclableStream.DisposeAsync().ConfigureAwait(false);
                }
            }
            finally
            {
                response.Dispose();
            }
        }
        private static DdbConverter <TValue> CreateValueConverter(DynamoDbContextMetadata metadata)
        {
            var transactResponseType = typeof(TValue);

            return((DdbConverter <TValue>)metadata.GetOrAddConverter(transactResponseType, typeof(JsonObjectDdbConverter <>).MakeGenericType(transactResponseType)));
        }
Exemple #24
0
 public StringSetDdbConverter(DynamoDbContextMetadata metadata) : base(metadata)
 {
     _isString = typeof(T) == typeof(string);
 }
Exemple #25
0
 protected SetDdbConverter(DynamoDbContextMetadata metadata)
 {
     ElementConverter         = metadata.GetOrAddConverter <TElement>();
     ElementSetValueConverter = ElementConverter as ISetValueConverter <TElement> ??
                                throw new DdbException($"{ElementConverter.GetType().Name} must implement ISetValueConverter in order to store value as a part of dynamodb set.");
 }
 public override DdbConverter CreateConverter(Type typeToConvert, DynamoDbContextMetadata metadata) => new DocumentDdbConverter();
 public override DdbConverter CreateConverter(Type typeToConvert, DynamoDbContextMetadata metadata)
 {
     return(new BinaryDdbConverter());
 }
 public StringSetDdbConverter(DynamoDbContextMetadata metadata) : base(metadata)
 {
 }
 public TransactGetItemsResponsesConverter(DynamoDbContextMetadata metadata) : base(CreateValueConverter(metadata))
 {
 }