vtt/src/ttfrog/schema.py

59 lines
1.5 KiB
Python
Raw Normal View History

2025-09-24 01:28:23 -07:00
from collections import namedtuple
from dataclasses import dataclass
import nanoid
Metadata = namedtuple("Metadata", ["table", "fields"])
@dataclass
class Field:
"""
Represents a single field in a Record.
"""
name: str
value_type: type = str
default: value_type | None = None
unique: bool = False
class Record(dict):
"""
Base type for a single database record.
"""
_fields = [Field("uid", default="", unique=True)]
def __init__(self, raw_doc: dict = {}, doc_id: int = None, **params):
# populate the metadata
fields = Record._fields
if self.__class__ != Record:
fields += self._fields
self._metadata = Metadata(table=self.__class__.__name__, fields={f.name: f for f in fields})
self.doc_id = doc_id
vals = dict({field.name: field.default for field in fields}, **raw_doc, **params)
if not vals["uid"]:
vals["uid"] = nanoid.generate(size=8) # 1% collision rate at ~2M records
super().__init__(vals)
def __setattr__(self, key, value):
if key in self:
self[key] = value
super().__setattr__(key, value)
def __getattr__(self, attr_name):
if attr_name in self:
return self.get(attr_name)
return super().__getattr__(attr_name)
def __repr__(self):
return f"{self.__class__.__name__}[{self.doc_id}]: {self.items()}"
class User(Record):
_fields = [Field("name"), Field("email", unique=True)]