import copy from functools import wraps from typing import Dict, List, Optional import requests from service.utils.aws_connectors import run_query def chunks(lst, n): """Yield successive n-sized chunks from lst.""" for i in range(0, len(lst), n): end = i + n yield lst[i:end] class ServiceRequestsHandler: base_path: Optional[str] = None def make_request( self, method, endpoint, json_response=True, base_path=None, **kwargs ): endpoint = (base_path or self.base_path) + endpoint if method not in ["POST", "GET", "DELETE"]: raise RuntimeError(f"Unsupported method provided - {method}") if method == "GET": response = requests.get(url=endpoint, **kwargs) elif method == "POST": headers = {"content-type": "application/json", "accept": "application/json"} kwargs["headers"] = kwargs.get("headers", {}) for key in headers: kwargs["headers"][key] = kwargs["headers"].get(key, headers[key]) response = requests.request(method="POST", url=endpoint, **kwargs) else: raise RuntimeError(f"Unsupported method provided - {method}") if json_response: return {"data": response.json(), "headers": response.headers} else: return {"data": response.text, "headers": response.headers} class ServiceDbHandler: @staticmethod def list_of_dicts_to_db_safe( schema, table_name, data: List[dict], return_all=False ): """Inserts the list of dicts in to provided table -- It expects the structure of dicts to be consistent through entire list -- It expects dict has the same name as table columns """ data_copy = copy.deepcopy(data) insert_fields = '("' + '", "'.join([key for key in data_copy[0]]) + '")' insert_values_list = [] params = {} for index, row in enumerate(data_copy): insert_values_list.append( "(" + ", ".join(["%(" + key + str(index) + ")s" for key in row]) + ")" ) for key in row: final_key = key + str(index) params[final_key] = row[key] insert_values = ", ".join(insert_values_list) if return_all: return_statement = "RETURNING *" else: return_statement = "" query = f""" INSERT INTO {schema}.{table_name} {insert_fields} VALUES {insert_values} {return_statement}; """ df = run_query(query, params, return_type="df") return df result_fields_mapping = { "collection_id": "collectionId", "shared_with": "sharedWith", "parent_id": "parentId", "timestamp_created": "timestampCreated", "timestamp_last_updated": "timestampUpdated", "timestamp_updated": "timestampUpdated", "granted_scopes": "grantedScopes", "person_count": "personCount", "list_type": "listType", "shared_status": "sharedStatus", "business_id": "businessId", "business_name": "businessName", "adaccount_id": "adaccountId", } def field_mapper(func): """Expects the result to be either dict or list of dicts""" @wraps(func) def wrapper(*args, **kwargs): result = func(*args, **kwargs) if isinstance(result, list): lst = [] for i in result: lst.append(_update_dict(i, result_fields_mapping)) return lst elif isinstance(result, dict): return _update_dict(result, result_fields_mapping) else: return result return wrapper def _update_dict(d: Dict, mapping_set: dict): """Recurcively goes through every element of mapping""" result_dict = dict() keys_to_map = mapping_set.keys() if not isinstance(d, dict): """If provided d is not a dict but a single value for example 'str' or `int`""" result_dict = d else: for key, value in d.items(): if isinstance(value, dict): result = _update_dict(value, mapping_set) if key in keys_to_map: result_dict[mapping_set[key]] = result else: result_dict[key] = result elif isinstance(value, list): result = [] for i in value: result.append(_update_dict(i, mapping_set)) if key in keys_to_map: result_dict[mapping_set[key]] = result else: result_dict[key] = result else: if key in keys_to_map: result_dict[mapping_set[key]] = value else: result_dict[key] = value """Replacinge field with the mapped one""" return result_dict def flatten_json(y): """Recurcively flattning the dictionary""" out = {} def flatten(x, name=""): if type(x) is dict: for a in x: flatten(x[a], name + a + ".") elif type(x) is list: i = 0 for a in x: flatten(a, name + str(i) + ".") i += 1 else: out[name[:-1]] = x flatten(y) return out