import hashlib import logging from typing import Dict, List from service.tasks.analytics.services.cache import ( delete_cache, get_cached_result_json, update_cache_json, ) from service.utils.aws_connectors import run_query from .params import Param logger = logging.getLogger(__name__) ANALYTICS_CACHE_KEY_SALT = "49cd56a56ea370469b870a893a922188ad3d4d8466d2b44cd30880ddbb05eacbce153913d8f86dc7b51674c6308c4a07269c394a68bed35affa705bc7787fe8b".encode() class AnalyticsModuleInterface: inputs = [ Param("sort_list", list, required=False), Param("sort_column", str, required=False), ] outputs: List[Param] = [] def __init__(self, **kwargs): self.params = {} # the parameters in kwargs are taken from conf['inputs'] field by analytics.modules.get_am(conf), # this validation process ensures, that all required params would be present and # optional params would have their default values applied. for param in self.config_get_inputs(): self.params.update(param(kwargs)) @classmethod def config_get_inputs(cls) -> List[Param]: return AnalyticsModuleInterface.inputs + cls.inputs @classmethod def get_output_map(cls) -> Dict[str, Param]: return {param.name: param for param in cls.outputs} @classmethod def get_input_map(cls) -> Dict[str, Param]: return {param.name: param for param in cls.inputs} @classmethod def get_cache_key(cls, *args, **kwargs): cache_key_hash = hashlib.sha512(ANALYTICS_CACHE_KEY_SALT) cache_key_hash.update(cls.__name__.encode()) cache_key_hash.update(str(args).encode()) cache_key_hash.update(str(kwargs).encode()) return cache_key_hash.hexdigest() @staticmethod def get_query(*args, **kwargs): """Should return parametrized query string with named parameters as %(name)s""" return "" def get_result(self, recalculate=False, use_cache=True): cache_key = self.get_cache_key(**self.params) result = None if recalculate: delete_cache(cache_key, self.params["schema"]) elif use_cache: timestamp, result = get_cached_result_json(cache_key, self.params["schema"]) if result is None: query = self.get_query(**self.params) try: result = run_query(query, self.params) result = self._apply_sort_list(result) except Exception as e: logger.exception(f"Query: {query} :: Params: {self.params}") raise e if use_cache: timestamp, result = update_cache_json( cache_key, result, query, self.params, self.params["schema"] ) return result def _apply_sort_list(self, result): if "sort_list" in self.params and self.params["sort_list"]: idx = self.get_output_map()[self.params["sort_column"]].idx res = {row[idx]: row for row in result} return [res[val] for val in self.params["sort_list"] if val in res] else: return result def recalculate(self): pass @staticmethod def populate_attribute_ids(conf, available_fields_list): field_name = conf["inputs"]["field_name"] if field_name in available_fields_list: return {"attribute_id": available_fields_list.get(field_name, None)} return None