106 lines
3.7 KiB
Python
106 lines
3.7 KiB
Python
from typing import Any
|
|
|
|
from core.Expando import Expando
|
|
from workflow.engine import DataPresenter
|
|
|
|
|
|
class DefaultDataPresenter(DataPresenter):
|
|
"""Default data presenter that returns the input data unchanged."""
|
|
|
|
def __init__(self, component_id: str, mappings_definition: str):
|
|
super().__init__(component_id)
|
|
self._mappings_definition = mappings_definition
|
|
self._split_definitions = [definition.strip() for definition in mappings_definition.split(",")]
|
|
|
|
if "*" not in mappings_definition:
|
|
self._static_mappings = self._get_static_mappings()
|
|
else:
|
|
self._static_mappings = None
|
|
|
|
def present(self, data: Any) -> Any:
|
|
self._validate_mappings_definition()
|
|
|
|
if self._static_mappings:
|
|
return Expando(data.to_dict(self._static_mappings))
|
|
|
|
dynamic_mappings = self._get_dynamic_mappings(data)
|
|
return Expando(data.to_dict(dynamic_mappings))
|
|
|
|
def _get_dynamic_mappings(self, data):
|
|
|
|
manage_conflicts = {}
|
|
|
|
mappings = {}
|
|
for mapping in self._split_definitions:
|
|
if "=" in mapping:
|
|
key, value = [s.strip() for s in mapping.split('=', 1)]
|
|
if key == "*":
|
|
# all fields
|
|
if value != "*":
|
|
raise ValueError("Only '*' is accepted when renaming wildcard.")
|
|
for key in data.as_dict().keys():
|
|
if key in manage_conflicts:
|
|
raise ValueError(f"Collision detected for field '{key}'. It is mapped from both '{manage_conflicts[key]}' and '{mapping}'.")
|
|
manage_conflicts[key] = mapping
|
|
mappings[key] = key
|
|
elif key.endswith(".*"):
|
|
# all fields in a sub-object
|
|
if value != "*" and value != "":
|
|
raise ValueError("Only '*' is accepted when renaming wildcard.")
|
|
obj_path = key[:-2]
|
|
sub_obj = data.get(obj_path)
|
|
if isinstance(sub_obj, dict):
|
|
for sub_field in sub_obj:
|
|
if sub_field in manage_conflicts:
|
|
raise ValueError(
|
|
f"Collision detected for field '{sub_field}'. It is mapped from both '{manage_conflicts[sub_field]}' and '{mapping}'.")
|
|
manage_conflicts[sub_field] = mapping
|
|
mappings[f"{obj_path}.{sub_field}"] = sub_field
|
|
else:
|
|
raise ValueError(f"Field '{obj_path}' is not an object.")
|
|
else:
|
|
mappings[key.strip()] = value.strip()
|
|
|
|
|
|
else:
|
|
if mapping == "*":
|
|
# all fields
|
|
for key in data.as_dict().keys():
|
|
mappings[key] = key
|
|
elif mapping.endswith(".*"):
|
|
# all fields in a sub-object
|
|
obj_path = mapping[:-2]
|
|
sub_obj = data.get(obj_path)
|
|
if isinstance(sub_obj, dict):
|
|
for sub_field in sub_obj:
|
|
mappings[f"{obj_path}.{sub_field}"] = f"{obj_path}.{sub_field}"
|
|
else:
|
|
raise ValueError(f"Field '{obj_path}' is not an object.")
|
|
else:
|
|
mappings[mapping] = mapping
|
|
|
|
return mappings
|
|
|
|
def _get_static_mappings(self):
|
|
mappings = {}
|
|
for mapping in self._split_definitions:
|
|
if "=" in mapping:
|
|
key, value = [s.strip() for s in mapping.split('=', 1)]
|
|
if not value:
|
|
value = key.split(".")[-1]
|
|
mappings[key] = value
|
|
else:
|
|
mappings[mapping] = mapping
|
|
|
|
return mappings
|
|
|
|
def _validate_mappings_definition(self):
|
|
last_char_was_comma = False
|
|
for i, char in enumerate(self._mappings_definition):
|
|
if char == ',':
|
|
if last_char_was_comma:
|
|
raise ValueError(f"Invalid mappings definition: Error found at index {i}")
|
|
last_char_was_comma = True
|
|
elif not char.isspace():
|
|
last_char_was_comma = False
|