I want to write a typed BaseCollection
class for a database layer, which I then plan to subclass for specific collections, e.g., for UserCollection
. The goal is to a) have a standardized interface and to implement generic methods such as get() which can be used for all collections.
The problem is that I have two different “base” models for each collection. A model with editable fields (e.g. UserBase
) and a DB model with fields that are managed by the database in addition to the editable fields (e.g. UserInDB
). So, for the BaseCollection
I have two generic types: An input type (IT) and a return type (RT). Here, RT extends IT by additional fields. So, I would like to be able to write something like this:
from abc import ABC
from typing import Generic, Type, TypeVar
from pydantic import BaseModel
from models import UserBase, UserInDB
class ModelInDB:
id: str
# ...
IT = TypeVar("IT", bound=BaseModel)
class BaseCollection(ABC, Generic[IT]):
RT = ??? # Somehow derive gernic RT from IT with bound=(IT, ModelInDB)
model: Type[RT] = None
def create(self, data: IT) -> RT:
data = ... # generic implementation here
return self.model(**data)
def get(self, id: str) -> RT
data = ... # generic implementation here
return self.model(**data)
class UserCollection(BaseCollection[UserBase]):
model = User
# now it's time to harvest fruits and use my typed user collection :)