Skip to content

Commit

Permalink
add python-gino support
Browse files Browse the repository at this point in the history
  • Loading branch information
turalpb committed May 31, 2021
1 parent 0a17650 commit 376f502
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 9 deletions.
10 changes: 3 additions & 7 deletions fastapi_crudrouter/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
from .core import (
DatabasesCRUDRouter,
MemoryCRUDRouter,
OrmarCRUDRouter,
SQLAlchemyCRUDRouter,
TortoiseCRUDRouter,
)
from .core import (DatabasesCRUDRouter, GinoCRUDRouter, MemoryCRUDRouter,
OrmarCRUDRouter, SQLAlchemyCRUDRouter, TortoiseCRUDRouter)

__all__ = [
"MemoryCRUDRouter",
"SQLAlchemyCRUDRouter",
"DatabasesCRUDRouter",
"TortoiseCRUDRouter",
"OrmarCRUDRouter",
"GinoCRUDRouter"
]
4 changes: 3 additions & 1 deletion fastapi_crudrouter/core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from . import _utils
from ._base import CRUDGenerator, NOT_FOUND
from ._base import NOT_FOUND, CRUDGenerator
from .databases import DatabasesCRUDRouter
from .gino_starlette import GinoCRUDRouter
from .mem import MemoryCRUDRouter
from .ormar import OrmarCRUDRouter
from .sqlalchemy import SQLAlchemyCRUDRouter
Expand All @@ -15,4 +16,5 @@
"DatabasesCRUDRouter",
"TortoiseCRUDRouter",
"OrmarCRUDRouter",
"GinoCRUDRouter",
]
133 changes: 133 additions & 0 deletions fastapi_crudrouter/core/gino_starlette.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
from typing import Any, Callable, List, Optional, Type, Union

from fastapi import HTTPException

from . import NOT_FOUND, CRUDGenerator, _utils
from ._types import DEPENDENCIES, PAGINATION
from ._types import PYDANTIC_SCHEMA as SCHEMA

try:
import asyncpg
from gino import Gino

from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import DeclarativeMeta as Model
except ImportError:
Model: Any = None # type: ignore
gino_installed = False
else:
gino_installed = True


class GinoCRUDRouter(CRUDGenerator[SCHEMA]):
def __init__(
self,
schema: Type[SCHEMA],
db_model: Model,
db: "Gino",
create_schema: Optional[Type[SCHEMA]] = None,
update_schema: Optional[Type[SCHEMA]] = None,
prefix: Optional[str] = None,
tags: Optional[List[str]] = None,
paginate: Optional[int] = None,
get_all_route: Union[bool, DEPENDENCIES] = True,
get_one_route: Union[bool, DEPENDENCIES] = True,
create_route: Union[bool, DEPENDENCIES] = True,
update_route: Union[bool, DEPENDENCIES] = True,
delete_one_route: Union[bool, DEPENDENCIES] = True,
delete_all_route: Union[bool, DEPENDENCIES] = True,
**kwargs: Any
) -> None:
assert gino_installed, "Gino must be installed to use the GinoCRUDRouter."

self.db_model = db_model
self.db = db
self._pk: str = db_model.__table__.primary_key.columns.keys()[0]
self._pk_type: type = _utils.get_pk_type(schema, self._pk)

super().__init__(
schema=schema,
create_schema=create_schema,
update_schema=update_schema,
prefix=prefix or db_model.__tablename__,
tags=tags,
paginate=paginate,
get_all_route=get_all_route,
get_one_route=get_one_route,
create_route=create_route,
update_route=update_route,
delete_one_route=delete_one_route,
delete_all_route=delete_all_route,
**kwargs
)

def _get_all(self, *args: Any, **kwargs: Any) -> Callable[..., List[Model]]:
async def route(
pagination: PAGINATION = self.pagination,
) -> List[Model]:
skip, limit = pagination.get("skip"), pagination.get("limit")

db_models: List[Model] = (
await self.db_model.query.limit(limit).offset(skip).gino.all()
)
return db_models

return route

def _get_one(self, *args: Any, **kwargs: Any) -> Callable[..., Model]:
async def route(item_id: self._pk_type) -> Model:
model: Model = await self.db_model.get(item_id)

if model:
return model
else:
raise NOT_FOUND

return route

def _create(self, *args: Any, **kwargs: Any) -> Callable[..., Model]:
async def route(
model: self.create_schema, # type: ignore
) -> Model:
try:
async with self.db.transaction():
db_model: Model = await self.db_model.create(**model.dict())
return db_model
except (IntegrityError, asyncpg.exceptions.UniqueViolationError):
raise HTTPException(422, "Key already exists")

return route

def _update(self, *args: Any, **kwargs: Any) -> Callable[..., Model]:
async def route(
item_id: self._pk_type, # type: ignore
model: self.update_schema, # type: ignore
) -> Model:
try:
print("PKK")
db_model: Model = await self._get_one()(item_id)
async with self.db.transaction():
model = model.dict(exclude={self._pk})
await db_model.update(**model).apply()

return db_model
except (IntegrityError, asyncpg.exceptions.UniqueViolationError) as e:
raise HTTPException(422, ", ".join(e.args))

return route

def _delete_all(self, *args: Any, **kwargs: Any) -> Callable[..., List[Model]]:
async def route() -> List[Model]:
await self.db_model.delete.gino.status()
return await self._get_all()(pagination={"skip": 0, "limit": None})

return route

def _delete_one(self, *args: Any, **kwargs: Any) -> Callable[..., Model]:
async def route(item_id: self._pk_type) -> Model: # type: ignore
db_model: Model = await self._get_one()(item_id)
await db_model.delete()

return db_model

return route
5 changes: 4 additions & 1 deletion tests/test_integration/test_backend_not_installed.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ def test_virtualenv(virtualenv):


if __name__ == "__main__":
# print("OKKK")
from fastapi_crudrouter import (
SQLAlchemyCRUDRouter,
DatabasesCRUDRouter,
GinoCRUDRouter,
OrmarCRUDRouter,
SQLAlchemyCRUDRouter,
TortoiseCRUDRouter,
)

Expand All @@ -23,6 +25,7 @@ def test_virtualenv(virtualenv):
DatabasesCRUDRouter,
OrmarCRUDRouter,
TortoiseCRUDRouter,
GinoCRUDRouter,
]

for crud_router in routers:
Expand Down

0 comments on commit 376f502

Please sign in to comment.