Commit e48ba9c1 authored by Jakob Moser's avatar Jakob Moser
Browse files

Merge branch 'backend/add-db' into 'master'

Add database

See merge request moser/poolpay!1
parents 06b53773 c2882892
Loading
Loading
Loading
Loading

poolpay/__main__.py

0 → 100644
+18 −0
Original line number Diff line number Diff line
from pathlib import Path

from sqlalchemy import create_engine
from sqlalchemy.orm import Session

from poolpay import db
from poolpay.model.Retrievable import Retrievable

proj_dir = Path(__file__).parent.parent.resolve()
instance_dir = proj_dir / "instance"
db_file = instance_dir / "poolpay.db"
try:

    engine = create_engine(f"sqlite:///{db_file}")
    Retrievable.metadata.create_all(engine)
    db.session = Session(engine)
finally:
    pass

poolpay/db.py

0 → 100644
+3 −0
Original line number Diff line number Diff line
from sqlalchemy.orm import Session

session: Session | None = None

poolpay/model/Base.py

0 → 100644
+40 −0
Original line number Diff line number Diff line
from __future__ import annotations

from uuid import UUID, uuid4

from sqlalchemy.orm import Mapped, mapped_column

from poolpay.model.InvalidUuidError import InvalidUuidError
from poolpay.model.Retrievable import Retrievable
from poolpay.model.Uuid import Uuid


class Base(Retrievable):
    """
    A type with a UUID, stored in the database.

    It also has a method to return a dictionary representation for easy serialization.
    """

    # See https://docs.sqlalchemy.org/en/20/orm/declarative_config.html#abstract
    __abstract__ = True

    uuid: Mapped[UUID] = mapped_column(Uuid(), primary_key=True, default=uuid4)

    @classmethod
    def get_only(cls, uuid: str | UUID) -> Base | None:
        if isinstance(uuid, str):
            try:
                # Manually convert the uuid to a UUID object (even though sqlalchemy-uuid would do that
                # automatically for us), so we can catch errors.
                uuid_obj = UUID(uuid)
            except ValueError:
                raise InvalidUuidError()
        else:
            uuid_obj = uuid

        return super().get_only(uuid_obj)

    @property
    def primary_key(self) -> UUID:
        return self.uuid
+2 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ class Person(Base):
      means the person owes us money).
    """

    __tablename__ = "person"

    name: Mapped[str]
    cl_account_name: Mapped[str] = mapped_column(unique=True)
    balance_cents: int = 0
+53 −0
Original line number Diff line number Diff line
from __future__ import annotations

from typing import Any

from sqlalchemy.orm import DeclarativeBase, MappedColumn

from poolpay import db


class Retrievable(DeclarativeBase):
    """
    A type whose instances can be retrieved from the database.

    It has methods to get all instances and a specific instance by its primary key.
    """

    # See https://docs.sqlalchemy.org/en/20/orm/declarative_config.html#abstract
    __abstract__ = True

    @classmethod
    def get_canonical_order_column(cls) -> MappedColumn | None:
        """
        Return the colum by which instances of this type should be canonically ordered
        when retrieving them all from the database.

        By default, the column is None, i.e. no order is enforced.
        """
        return None

    @classmethod
    def get_all(cls) -> list[Retrievable]:
        """
        Return all instances of this type.
        """
        return db.session.execute(
            db.select(cls).order_by(cls.get_canonical_order_column())
        ).scalars()

    @classmethod
    def get_only(cls, primary_key: Any) -> Retrievable | None:
        """
        Return the instance of this type with the given primary key or None if it doesn't exist.
        """
        return db.session.get(cls, primary_key)

    @property
    def primary_key(self) -> Any:
        """
        Return the primary key that can be used to identify an instance of this class.
        """
        raise NotImplementedError(
            "The primary key property needs to be implemented by subclasses."
        )
Loading