Skip to content

Commit 49bc05f

Browse files
authored
Merge pull request #1 from mts-ai/added_sqlalchemy
Added SQLAlchemy
2 parents 502eeaf + 6609940 commit 49bc05f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+3993
-1004
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
/db.sqlite3-shm
77
/db.sqlite3-wal
88
/.idea
9+
/examples/api_for_sqlalchemy/db.sqlite3
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
## App API-FOR-TORTOISE-ORM
2+
3+
### Start app
4+
```shell
5+
# in dir fastapi-rest-jsonapi
6+
7+
export PYTHOPATH="${PYTHONPATH}:./"
8+
python examples/api_for_tortoise_orm/main.py
9+
```
10+
http://0.0.0.0:8080/docs

examples/api_for_sqlalchemy/__init__.py

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""service API package."""
2+
3+
from .user import UserFactory
4+
5+
__all__ = [
6+
"UserFactory",
7+
]
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
from http import HTTPStatus
2+
from typing import (
3+
List,
4+
Union,
5+
)
6+
7+
from fastapi import Depends
8+
from sqlalchemy import select, desc
9+
from sqlalchemy.ext.asyncio import AsyncSession
10+
from tortoise.exceptions import DoesNotExist
11+
from tortoise.queryset import QuerySet
12+
13+
from examples.api_for_sqlalchemy.extensions.sqlalchemy import Connector
14+
from examples.api_for_sqlalchemy.helpers.factories.meta_base import FactoryUseMode
15+
from examples.api_for_sqlalchemy.helpers.factories.user import UserFactory, ErrorCreateUserObject
16+
from examples.api_for_sqlalchemy.helpers.updaters.exceptions import ObjectNotFound
17+
from examples.api_for_sqlalchemy.helpers.updaters.update_user import UpdateUser, ErrorUpdateUserObject
18+
from examples.api_for_sqlalchemy.models.pydantic import UserSchema, UserPatchSchema
19+
from examples.api_for_sqlalchemy.models.pydantic.user import UserInSchema
20+
from examples.api_for_sqlalchemy.models.sqlalchemy import User
21+
from fastapi_rest_jsonapi import SqlalchemyEngine
22+
23+
from fastapi_rest_jsonapi.exceptions import (
24+
BadRequest,
25+
HTTPException,
26+
)
27+
from fastapi_rest_jsonapi.querystring import QueryStringManager
28+
from fastapi_rest_jsonapi.schema import JSONAPIResultListSchema
29+
30+
31+
class UserDetail:
32+
@classmethod
33+
async def get_user(cls, user_id, query_params: QueryStringManager, session: AsyncSession) -> User:
34+
"""
35+
Get user by id from ORM.
36+
37+
:param user_id: int
38+
:param query_params: QueryStringManager
39+
:return: User model.
40+
:raises HTTPException: if user not found.
41+
"""
42+
user: User
43+
try:
44+
user = (await session.execute(select(User).where(User.id == user_id))).scalar_one()
45+
except DoesNotExist:
46+
raise HTTPException(
47+
status_code=HTTPStatus.FORBIDDEN,
48+
detail="User with id {id} not found".format(id=user_id),
49+
)
50+
51+
return user
52+
53+
@classmethod
54+
async def get(cls, obj_id, query_params: QueryStringManager, session: AsyncSession = Depends(Connector.get_session)) -> UserSchema:
55+
user: User = await cls.get_user(user_id=obj_id, query_params=query_params, session=session)
56+
return UserSchema.from_orm(user)
57+
58+
@classmethod
59+
async def patch(cls, obj_id, data: UserPatchSchema, query_params: QueryStringManager, session: AsyncSession = Depends(Connector.get_session)) -> UserSchema:
60+
user_obj: User
61+
try:
62+
user_obj = await UpdateUser.update(
63+
obj_id,
64+
data.dict(exclude_unset=True),
65+
query_params.headers,
66+
session=session,
67+
)
68+
except ErrorUpdateUserObject as ex:
69+
raise BadRequest(ex.description, ex.field)
70+
except ObjectNotFound as ex:
71+
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail=ex.description)
72+
73+
user = UserSchema.from_orm(user_obj)
74+
return user
75+
76+
77+
class UserList:
78+
@classmethod
79+
async def get(cls, query_params: QueryStringManager, session: AsyncSession = Depends(Connector.get_session)) -> Union[QuerySet, JSONAPIResultListSchema]:
80+
user_query = select(User).order_by(desc(User.id))
81+
dl = SqlalchemyEngine(query=user_query, schema=UserSchema, model=User, session=session)
82+
count, users_db = await dl.get_collection(qs=query_params)
83+
total_pages = count // query_params.pagination.size + (count % query_params.pagination.size and 1)
84+
users: List[UserSchema] = [UserSchema.from_orm(i_user) for i_user in users_db]
85+
return JSONAPIResultListSchema(
86+
meta={"count": count, "totalPages": total_pages},
87+
data=[{"id": i_obj.id, "attributes": i_obj.dict(), "type": "user"} for i_obj in users],
88+
)
89+
90+
@classmethod
91+
async def post(cls, data: UserInSchema, query_params: QueryStringManager, session: AsyncSession = Depends(Connector.get_session)) -> UserSchema:
92+
try:
93+
user_obj = await UserFactory.create(
94+
data=data.dict(),
95+
mode=FactoryUseMode.production,
96+
header=query_params.headers,
97+
session=session,
98+
)
99+
except ErrorCreateUserObject as ex:
100+
raise BadRequest(ex.description, ex.field)
101+
102+
user = UserSchema.from_orm(user_obj)
103+
return user
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"""Factory call module."""
2+
3+
from examples.api_for_sqlalchemy.main import create_app
4+
5+
app = create_app()

examples/api_for_sqlalchemy/extensions/__init__.py

Whitespace-only changes.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from typing import Optional
2+
3+
from sqlalchemy.engine import make_url
4+
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
5+
from sqlalchemy.ext.declarative import declarative_base
6+
from sqlalchemy.orm import sessionmaker
7+
8+
9+
Base = declarative_base()
10+
11+
12+
def async_session() -> sessionmaker:
13+
uri = "sqlite+aiosqlite:///db.sqlite3"
14+
engine = create_async_engine(url=make_url(uri))
15+
_async_session = sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False)
16+
return _async_session
17+
18+
19+
class Connector:
20+
21+
@classmethod
22+
async def get_session(cls):
23+
"""
24+
Получение сессии к БД.
25+
26+
:return:
27+
"""
28+
async_session_ = async_session()
29+
async with async_session_() as db_session:
30+
async with db_session.begin():
31+
yield db_session
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Helpers for service package. Contains factories and updaters packages."""
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"""
2+
factories package.
3+
4+
Contains factories for creating user models.
5+
"""

0 commit comments

Comments
 (0)