etlt.dimension.Type2ReferenceDimension   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 124
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
eloc 43
dl 0
loc 124
ccs 0
cts 37
cp 0
rs 10
c 0
b 0
f 0
wmc 14

6 Methods

Rating   Name   Duplication   Size   Complexity  
A Type2ReferenceDimension.post_call_stored_procedure() 0 10 1
A Type2ReferenceDimension.__init__() 0 27 1
C Type2ReferenceDimension.get_id() 0 42 9
A Type2ReferenceDimension.pre_call_stored_procedure() 0 7 1
A Type2ReferenceDimension.call_stored_procedure() 0 11 1
A Type2ReferenceDimension.pre_load_data() 0 5 1
1
import abc
2
import datetime
3
from typing import Any, Dict, List, Optional
4
5
6
class Type2ReferenceDimension(metaclass=abc.ABCMeta):
7
    """
8
    Abstract class for type2 dimensions for which the reference data is supplied with date intervals.
9
    """
10
11
    # ------------------------------------------------------------------------------------------------------------------
12
    def __init__(self):
13
        """
14
        Object constructor.
15
        """
16
17
        self._key_key: str = ''
18
        """
19
        The key in the dict returned by call_stored_procedure holding the technical ID.
20
        """
21
22
        self._key_date_start: str = ''
23
        """
24
        The key in the dict returned by call_stored_procedure holding the start date.
25
        """
26
27
        self._key_date_end: str = ''
28
        """
29
        The key in the dict returned by call_stored_procedure holding the end date.
30
        """
31
32
        self._map: Dict[Any, List[Any]] = {}
33
        """
34
        The map from natural keys to lists of tuples with start date, end date, and technical keys. The dates must be in
35
        ISO 8601 (YYYY-MM-DD) format.
36
        """
37
38
        self.pre_load_data()
39
40
    # ------------------------------------------------------------------------------------------------------------------
41
    def get_id(self, natural_key: Any, date: str, enhancement: Any = None) -> Optional[int]:
42
        """
43
        Returns the technical ID for a natural key at a date or None if the given natural key is not valid.
44
45
        :param natural_key: The natural key.
46
        :param date: The date in ISO 8601 (YYYY-MM-DD) format.
47
        :param enhancement: Enhancement data of the dimension row.
48
        """
49
        if not date:
50
            return None
51
52
        # If the natural key is known return the technical ID immediately.
53
        if natural_key in self._map:
54
            for row in self._map[natural_key]:
55
                if row[0] <= date <= row[1]:
56
                    return row[2]
57
58
        # The natural key is not in the map of this dimension. Call a stored procedure for translating the natural key
59
        # to a technical key.
60
        self.pre_call_stored_procedure()
61
        success = False
62
        try:
63
            row = self.call_stored_procedure(natural_key, date, enhancement)
64
            # Convert dates to strings in ISO 8601 format.
65
            if isinstance(row[self._key_date_start], datetime.date):
66
                row[self._key_date_start] = row[self._key_date_start].isoformat()
67
            if isinstance(row[self._key_date_end], datetime.date):
68
                row[self._key_date_end] = row[self._key_date_end].isoformat()
69
            success = True
70
        finally:
71
            self.post_call_stored_procedure(success)
72
73
        # Make sure the natural key is in the map.
74
        if natural_key not in self._map:
75
            self._map[natural_key] = []
76
77
        if row[self._key_key]:
78
            self._map[natural_key].append((row[self._key_date_start], row[self._key_date_end], row[self._key_key]))
79
        else:
80
            self._map[natural_key].append((date, date, None))
81
82
        return row[self._key_key]
83
84
    # ------------------------------------------------------------------------------------------------------------------
85
    @abc.abstractmethod
86
    def call_stored_procedure(self, natural_key: Any, date: str, enhancement: Any) -> Dict[str, Any]:
87
        """
88
        Call a stored procedure for getting the technical key of a natural key at a date. Returns the technical ID or
89
        None if the given natural key is not valid.
90
91
        :param natural_key: The natural key.
92
        :param date: The date in ISO 8601 (YYYY-MM-DD) format.
93
        :param enhancement: Enhancement data of the dimension row.
94
        """
95
        raise NotImplementedError()
96
97
    # ------------------------------------------------------------------------------------------------------------------
98
    def pre_load_data(self) -> None:
99
        """
100
        Can be overridden to preload lookup data from a dimension table.
101
        """
102
        pass
103
104
    # ------------------------------------------------------------------------------------------------------------------
105
    def pre_call_stored_procedure(self) -> None:
106
        """
107
        This method is invoked before call the stored procedure for getting the technical key of a natural key.
108
109
        In a concurrent environment override this method to acquire a lock on the dimension or dimension hierarchy.
110
        """
111
        pass
112
113
    # ------------------------------------------------------------------------------------------------------------------
114
    def post_call_stored_procedure(self, success: bool) -> None:
115
        """
116
        This method is invoked after calling the stored procedure for getting the technical key of a natural key.
117
118
        In a concurrent environment override this method to release a lock on the dimension or dimension hierarchy and
119
        to commit or rollback the transaction.
120
121
        :param success: True: the stored procedure is executed successfully. False: an exception has occurred.
122
        """
123
        pass
124
125
# ----------------------------------------------------------------------------------------------------------------------
126