-
Notifications
You must be signed in to change notification settings - Fork 3
/
models.py
114 lines (76 loc) · 3.26 KB
/
models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
"""ORM (object-relational mapping) provides data structures for the application."""
from __future__ import annotations
import datetime as dt
import enum
import uuid
from typing import Any
import sqlalchemy
from sqlalchemy import orm
now = dt.datetime.now
def round(datetime: dt.datetime) -> dt.datetime:
"""Floor the given datetime to the nearest hour."""
return datetime.replace(minute=0, second=0, microsecond=0)
class Color(enum.IntEnum):
"""A cat's fur color."""
BLACK = enum.auto()
GRAY = enum.auto()
ORANGE = enum.auto()
OTHER = enum.auto()
class Base(orm.DeclarativeBase):
"""Collect metadata for mapping database tables to Python data structures.
Additionally, it defines a default primary key that will be used by all subclasses for all
tables.
"""
id: orm.Mapped[uuid.UUID] = orm.mapped_column(primary_key=True, default=uuid.uuid4)
@orm.declared_attr.directive
def __tablename__(cls) -> str: # noqa: N805
"""The table name is based on the class name."""
return cls.__name__.lower()
@classmethod
def fk(cls, table: str, **kwargs: Any) -> orm.Mapped[uuid.UUID]:
"""Create a foreign key column to the given table."""
return orm.mapped_column(sqlalchemy.ForeignKey(f'{table}.id'), **kwargs)
def __repr__(self) -> str:
"""Represent objects by their class name and field values.
>>> class Example(Base):
... a_field: orm.Mapped[str]
>>> Example(a_field='a value')
Example(a_field='a value')
"""
pairs: list[str] = []
for field_name in self.__table__.columns.keys():
value = getattr(self, field_name)
pairs.append(f'{field_name}={value!r}')
args = ', '.join(pairs)
return f'{self.__class__.__name__}({args})'
class Person(Base):
"""A human who might or might not own a cat."""
given_name: orm.Mapped[str]
surname: orm.Mapped[str]
class Cat(Base):
"""Store data about a cat."""
name: orm.Mapped[str]
age: orm.Mapped[int] = orm.mapped_column(default=0) # years
color: orm.Mapped[Color] = orm.mapped_column(default=Color.OTHER)
lives: orm.Mapped[int] = orm.mapped_column(default=9)
owner_id: orm.Mapped[uuid.UUID] = Base.fk('person')
class Clinic(Base):
"""A clinic where veterinarians work to care for cats and owners."""
name: orm.Mapped[str]
class Veterinarian(Person):
"""A person who cares for cats and owners."""
license_number: orm.Mapped[str]
# this field is both a primary key and a foreign key
id: orm.Mapped[uuid.UUID] = Base.fk('person', primary_key=True)
clinic_id: orm.Mapped[uuid.UUID] = Base.fk('clinic')
class Appointment(Base):
"""A pet owner's appoint to see their vet at the clinic."""
# default: this time tomorrow, but rounded down to the nearest hour
start: orm.Mapped[dt.datetime] = orm.mapped_column(
default=lambda: round(now() + dt.timedelta(days=1))
)
duration: orm.Mapped[dt.timedelta] = orm.mapped_column(default=dt.timedelta(minutes=30))
cat_id: orm.Mapped[uuid.UUID] = Base.fk('cat')
clinic_id: orm.Mapped[uuid.UUID] = Base.fk('clinic')
owner_id: orm.Mapped[uuid.UUID] = Base.fk('person')
veterinarian_id: orm.Mapped[uuid.UUID] = Base.fk('veterinarian')