Enum Mapping PatternΒΆ
Demonstrates mapping between related enums using dictionary mapping with property access versus dataclass approaches
When you need to map between related enums (e.g., database object types to table types), use dictionary mapping with property access (pattern 1) rather than embedding values in dataclasses (pattern 2). This provides cleaner syntax (obj.table_type vs mapping[obj]), better flexibility for partial mappings, and maintains enum independence while offering convenient cross-references.
enum_mapping_pattern_1.py
1# -*- coding: utf-8 -*-
2
3"""
4Enum Mapping Pattern Example (recommended)
5
6This module demonstrates best practices for creating mappings between multiple enums.
7We explore a scenario where we have two enums with values that need to be mapped to each other.
8
9Example Use Case:
10
11We have a DatabaseObject enum and a TableType enum. DatabaseObject represents database entities
12(schemas, databases, tables, views) with descriptive names, while TableType has encoded names
13suitable for programming contexts (e.g., "materialized view" becomes "MaterializedView" to
14avoid spaces in identifiers).
15
16Two Approaches Considered:
17
181. Dictionary Mapping with Property Access (Implemented):
19 - Define separate enums for DatabaseObject and TableType
20 - Create a dictionary mapping between them
21 - Add a property to the enum class for convenient access
22 - Benefits: Easy to use, no need to import mapping dictionary or TableType enum
23 - Usage: database_obj.table_type instead of mapping[database_obj]
24
252. Tuple-based DataClass (Not Implemented):
26 - Define a single dataclass containing both enum values as fields
27 - Benefits: Guaranteed consistency between related values
28 - Drawbacks: Less flexible, can't iterate over individual enum types separately
29 - Not suitable for cases where not all values have mappings (e.g., database has no TableType)
30
31This example focuses on approach #1 as it provides better flexibility and ease of use
32for our specific requirements.
33"""
34
35from enum_mate.api import BetterStrEnum
36
37
38class DbObjectTypeEnum(BetterStrEnum):
39 database = "database"
40 table = "table"
41 view = "view"
42 materialized_view = "materialized view"
43
44 @property
45 def table_type(self) -> "TableTypeEnum":
46 return db_obj_type_to_table_type_mapping[self]
47
48
49class TableTypeEnum(BetterStrEnum):
50 Table = "Table"
51 View = "View"
52 MaterializedView = "MaterializedView"
53
54
55db_obj_type_to_table_type_mapping = {
56 DbObjectTypeEnum.table: TableTypeEnum.Table,
57 DbObjectTypeEnum.view: TableTypeEnum.View,
58 DbObjectTypeEnum.materialized_view: TableTypeEnum.MaterializedView,
59}
60
61if __name__ == "__main__":
62 print(f"{DbObjectTypeEnum.table.table_type.value = }")
63 print(f"{DbObjectTypeEnum.database.table_type.value = }")
enum_mapping_pattern_2.py
1# -*- coding: utf-8 -*-
2
3"""
4Enum Mapping Pattern Example 2 (Not recommended)
5"""
6
7import enum
8import typing as T
9import dataclasses
10from enum_mate.api import EnumMixin
11
12
13@dataclasses.dataclass
14class DbObject:
15 type: str = dataclasses.field()
16 table_type: T.Optional[str] = dataclasses.field()
17
18 def __hash__(self):
19 return hash(self.type)
20
21
22class DbObjectTypeEnum(EnumMixin, enum.Enum):
23 # fmt: off
24 database = DbObject(type="database", table_type=None)
25 table = DbObject(type="table", table_type="Table")
26 view = DbObject(type="view", table_type="View")
27 materialized_view = DbObject(type="materialized_view", table_type="MaterializedView")
28 # fmt: on
29
30
31if __name__ == "__main__":
32 print(f"{DbObjectTypeEnum.table.value = }")
33 print(f"{DbObjectTypeEnum.table.value.table_type = }")