pckage Amazon::DynamoDB::Types;

use Type::Library
    -base
    -declare => qw( 
                      TableNameType
                      SelectType
                      ReturnValuesType
                      ReturnItemCollectionMetricsType
                      ReturnConsumedCapacityType
                      ConditionalOperatorType
                      StringBooleanType
                      AttributeDefinitionsType
                      AttributeNameType
                      AttributeValueType
                      KeySchemaType
                      GlobalSecondaryIndexType
                      LocalSecondaryIndexType
                      TableStatusType
                      ExpectedType
                      AttributeUpdatesType
                      ItemType
                      KeyType
                      BatchWritePutItemType
                      BatchWriteDeleteItemType
                      BatchWriteRequestItemsType
                      BatchGetItemsType
                      KeyConditionsType
                      QueryFilterType
                      ScanFilterType
                      AttributesToGetType
              );
use Type::Utils -all;
use Types::Standard -types;


declare AttributeNameType, as Str, where { length($_) >= 1 && length($_) <= 255 };

BEGIN {
    declare "TableNameType", as StrMatch[qr/^[a-zA-Z0-9_\-\.]{3,255}$/];
    coerce TableNameType, from Str->coercibles, via {
        TableNameType->new($_);
    };

    print TableNameType->has_coercion() . "\n";
};




declare SelectType, as StrMatch[qr/^(ALL_ATTRIBUTES|ALL_PROJECTED_ATTRIBUTES|SPECIFIC_ATTRIBUTES|COUNT)$/];
declare ReturnValuesType, as StrMatch[qr/^(NONE|ALL_OLD|UPDATED_OLD|ALL_NEW|UPDATED_NEW)$/];
declare ReturnItemCollectionMetricsType, as StrMatch[qr/^(NONE|SIZE)$/];
declare ReturnConsumedCapacityType, as StrMatch[qr/^(INDEXES|TOTAL|NONE)$/];
declare ConditionalOperatorType, as StrMatch[qr/^(AND|OR)$/];    
declare StringBooleanType, as StrMatch[qr/^(true|false)$/];
declare AttributeDefinitionsType => Map[AttributeNameType, StrMatch[qr/^(S|N|B)$/]];


declare AttributeValueType, as Defined, where { 
    (!ref($_) && "$_" =~ /\S/) || (ref($_) eq 'ARRAY' && scalar(@$_) > 0) || (ref($_) eq 'SCALAR'); 
};

declare AttributesToGetType, as ArrayRef[AttributeNameType], where { scalar(@$_) > 1 };

    
declare KeySchemaType, as ArrayRef[AttributeNameType], where { scalar(@$_) <= 2 && scalar(@$_) > 0 };

declare GlobalSecondaryIndexType, as Dict[IndexName => TableNameType,
                                            ProvisionedThroughput => Optional[Dict[ReadCapacityUnits => Optional[Int],
                                                                                   WriteCapacityUnits => Optional[Int]
                                                                               ]
                                                                          ],
                                            KeySchema => KeySchemaType,
                                            Projection => Optional[Dict[ProjectionType => StrMatch[qr/^(KEYS_ONLY|INCLUDE|ALL)$/],
                                                                        NonKeyAttributes => Optional[ArrayRef[AttributeNameType]]]],
                                       ];

declare LocalSecondaryIndexType, as Dict[IndexName => TableNameType,
                                           KeySchema => KeySchemaType,
                                           Projection => Optional[Dict[ProjectionType => StrMatch[qr/^(KEYS_ONLY|INCLUDE|ALL)$/],
                                                                       NonKeyAttributes => Optional[ArrayRef[AttributeNameType]]]]
                                       ];

declare TableStatusType, as StrMatch[qr/^(CREATING|UPDATING|DELETING|ACTIVE)$/];

declare ExpectedType, as Map[AttributeNameType, Dict[AttributeValueList => Optional[Value],
                                                       ComparisonOperator => Optional[ConditionalOperatorType],
                                                       Exists => Optional[StringBooleanType],
                                                       Value => Optional[Value],
                                                   ], where { scalar(keys %$_) > 0 }
                           ];

declare AttributeUpdatesType, as Map[AttributeNameType, Dict[Action => StrMatch[qr/^(PUT|DELETE|ADD)$/],
                                                               Value => Optional[Value]]];


declare ItemType, as Map[AttributeNameType, AttributeValueType];
declare KeyType, as Map[AttributeNameType, AttributeValueType], where { scalar(keys %$_) > 0 && scalar(keys %$_) < 3 
                                                                              && length($_->[0]) <= 2048 
                                                                              && ((scalar(@$_) == 1) || length($_->[1]) <= 1024)
                                                                          };

declare BatchWritePutItemType, as Dict[PutRequest => Dict[Item => ItemType]];
declare BatchWriteDeleteItemType, as Dict[DeleteRequest => Dict[Key => KeyType]];
declare BatchWriteRequestItemsType, as Map[TableNameType, ArrayRef[BatchWritePutItemType,BatchWriteDeleteItemType]], where { scalar(@$_) > 0};

declare BatchGetItemsType, as Map[TableNameType, Dict[AttributesToGet => Optional[AttributesToGetType],
                                                        ConsistentRead => Optional[StringBooleanType],
                                                        Keys => ArrayRef[KeyType]]
                                ], where { scalar(%$_) > 0 };


declare KeyConditionsType, as Map[AttributeNameType, Dict[AttributeValueList => AttributeValueType,
                                                            ComparisonOperator => StrMatch[qr/^(EQ|LE|LT|GE|GT|BEGINS_WITH|BETWEEN)$/]
                                                        ]];


declare QueryFilterType, as Map[AttributeNameType, Dict[AttributeValueList => AttributeValueType,
                                                          ComparisonOperator => StrMatch[qr/^(EQ|NE|LE|LT|GE|GT|NOT_NULL|NULL|CONTAINS|NOT_CONTAINS|BEGINS_WITH|IN|BETWEEN)$/]
                                                      ]];


declare ScanFilterType, as Map[AttributeNameType, Dict[AttributeValueList => AttributeValueType,
                                                         ComparisonOperator => StrMatch[qr/^(EQ|NE|LE|LT|GE|GT|NOT_NULL|NULL|CONTAINS|NOT_CONTAINS|BEGINS_WITH|IN|BETWEEN)$/]
                                                     ]];

1;