618 lines
23 KiB
C#
618 lines
23 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using Amazon.DynamoDBv2.Model;
|
|
using Amazon.DynamoDBv2;
|
|
using Amazon.Runtime.Internal;
|
|
using Amazon.DynamoDBv2.DocumentModel;
|
|
using NLog.Conditions;
|
|
|
|
|
|
using ServerCore; using ServerBase;
|
|
|
|
|
|
using DYNAMO_DB_TABLE_FULL_NAME = System.String;
|
|
|
|
|
|
namespace ServerBase;
|
|
|
|
public static class DynamoDbItemRequestHelper
|
|
{
|
|
public enum AttribValueAction
|
|
{
|
|
None = 0,
|
|
|
|
Increase, // Atomic 기반 증가
|
|
Decrease, // Atomic 기반 감소
|
|
Update // 값의 변경
|
|
}
|
|
|
|
public class AttribAction
|
|
{
|
|
public AttribValueAction ValueAction { get; set; } = AttribValueAction.None;
|
|
public AttributeValue Value { get; set; } = new();
|
|
}
|
|
|
|
public static (Result, DynamoDbItemRequestQueryContext?) makeUpdateItemRequestWithDoc<TAttrib>( DynamoDbDocBase targetDoc
|
|
, Dictionary<string, AttribAction> toChangeAttibValues
|
|
, DynamoDbQueryExceptionNotifier.ExceptionHandler? exceptionHandler = null )
|
|
where TAttrib : AttribBase
|
|
{
|
|
ConditionValidCheckHelper.throwIfFalseWithCondition(() => 0 < toChangeAttibValues.Count, () => $"Invalid toChangeAttibValues.Count !!! : 0 < {toChangeAttibValues.Count}");
|
|
|
|
var server_logic = ServerLogicApp.getServerLogicApp();
|
|
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic client is null !!! ");
|
|
var db_connector = server_logic.getDynamoDbClient();
|
|
NullReferenceCheckHelper.throwIfNull(db_connector, () => $"db_connector client is null !!! ");
|
|
|
|
var result = new Result();
|
|
|
|
var primary_key = targetDoc.getPrimaryKey();
|
|
|
|
var query_builder = new DynamoDbItemRequestHelper.UpdateItemRequestBuilder(db_connector.getTableFullName(targetDoc.TableName));
|
|
query_builder.withKeys(primary_key.toKeyWithAttributeValue());
|
|
|
|
var attrib_path_json_string = targetDoc.toJsonStringOfAttribs();
|
|
|
|
var update_expression = "SET ";
|
|
var expression_idx = 0;
|
|
var expression_attribute_names = new Dictionary<string, string>();
|
|
var expression_attribute_values = new Dictionary<string, AttributeValue>();
|
|
|
|
var update_item_request = query_builder.getItemRequest();
|
|
|
|
foreach (var each in toChangeAttibValues)
|
|
{
|
|
var attrib_key = each.Key;
|
|
var attrib_value = each.Value;
|
|
|
|
var target_key = JsonHelper.getJsonPropertyName<TAttrib>(attrib_key);
|
|
(var is_success, var attribute_expression) = DynamoDbClientHelper.toAttributeExpressionFromJson(attrib_path_json_string, target_key);
|
|
if (false == is_success)
|
|
{
|
|
var err_msg = $"Failed to DynamoDbClientHelper.toAttributeExpressionFromJson() !!! : attribPath:{attrib_path_json_string}, targetKey:{target_key} - {primary_key.toBasicString()}";
|
|
result.setFail(ServerErrorCode.AttribPathMakeFailed, err_msg);
|
|
Log.getLogger().error(result.toBasicString());
|
|
|
|
continue;
|
|
}
|
|
|
|
var attribute_names = DynamoDbClientHelper.toExpressionAttributeNamesFromJson(attrib_path_json_string, target_key);
|
|
foreach (var name in attribute_names)
|
|
{
|
|
expression_attribute_names.TryAdd(name.Key, name.Value);
|
|
}
|
|
|
|
if (expression_idx > 0) update_expression += ", ";
|
|
|
|
var data = attrib_value.Value;
|
|
if (AttribValueAction.Increase == attrib_value.ValueAction)
|
|
{
|
|
var start_key = $":start_{expression_idx}";
|
|
var incr_key = $":incr_{expression_idx}";
|
|
|
|
update_expression += $"{attribute_expression} = if_not_exists({attribute_expression}, {start_key}) + {incr_key}";
|
|
expression_attribute_values.Add(incr_key, data);
|
|
expression_attribute_values.TryAdd(start_key, new AttributeValue { N = "0" });
|
|
}
|
|
else if(AttribValueAction.Decrease== attrib_value.ValueAction)
|
|
{
|
|
var start_key = $":start_{expression_idx}";
|
|
var decr_key = $":decr_{expression_idx}";
|
|
|
|
update_expression += $"{attribute_expression} = if_not_exists({attribute_expression}, {start_key}) - {decr_key}";
|
|
expression_attribute_values.Add(decr_key, data);
|
|
expression_attribute_values.TryAdd(start_key, new AttributeValue { N = "0" });
|
|
}
|
|
else if (AttribValueAction.Update == attrib_value.ValueAction)
|
|
{
|
|
var new_value_key = $":newValue_{expression_idx}";
|
|
|
|
update_expression += $"{attribute_expression} = {new_value_key}";
|
|
expression_attribute_values.Add(new_value_key, data);
|
|
}
|
|
|
|
expression_idx++;
|
|
}
|
|
|
|
query_builder.withExpressionAttributeNames(expression_attribute_names);
|
|
query_builder.withUpdateExpression(update_expression);
|
|
query_builder.withExpressionAttributeValues(expression_attribute_values);
|
|
query_builder.withReturnValues(ReturnValue.ALL_NEW);
|
|
|
|
(result, var builded_update_item_request) = query_builder.build();
|
|
if(result.isFail())
|
|
{
|
|
return (result, null);
|
|
}
|
|
NullReferenceCheckHelper.throwIfNull(builded_update_item_request, () => $"builded_update_item_request is null !!! - {primary_key.toBasicString()}");
|
|
|
|
var exception_handler = new DynamoDbQueryExceptionNotifier.ExceptionHandler(DynamoDbQueryExceptionNotifier.ConditionalCheckFailed, ServerErrorCode.LackOfTotalCalium);
|
|
|
|
return (result, builded_update_item_request.createItemRequestQueryContext(QueryType.Update, exceptionHandler));
|
|
}
|
|
|
|
|
|
//=========================================================================================
|
|
// UpdateItemRequest Builder
|
|
//=========================================================================================
|
|
public class UpdateItemRequestBuilder
|
|
{
|
|
private readonly UpdateItemRequest m_request;
|
|
|
|
private Document? m_document;
|
|
|
|
private readonly bool m_is_upsert;
|
|
|
|
public UpdateItemRequestBuilder(DYNAMO_DB_TABLE_FULL_NAME tableFullName, bool isUpsert = false)
|
|
{
|
|
ConditionValidCheckHelper.throwIfFalseWithCondition(() => false == tableFullName.isNullOrWhiteSpace(), () => $"Invalid TableFullName !!!, Null or WhiteSpace !!!");
|
|
|
|
m_request = new UpdateItemRequest
|
|
{
|
|
TableName = tableFullName,
|
|
Key = new Dictionary<string, AttributeValue>(),
|
|
AttributeUpdates = new Dictionary<string, AttributeValueUpdate>(),
|
|
UpdateExpression = string.Empty,
|
|
};
|
|
|
|
m_is_upsert = isUpsert;
|
|
}
|
|
|
|
public UpdateItemRequest getItemRequest() => m_request;
|
|
|
|
public UpdateItemRequestBuilder withDocument(Document document)
|
|
{
|
|
m_document = document;
|
|
return this;
|
|
}
|
|
|
|
public UpdateItemRequestBuilder withReturnValues(ReturnValue returnValue)
|
|
{
|
|
m_request.ReturnValues = returnValue;
|
|
return this;
|
|
}
|
|
|
|
public UpdateItemRequestBuilder withConditionExpression(string conditionExpression)
|
|
{
|
|
m_request.ConditionExpression = conditionExpression;
|
|
return this;
|
|
}
|
|
|
|
public UpdateItemRequestBuilder withExpressionAttributeNames(Dictionary<string, string> expressionAttributeNames)
|
|
{
|
|
m_request.ExpressionAttributeNames = expressionAttributeNames;
|
|
return this;
|
|
}
|
|
|
|
public UpdateItemRequestBuilder withExpressionAttributeValues(Dictionary<string, AttributeValue> expressionAttributeValues)
|
|
{
|
|
m_request.ExpressionAttributeValues = expressionAttributeValues;
|
|
return this;
|
|
}
|
|
|
|
public UpdateItemRequestBuilder withKeys(Dictionary<string, AttributeValue> keyValue)
|
|
{
|
|
m_request.Key = keyValue;
|
|
return this;
|
|
}
|
|
|
|
public UpdateItemRequestBuilder addKey(string keyName, string keyValue)
|
|
{
|
|
m_request.Key[keyName] = new AttributeValue { S = keyValue };
|
|
return this;
|
|
}
|
|
|
|
public UpdateItemRequestBuilder addKey(string keyName, int keyValue)
|
|
{
|
|
m_request.Key[keyName] = new AttributeValue { N = keyValue.ToString() };
|
|
return this;
|
|
}
|
|
|
|
public UpdateItemRequestBuilder addKey(string keyName, long keyValue)
|
|
{
|
|
m_request.Key[keyName] = new AttributeValue { N = keyValue.ToString() };
|
|
return this;
|
|
}
|
|
|
|
public UpdateItemRequestBuilder addKey(string keyName, float keyValue)
|
|
{
|
|
m_request.Key[keyName] = new AttributeValue { N = keyValue.ToString() };
|
|
return this;
|
|
}
|
|
|
|
public UpdateItemRequestBuilder addKey(string keyName, double keyValue)
|
|
{
|
|
m_request.Key[keyName] = new AttributeValue { N = keyValue.ToString() };
|
|
return this;
|
|
}
|
|
|
|
public UpdateItemRequestBuilder addKey(string keyName, bool keyValue)
|
|
{
|
|
m_request.Key[keyName] = new AttributeValue { BOOL = keyValue };
|
|
return this;
|
|
}
|
|
|
|
public UpdateItemRequestBuilder addKey(string keyName, AttributeValue keyValue)
|
|
{
|
|
m_request.Key[keyName] = keyValue;
|
|
return this;
|
|
}
|
|
|
|
public UpdateItemRequestBuilder withReturnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity)
|
|
{
|
|
m_request.ReturnConsumedCapacity = returnConsumedCapacity;
|
|
return this;
|
|
}
|
|
|
|
public UpdateItemRequestBuilder withReturnItemCollectionMetrics(ReturnItemCollectionMetrics returnItemCollectionMetrics)
|
|
{
|
|
m_request.ReturnItemCollectionMetrics = returnItemCollectionMetrics;
|
|
return this;
|
|
}
|
|
|
|
public UpdateItemRequestBuilder withUpdateExpression(string updateExpression)
|
|
{
|
|
m_request.UpdateExpression = updateExpression;
|
|
return this;
|
|
}
|
|
|
|
public UpdateItemRequestBuilder withConditionCheck(string conditionExpression)
|
|
{
|
|
m_request.ConditionExpression = conditionExpression;
|
|
return this;
|
|
}
|
|
|
|
public (Result, UpdateItemRequest?) build()
|
|
{
|
|
var result = new Result();
|
|
|
|
if(null != m_document)
|
|
{
|
|
result = m_document.tryFillupUpdateItemRequest(m_request, m_is_upsert);
|
|
if(result.isFail())
|
|
{
|
|
return (result, null);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( false == m_is_upsert
|
|
&& null != m_request.ConditionExpression
|
|
&& m_request.ConditionExpression.isNullOrWhiteSpace() )
|
|
{
|
|
m_request.ConditionExpression = $"attribute_exists({PrimaryKey.PK_Define}) AND attribute_exists({PrimaryKey.SK_Define})";
|
|
}
|
|
}
|
|
|
|
return (result, m_request);
|
|
}
|
|
}
|
|
|
|
//=========================================================================================
|
|
// GetItemRequest Builder
|
|
//=========================================================================================
|
|
public class GetItemRequestBuilder
|
|
{
|
|
private readonly GetItemRequest m_request;
|
|
public GetItemRequestBuilder(string tableName)
|
|
{
|
|
m_request = new GetItemRequest
|
|
{
|
|
TableName = tableName,
|
|
Key = new Dictionary<string, AttributeValue>(),
|
|
ExpressionAttributeNames = new Dictionary<string, string>()
|
|
};
|
|
}
|
|
|
|
public GetItemRequestBuilder withKeys(Dictionary<string, AttributeValue> keyValue)
|
|
{
|
|
m_request.Key = keyValue;
|
|
return this;
|
|
}
|
|
|
|
public GetItemRequestBuilder addKey(string keyName, string keyValue)
|
|
{
|
|
m_request.Key[keyName] = new AttributeValue { S = keyValue };
|
|
return this;
|
|
}
|
|
|
|
public GetItemRequestBuilder addKey(string keyName, int keyValue)
|
|
{
|
|
m_request.Key[keyName] = new AttributeValue { N = keyValue.ToString() };
|
|
return this;
|
|
}
|
|
|
|
public GetItemRequestBuilder addKey(string keyName, long keyValue)
|
|
{
|
|
m_request.Key[keyName] = new AttributeValue { N = keyValue.ToString() };
|
|
return this;
|
|
}
|
|
|
|
public GetItemRequestBuilder addKey(string keyName, double keyValue)
|
|
{
|
|
m_request.Key[keyName] = new AttributeValue { N = keyValue.ToString() };
|
|
return this;
|
|
}
|
|
|
|
public GetItemRequestBuilder addKey(string keyName, float keyValue)
|
|
{
|
|
m_request.Key[keyName] = new AttributeValue { N = keyValue.ToString() };
|
|
return this;
|
|
}
|
|
|
|
public GetItemRequestBuilder addKey(string keyName, bool keyValue)
|
|
{
|
|
m_request.Key[keyName] = new AttributeValue { BOOL = keyValue };
|
|
return this;
|
|
}
|
|
|
|
public GetItemRequestBuilder withConsistentRead(bool isConsistentRead)
|
|
{
|
|
m_request.ConsistentRead = isConsistentRead;
|
|
return this;
|
|
}
|
|
|
|
public GetItemRequestBuilder withProjectionExpression(string projectExpression)
|
|
{
|
|
m_request.ProjectionExpression = projectExpression;
|
|
return this;
|
|
}
|
|
|
|
public GetItemRequestBuilder withExpressionAttributeNames(Dictionary<string, string> expressionAttributeNames)
|
|
{
|
|
m_request.ExpressionAttributeNames = expressionAttributeNames;
|
|
return this;
|
|
}
|
|
|
|
public GetItemRequestBuilder withReturnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity)
|
|
{
|
|
m_request.ReturnConsumedCapacity = returnConsumedCapacity;
|
|
return this;
|
|
}
|
|
|
|
public GetItemRequest build()
|
|
{
|
|
return m_request;
|
|
}
|
|
}
|
|
|
|
//=========================================================================================
|
|
// PutItemRequest Builder
|
|
//=========================================================================================
|
|
public class PutItemRequestBuilder
|
|
{
|
|
private readonly PutItemRequest m_request;
|
|
|
|
public PutItemRequestBuilder(string tableName)
|
|
{
|
|
m_request = new PutItemRequest
|
|
{
|
|
TableName = tableName,
|
|
Item = new Dictionary<string, AttributeValue>(),
|
|
ExpressionAttributeNames = new Dictionary<string, string>(),
|
|
ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
|
|
};
|
|
}
|
|
|
|
public PutItemRequestBuilder withItem(Dictionary<string, AttributeValue> attributeValues)
|
|
{
|
|
m_request.Item = attributeValues;
|
|
return this;
|
|
}
|
|
|
|
public PutItemRequestBuilder addItem(string keyName, string keyValue)
|
|
{
|
|
m_request.Item[keyName] = new AttributeValue { S = keyValue };
|
|
return this;
|
|
}
|
|
|
|
public PutItemRequestBuilder addItem(string keyName, int keyValue)
|
|
{
|
|
m_request.Item[keyName] = new AttributeValue { N = keyValue.ToString() };
|
|
return this;
|
|
}
|
|
|
|
public PutItemRequestBuilder addItem(string keyName, long keyValue)
|
|
{
|
|
m_request.Item[keyName] = new AttributeValue { N = keyValue.ToString() };
|
|
return this;
|
|
}
|
|
|
|
public PutItemRequestBuilder addItem(string keyName, double keyValue)
|
|
{
|
|
m_request.Item[keyName] = new AttributeValue { N = keyValue.ToString() };
|
|
return this;
|
|
}
|
|
|
|
public PutItemRequestBuilder addItem(string keyName, float keyValue)
|
|
{
|
|
m_request.Item[keyName] = new AttributeValue { N = keyValue.ToString() };
|
|
return this;
|
|
}
|
|
|
|
public PutItemRequestBuilder addItem(string keyName, bool keyValue)
|
|
{
|
|
m_request.Item[keyName] = new AttributeValue { BOOL = keyValue };
|
|
return this;
|
|
}
|
|
|
|
public PutItemRequestBuilder withConditionalOperator(ConditionalOperator conditionalOperator)
|
|
{
|
|
m_request.ConditionalOperator = conditionalOperator;
|
|
return this;
|
|
}
|
|
|
|
public PutItemRequestBuilder withConditionalCapacity(ReturnConsumedCapacity returnConsumedCapacity)
|
|
{
|
|
m_request.ReturnConsumedCapacity = returnConsumedCapacity;
|
|
return this;
|
|
}
|
|
|
|
public PutItemRequestBuilder withConditionExpression(string conditionExpression)
|
|
{
|
|
m_request.ConditionExpression = conditionExpression;
|
|
return this;
|
|
}
|
|
|
|
public PutItemRequestBuilder withExpressionAttributeNames(Dictionary<string, string> expressAttributeNames)
|
|
{
|
|
m_request.ExpressionAttributeNames = expressAttributeNames;
|
|
return this;
|
|
}
|
|
|
|
public PutItemRequestBuilder withExpressionAttributeValues(Dictionary<string, AttributeValue> expressAttributeValues)
|
|
{
|
|
m_request.ExpressionAttributeValues = expressAttributeValues;
|
|
return this;
|
|
}
|
|
|
|
public PutItemRequestBuilder withReturnConsumedCapacity(ReturnConsumedCapacity retrunConsumedCapacity)
|
|
{
|
|
m_request.ReturnConsumedCapacity = retrunConsumedCapacity;
|
|
return this;
|
|
}
|
|
|
|
public PutItemRequestBuilder withReturnItemCollectionMetrics(ReturnItemCollectionMetrics returnItemCollectionMetrics)
|
|
{
|
|
m_request.ReturnItemCollectionMetrics = returnItemCollectionMetrics;
|
|
return this;
|
|
}
|
|
|
|
public PutItemRequest build()
|
|
{
|
|
return m_request;
|
|
}
|
|
}
|
|
|
|
//=========================================================================================
|
|
// DeleteItemRequest Builder
|
|
//=========================================================================================
|
|
public class DeleteItemRequestBuilder
|
|
{
|
|
private readonly DeleteItemRequest m_request;
|
|
|
|
public DeleteItemRequestBuilder(string tableName)
|
|
{
|
|
m_request = new DeleteItemRequest
|
|
{
|
|
TableName = tableName,
|
|
Key = new Dictionary<string, AttributeValue>(),
|
|
ExpressionAttributeNames = new Dictionary<string, string>(),
|
|
ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
|
|
};
|
|
}
|
|
|
|
public DeleteItemRequestBuilder withKeys(Dictionary<string, AttributeValue> keys)
|
|
{
|
|
m_request.Key = keys;
|
|
return this;
|
|
}
|
|
|
|
public DeleteItemRequestBuilder addKey(string attributeName, string attributeValue)
|
|
{
|
|
m_request.Key[attributeName] = new AttributeValue { S = attributeValue };
|
|
return this;
|
|
}
|
|
|
|
public DeleteItemRequestBuilder addKey(string attributeName, int attributeValue)
|
|
{
|
|
m_request.Key[attributeName] = new AttributeValue { N = attributeValue.ToString() };
|
|
return this;
|
|
}
|
|
|
|
public DeleteItemRequestBuilder addKey(string attributeName, long attributeValue)
|
|
{
|
|
m_request.Key[attributeName] = new AttributeValue { N = attributeValue.ToString() };
|
|
return this;
|
|
}
|
|
|
|
public DeleteItemRequestBuilder addKey(string attributeName, double attributeValue)
|
|
{
|
|
m_request.Key[attributeName] = new AttributeValue { N = attributeValue.ToString() };
|
|
return this;
|
|
}
|
|
|
|
public DeleteItemRequestBuilder addKey(string attributeName, float attributeValue)
|
|
{
|
|
m_request.Key[attributeName] = new AttributeValue { N = attributeValue.ToString() };
|
|
return this;
|
|
}
|
|
|
|
public DeleteItemRequestBuilder addKey(string attributeName, bool attributeValue)
|
|
{
|
|
m_request.Key[attributeName] = new AttributeValue { BOOL = attributeValue };
|
|
return this;
|
|
}
|
|
|
|
public DeleteItemRequestBuilder withConditionalOperator(ConditionalOperator conditionalOperator)
|
|
{
|
|
m_request.ConditionalOperator = conditionalOperator;
|
|
return this;
|
|
}
|
|
|
|
public DeleteItemRequestBuilder withReturnValues(ReturnValue returnValue)
|
|
{
|
|
m_request.ReturnValues = returnValue;
|
|
return this;
|
|
}
|
|
|
|
public DeleteItemRequestBuilder withConditionExpression(string conditionExpression)
|
|
{
|
|
m_request.ConditionExpression = conditionExpression;
|
|
return this;
|
|
}
|
|
|
|
public DeleteItemRequestBuilder withExpressionAttributeNames(Dictionary<string, string> expressionAttributeNames)
|
|
{
|
|
m_request.ExpressionAttributeNames = expressionAttributeNames;
|
|
return this;
|
|
}
|
|
|
|
public DeleteItemRequestBuilder withExpressionAttributeValues(Dictionary<string, AttributeValue> expressionAttributeValues)
|
|
{
|
|
m_request.ExpressionAttributeValues = expressionAttributeValues;
|
|
return this;
|
|
}
|
|
|
|
public DeleteItemRequestBuilder withReturnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity)
|
|
{
|
|
m_request.ReturnConsumedCapacity = returnConsumedCapacity;
|
|
return this;
|
|
}
|
|
|
|
public DeleteItemRequestBuilder withReturnItemCollectionMetrics(ReturnItemCollectionMetrics returnItemCollectionMetrics)
|
|
{
|
|
m_request.ReturnItemCollectionMetrics = returnItemCollectionMetrics;
|
|
return this;
|
|
}
|
|
|
|
public DeleteItemRequest build()
|
|
{
|
|
return m_request;
|
|
}
|
|
}
|
|
|
|
public static DynamoDbItemRequestQueryContext createItemRequestQueryContext( this AmazonDynamoDBRequest itemRequest
|
|
, QueryType queryType
|
|
, DynamoDbQueryExceptionNotifier.ExceptionHandler? exceptionHandler = null)
|
|
{
|
|
return new DynamoDbItemRequestQueryContext(itemRequest, queryType, exceptionHandler);
|
|
}
|
|
|
|
public static bool isValid(this AmazonDynamoDBRequest itemRequest)
|
|
{
|
|
//if (document.getPK() == string.Empty || document.getSK() == string.Empty || document.getDocType() == string.Empty)
|
|
//{
|
|
// Log.getLogger().error($"PK or SK or DocType is empty !!! : {document.toBasicString()}");
|
|
// return false;
|
|
//}
|
|
|
|
return true;
|
|
}
|
|
}
|