|
8 | 8 | from decimal import Decimal |
9 | 9 | from typing import Any, Dict, Generic, List, Optional, Tuple, TypeVar |
10 | 10 |
|
| 11 | +from dateutil.relativedelta import relativedelta |
| 12 | + |
11 | 13 | if sys.version_info >= (3, 9): |
12 | 14 | from zoneinfo import ZoneInfo |
13 | 15 | else: |
@@ -172,6 +174,33 @@ def _fraction_to_decimal(fractional_str: str) -> Decimal: |
172 | 174 | return Decimal(fractional_str or 0) / POWERS_OF_TEN[len(fractional_str)] |
173 | 175 |
|
174 | 176 |
|
| 177 | +class IntervalYearToMonthMapper(ValueMapper[relativedelta]): |
| 178 | + def map(self, value: Any) -> Optional[relativedelta]: |
| 179 | + if value is None: |
| 180 | + return None |
| 181 | + is_negative = value[0] == "-" |
| 182 | + years, months = (value[1:] if is_negative else value).split('-') |
| 183 | + years, months = int(years), int(months) |
| 184 | + if is_negative: |
| 185 | + years, months = -years, -months |
| 186 | + return relativedelta(years=years, months=months) |
| 187 | + |
| 188 | + |
| 189 | +class IntervalDayToSecondMapper(ValueMapper[timedelta]): |
| 190 | + def map(self, value: Any) -> Optional[timedelta]: |
| 191 | + if value is None: |
| 192 | + return None |
| 193 | + is_negative = value[0] == "-" |
| 194 | + days, time = (value[1:] if is_negative else value).split(' ') |
| 195 | + hours, minutes, seconds_milliseconds = time.split(':') |
| 196 | + seconds, milliseconds = seconds_milliseconds.split('.') |
| 197 | + days, hours, minutes, seconds, milliseconds = (int(days), int(hours), int(minutes), int(seconds), |
| 198 | + int(milliseconds)) |
| 199 | + if is_negative: |
| 200 | + days, hours, minutes, seconds, milliseconds = -days, -hours, -minutes, -seconds, -milliseconds |
| 201 | + return timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds, milliseconds=milliseconds) |
| 202 | + |
| 203 | + |
175 | 204 | class ArrayValueMapper(ValueMapper[List[Optional[Any]]]): |
176 | 205 | def __init__(self, mapper: ValueMapper[Any]): |
177 | 206 | self.mapper = mapper |
@@ -276,6 +305,10 @@ def _create_value_mapper(self, column: Dict[str, Any]) -> ValueMapper[Any]: |
276 | 305 | return TimestampValueMapper(self._get_precision(column)) |
277 | 306 | if col_type == 'timestamp with time zone': |
278 | 307 | return TimestampWithTimeZoneValueMapper(self._get_precision(column)) |
| 308 | + if col_type == 'interval year to month': |
| 309 | + return IntervalYearToMonthMapper() |
| 310 | + if col_type == 'interval day to second': |
| 311 | + return IntervalDayToSecondMapper() |
279 | 312 |
|
280 | 313 | # structural types |
281 | 314 | if col_type == 'array': |
|
0 commit comments