11import datetime
22import logging
3+ import os
34from typing import Any , Dict , Optional
45
56import boto3
67from botocore .config import Config
78
9+ from aws_lambda_powertools .shared import constants
810from aws_lambda_powertools .utilities .idempotency import BasePersistenceLayer
911from aws_lambda_powertools .utilities .idempotency .exceptions import (
1012 IdempotencyItemAlreadyExistsError ,
@@ -20,6 +22,8 @@ def __init__(
2022 self ,
2123 table_name : str ,
2224 key_attr : str = "id" ,
25+ static_pk_value : str = f"idempotency#{ os .getenv (constants .LAMBDA_FUNCTION_NAME_ENV , '' )} " ,
26+ sort_key_attr : Optional [str ] = None ,
2327 expiry_attr : str = "expiration" ,
2428 status_attr : str = "status" ,
2529 data_attr : str = "data" ,
@@ -35,7 +39,12 @@ def __init__(
3539 table_name: str
3640 Name of the table to use for storing execution records
3741 key_attr: str, optional
38- DynamoDB attribute name for key, by default "id"
42+ DynamoDB attribute name for partition key, by default "id"
43+ static_pk_value: str, optional
44+ DynamoDB attribute value for partition key, by default "idempotency#<function-name>".
45+ This will be used if the sort_key_attr is set.
46+ sort_key_attr: str, optional
47+ DynamoDB attribute name for the sort key
3948 expiry_attr: str, optional
4049 DynamoDB attribute name for expiry timestamp, by default "expiration"
4150 status_attr: str, optional
@@ -64,10 +73,14 @@ def __init__(
6473
6574 self ._boto_config = boto_config or Config ()
6675 self ._boto3_session = boto3_session or boto3 .session .Session ()
76+ if sort_key_attr == key_attr :
77+ raise ValueError (f"key_attr [{ key_attr } ] and sort_key_attr [{ sort_key_attr } ] cannot be the same!" )
6778
6879 self ._table = None
6980 self .table_name = table_name
7081 self .key_attr = key_attr
82+ self .static_pk_value = static_pk_value
83+ self .sort_key_attr = sort_key_attr
7184 self .expiry_attr = expiry_attr
7285 self .status_attr = status_attr
7386 self .data_attr = data_attr
@@ -93,6 +106,11 @@ def table(self, table):
93106 """
94107 self ._table = table
95108
109+ def _get_key (self , idempotency_key : str ) -> dict :
110+ if self .sort_key_attr :
111+ return {self .key_attr : self .static_pk_value , self .sort_key_attr : idempotency_key }
112+ return {self .key_attr : idempotency_key }
113+
96114 def _item_to_data_record (self , item : Dict [str , Any ]) -> DataRecord :
97115 """
98116 Translate raw item records from DynamoDB to DataRecord
@@ -117,7 +135,7 @@ def _item_to_data_record(self, item: Dict[str, Any]) -> DataRecord:
117135 )
118136
119137 def _get_record (self , idempotency_key ) -> DataRecord :
120- response = self .table .get_item (Key = { self .key_attr : idempotency_key } , ConsistentRead = True )
138+ response = self .table .get_item (Key = self ._get_key ( idempotency_key ) , ConsistentRead = True )
121139
122140 try :
123141 item = response ["Item" ]
@@ -127,7 +145,7 @@ def _get_record(self, idempotency_key) -> DataRecord:
127145
128146 def _put_record (self , data_record : DataRecord ) -> None :
129147 item = {
130- self .key_attr : data_record .idempotency_key ,
148+ ** self ._get_key ( data_record .idempotency_key ) ,
131149 self .expiry_attr : data_record .expiry_timestamp ,
132150 self .status_attr : data_record .status ,
133151 }
@@ -168,7 +186,7 @@ def _update_record(self, data_record: DataRecord):
168186 expression_attr_names ["#validation_key" ] = self .validation_key_attr
169187
170188 kwargs = {
171- "Key" : { self .key_attr : data_record .idempotency_key } ,
189+ "Key" : self ._get_key ( data_record .idempotency_key ) ,
172190 "UpdateExpression" : update_expression ,
173191 "ExpressionAttributeValues" : expression_attr_values ,
174192 "ExpressionAttributeNames" : expression_attr_names ,
@@ -178,4 +196,4 @@ def _update_record(self, data_record: DataRecord):
178196
179197 def _delete_record (self , data_record : DataRecord ) -> None :
180198 logger .debug (f"Deleting record for idempotency key: { data_record .idempotency_key } " )
181- self .table .delete_item (Key = { self .key_attr : data_record .idempotency_key } )
199+ self .table .delete_item (Key = self ._get_key ( data_record .idempotency_key ) )
0 commit comments