Skip to content

Commit a4c783f

Browse files
suseriAtlanclaude
andcommitted
feat(assets): add DynamoDBAttribute asset class
Add DynamoDBAttribute(Column) to support DynamoDB column-level assets, matching the new type definition in the models repo with superTypes ["DynamoDB", "Column"] and the dynamo_db_table_dynamo_db_columns containment relationship. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 09ad9fb commit a4c783f

File tree

4 files changed

+471
-0
lines changed

4 files changed

+471
-0
lines changed

pyatlan/model/assets/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@
430430
"azure_event_hub_consumer_group": ["AzureEventHubConsumerGroup"],
431431
"dynamo_d_b_local_secondary_index": ["DynamoDBLocalSecondaryIndex"],
432432
"dynamo_d_b_global_secondary_index": ["DynamoDBGlobalSecondaryIndex"],
433+
"dynamo_d_b_attribute": ["DynamoDBAttribute"],
433434
}
434435

435436
lazy_loader = lazy.attach(__name__, submod_attrs=__PYATLAN_ASSETS__)
Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
# Copyright 2025 Atlan Pte. Ltd.
3+
4+
5+
from __future__ import annotations
6+
7+
from typing import ClassVar, List, Optional
8+
9+
from pydantic.v1 import Field, validator
10+
11+
from pyatlan.model.enums import AtlanConnectorType, DynamoDBStatus
12+
from pyatlan.model.fields.atlan_fields import (
13+
KeywordField,
14+
NumericField,
15+
RelationField,
16+
TextField,
17+
)
18+
from pyatlan.utils import init_guid, validate_required_fields
19+
20+
from .core.column import Column
21+
22+
23+
class DynamoDBAttribute(Column):
24+
"""Description"""
25+
26+
@classmethod
27+
@init_guid
28+
def creator(
29+
cls,
30+
*,
31+
name: str,
32+
parent_qualified_name: str,
33+
order: int,
34+
parent_name: Optional[str] = None,
35+
connection_qualified_name: Optional[str] = None,
36+
) -> DynamoDBAttribute:
37+
"""
38+
Builds the minimal object necessary to create a DynamoDBAttribute.
39+
40+
:param name: name of the DynamoDBAttribute
41+
:param parent_qualified_name: unique name of the DynamoDBTable
42+
in which this attribute exists
43+
:param order: the order the attribute appears within its parent
44+
:param parent_name: simple name of the DynamoDBTable
45+
in which the attribute is contained
46+
:param connection_qualified_name: unique name of the connection
47+
in which the attribute should be created
48+
:returns: the minimal request necessary to create the DynamoDBAttribute
49+
"""
50+
return DynamoDBAttribute(
51+
attributes=DynamoDBAttribute.Attributes.create(
52+
name=name,
53+
parent_qualified_name=parent_qualified_name,
54+
order=order,
55+
parent_name=parent_name,
56+
connection_qualified_name=connection_qualified_name,
57+
)
58+
)
59+
60+
type_name: str = Field(default="DynamoDBAttribute", allow_mutation=False)
61+
62+
@validator("type_name")
63+
def validate_type_name(cls, v):
64+
if v != "DynamoDBAttribute":
65+
raise ValueError("must be DynamoDBAttribute")
66+
return v
67+
68+
def __setattr__(self, name, value):
69+
if name in DynamoDBAttribute._convenience_properties:
70+
return object.__setattr__(self, name, value)
71+
super().__setattr__(name, value)
72+
73+
DYNAMO_DB_STATUS: ClassVar[KeywordField] = KeywordField(
74+
"dynamoDBStatus", "dynamoDBStatus"
75+
)
76+
"""
77+
Status of the DynamoDB Asset
78+
"""
79+
DYNAMO_DB_PARTITION_KEY: ClassVar[KeywordField] = KeywordField(
80+
"dynamoDBPartitionKey", "dynamoDBPartitionKey"
81+
)
82+
"""
83+
Specifies the partition key of the DynamoDB Table/Index
84+
"""
85+
DYNAMO_DB_SORT_KEY: ClassVar[KeywordField] = KeywordField(
86+
"dynamoDBSortKey", "dynamoDBSortKey"
87+
)
88+
"""
89+
Specifies the sort key of the DynamoDB Table/Index
90+
"""
91+
DYNAMO_DB_READ_CAPACITY_UNITS: ClassVar[NumericField] = NumericField(
92+
"dynamoDBReadCapacityUnits", "dynamoDBReadCapacityUnits"
93+
)
94+
"""
95+
The maximum number of strongly consistent reads consumed per second before DynamoDB returns a ThrottlingException
96+
"""
97+
DYNAMO_DB_WRITE_CAPACITY_UNITS: ClassVar[NumericField] = NumericField(
98+
"dynamoDBWriteCapacityUnits", "dynamoDBWriteCapacityUnits"
99+
)
100+
"""
101+
The maximum number of writes consumed per second before DynamoDB returns a ThrottlingException
102+
"""
103+
NO_SQL_SCHEMA_DEFINITION: ClassVar[TextField] = TextField(
104+
"noSQLSchemaDefinition", "noSQLSchemaDefinition"
105+
)
106+
"""
107+
Represents attributes for describing the key schema for the table and indexes.
108+
"""
109+
110+
DYNAMO_DB_TABLE: ClassVar[RelationField] = RelationField("dynamoDBTable")
111+
"""
112+
TBC
113+
"""
114+
115+
_convenience_properties: ClassVar[List[str]] = [
116+
"dynamo_d_b_status",
117+
"dynamo_d_b_partition_key",
118+
"dynamo_d_b_sort_key",
119+
"dynamo_d_b_read_capacity_units",
120+
"dynamo_d_b_write_capacity_units",
121+
"no_s_q_l_schema_definition",
122+
"dynamo_dbtable",
123+
]
124+
125+
@property
126+
def dynamo_d_b_status(self) -> Optional[DynamoDBStatus]:
127+
return None if self.attributes is None else self.attributes.dynamo_d_b_status
128+
129+
@dynamo_d_b_status.setter
130+
def dynamo_d_b_status(self, dynamo_d_b_status: Optional[DynamoDBStatus]):
131+
if self.attributes is None:
132+
self.attributes = self.Attributes()
133+
self.attributes.dynamo_d_b_status = dynamo_d_b_status
134+
135+
@property
136+
def dynamo_d_b_partition_key(self) -> Optional[str]:
137+
return (
138+
None if self.attributes is None else self.attributes.dynamo_d_b_partition_key
139+
)
140+
141+
@dynamo_d_b_partition_key.setter
142+
def dynamo_d_b_partition_key(self, dynamo_d_b_partition_key: Optional[str]):
143+
if self.attributes is None:
144+
self.attributes = self.Attributes()
145+
self.attributes.dynamo_d_b_partition_key = dynamo_d_b_partition_key
146+
147+
@property
148+
def dynamo_d_b_sort_key(self) -> Optional[str]:
149+
return None if self.attributes is None else self.attributes.dynamo_d_b_sort_key
150+
151+
@dynamo_d_b_sort_key.setter
152+
def dynamo_d_b_sort_key(self, dynamo_d_b_sort_key: Optional[str]):
153+
if self.attributes is None:
154+
self.attributes = self.Attributes()
155+
self.attributes.dynamo_d_b_sort_key = dynamo_d_b_sort_key
156+
157+
@property
158+
def dynamo_d_b_read_capacity_units(self) -> Optional[int]:
159+
return (
160+
None
161+
if self.attributes is None
162+
else self.attributes.dynamo_d_b_read_capacity_units
163+
)
164+
165+
@dynamo_d_b_read_capacity_units.setter
166+
def dynamo_d_b_read_capacity_units(
167+
self, dynamo_d_b_read_capacity_units: Optional[int]
168+
):
169+
if self.attributes is None:
170+
self.attributes = self.Attributes()
171+
self.attributes.dynamo_d_b_read_capacity_units = dynamo_d_b_read_capacity_units
172+
173+
@property
174+
def dynamo_d_b_write_capacity_units(self) -> Optional[int]:
175+
return (
176+
None
177+
if self.attributes is None
178+
else self.attributes.dynamo_d_b_write_capacity_units
179+
)
180+
181+
@dynamo_d_b_write_capacity_units.setter
182+
def dynamo_d_b_write_capacity_units(
183+
self, dynamo_d_b_write_capacity_units: Optional[int]
184+
):
185+
if self.attributes is None:
186+
self.attributes = self.Attributes()
187+
self.attributes.dynamo_d_b_write_capacity_units = (
188+
dynamo_d_b_write_capacity_units
189+
)
190+
191+
@property
192+
def no_s_q_l_schema_definition(self) -> Optional[str]:
193+
return (
194+
None
195+
if self.attributes is None
196+
else self.attributes.no_s_q_l_schema_definition
197+
)
198+
199+
@no_s_q_l_schema_definition.setter
200+
def no_s_q_l_schema_definition(self, no_s_q_l_schema_definition: Optional[str]):
201+
if self.attributes is None:
202+
self.attributes = self.Attributes()
203+
self.attributes.no_s_q_l_schema_definition = no_s_q_l_schema_definition
204+
205+
@property
206+
def dynamo_dbtable(self) -> Optional[DynamoDBTable]:
207+
return None if self.attributes is None else self.attributes.dynamo_dbtable
208+
209+
@dynamo_dbtable.setter
210+
def dynamo_dbtable(self, dynamo_dbtable: Optional[DynamoDBTable]):
211+
if self.attributes is None:
212+
self.attributes = self.Attributes()
213+
self.attributes.dynamo_dbtable = dynamo_dbtable
214+
215+
class Attributes(Column.Attributes):
216+
dynamo_d_b_status: Optional[DynamoDBStatus] = Field(
217+
default=None, description=""
218+
)
219+
dynamo_d_b_partition_key: Optional[str] = Field(default=None, description="")
220+
dynamo_d_b_sort_key: Optional[str] = Field(default=None, description="")
221+
dynamo_d_b_read_capacity_units: Optional[int] = Field(
222+
default=None, description=""
223+
)
224+
dynamo_d_b_write_capacity_units: Optional[int] = Field(
225+
default=None, description=""
226+
)
227+
no_s_q_l_schema_definition: Optional[str] = Field(
228+
default=None, description=""
229+
)
230+
dynamo_dbtable: Optional[DynamoDBTable] = Field(
231+
default=None, description=""
232+
) # relationship
233+
234+
@classmethod
235+
@init_guid
236+
def create(
237+
cls,
238+
*,
239+
name: str,
240+
parent_qualified_name: str,
241+
order: int,
242+
parent_name: Optional[str] = None,
243+
connection_qualified_name: Optional[str] = None,
244+
) -> DynamoDBAttribute.Attributes:
245+
"""
246+
Builds the minimal object necessary to create a DynamoDBAttribute.
247+
248+
:param name: name of the DynamoDBAttribute
249+
:param parent_qualified_name: unique name of the DynamoDBTable
250+
in which this attribute exists
251+
:param order: the order the attribute appears within its parent
252+
:param parent_name: simple name of the DynamoDBTable
253+
in which the attribute is contained
254+
:param connection_qualified_name: unique name of the connection
255+
in which the attribute should be created
256+
:returns: the minimal request necessary to create the DynamoDBAttribute
257+
"""
258+
validate_required_fields(
259+
["name", "parent_qualified_name", "order"],
260+
[name, parent_qualified_name, order],
261+
)
262+
if connection_qualified_name:
263+
connector_name = AtlanConnectorType.get_connector_name(
264+
connection_qualified_name
265+
)
266+
else:
267+
connection_qn, connector_name = AtlanConnectorType.get_connector_name(
268+
parent_qualified_name, "parent_qualified_name", 4
269+
)
270+
if order < 0:
271+
raise ValueError("Order must be be a positive integer")
272+
273+
fields = parent_qualified_name.split("/")
274+
qualified_name = f"{parent_qualified_name}/{name}"
275+
connection_qualified_name = connection_qualified_name or connection_qn
276+
parent_name = parent_name or fields[3]
277+
278+
return DynamoDBAttribute.Attributes(
279+
name=name,
280+
order=order,
281+
qualified_name=qualified_name,
282+
connector_name=connector_name,
283+
connection_qualified_name=connection_qualified_name,
284+
table_name=parent_name,
285+
table_qualified_name=parent_qualified_name,
286+
dynamo_dbtable=DynamoDBTable.ref_by_qualified_name(
287+
parent_qualified_name
288+
),
289+
)
290+
291+
attributes: DynamoDBAttribute.Attributes = Field(
292+
default_factory=lambda: DynamoDBAttribute.Attributes(),
293+
description=(
294+
"Map of attributes in the instance and their values. "
295+
"The specific keys of this map will vary by type, "
296+
"so are described in the sub-types of this schema."
297+
),
298+
)
299+
300+
301+
from .dynamo_dbtable import DynamoDBTable # noqa: E402, F401
302+
303+
DynamoDBAttribute.Attributes.update_forward_refs()

