import datetime from typing import List, Tuple from wow_token.db.cached_range import CachedRange from wow_token.db.compacted import Compacted from wow_token.db.recent import Recent from wow_token.db.trinity import Trinity from wow_token.flavor import Flavor from wow_token.path_handler.relative_error import InvalidRelativePathError from wow_token.region import Region class RelativePathHandler: _cdb : Compacted _rdb : Recent def __init__(self, cdb: Compacted, rdb: Recent): self._cdb = cdb self._rdb = rdb def get_by_timedelta(self, flavor: Flavor, region: Region, timedelta: datetime.timedelta) -> List[Tuple[str, int]]: current_time = datetime.datetime.now(datetime.UTC) start_time = current_time - timedelta if timedelta.days < 61: return self._rdb.get_after_unix_timestamp(flavor, region, int(start_time.timestamp())) elif timedelta.days <= 90: trinity = Trinity(region, flavor, CachedRange('90d')) elif timedelta.days <= 183: trinity = Trinity(region, flavor, CachedRange('6m')) elif timedelta.days <= 365: trinity = Trinity(region, flavor, CachedRange('1y')) elif timedelta.days <= 730: trinity = Trinity(region, flavor, CachedRange('2y')) else: trinity = Trinity(region, flavor, CachedRange('all')) # If the data is exactly the size of the precomputed structure, go ahead and return it directly if timedelta.days == 90 or timedelta.days == 182 or timedelta.days == 365 or timedelta.days == 730: return self._cdb.get_precomputed_range(trinity, str) final_data = [] data = self._cdb.get_precomputed_range(trinity) for timestamp, price in data: if timestamp >= start_time: final_data.append((timestamp.isoformat(), price)) return final_data def relative_time_handler(self, flavor: Flavor, region: Region, relative_range: str) -> List[Tuple[str, int]]: if relative_range == '30d': relative_range = '744h' relative_unit = relative_range[-1] match relative_unit: case 'h': hours = int(relative_range[:-1]) if hours > 1488: raise InvalidRelativePathError start_time = datetime.datetime.now(datetime.UTC) - datetime.timedelta(hours=hours) return self._rdb.get_after_unix_timestamp(flavor, region, int(start_time.timestamp())) case 'd': days = int(relative_range[:-1]) if days > 730: raise InvalidRelativePathError delta = datetime.timedelta(days=days) return self.get_by_timedelta(flavor, region, delta) case 'm': months = int(relative_range[:-1]) if months > 48: raise InvalidRelativePathError delta = datetime.timedelta(days=int(30.437*months)) return self.get_by_timedelta(flavor, region, delta) case 'y': years = int(relative_range[:-1]) if years > 10: raise InvalidRelativePathError delta = datetime.timedelta(days=int(365.25*years)) return self.get_by_timedelta(flavor, region, delta) case _: if relative_range == 'all': return self._cdb.get_precomputed_range(Trinity(region, flavor, CachedRange('all')), str) raise InvalidRelativePathError def path_handler(self, uri) -> List[Tuple[str, int]]: # This URI takes the form of /v2/relative/{flavor}/{region}/{range} split_uri = uri.split('/') flavor = Flavor(split_uri[-3]) region = Region(split_uri[-2]) _range = split_uri[-1] if split_uri[-1].endswith('.json'): _range = split_uri[-1][:-5] return self.relative_time_handler(flavor, region, _range)