import copy from redis.client import Redis class EntityAttributes: def __init__(self, parent, entity_key_attributes, validators, transcoders={}): self.__parent = parent self.__redis_client : Redis = self.__parent.get_context().get_redis_client() self.__entity_key_attributes = entity_key_attributes.format(**self.__parent.__dict__) 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) validator = self.__validators.get(attribute_name) 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=[]): if len(attributes) == 0: # retrieve all keys_values = self.__redis_client.hgetall(self.__entity_key_attributes).items() else: # retrieve selected names = list(attributes) keys_values = zip(names, self.__redis_client.hmget(self.__entity_key_attributes, attributes)) attributes = {} for key,value in keys_values: str_key = key.decode('UTF-8') if isinstance(key, bytes) else key str_value = value.decode('UTF-8') if isinstance(value, bytes) else value attributes[str_key] = self.transcode(str_key, str_value) return attributes 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))) if len(remove_attributes) > 0: self.__redis_client.hdel(self.__entity_key_attributes, remove_attributes) if len(update_attributes) > 0: self.__redis_client.hmset(self.__entity_key_attributes, update_attributes) return self def delete(self, attributes=[]): if len(attributes) == 0: # delete all self.__redis_client.delete(self.__entity_key_attributes) else: # delete selected self.__redis_client.hdel(self.__entity_key_attributes, attributes)