pyatlan/model/assets/dynamo_dbtable.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,10 @@ def __setattr__(self, name, value):
347347
"""
348348
TBC
349349
"""
350+
DYNAMO_DB_COLUMNS: ClassVar[RelationField] = RelationField("dynamoDBColumns")
351+
"""
352+
TBC
353+
"""
350354

351355
_convenience_properties: ClassVar[List[str]] = [
352356
"dynamo_dbtable_g_s_i_count",
@@ -404,6 +408,7 @@ def __setattr__(self, name, value):
404408
"no_s_q_l_schema_definition",
405409
"dynamo_d_b_local_secondary_indexes",
406410
"dynamo_d_b_global_secondary_indexes",
411+
"dynamo_d_b_columns",
407412
]
408413

409414
@property
@@ -1068,6 +1073,25 @@ def dynamo_d_b_global_secondary_indexes(
10681073
dynamo_d_b_global_secondary_indexes
10691074
)
10701075

1076+
@property
1077+
def dynamo_d_b_columns(
1078+
self,
1079+
) -> Optional[List[DynamoDBAttribute]]:
1080+
return (
1081+
None
1082+
if self.attributes is None
1083+
else self.attributes.dynamo_d_b_columns
1084+
)
1085+
1086+
@dynamo_d_b_columns.setter
1087+
def dynamo_d_b_columns(
1088+
self,
1089+
dynamo_d_b_columns: Optional[List[DynamoDBAttribute]],
1090+
):
1091+
if self.attributes is None:
1092+
self.attributes = self.Attributes()
1093+
self.attributes.dynamo_d_b_columns = dynamo_d_b_columns
1094+
10711095
class Attributes(Table.Attributes):
10721096
dynamo_dbtable_g_s_i_count: Optional[int] = Field(default=None, description="")
10731097
dynamo_dbtable_l_s_i_count: Optional[int] = Field(default=None, description="")
@@ -1144,6 +1168,9 @@ class Attributes(Table.Attributes):
11441168
dynamo_d_b_global_secondary_indexes: Optional[
11451169
List[DynamoDBGlobalSecondaryIndex]
11461170
] = Field(default=None, description="") # relationship
1171+
dynamo_d_b_columns: Optional[List[DynamoDBAttribute]] = Field(
1172+
default=None, description=""
1173+
) # relationship
11471174

11481175
attributes: DynamoDBTable.Attributes = Field(
11491176
default_factory=lambda: DynamoDBTable.Attributes(),
@@ -1155,6 +1182,7 @@ class Attributes(Table.Attributes):
11551182
)
11561183

11571184

1185+
from .dynamo_d_b_attribute import DynamoDBAttribute # noqa: E402, F401
11581186
from .dynamo_d_b_global_secondary_index import (
11591187
DynamoDBGlobalSecondaryIndex, # noqa: E402, F401
11601188
)

0 commit comments

Comments
 (0)