root_entity.py 1.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. # (c) Nelen & Schuurmans
  2. from datetime import datetime
  3. from datetime import timezone
  4. from typing import Optional
  5. from typing import Type
  6. from typing import TypeVar
  7. from .exceptions import BadRequest
  8. from .types import Id
  9. from .value_object import ValueObject
  10. __all__ = ["RootEntity", "now"]
  11. def now():
  12. # this function is there so that we can mock it in tests
  13. return datetime.now(timezone.utc)
  14. T = TypeVar("T", bound="RootEntity")
  15. class RootEntity(ValueObject):
  16. id: Optional[Id] = None
  17. created_at: datetime
  18. updated_at: datetime
  19. @classmethod
  20. def create(cls: Type[T], **values) -> T:
  21. values.setdefault("created_at", now())
  22. values.setdefault("updated_at", values["created_at"])
  23. return super(RootEntity, cls).create(**values)
  24. def update(self: T, **values) -> T:
  25. if "id" in values and self.id is not None and values["id"] != self.id:
  26. raise BadRequest("Cannot change the id of an entity")
  27. values.setdefault("updated_at", now())
  28. return super().update(**values)
  29. def __hash__(self):
  30. assert self.id is not None
  31. return hash(self.__class__) + hash(self.id)