import logging from service.async_task_manager import io_task from service.tasks.analytics.modules import get_am from service.utils.data_model_utils import get_attribute_id from .param_handlers import finalize_param, get_param_handler logger = logging.getLogger(__name__) class Filter: """renders filter from filterconf and optionally adding values""" def __init__(self, conf, schema, values=None, recalculate=False): self.conf = conf self.schema = schema self.values = values self._validated = False self.am = None self._options_task = None self._params = {} self._make_params(recalculate=recalculate) inputs = self.conf.setdefault("inputs", {}) inputs["schema"] = self.schema if "attribute_name" in self.conf: inputs["attribute_id"] = get_attribute_id( schema, self.conf["attribute_name"] ) def json_for_appsync(self): return { "id": self.conf["fid"], "type": self.conf["type"], "label": self.conf["name"], "options": self.get_options(), } def extra_sql_fragments(self, schema, set_collection_ids_for_values): return {} def fragment_sql(self, schema, parent_collection_join, context): sql_condition = self.sql_condition(context) return ( f"SELECT DISTINCT fa.fan_id FROM {schema}.fan_attribute fa " f"{parent_collection_join}" f"WHERE {sql_condition}" ) def sql_condition(self, context): """:argument context SQL context to be used with sql.Literal, if needed""" raise NotImplementedError @io_task def _prepare_options(self, **kwargs): """retrieve values for options building""" return self._do_options() def _do_options(self): """Override this fot filter specific option making""" self.am = get_am(self.conf) return self.am.get_result(use_cache=False) def _make_params(self, recalculate=False): if "params" in self.conf: for name, param_conf in self.conf["params"].items(): self._params[name] = self._get_param(param_conf) def _get_param(self, param_conf, recalculate=False): param_type = param_conf.get("type", None) return get_param_handler(param_type)( param_conf, self.schema, recalculate=recalculate ) def get_param(self, name): return finalize_param(self._params[name]) def prepare_options(self): """Could also be overridden, if the io_task is not necessary""" if self._options_task is None: self._options_task = self._prepare_options() return self def get_options(self): self.prepare_options() return self._options_task.wait_for_result() def validate(self): raise RuntimeError( f"Filter validation error: {self.conf['name']} with invalid value" ) def has_values(self): return bool(self.values) def wait_for_done(self): for param in self._params: try: self.get_param(param) except Exception as e: logger.exception(e) return True