from __future__ import annotations import copy from typing import Any, Dict, TYPE_CHECKING from ...engines._DatabaseEngine import _DatabaseEngine from .Tools import format_key if TYPE_CHECKING: from ._Entity import _Entity class EntityAttributes: def __init__(self, parent : '_Entity', entity_key : str, validators : Dict, transcoders : Dict = {}): self._parent = parent self._database_engine : _DatabaseEngine = self._parent.database_engine self._entity_key = format_key(entity_key, self._parent) self._validators = validators self._transcoders = transcoders def validate(self, update_attributes, remove_attributes, attribute_name): remove_attributes.discard(attribute_name) value = update_attributes.pop(attribute_name, None) if value is None: return validator = self._validators.get(attribute_name) if validator is None: return if not validator(value): raise AttributeError('{} is invalid'.format(attribute_name)) def transcode(self, attribute_name, attribute_value): transcoder_set = self._transcoders.get(attribute_name, {}) transcoder = transcoder_set.get(type(attribute_value)) return attribute_value if transcoder is None else transcoder(attribute_value) def get(self, attributes=[]) -> Dict[str, Any]: return { k:self.transcode(k, v) for k,v in self._database_engine.dict_get(self._entity_key, fields=attributes).items() } def update(self, update_attributes={}, remove_attributes=[]): remove_attributes = set(remove_attributes) copy_update_attributes = copy.deepcopy(update_attributes) copy_remove_attributes = copy.deepcopy(remove_attributes) for attribute_name in self._validators.keys(): self.validate(copy_update_attributes, copy_remove_attributes, attribute_name) attribute_value = update_attributes.get(attribute_name) if attribute_value is None: continue update_attributes[attribute_name] = self.transcode(attribute_name, attribute_value) if len(copy_update_attributes) > 0: raise AttributeError('Unexpected update_attributes: {}'.format(str(copy_update_attributes))) if len(copy_remove_attributes) > 0: raise AttributeError('Unexpected remove_attributes: {}'.format(str(copy_remove_attributes))) self._database_engine.dict_update(self._entity_key, update_attributes, remove_attributes) return self def delete(self, attributes=[]): self._database_engine.dict_delete(self._entity_key, attributes)