Coverage for dynamodx / transact_get.py: 100%
40 statements
« prev ^ index » next coverage.py v7.13.2, created at 2026-02-18 17:37 -0300
« prev ^ index » next coverage.py v7.13.2, created at 2026-02-18 17:37 -0300
1from typing import TYPE_CHECKING, Any
3import jmespath
5from dynamodx.keys import PrimaryKey, PrimaryKeySet
6from dynamodx.types import deserialize, serialize
8if TYPE_CHECKING:
9 from mypy_boto3_dynamodb.client import DynamoDBClient
10 from mypy_boto3_dynamodb.type_defs import GetTypeDef, TransactGetItemTypeDef
12else:
13 DynamoDBClient = Any
14 GetTypeDef = Any
15 TransactGetItemTypeDef = Any
18class TransactGet:
19 def __init__(
20 self,
21 table_name: str,
22 *,
23 client: DynamoDBClient,
24 ) -> None:
25 self._table_name = table_name
26 self._client = client
28 def get_items(
29 self,
30 keyset: PrimaryKeySet,
31 *,
32 flatten_top: bool = True,
33 ) -> dict[str, Any]:
34 """Get multiple items via a transaction based on the provided PrimaryKeySet.
36 Parameters
37 ----------
38 keyset : PrimaryKeySet
39 Primary keys of the items to fetch in the transaction.
41 flatten_top : bool, optional
42 Determines whether the first nested item in the transaction result
43 should be flattened,
45 i.e., extracted to serve as the primary item at the top level of
46 the returned dict.
48 If True, the nested item is promoted to the top level.
50 Returns
51 -------
52 dict[str, Any]
53 A dict of items retrieved from the transaction.
55 Notes
56 -----
57 Missing items are ignored and are not included in the returned dict.
58 The order of items follows the order defined in ``keyset.pairs``.
59 """
60 table_name = self._table_name
61 transact_items: list[TransactGetItemTypeDef] = [
62 _build_get(pk, table_name) for pk in keyset.pairs
63 ]
65 output = self._client.transact_get_items(TransactItems=transact_items)
66 items = [deserialize(r.get('Item', {})) for r in output.get('Responses', [])]
68 if flatten_top and items:
69 head, tail = items[0], items[1:]
70 else:
71 head, tail = {}, items
73 pairs = keyset.pairs[1:] if flatten_top else keyset.pairs
74 nested = {
75 _output_key(pk): project_item(pk, item)
76 for pk, item in zip(pairs, tail, strict=True)
77 if item
78 }
80 return {**head, **nested}
83def _build_get(pk: PrimaryKey, table_name: str) -> TransactGetItemTypeDef:
84 sk = pk[pk.name_sk]
85 attrs: GetTypeDef = {
86 'TableName': pk.table_name or table_name,
87 'Key': serialize(pk),
88 }
90 projection_expr = getattr(sk, 'projection_expr', None)
91 expr_attr_names = getattr(sk, 'expr_attr_names', None)
93 if projection_expr is not None:
94 attrs['ProjectionExpression'] = projection_expr
96 if expr_attr_names is not None:
97 attrs['ExpressionAttributeNames'] = expr_attr_names
99 return {'Get': attrs}
102def _output_key(pk: PrimaryKey) -> str:
103 sk = pk.sk
104 return str(getattr(sk, 'rename_key', sk))
107def project_item(pk: PrimaryKey, item: dict) -> dict:
108 path_spec = getattr(pk.sk, 'path_spec', None)
110 if path_spec is None:
111 return item
113 return jmespath.compile(path_spec).search(item)