From ffbc6bf88b55b013a68d0cffb283d54706fa3149 Mon Sep 17 00:00:00 2001 From: Dmitry Chumak Date: Mon, 15 May 2023 21:14:06 +0300 Subject: [PATCH] BaseCRUD model --- app/database/db.py | 21 +++++++++++ app/database/models.py | 80 ++++++++++++++++++++++++++++++++++++++++++ app/db.py | 49 -------------------------- migrations/env.py | 6 ++-- 4 files changed, 105 insertions(+), 51 deletions(-) create mode 100644 app/database/db.py create mode 100644 app/database/models.py delete mode 100644 app/db.py diff --git a/app/database/db.py b/app/database/db.py new file mode 100644 index 0000000..4aa0d91 --- /dev/null +++ b/app/database/db.py @@ -0,0 +1,21 @@ +from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine +from sqlalchemy.orm import sessionmaker, declarative_base +from app.settings import settings + +Base = declarative_base() + +from sqlalchemy.pool import QueuePool + +# Create async engine with connection pooling +engine = create_async_engine( + settings.DATABASE_URL, + echo=True, + poolclass=QueuePool, + pool_size=5, + max_overflow=10, +) + +# Create async session factory +async_session = sessionmaker( + engine, class_=AsyncSession, expire_on_commit=False +) diff --git a/app/database/models.py b/app/database/models.py new file mode 100644 index 0000000..ebd7636 --- /dev/null +++ b/app/database/models.py @@ -0,0 +1,80 @@ +from typing import List +from sqlalchemy import Column, String +from sqlalchemy import update as sqlalchemy_update, delete as sqlalchemy_delete +from sqlalchemy.future import select + +from app.database.db import Base, async_session + +from uuid import uuid4 +from typing_extensions import Self + +class BaseCRUD(Base): + __abstract__ = True + id = Column(String, primary_key=True) + + def __repr__(self): + return ( + f"<{self.__class__.__name__}(" + f"id={self.id}, " + f"name={self.name}, " + f")>" + ) + + @classmethod + async def create(cls, **kwargs) -> Self: + async with async_session() as db: + server = cls(id=str(uuid4()), **kwargs) + db.add(server) + try: + await db.commit() + await db.refresh(server) + except Exception: + await db.rollback() + raise + return server + + @classmethod + async def update(cls, id, **kwargs) -> Self: + async with async_session() as db: + query = ( + sqlalchemy_update(cls) + .where(cls.id == id) + .values(**kwargs) + .execution_options(synchronize_session="fetch") + ) + await db.execute(query) + try: + await db.commit() + except Exception: + await db.rollback() + raise + return await cls.get(id) + + @classmethod + async def get(cls, id) -> Self: + async with async_session() as db: + query = select(cls).where(cls.id == id) + servers = await db.execute(query) + (server,) = servers.first() + return server + + @classmethod + async def get_all(cls) -> List[Self]: + async with async_session() as db: + query = select(cls) + servers = await db.execute(query) + servers = servers.scalars().all() + return servers + + @classmethod + async def delete(cls, id) -> bool: + async with async_session() as db: + query = sqlalchemy_delete(cls).where(cls.id == id) + await db.execute(query) + try: + await db.commit() + except Exception: + await db.rollback() + raise + return True + diff --git a/app/db.py b/app/db.py deleted file mode 100644 index 17ad6e3..0000000 --- a/app/db.py +++ /dev/null @@ -1,49 +0,0 @@ -from sqlalchemy import future -from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine -from sqlalchemy.orm import sessionmaker, declarative_base -from app.settings import settings - -Base = declarative_base() - -# engine = create_async_engine(settings.DATABASE_URL, echo=True, future=True) - -# Session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) - -# def get_session(): -# with Session() as session: -# yield session - -class AsyncDatabaseSession: - def __init__(self): - self._session = None - self._engine = None - self._engine = create_async_engine( - settings.DATABASE_URL, - future=True, - echo=True, - ) - self._session = sessionmaker( - self._engine, expire_on_commit=False, class_=AsyncSession - )() - - def __getattr__(self, name): - return getattr(self._session, name) - - # def init(self): - -db = AsyncDatabaseSession() - -# async def get_session() -> AsyncSession: -# async_session = sessionmaker( -# engine, class_=AsyncSession, expire_on_commit=False -# ) -# async with async_session() as session: -# yield session -# # from sqlalchemy import create_engine -# # from sqlalchemy.ext.declarative import declarative_base -# # from sqlalchemy.orm import sessionmaker - -# engine = create_engine(settings.DATABASE_URL) -# SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) - - diff --git a/migrations/env.py b/migrations/env.py index b5de3f3..2d65069 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -9,7 +9,9 @@ from sqlalchemy.ext.asyncio import AsyncEngine from alembic import context from app.settings import settings -import users +from app.database import db + +# your models to import for migrations processing from users.models import * # this is the Alembic Config object, which provides @@ -27,7 +29,7 @@ config.set_main_option('sqlalchemy.url', settings.DATABASE_URL) # for 'autogenerate' support # from myapp import mymodel # target_metadata = mymodel.Base.metadata -target_metadata = [users.models.Base.metadata] +target_metadata = db.Base.metadata # other values from the config, defined by the needs of env.py, # can be acquired: