from __future__ import annotations
from datetime import datetime # noqa: TC003
from typing import Any
from uuid import uuid4
import msgspec
from typing_extensions import TypeVar
from eventsourcing.domain import (
BaseAggregate,
CanInitAggregate,
CanMutateAggregate,
event,
)
from examples.dcb_enrolment.interface import (
AlreadyJoinedError,
CourseID,
FullyBookedError,
StudentID,
TooManyCoursesError,
)
[docs]
class DomainEvent(msgspec.Struct, frozen=True):
originator_id: str
originator_version: int
timestamp: datetime
[docs]
class MsgspecStringIDEvent(DomainEvent, CanMutateAggregate[str], frozen=True):
def _as_dict(self) -> dict[str, Any]:
return {key: getattr(self, key) for key in self.__struct_fields__}
[docs]
class MsgspecStringIDCreatedEvent(DomainEvent, CanInitAggregate[str], frozen=True):
originator_topic: str
TID = TypeVar("TID", bound=str, default=str)
[docs]
class MsgspecStringIDAggregate(BaseAggregate[TID]):
[docs]
class Event(MsgspecStringIDEvent, frozen=True):
pass
class Created(Event, MsgspecStringIDCreatedEvent, frozen=True):
pass
[docs]
class Aggregate(MsgspecStringIDAggregate[TID]):
pass
[docs]
class Student(Aggregate[StudentID]):
[docs]
@staticmethod
def create_id() -> StudentID:
return StudentID("student-" + str(uuid4()))
[docs]
def __init__(self, name: str, max_courses: int) -> None:
self.name = name
self.max_courses = max_courses
self.course_ids: list[CourseID] = []
[docs]
@event("CourseJoined")
def join_course(self, course_id: CourseID) -> None:
if len(self.course_ids) >= self.max_courses:
raise TooManyCoursesError
self.course_ids.append(course_id)
[docs]
class Course(Aggregate[CourseID]):
[docs]
@staticmethod
def create_id() -> CourseID:
return CourseID("course-" + str(uuid4()))
[docs]
def __init__(self, name: str, places: int) -> None:
self.name = name
self.places = places
self.student_ids: list[StudentID] = []
[docs]
@event("StudentAccepted")
def accept_student(self, student_id: StudentID) -> None:
if len(self.student_ids) >= self.places:
raise FullyBookedError
if student_id in self.student_ids:
raise AlreadyJoinedError
self.student_ids.append(student_id)