2
2
from datetime import datetime
3
3
from typing import Any , Dict , List , Literal , Optional , Type , Union
4
4
5
- from pydantic import BaseModel , field_validator
6
-
5
+ from pydantic import BaseModel , Field , field_validator
7
6
from aws_lambda_powertools .shared .dynamodb_deserializer import TypeDeserializer
8
7
9
8
_DESERIALIZER = TypeDeserializer ()
10
9
11
10
12
11
class DynamoDBStreamChangedRecordModel (BaseModel ):
13
- ApproximateCreationDateTime : Optional [datetime ] = None
14
- Keys : Dict [str , Any ]
15
- NewImage : Optional [Union [Dict [str , Any ], Type [BaseModel ], BaseModel ]] = None
16
- OldImage : Optional [Union [Dict [str , Any ], Type [BaseModel ], BaseModel ]] = None
17
- SequenceNumber : str
18
- SizeBytes : int
19
- StreamViewType : Literal ["NEW_AND_OLD_IMAGES" , "KEYS_ONLY" , "NEW_IMAGE" , "OLD_IMAGE" ]
20
-
21
- # context on why it's commented: https://github.com/aws-powertools/powertools-lambda-python/pull/118
22
- # since both images are optional, they can both be None. However, at least one must
23
- # exist in a legal model of NEW_AND_OLD_IMAGES type
24
- # @root_validator
25
- # def check_one_image_exists(cls, values): # noqa: ERA001
26
- # new_img, old_img = values.get("NewImage"), values.get("OldImage") # noqa: ERA001
27
- # stream_type = values.get("StreamViewType") # noqa: ERA001
28
- # if stream_type == "NEW_AND_OLD_IMAGES" and not new_img and not old_img: # noqa: ERA001
29
- # raise TypeError("DynamoDB streams model failed validation, missing both new & old stream images") # noqa: ERA001,E501
30
- # return values # noqa: ERA001
12
+ ApproximateCreationDateTime : Optional [float ] = Field ( # AWS sends this as Unix epoch float
13
+ default = None ,
14
+ description = "The approximate date and time when the stream record was created (Unix epoch time)." ,
15
+ examples = [1693997155.0 ]
16
+ )
17
+ Keys : Dict [str , Any ] = Field (
18
+ description = "Primary key attributes for the item." ,
19
+ examples = [{"Id" : {"N" : "101" }}]
20
+ )
21
+ NewImage : Optional [Union [Dict [str , Any ], Type [BaseModel ], BaseModel ]] = Field (
22
+ default = None ,
23
+ description = "The item after modifications, in DynamoDB attribute-value format." ,
24
+ examples = [{
25
+ "Message" : {"S" : "New item!" },
26
+ "Id" : {"N" : "101" }
27
+ }]
28
+ )
29
+ OldImage : Optional [Union [Dict [str , Any ], Type [BaseModel ], BaseModel ]] = Field (
30
+ default = None ,
31
+ description = "The item before modifications, in DynamoDB attribute-value format." ,
32
+ examples = [{
33
+ "Message" : {"S" : "Old item!" },
34
+ "Id" : {"N" : "100" }
35
+ }]
36
+ )
37
+ SequenceNumber : str = Field (
38
+ description = "A unique identifier for the stream record." ,
39
+ examples = ["222" ]
40
+ )
41
+ SizeBytes : int = Field (
42
+ description = "The size of the stream record, in bytes." ,
43
+ examples = [26 ]
44
+ )
45
+ StreamViewType : Literal ["NEW_AND_OLD_IMAGES" , "KEYS_ONLY" , "NEW_IMAGE" , "OLD_IMAGE" ] = Field (
46
+ description = "The type of data included in the stream record." ,
47
+ examples = ["NEW_AND_OLD_IMAGES" ]
48
+ )
31
49
32
50
@field_validator ("Keys" , "NewImage" , "OldImage" , mode = "before" )
33
51
def deserialize_field (cls , value ):
34
- return {k : _DESERIALIZER .deserialize (v ) for k , v in value .items ()}
52
+ return {k : _DESERIALIZER .deserialize (v ) for k , v in value .items ()} if value else value
35
53
36
54
37
55
class UserIdentity (BaseModel ):
38
- type : Literal ["Service" ] # noqa: VNE003, A003
39
- principalId : Literal ["dynamodb.amazonaws.com" ]
56
+ type : Literal ["Service" ] = Field (
57
+ default = "Service" ,
58
+ description = "The type of identity that made the request, which is always 'Service' for DynamoDB streams." ,
59
+ examples = ["Service" ]
60
+ )
61
+ principalId : str = Field (
62
+ description = "The unique identifier for the principal that made the request." ,
63
+ examples = ["dynamodb.amazonaws.com" ]
64
+ )
40
65
41
66
42
67
class DynamoDBStreamRecordModel (BaseModel ):
43
- eventID : str
44
- eventName : Literal ["INSERT" , "MODIFY" , "REMOVE" ]
45
- eventVersion : float
46
- eventSource : Literal ["aws:dynamodb" ]
47
- awsRegion : str
48
- eventSourceARN : str
49
- dynamodb : DynamoDBStreamChangedRecordModel
50
- userIdentity : Optional [UserIdentity ] = None
68
+ eventID : str = Field (
69
+ description = "A unique identifier for the event." ,
70
+ examples = ["1" ]
71
+ )
72
+ eventName : Literal ["INSERT" , "MODIFY" , "REMOVE" ] = Field (
73
+ description = "The type of operation that was performed on the item." ,
74
+ examples = ["INSERT" ]
75
+ )
76
+ eventVersion : str = Field (
77
+ default = "1.0" ,
78
+ description = "The version of the stream record format." ,
79
+ examples = ["1.0" ]
80
+ )
81
+ eventSource : str = Field (
82
+ default = "aws:dynamodb" ,
83
+ description = "The source of the event, which is always 'aws:dynamodb' for DynamoDB streams." ,
84
+ examples = ["aws:dynamodb" ]
85
+ )
86
+ awsRegion : str = Field (
87
+ description = "The AWS region where the stream record was generated." ,
88
+ examples = ["us-west-2" ]
89
+ )
90
+ eventSourceARN : str = Field (
91
+ description = "The Amazon Resource Name (ARN) of the DynamoDB stream." ,
92
+ examples = ["arn:aws:dynamodb:us-west-2:123456789012:table/ExampleTable/stream/2021-01-01T00:00:00.000" ]
93
+ )
94
+ dynamodb : DynamoDBStreamChangedRecordModel = Field (
95
+ description = "Contains the details of the DynamoDB stream record." ,
96
+ examples = [{
97
+ "ApproximateCreationDateTime" : 1693997155.0 ,
98
+ "Keys" : {"Id" : {"N" : "101" }},
99
+ "NewImage" : {"Message" : {"S" : "New item!" }, "Id" : {"N" : "101" }},
100
+ "OldImage" : {"Message" : {"S" : "Old item!" }, "Id" : {"N" : "100" }},
101
+ "SequenceNumber" : "222" ,
102
+ "SizeBytes" : 26 ,
103
+ "StreamViewType" : "NEW_AND_OLD_IMAGES"
104
+ }]
105
+ )
106
+ userIdentity : Optional [UserIdentity ] = Field (
107
+ default = None ,
108
+ description = "Information about the identity that made the request." ,
109
+ examples = [{"type" : "Service" , "principalId" : "dynamodb.amazonaws.com" }]
110
+ )
51
111
52
112
53
113
class DynamoDBStreamModel (BaseModel ):
54
- Records : List [DynamoDBStreamRecordModel ]
114
+ Records : List [DynamoDBStreamRecordModel ] = Field (
115
+ description = "A list of records that contain the details of the DynamoDB stream events." ,
116
+ examples = [{
117
+ "eventID" : "1" ,
118
+ "eventName" : "INSERT" ,
119
+ "eventVersion" : "1.0" ,
120
+ "eventSource" : "aws:dynamodb" ,
121
+ "awsRegion" : "us-west-2" ,
122
+ "eventSourceARN" : "arn:aws:dynamodb:us-west-2:123456789012:table/ExampleTable/stream/2021-01-01T00:00:00.000" ,
123
+ "dynamodb" : {
124
+ "ApproximateCreationDateTime" : 1693997155.0 ,
125
+ "Keys" : {"Id" : {"N" : "101" }},
126
+ "NewImage" : {"Message" : {"S" : "New item!" }, "Id" : {"N" : "101" }},
127
+ "OldImage" : {"Message" : {"S" : "Old item!" }, "Id" : {"N" : "100" }},
128
+ "SequenceNumber" : "222" ,
129
+ "SizeBytes" : 26 ,
130
+ "StreamViewType" : "NEW_AND_OLD_IMAGES"
131
+ },
132
+ "userIdentity" : {"type" : "Service" , "principalId" : "dynamodb.amazonaws.com" }
133
+ }]
134
+ )
0 commit comments