|
1 | | -from decimal import Clamped, Context, Decimal, Inexact, Overflow, Rounded, Underflow |
2 | 1 | from enum import Enum |
3 | | -from typing import Any, Callable, Dict, Iterator, Optional, Sequence, Set |
| 2 | +from typing import Any, Dict, Iterator, Optional |
4 | 3 |
|
| 4 | +from aws_lambda_powertools.shared.dynamodb_deserializer import TypeDeserializer |
5 | 5 | from aws_lambda_powertools.utilities.data_classes.common import DictWrapper |
6 | 6 |
|
7 | | -# NOTE: DynamoDB supports up to 38 digits precision |
8 | | -# Therefore, this ensures our Decimal follows what's stored in the table |
9 | | -DYNAMODB_CONTEXT = Context( |
10 | | - Emin=-128, |
11 | | - Emax=126, |
12 | | - prec=38, |
13 | | - traps=[Clamped, Overflow, Inexact, Rounded, Underflow], |
14 | | -) |
15 | | - |
16 | | - |
17 | | -class TypeDeserializer: |
18 | | - """ |
19 | | - Deserializes DynamoDB types to Python types. |
20 | | -
|
21 | | - It's based on boto3's [DynamoDB TypeDeserializer](https://boto3.amazonaws.com/v1/documentation/api/latest/_modules/boto3/dynamodb/types.html). |
22 | | -
|
23 | | - The only notable difference is that for Binary (`B`, `BS`) values we return Python Bytes directly, |
24 | | - since we don't support Python 2. |
25 | | - """ |
26 | | - |
27 | | - def deserialize(self, value: Dict) -> Any: |
28 | | - """Deserialize DynamoDB data types into Python types. |
29 | | -
|
30 | | - Parameters |
31 | | - ---------- |
32 | | - value: Any |
33 | | - DynamoDB value to be deserialized to a python type |
34 | | -
|
35 | | -
|
36 | | - Here are the various conversions: |
37 | | -
|
38 | | - DynamoDB Python |
39 | | - -------- ------ |
40 | | - {'NULL': True} None |
41 | | - {'BOOL': True/False} True/False |
42 | | - {'N': Decimal(value)} Decimal(value) |
43 | | - {'S': string} string |
44 | | - {'B': bytes} bytes |
45 | | - {'NS': [str(value)]} set([str(value)]) |
46 | | - {'SS': [string]} set([string]) |
47 | | - {'BS': [bytes]} set([bytes]) |
48 | | - {'L': list} list |
49 | | - {'M': dict} dict |
50 | | -
|
51 | | - Parameters |
52 | | - ---------- |
53 | | - value: Any |
54 | | - DynamoDB value to be deserialized to a python type |
55 | | -
|
56 | | - Returns |
57 | | - -------- |
58 | | - any |
59 | | - Python native type converted from DynamoDB type |
60 | | - """ |
61 | | - |
62 | | - dynamodb_type = list(value.keys())[0] |
63 | | - deserializer: Optional[Callable] = getattr(self, f"_deserialize_{dynamodb_type}".lower(), None) |
64 | | - if deserializer is None: |
65 | | - raise TypeError(f"Dynamodb type {dynamodb_type} is not supported") |
66 | | - |
67 | | - return deserializer(value[dynamodb_type]) |
68 | | - |
69 | | - def _deserialize_null(self, value: bool) -> None: |
70 | | - return None |
71 | | - |
72 | | - def _deserialize_bool(self, value: bool) -> bool: |
73 | | - return value |
74 | | - |
75 | | - def _deserialize_n(self, value: str) -> Decimal: |
76 | | - return DYNAMODB_CONTEXT.create_decimal(value) |
77 | | - |
78 | | - def _deserialize_s(self, value: str) -> str: |
79 | | - return value |
80 | | - |
81 | | - def _deserialize_b(self, value: bytes) -> bytes: |
82 | | - return value |
83 | | - |
84 | | - def _deserialize_ns(self, value: Sequence[str]) -> Set[Decimal]: |
85 | | - return set(map(self._deserialize_n, value)) |
86 | | - |
87 | | - def _deserialize_ss(self, value: Sequence[str]) -> Set[str]: |
88 | | - return set(map(self._deserialize_s, value)) |
89 | | - |
90 | | - def _deserialize_bs(self, value: Sequence[bytes]) -> Set[bytes]: |
91 | | - return set(map(self._deserialize_b, value)) |
92 | | - |
93 | | - def _deserialize_l(self, value: Sequence[Dict]) -> Sequence[Any]: |
94 | | - return [self.deserialize(v) for v in value] |
95 | | - |
96 | | - def _deserialize_m(self, value: Dict) -> Dict: |
97 | | - return {k: self.deserialize(v) for k, v in value.items()} |
98 | | - |
99 | 7 |
|
100 | 8 | class StreamViewType(Enum): |
101 | 9 | """The type of data from the modified DynamoDB item that was captured in this stream record""" |
|
0 commit comments