Skip to content

Commit

Permalink
Regenerate fastapp
Browse files Browse the repository at this point in the history
  • Loading branch information
goFrendiAsgard committed Nov 19, 2024
1 parent 17d99dc commit 39c37d8
Show file tree
Hide file tree
Showing 27 changed files with 301 additions and 259 deletions.
18 changes: 18 additions & 0 deletions amalgam/fastapp/common/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from contextlib import asynccontextmanager

from common.db_engine import engine
from config import APP_MODE, APP_MODULES
from fastapi import FastAPI
from sqlmodel import SQLModel


@asynccontextmanager
async def lifespan(app: FastAPI):
SQLModel.metadata.create_all(engine)
yield


app_title = (
"Fastapp" if APP_MODE == "monolith" else f"Fastapp - {', '.join(APP_MODULES)}"
)
app = FastAPI(title=app_title, lifespan=lifespan)
9 changes: 0 additions & 9 deletions amalgam/fastapp/common/app_factory.py

This file was deleted.

5 changes: 5 additions & 0 deletions amalgam/fastapp/common/db_engine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from config import APP_DB_URL
from sqlmodel import create_engine

connect_args = {"check_same_thread": False}
engine = create_engine(APP_DB_URL, connect_args=connect_args)
32 changes: 0 additions & 32 deletions amalgam/fastapp/common/db_migration.py

This file was deleted.

140 changes: 140 additions & 0 deletions amalgam/fastapp/common/db_repository.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
from typing import Any, Callable, Generic, Type, TypeVar

from sqlalchemy import Engine
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession
from sqlmodel import Session, SQLModel, select

DBModel = TypeVar("DBModel", bound=SQLModel)
ResponseModel = TypeVar("Model", bound=SQLModel)
CreateModel = TypeVar("CreateModel", bound=SQLModel)
UpdateModel = TypeVar("UpdateModel", bound=SQLModel)


class BaseDBRepository(Generic[DBModel, ResponseModel, CreateModel, UpdateModel]):
db_model: Type[DBModel]
response_model: Type[ResponseModel]
create_model: Type[CreateModel]
update_model: Type[UpdateModel]
column_preprocessors: dict[str, Callable[[Any], Any]] = {}

def __init__(self, engine: Engine | AsyncEngine):
self.engine = engine
self.is_async = isinstance(engine, AsyncEngine)

def _to_response(self, db_instance: DBModel) -> ResponseModel:
return self.response_model(**db_instance.model_dump())

async def create(self, data: CreateModel) -> ResponseModel:
data_dict = data.model_dump(exclude_unset=True)
for key, preprocessor in self.column_preprocessors.items():
if key in data_dict:
data_dict[key] = preprocessor(data_dict[key])
db_instance = self.db_model(**data_dict)

if self.is_async:
async with AsyncSession(self.engine) as session:
session.add(db_instance)
await session.commit()
await session.refresh(db_instance)
else:
with Session(self.engine) as session:
session.add(db_instance)
session.commit()
session.refresh(db_instance)

return self._to_response(db_instance)

async def get_by_id(self, item_id: str) -> ResponseModel | None:
if self.is_async:
async with AsyncSession(self.engine) as session:
db_instance = await session.get(self.db_model, item_id)
else:
with Session(self.engine) as session:
db_instance = session.get(self.db_model, item_id)

return self._to_response(db_instance) if db_instance else None

async def get_all(self, page: int = 1, page_size: int = 10) -> list[ResponseModel]:
offset = (page - 1) * page_size
statement = select(self.db_model).offset(offset).limit(page_size)

if self.is_async:
async with AsyncSession(self.engine) as session:
result = await session.execute(statement)
results = result.scalars().all()
else:
with Session(self.engine) as session:
results = session.exec(statement).all()

return [self._to_response(instance) for instance in results]

async def update(self, item_id: str, data: UpdateModel) -> ResponseModel | None:
update_data = data.model_dump(exclude_unset=True)
for key, value in update_data.items():
if key in self.column_preprocessors:
update_data[key] = self.column_preprocessors[key](value)

