from enum import Enum from datetime import datetime, date from typing import List, Literal from pydantic import Field, BaseModel, validator from beanie import Document, Link class EntityType(BaseModel): @property def label(self) -> str: return self.title class Individual(EntityType): type: Literal['individual'] = 'individual' firstname: str middlenames: List[str] = Field(default=[]) lastname: str surnames: List[str] = Field(default=[]) day_of_birth: date job: str employer: str @property def label(self) -> str: if len(self.surnames) > 0: return '{} "{}" {}'.format(self.firstname, self.surnames[0], self.lastname) return '{} {}'.format(self.firstname, self.lastname) @staticmethod def get_label(data) -> str: if len(data['surname']) > 0: return '{} "{}" {}'.format(data['firstname'], data['surnames'][0], data['lastname']) return '{} {}'.format(data['firstname'], data['lastname']) class Employee(EntityType): role: str entity_id: str = Field(foreignKey={ "reference": { "resource": "entity", "displayName": "_id", "condition": "entity_data.type=individual" } }) class Corporation(EntityType): type: Literal['corporation'] = 'corporation' title: str activity: str employees: List[Employee] = Field(default=[]) class Institution(BaseModel): type: Literal['institution'] = 'institution' title: str activity: str employees: List[Employee] = Field(default=[]) class Entity(Document): _id: str address: str entity_data: Individual | Corporation | Institution = Field(..., discriminator='type') label: str = None @validator("label", always=True) def generate_label(cls, v, values, **kwargs): return values['entity_data'].label created_at: datetime = Field(default=datetime.utcnow(), nullable=False) updated_at: datetime = Field(default_factory=datetime.utcnow, nullable=False) class Settings: bson_encoders = { date: lambda dt: dt if hasattr(dt, 'hour') else datetime(year=dt.year, month=dt.month, day=dt.day, hour=0, minute=0, second=0) }