value_object.py 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. # (c) Nelen & Schuurmans
  2. from typing import Optional
  3. from typing import Type
  4. from typing import TypeVar
  5. from pydantic import BaseModel
  6. from pydantic import ConfigDict
  7. from pydantic import ValidationError
  8. from .exceptions import BadRequest
  9. from .types import Id
  10. __all__ = ["ValueObject", "ValueObjectWithId"]
  11. T = TypeVar("T", bound="ValueObject")
  12. class ValueObject(BaseModel):
  13. model_config = ConfigDict(frozen=True)
  14. def run_validation(self: T) -> T:
  15. try:
  16. return self.__class__(**self.model_dump())
  17. except ValidationError as e:
  18. raise BadRequest(e)
  19. @classmethod
  20. def create(cls: Type[T], **values) -> T:
  21. try:
  22. return cls(**values)
  23. except ValidationError as e:
  24. raise BadRequest(e)
  25. def update(self: T, **values) -> T:
  26. try:
  27. return self.__class__(**{**self.model_dump(), **values})
  28. except ValidationError as e:
  29. raise BadRequest(e)
  30. def __hash__(self):
  31. return hash(self.__class__) + hash(tuple(self.__dict__.values()))
  32. K = TypeVar("K", bound="ValueObjectWithId")
  33. class ValueObjectWithId(ValueObject):
  34. id: Optional[Id] = None
  35. def update(self: K, **values) -> K:
  36. if "id" in values and self.id is not None and values["id"] != self.id:
  37. raise ValueError("Cannot change the id")
  38. return super().update(**values)