if self.is_async:
async with AsyncSession(self.engine) as session:
db_instance = await session.get(self.db_model, item_id)
if not db_instance:
return None
for key, value in update_data.items():
setattr(db_instance, key, value)
session.add(db_instance)
await session.commit()
await session.refresh(db_instance)
else:
with Session(self.engine) as session:
db_instance = session.get(self.db_model, item_id)
if not db_instance:
return None
for key, value in update_data.items():
setattr(db_instance, key, value)
session.add(db_instance)
session.commit()
session.refresh(db_instance)

return self._to_response(db_instance)

async def delete(self, item_id: str) -> bool:
if self.is_async:
async with AsyncSession(self.engine) as session:
db_instance = await session.get(self.db_model, item_id)
if not db_instance:
return False
await session.delete(db_instance)
await session.commit()
else:
with Session(self.engine) as session:
db_instance = session.get(self.db_model, item_id)
if not db_instance:
return False
session.delete(db_instance)
session.commit()

return True

async def create_bulk(self, data_list: list[CreateModel]) -> list[ResponseModel]:
db_instances = []
for data in data_list:
data_dict = data.model_dump(exclude_unset=True)
for key, preprocessor in self.column_preprocessors.items():
if key in data_dict:
data_dict[key] = preprocessor(data_dict[key])
db_instances.append(self.db_model(**data_dict))

if self.is_async:
async with AsyncSession(self.engine) as session:
session.add_all(db_instances)
await session.commit()
for instance in db_instances:
await session.refresh(instance)
else:
with Session(self.engine) as session:
session.add_all(db_instances)
session.commit()
for instance in db_instances:
session.refresh(instance)

return [self._to_response(instance) for instance in db_instances]
8 changes: 0 additions & 8 deletions amalgam/fastapp/common/db_session_maker_factory.py

This file was deleted.

File renamed without changes.
9 changes: 3 additions & 6 deletions amalgam/fastapp/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,10 @@
)
APP_REPOSITORY_TYPE = os.getenv("APP_REPOSITORY_TYPE", "db")

_DEFAULT_ASYNC_DB_URL = "sqlite+aiosqlite:///monolith.db"
_DEFAULT_SYNC_DB_URL = "sqlite:///monolith.db"
_DEFAULT_DB_URL = "sqlite:///monolith.db"
if APP_MODE != "monolith":
_DEFAULT_ASYNC_DB_URL = "sqlite+aiosqlite:///microservices.db"
_DEFAULT_SYNC_DB_URL = "sqlite:///microservices.db"
APP_DB_URL = os.getenv("APP_DB_URL", _DEFAULT_ASYNC_DB_URL)
APP_DB_MIGRATION_URL = os.getenv("APP_DB_MIGRATION_URL", _DEFAULT_SYNC_DB_URL)
_DEFAULT_DB_URL = "sqlite:///microservices.db"
APP_DB_URL = os.getenv("APP_DB_URL", _DEFAULT_DB_URL)

_DEFAULT_MIGRATION_TABLE = "migration_table"
if APP_MODE != "monolith" and len(APP_MODULES) > 0:
Expand Down
6 changes: 3 additions & 3 deletions amalgam/fastapp/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .common.app_factory import app
from .module.auth import route as auth_route
from .module.gateway import route as gateway_route
from common.app import app
from module.auth import route as auth_route
from module.gateway import route as gateway_route

assert app
assert gateway_route
Expand Down
Binary file removed amalgam/fastapp/microservices.db
Binary file not shown.
2 changes: 1 addition & 1 deletion amalgam/fastapp/migrate.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .module.auth import migration as auth_migration
from module.auth import migration as auth_migration

