/*
* 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 System.IO;
using System.Linq;
using Amazon.DynamoDBv2.Model;
using Amazon.Util;
namespace Amazon.DynamoDBv2.DocumentModel
{
///
/// Expressions are used for conditional deletes and filtering for query and scan operations.
///
public class Expression
{
private Dictionary _expressionAttributeNames = new Dictionary(StringComparer.Ordinal);
private Dictionary _expressionAttributeValues = new Dictionary(StringComparer.Ordinal);
internal bool IsSet
{
get { return this.ExpressionStatement != null; }
}
///
/// Gets and sets the property ExpressionStatement. "Price > :price" is an example expression statement.
/// :price is a variable which gets its value from the ExpressionAttributeValues collection. If this is used
/// for deletes then it prevents the delete from happening if the Price attribute on the item is less then the passed
/// in price. For query and scan it will only return back items where the Price attribute is greater then passed
/// in price.
///
public string ExpressionStatement
{
get;
set;
}
///
/// Gets and sets the property ExpressionAttributeNames. This collection contains attribute names from the item
/// that should be substituted in the expression when it is evaluated. For example the expression "#C < #U" will
/// expect the attribute names to be added to this collection.
///
/// expression.ExpressionAttributeNames["#C"] = "CriticRating"
/// expression.ExpressionAttributeNames["#U"] = "UserRating"
///
///
public Dictionary ExpressionAttributeNames
{
get { return this._expressionAttributeNames; }
set { this._expressionAttributeNames = value; }
}
///
/// Gets and sets the property ExpressionAttributeValues. This collection contains the values to be substituted in the expression.
/// For example the expression "Price > :price" will contain one entry in this collection a key of ":price".
///
/// DynamoDBEntry contains many common implicit cast operations so assignment can be done with the basic .NET types.
/// In the price example shown above the value to be used for the expression can be provided using the following code snippet:
///
/// expression.ExpressionAttributeValues[":price"] = 3.99;
///
///
///
public Dictionary ExpressionAttributeValues
{
get { return this._expressionAttributeValues; }
set { this._expressionAttributeValues = value; }
}
internal void ApplyExpression(ScanRequest request, Table table)
{
request.FilterExpression = this.ExpressionStatement;
request.ExpressionAttributeNames = new Dictionary(this.ExpressionAttributeNames);
request.ExpressionAttributeValues = ConvertToAttributeValues(this.ExpressionAttributeValues, table);
}
internal void ApplyExpression(DeleteItemRequest request, Table table)
{
request.ConditionExpression = this.ExpressionStatement;
request.ExpressionAttributeNames = new Dictionary(this.ExpressionAttributeNames);
request.ExpressionAttributeValues = ConvertToAttributeValues(this.ExpressionAttributeValues, table);
}
internal void ApplyExpression(PutItemRequest request, Table table)
{
request.ConditionExpression = this.ExpressionStatement;
request.ExpressionAttributeNames = new Dictionary(this.ExpressionAttributeNames);
request.ExpressionAttributeValues = ConvertToAttributeValues(this.ExpressionAttributeValues, table);
}
internal void ApplyExpression(UpdateItemRequest request, Table table)
{
request.ConditionExpression = this.ExpressionStatement;
request.ExpressionAttributeNames = new Dictionary(this.ExpressionAttributeNames);
request.ExpressionAttributeValues = ConvertToAttributeValues(this.ExpressionAttributeValues, table);
}
internal void ApplyExpression(Get request, Table table)
{
request.ProjectionExpression = ExpressionStatement;
request.ExpressionAttributeNames = new Dictionary(this.ExpressionAttributeNames);
}
internal void ApplyExpression(Put request, Table table)
{
request.ConditionExpression = ExpressionStatement;
request.ExpressionAttributeNames = new Dictionary(ExpressionAttributeNames);
request.ExpressionAttributeValues = ConvertToAttributeValues(ExpressionAttributeValues, table);
}
internal void ApplyExpression(Update request, Table table)
{
request.ConditionExpression = ExpressionStatement;
request.ExpressionAttributeNames = new Dictionary(ExpressionAttributeNames);
request.ExpressionAttributeValues = ConvertToAttributeValues(ExpressionAttributeValues, table);
}
internal void ApplyExpression(Delete request, Table table)
{
request.ConditionExpression = ExpressionStatement;
request.ExpressionAttributeNames = new Dictionary(ExpressionAttributeNames);
request.ExpressionAttributeValues = ConvertToAttributeValues(ExpressionAttributeValues, table);
}
internal void ApplyExpression(ConditionCheck request, Table table)
{
request.ConditionExpression = ExpressionStatement;
request.ExpressionAttributeNames = new Dictionary(ExpressionAttributeNames);
request.ExpressionAttributeValues = ConvertToAttributeValues(ExpressionAttributeValues, table);
}
internal static void ApplyExpression(QueryRequest request, Table table,
Expression keyExpression, Expression filterExpression)
{
if (keyExpression == null)
keyExpression = new Expression();
if (filterExpression == null)
filterExpression = new Expression();
if (!keyExpression.IsSet && !filterExpression.IsSet)
return;
if (keyExpression.IsSet)
request.KeyConditionExpression = keyExpression.ExpressionStatement;
if (filterExpression.IsSet)
request.FilterExpression = filterExpression.ExpressionStatement;
var kean = keyExpression.ExpressionAttributeNames;
var fean = filterExpression.ExpressionAttributeNames;
var combinedEan = Common.Combine(kean, fean, StringComparer.Ordinal);
request.ExpressionAttributeNames = combinedEan;
var keav = new Document(keyExpression.ExpressionAttributeValues).ForceConversion(table.Conversion);
var feav = new Document(filterExpression.ExpressionAttributeValues).ForceConversion(table.Conversion);
var combinedEav = Common.Combine(keav, feav, null);
request.ExpressionAttributeValues = ConvertToAttributeValues(combinedEav, table);
}
internal static Dictionary ConvertToAttributeValues(
Dictionary valueMap, Table table)
{
var convertedValues = new Dictionary();
if (valueMap != null)
{
foreach (var kvp in valueMap)
{
var attributeName = kvp.Key;
var entry = kvp.Value;
if (entry == null)
convertedValues[attributeName] = new AttributeValue { NULL = true };
else
{
if (table.StoreAsEpoch.Contains(attributeName))
entry = Document.DateTimeToEpochSeconds(entry, attributeName);
var attributeConversionConfig = new DynamoDBEntry.AttributeConversionConfig(table.Conversion, table.IsEmptyStringValueEnabled);
convertedValues[attributeName] = entry.ConvertToAttributeValue(attributeConversionConfig);
}
}
}
return convertedValues;
}
}
}