# (c) Nelen & Schuurmans from typing import Optional from typing import Type from typing import TypeVar from pydantic import BaseModel from pydantic import ConfigDict from pydantic import ValidationError from .exceptions import BadRequest from .types import Id __all__ = ["ValueObject", "ValueObjectWithId"] T = TypeVar("T", bound="ValueObject") class ValueObject(BaseModel): model_config = ConfigDict(frozen=True) def run_validation(self: T) -> T: try: return self.__class__(**self.model_dump()) except ValidationError as e: raise BadRequest(e) @classmethod def create(cls: Type[T], **values) -> T: try: return cls(**values) except ValidationError as e: raise BadRequest(e) def update(self: T, **values) -> T: try: return self.__class__(**{**self.model_dump(), **values}) except ValidationError as e: raise BadRequest(e) def __hash__(self): return hash(self.__class__) + hash(tuple(self.__dict__.values())) K = TypeVar("K", bound="ValueObjectWithId") class ValueObjectWithId(ValueObject): id: Optional[Id] = None def update(self: K, **values) -> K: if "id" in values and self.id is not None and values["id"] != self.id: raise ValueError("Cannot change the id") return super().update(**values)