init
This commit is contained in:
27
app/infrastructure/db/sqlalchemy/models.py
Normal file
27
app/infrastructure/db/sqlalchemy/models.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from uuid import uuid4
|
||||
|
||||
from sqlalchemy import Boolean, DateTime, String
|
||||
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
||||
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
pass
|
||||
|
||||
|
||||
class UserModel(Base):
|
||||
__tablename__ = "users"
|
||||
|
||||
id: Mapped[str] = mapped_column(
|
||||
String(320), primary_key=True, default=lambda: str(uuid4())
|
||||
)
|
||||
full_name: Mapped[str] = mapped_column(String(200), nullable=False)
|
||||
email: Mapped[str] = mapped_column(
|
||||
String(320), unique=True, index=True, nullable=False
|
||||
)
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False
|
||||
)
|
||||
@@ -0,0 +1,54 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from uuid import UUID
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.application.users.ports.user_repository import UserRepository
|
||||
from app.domain.users.entities import User
|
||||
from app.domain.users.value_objects import Email
|
||||
from app.infrastructure.db.sqlalchemy.models import UserModel
|
||||
|
||||
|
||||
class SqlAlchemyUserRepository(UserRepository):
|
||||
def __init__(self, session: AsyncSession) -> None:
|
||||
self._session = session
|
||||
|
||||
async def add(self, user: User) -> None:
|
||||
model = UserModel(
|
||||
id=str(user.id),
|
||||
email=str(user.email),
|
||||
full_name=user.full_name,
|
||||
is_active=user.is_active,
|
||||
created_at=user.created_at,
|
||||
)
|
||||
self._session.add(model)
|
||||
|
||||
async def get_by_id(self, user_id: UUID) -> User | None:
|
||||
stmt = select(UserModel).where(UserModel.id == str(user_id))
|
||||
res = await self._session.execute(stmt)
|
||||
model = res.scalar_one_or_none()
|
||||
if model is None:
|
||||
return None
|
||||
return User(
|
||||
id=UUID(model.id),
|
||||
email=Email(model.email),
|
||||
full_name=model.full_name,
|
||||
is_active=model.is_active,
|
||||
created_at=model.created_at,
|
||||
)
|
||||
|
||||
async def get_by_email(self, email: str) -> User | None:
|
||||
stmt = select(UserModel).where(UserModel.email == email)
|
||||
res = await self._session.execute(stmt)
|
||||
model = res.scalar_one_or_none()
|
||||
if model is None:
|
||||
return None
|
||||
return User(
|
||||
id=UUID(model.id),
|
||||
email=Email(model.email),
|
||||
full_name=model.full_name,
|
||||
is_active=model.is_active,
|
||||
created_at=model.created_at,
|
||||
)
|
||||
25
app/infrastructure/db/sqlalchemy/session.py
Normal file
25
app/infrastructure/db/sqlalchemy/session.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
from sqlalchemy.ext.asyncio import (
|
||||
AsyncEngine,
|
||||
AsyncSession,
|
||||
async_sessionmaker,
|
||||
create_async_engine,
|
||||
)
|
||||
|
||||
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite+aiosqlite:///./app.db")
|
||||
|
||||
_engine: AsyncEngine = create_async_engine(DATABASE_URL, echo=False, future=True)
|
||||
_sessionmaker: async_sessionmaker[AsyncSession] = async_sessionmaker(
|
||||
bind=_engine, expire_on_commit=False
|
||||
)
|
||||
|
||||
|
||||
def get_engine() -> AsyncEngine:
|
||||
return _engine
|
||||
|
||||
|
||||
def get_sessionmaker() -> async_sessionmaker[AsyncSession]:
|
||||
return _sessionmaker
|
||||
31
app/infrastructure/db/sqlalchemy/uow.py
Normal file
31
app/infrastructure/db/sqlalchemy/uow.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
|
||||
|
||||
from app.application.users.ports.unit_of_work import UnitOfWork
|
||||
from app.infrastructure.db.sqlalchemy.repositories.user_repository import (
|
||||
SqlAlchemyUserRepository,
|
||||
)
|
||||
|
||||
|
||||
class SqlAlchemyUnitOfWork(UnitOfWork):
|
||||
def __init__(self, sessionmaker: async_sessionmaker[AsyncSession]) -> None:
|
||||
self._sessionmaker = sessionmaker
|
||||
self._session: AsyncSession | None = None
|
||||
self.users = None
|
||||
|
||||
async def __aenter__(self) -> "SqlAlchemyUnitOfWork":
|
||||
self._session = self._sessionmaker()
|
||||
self.users = SqlAlchemyUserRepository(self._session)
|
||||
return self
|
||||
|
||||
async def __aexit__(self, exc_type, exc, tb) -> None:
|
||||
if exc:
|
||||
await self.rollback()
|
||||
await self._session.close() # type: ignore[union-attr]
|
||||
|
||||
async def commit(self) -> None:
|
||||
await self._session.commit() # type: ignore[union-attr]
|
||||
|
||||
async def rollback(self) -> None:
|
||||
await self._session.rollback() # type: ignore[union-attr]
|
||||
Reference in New Issue
Block a user