assert auth_migration
8 changes: 4 additions & 4 deletions amalgam/fastapp/module/auth/client/api_client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from ....config import APP_AUTH_BASE_URL
from ..service.user.usecase import user_usecase
from .base_client import BaseClient
from config import APP_AUTH_BASE_URL
from module.auth.client.base_client import BaseClient
from module.auth.service.user.usecase import user_usecase


class APIClient(BaseClient, user_usecase.as_api_client(base_url=APP_AUTH_BASE_URL)):
class APIClient(user_usecase.as_api_client(base_url=APP_AUTH_BASE_URL), BaseClient):
pass
14 changes: 7 additions & 7 deletions amalgam/fastapp/module/auth/client/base_client.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
from abc import ABC, abstractmethod

from ....schema.user import NewUserData, UpdateUserData, UserData
from schema.user import UserCreate, UserResponse, UserUpdate


class BaseClient(ABC):
@abstractmethod
async def get_user_by_id(self, user_id: str) -> UserData:
async def get_user_by_id(self, user_id: str) -> UserResponse:
pass

@abstractmethod
async def get_all_users(self) -> list[UserData]:
async def get_all_users(self) -> list[UserResponse]:
pass

@abstractmethod
async def create_user(
self, data: NewUserData | list[NewUserData]
) -> UserData | list[UserData]:
self, data: UserCreate | list[UserCreate]
) -> UserResponse | list[UserResponse]:
pass

@abstractmethod
async def update_user(self, user_id: str, data: UpdateUserData) -> UserData:
async def update_user(self, user_id: str, data: UserUpdate) -> UserResponse:
pass

@abstractmethod
async def delete_user(self, user_id: str) -> UserData:
async def delete_user(self, user_id: str) -> UserResponse:
pass
6 changes: 3 additions & 3 deletions amalgam/fastapp/module/auth/client/direct_client.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from ..service.user.usecase import user_usecase
from .base_client import BaseClient
from module.auth.client.base_client import BaseClient
from module.auth.service.user.usecase import user_usecase


class DirectClient(BaseClient, user_usecase.as_direct_client()):
class DirectClient(user_usecase.as_direct_client(), BaseClient):
pass
8 changes: 4 additions & 4 deletions amalgam/fastapp/module/auth/client/factory.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from ....config import APP_COMMUNICATION
from .api_client import APIClient
from .base_client import BaseClient
from .direct_client import DirectClient
from config import APP_COMMUNICATION
from module.auth.client.api_client import APIClient
from module.auth.client.base_client import BaseClient
from module.auth.client.direct_client import DirectClient

if APP_COMMUNICATION == "direct":
client: BaseClient = DirectClient()
Expand Down
5 changes: 0 additions & 5 deletions amalgam/fastapp/module/auth/db/baseclass.py

This file was deleted.

22 changes: 0 additions & 22 deletions amalgam/fastapp/module/auth/migration.py
Original file line number Diff line number Diff line change
@@ -1,22 +0,0 @@
from ...common.db_migration import run_db_migration
from ...config import (
APP_DB_MIGRATION_TABLE,
APP_DB_MIGRATION_URL,
APP_MODE,
APP_MODULES,
APP_REPOSITORY_TYPE,
)
from .db.baseclass import Base

if (
APP_REPOSITORY_TYPE == "db"
and (
(APP_MODE == "microservices" and "auth" in APP_MODULES)
or APP_MODE == "monolith"
)
):
run_db_migration(
db_url=APP_DB_MIGRATION_URL,
migration_table_name=APP_DB_MIGRATION_TABLE,
baseclass=Base
)
8 changes: 4 additions & 4 deletions amalgam/fastapp/module/auth/route.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from ...common.app_factory import app
from ...common.schema import BasicResponse
from ...config import APP_MODE, APP_MODULES
from .service.user.usecase import user_usecase
from common.app import app
from common.schema import BasicResponse
from config import APP_MODE, APP_MODULES
from module.auth.service.user.usecase import user_usecase

if APP_MODE == "microservices" and "auth" in APP_MODULES:

Expand Down
Loading

0 comments on commit 39c37d8

Please sign in to comment.