from glom import glom from typing import Any, Dict, Iterable, List, Optional, Tuple from server.constants.messages import MessageErrorType, MessageUniqueCheckError def prepare_request_bulk_data( items_list: List[dict], failed_items_list: List[dict] = None, extra_data: Optional[dict] = None, check_unique_key: Optional[str] = None, ) -> Tuple[Dict[int, dict], List[dict], Dict[Any, int]]: valid_index_to_item_map, unique_value_to_index_map = {}, {} failed_items_list = [] if failed_items_list is None else failed_items_list for item in items_list: index, data = item.pop("index"), item.pop("data") for k, v in (extra_data or {}).items(): data[k] = v if check_unique_key: error_type = None v = glom(data, check_unique_key, default=None) if not v: error_type = MessageUniqueCheckError.NO_CHECK_VALUE elif v in unique_value_to_index_map: error_type = MessageUniqueCheckError.DUPLICATED_REQUEST_DATA if error_type: failed_items_list.append( unique_check_failed_item(index=index, key=check_unique_key, value=v, error_type=error_type) ) continue unique_value_to_index_map[v] = index valid_index_to_item_map[index] = data return valid_index_to_item_map, failed_items_list, unique_value_to_index_map def prepare_response_bulk_data( obj_list: List[object], passed_attrs: Iterable[str], index_list: List[int], id_to_error: Optional[Dict[int, dict]] = None, id_attr_name: str = "id", ) -> Tuple[List[dict], List[dict]]: """Format model objects to dicts and extend them with indexes from the original data collection (if passed). Return two collections with succeed and failed items. Args: obj_list: list of model instances. passed_attrs: iterable of model attribute names to be only passed to the result. index_list: list of the indexes in the original data: original_index(obj_list[i]) = index_list[i] id_to_error: map of message ids to corresponding message's error. id_attr_name: id data key. """ ok_items, failed_items = [], [] for i, obj in enumerate(obj_list): obj_data = {"index": index_list[i]} if id_to_error and id_attr_name: error = id_to_error.get(getattr(obj, id_attr_name)) if error: obj_data["error"] = error failed_items.append(obj_data) continue for attr_name in passed_attrs or tuple(): obj_data[attr_name] = getattr(obj, attr_name) ok_items.append(obj_data) return ok_items, failed_items def ok_and_failed(ok: List[dict] = None, failed: List[dict] = None) -> dict: return {"ok": ok or [], "failed": failed or []} def unique_check_failed_item(key: str, value: Any, index: int, error_type: MessageUniqueCheckError) -> dict: return { "index": index, "error": {"type": MessageErrorType.UNIQUE_CHECK.value, "data": error_type.value.format(key, value)}, }