/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.Collections.Generic;
using Amazon.DynamoDBv2.DocumentModel;
using Amazon.DynamoDBv2.Model;
using System.Globalization;
using Amazon.Util;
namespace Amazon.DynamoDBv2.DataModel
{
///
/// Interface for converting arbitrary objects to DynamoDB-supported
/// object types.
///
/// Implementing type must be public, instantiable, and should have
/// a zero-parameter constructor.
///
public interface IPropertyConverter
{
///
/// Convert object to DynamoDBEntry
///
/// Object to be deserialized
/// Object deserialized as DynamoDBEntry
DynamoDBEntry ToEntry(object value);
///
/// Convert DynamoDBEntry to the specified object
///
/// DynamoDBEntry to be serialized
/// Serialized object
object FromEntry(DynamoDBEntry entry);
}
///
/// Configuration object for setting options on the DynamoDBContext.
/// and individual operations.
///
public class DynamoDBContextConfig
{
///
/// Default constructor
///
public DynamoDBContextConfig()
{
TableNamePrefix = AWSConfigsDynamoDB.Context.TableNamePrefix;
Conversion = DynamoDBEntryConversion.CurrentConversion;
}
///
/// Property that directs DynamoDBContext to use consistent reads.
/// If property is not set, behavior defaults to non-consistent reads.
///
public bool? ConsistentRead { get; set; }
///
/// Property that directs DynamoDBContext to skip version checks
/// when saving or deleting an object with a version attribute.
/// If property is not set, version checks are performed.
///
public bool? SkipVersionCheck { get; set; }
///
/// Property that directs DynamoDBContext to prefix all table names
/// with a specific string.
/// If property is null or empty, no prefix is used and default
/// table names are used.
///
public string TableNamePrefix { get; set; }
///
/// Property that directs DynamoDBContext to ignore null values
/// on attributes during a Save operation.
/// If the property is false (or not set), null values will be
/// interpreted as directives to delete the specific attribute.
///
public bool? IgnoreNullValues { get; set; }
///
/// Property that directs DynamoDBContext to enable empty string values
/// on attributes during a Save operation.
/// If the property is false (or not set), empty string values will be
/// interpreted as null values.
///
public bool? IsEmptyStringValueEnabled { get; set; }
///
/// Conversion specification which controls how conversion between
/// .NET and DynamoDB types happens.
///
public DynamoDBEntryConversion Conversion { get; set; }
}
///
/// Configuration object for setting options for individual operations.
/// This will override any settings specified by the DynamoDBContext's DynamoDBContextConfig object.
///
public class DynamoDBOperationConfig : DynamoDBContextConfig
{
///
/// Property that indicates the table to save an object to overriding the DynamoDBTable attribute
/// declared for the type.
///
public string OverrideTableName { get; set; }
///
/// Property that indicates a query should traverse the index backward.
/// If the property is false (or not set), traversal shall be forward.
///
public bool? BackwardQuery { get; set; }
///
/// Property indicating the name of the index to query or scan against.
/// This value is optional if the index name can be inferred from the call.
///
public string IndexName { get; set; }
///
/// A logical operator to apply to the filter conditions:
/// AND - If all of the conditions evaluate to true, then the entire filter evaluates to true.
/// OR - If at least one of the conditions evaluate to true, then the entire filter evaluates to true.
///
/// Default value is AND.
///
public ConditionalOperatorValues ConditionalOperator { get; set; }
///
/// Query filter for the Query operation operation. Evaluates the query results and returns only
/// the matching values. If you specify more than one condition, then by default all of the
/// conditions must evaluate to true. To match only some conditions, set ConditionalOperator to Or.
/// Note: Conditions must be against non-key properties.
///
public List QueryFilter { get; set; }
///
/// Default constructor
///
public DynamoDBOperationConfig()
{
QueryFilter = new List();
}
// Checks if the IndexName is set on the config
internal bool IsIndexOperation { get { return !string.IsNullOrEmpty(IndexName); } }
}
///
/// Class describing a single scan condition
///
public class ScanCondition
{
#region Public properties
///
/// Name of the property being tested
///
public string PropertyName { get; set; }
///
/// Comparison operator
///
public ScanOperator Operator { get; set; }
///
/// Values being tested against.
///
/// The values should be of the same type as the property.
/// In the cases where the property is a collection, the values
/// should be of the same type as the items in the collection.
///
public object[] Values { get; set; }
#endregion
#region Constructor
///
/// Initializes a ScanCondition with the target property, the
/// comparison operator and values being tested against.
///
/// Name of the property
/// Comparison operator
///
/// Value(s) being tested against.
///
/// The values should be of the same type as the property.
/// In the cases where the property is a collection, the values
/// should be of the same type as the items in the collection.
///
public ScanCondition(string propertyName, ScanOperator op, params object[] values)
{
PropertyName = propertyName;
Operator = op;
Values = values;
}
#endregion
}
///
/// Class describing a single query condition
///
public class QueryCondition
{
#region Public properties
///
/// Name of the property being tested
///
public string PropertyName { get; set; }
///
/// Comparison operator
///
public QueryOperator Operator { get; set; }
///
/// Values being tested against.
///
/// The values should be of the same type as the property.
/// In the cases where the property is a collection, the values
/// should be of the same type as the items in the collection.
///
public object[] Values { get; set; }
#endregion
#region Constructor
///
/// Initializes a ScanCondition with the target property, the
/// comparison operator and values being tested against.
///
/// Name of the property
/// Comparison operator
///
/// Value(s) being tested against.
///
/// The values should be of the same type as the property.
/// In the cases where the property is a collection, the values
/// should be of the same type as the items in the collection.
///
public QueryCondition(string propertyName, QueryOperator op, params object[] values)
{
PropertyName = propertyName;
Operator = op;
Values = values;
}
#endregion
}
internal class DynamoDBFlatConfig
{
public static string DefaultIndexName = string.Empty;
private static DynamoDBOperationConfig _emptyOperationConfig = new DynamoDBOperationConfig
{
ConsistentRead = null,
OverrideTableName = null,
SkipVersionCheck = null,
TableNamePrefix = null,
IgnoreNullValues = null,
BackwardQuery = null,
IndexName = null,
ConditionalOperator = ConditionalOperatorValues.And,
Conversion = null,
IsEmptyStringValueEnabled = null
};
private static DynamoDBContextConfig _emptyContextConfig = new DynamoDBContextConfig
{
ConsistentRead = null,
SkipVersionCheck = null,
TableNamePrefix = null,
IgnoreNullValues = null,
Conversion = null,
IsEmptyStringValueEnabled = null
};
public DynamoDBFlatConfig(DynamoDBOperationConfig operationConfig, DynamoDBContextConfig contextConfig)
{
if (operationConfig == null)
operationConfig = _emptyOperationConfig;
if (contextConfig == null)
contextConfig = _emptyContextConfig;
bool consistentRead = operationConfig.ConsistentRead ?? contextConfig.ConsistentRead ?? false;
bool skipVersionCheck = operationConfig.SkipVersionCheck ?? contextConfig.SkipVersionCheck ?? false;
bool ignoreNullValues = operationConfig.IgnoreNullValues ?? contextConfig.IgnoreNullValues ?? false;
bool isEmptyStringValueEnabled = operationConfig.IsEmptyStringValueEnabled ?? contextConfig.IsEmptyStringValueEnabled ?? false;
string overrideTableName =
!string.IsNullOrEmpty(operationConfig.OverrideTableName) ? operationConfig.OverrideTableName : string.Empty;
string tableNamePrefix =
!string.IsNullOrEmpty(operationConfig.TableNamePrefix) ? operationConfig.TableNamePrefix :
!string.IsNullOrEmpty(contextConfig.TableNamePrefix) ? contextConfig.TableNamePrefix : string.Empty;
bool backwardQuery = operationConfig.BackwardQuery ?? false;
string indexName =
!string.IsNullOrEmpty(operationConfig.IndexName) ? operationConfig.IndexName : DefaultIndexName;
List queryFilter = operationConfig.QueryFilter ?? new List();
ConditionalOperatorValues conditionalOperator = operationConfig.ConditionalOperator;
DynamoDBEntryConversion conversion = operationConfig.Conversion ?? contextConfig.Conversion ?? DynamoDBEntryConversion.CurrentConversion;
ConsistentRead = consistentRead;
SkipVersionCheck = skipVersionCheck;
IgnoreNullValues = ignoreNullValues;
IsEmptyStringValueEnabled = isEmptyStringValueEnabled;
OverrideTableName = overrideTableName;
TableNamePrefix = tableNamePrefix;
BackwardQuery = backwardQuery;
IndexName = indexName;
QueryFilter = queryFilter;
ConditionalOperator = conditionalOperator;
Conversion = conversion;
State = new OperationState();
}
///
/// Property that directs DynamoDBContext to use consistent reads.
/// If property is not set, behavior defaults to non-consistent reads.
///
public bool? ConsistentRead { get; set; }
///
/// Property that directs DynamoDBContext to skip version checks
/// when saving or deleting an object with a version attribute.
/// If property is not set, version checks are performed.
///
public bool? SkipVersionCheck { get; set; }
///
/// Property that directs DynamoDBContext to prefix all table names
/// with a specific string.
/// If property is null or empty, no prefix is used and default
/// table names are used.
///
public string TableNamePrefix { get; set; }
///
/// Property that directs DynamoDBContext to ignore null values
/// on attributes during a Save operation.
/// If the property is false (or not set), null values will be
/// interpreted as directives to delete the specific attribute.
///
public bool? IgnoreNullValues { get; set; }
///
/// Property that directs DynamoDBContext to enable empty string values
/// on attributes during a Save operation.
/// If the property is false (or not set), empty string values will be
/// interpreted as null values.
///
public bool IsEmptyStringValueEnabled { get; set; }
///
/// Property that indicates the table to save an object to overriding the DynamoDBTable attribute
/// declared for the type.
///
public string OverrideTableName { get; set; }
///
/// Property that indicates a query should traverse the index backward.
/// If the property is false (or not set), traversal shall be forward.
///
public bool? BackwardQuery { get; set; }
///
/// Property indicating the name of the index to query or scan against.
/// This value is optional if the index name can be inferred from the call.
///
public string IndexName { get; set; }
///
/// A logical operator to apply to the filter conditions:
/// AND - If all of the conditions evaluate to true, then the entire filter evaluates to true.
/// OR - If at least one of the conditions evaluate to true, then the entire filter evaluates to true.
///
/// Default value is AND.
///
public ConditionalOperatorValues ConditionalOperator { get; set; }
///
/// Query filter for the Query operation operation. Evaluates the query results and returns only
/// the matching values. If you specify more than one condition, then by default all of the
/// conditions must evaluate to true. To match only some conditions, set ConditionalOperator to Or.
/// Note: Conditions must be against non-key properties.
///
public List QueryFilter { get; set; }
///
/// Conversion specification which controls how conversion between
/// .NET and DynamoDB types happens.
///
public DynamoDBEntryConversion Conversion { get; set; }
// Checks if the IndexName is set on the config
internal bool IsIndexOperation { get { return !string.IsNullOrEmpty(IndexName); } }
// State of the operation using this config
internal OperationState State { get; private set; }
public class OperationState
{
private CircularReferenceTracking referenceTracking;
public OperationState()
{
referenceTracking = new CircularReferenceTracking();
}
public IDisposable Track(object target)
{
return referenceTracking.Track(target);
}
}
}
}