Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HAN-102: Rollback de SQL #11

Merged
merged 5 commits into from
Apr 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions app/exceptions/UserException.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ def __init__(self):


class InvalidURL(HTTPException):
def __init__(self, id: int):
def __init__(self, detail: str):
status_code = status.HTTP_400_BAD_REQUEST
detail = "Invalid URL"
super().__init__(status_code=status_code, detail=detail)
12 changes: 6 additions & 6 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@


@app.get("/")
async def root():
return {"message": "Hello World"}
def root():
return {"message": "users service"}


@app.get("/users/{user_id}")
async def get_users(user_id: int):
def get_users(user_id: int):
return users_controller.handle_get_user(user_id)


@app.get("/users")
async def get_all_users():
def get_all_users():
return users_controller.handle_get_all_users()


@app.post("/users")
async def create_user(user_data: CreateUserSchema):
def create_user(user_data: CreateUserSchema):
return users_controller.handle_create_user(user_data.dict())


Expand All @@ -38,5 +38,5 @@ def login_with_google(request: LoginRequest):


@app.patch("/users/{user_id}")
async def update_user(user_id: int, update_data: UpdateUserSchema):
def update_user(user_id: int, update_data: UpdateUserSchema):
return users_controller.handle_update_user(user_id, update_data.dict())
7 changes: 7 additions & 0 deletions app/repository/Users.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from models.database import Base
from models.users import User
from datetime import date
from .sql_exception_handling import withSQLExceptionsHandle


class UsersRepository:
Expand All @@ -27,22 +28,27 @@ def shutdown(self):
def rollback(self):
self.session.rollback()

@withSQLExceptionsHandle()
def add(self, record: Base):
self.session.add(record)
self.session.commit()

@withSQLExceptionsHandle()
def get_user(self, user_id: int):
user = self.session.query(User).filter_by(id=user_id).first()
return user.__dict__ if user else None

@withSQLExceptionsHandle()
def get_user_by_email(self, email: str):
user = self.session.query(User).filter_by(email=email).first()
return user.__dict__ if user else None

@withSQLExceptionsHandle()
def get_all_users(self):
users = self.session.query(User).all()
return self.__parse_result(users)

@withSQLExceptionsHandle()
def create_user(
self,
email: str,
Expand Down Expand Up @@ -76,6 +82,7 @@ def create_user(
self.session.commit()
return new_user

@withSQLExceptionsHandle()
def edit_user(self, user_id: int, data_to_edit: dict):
user = self.session.query(User).filter_by(id=user_id).first()
for field, value in data_to_edit.items():
Expand Down
59 changes: 59 additions & 0 deletions app/repository/sql_exception_handling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from psycopg2.errors import UniqueViolation
from sqlalchemy.exc import PendingRollbackError, IntegrityError, NoResultFound
from fastapi import status, HTTPException
import logging

logger = logging.getLogger("app")
logger.setLevel("DEBUG")


def handle_common_errors(err):
if isinstance(err, IntegrityError):
if isinstance(err.orig, UniqueViolation):
parsed_error = err.orig.pgerror.split("\n")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail={
"error": parsed_error[0],
"detail": parsed_error[1]
})

raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=format(err))

if isinstance(err, PendingRollbackError):
logger.warning(format(err))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=format(err)
)

if isinstance(err, NoResultFound):
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail=format(err)
)

logger.error(format(err))
raise err


def withSQLExceptionsHandle(async_mode: bool = False):
def decorator(func):
async def handleAsyncSQLException(*args, **kwargs):
try:
return await func(*args, **kwargs)
except Exception as err:
return handle_common_errors(err)

def handleSyncSQLException(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as err:
return handle_common_errors(err)

return (
handleAsyncSQLException if async_mode else handleSyncSQLException
)

return decorator
13 changes: 11 additions & 2 deletions app/service/Users.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ def get_all_users(self):
def create_user(self, user_data: dict):
if not self._validate_location(user_data.get("location")):
raise InvalidData()
return self.user_repository.create_user(**user_data)
try:
user = self.user_repository.create_user(**user_data)
return user
except Exception as e:
self.user_repository.rollback()
raise e

def update_user(self, user_id: int, update_data: dict):
# TODO: aca habria que chequear a partir del token, session o algo que
Expand All @@ -38,7 +43,11 @@ def update_user(self, user_id: int, update_data: dict):
if not re.match(r'^https?://(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,6}'
r'(?:/[^/#?]+)+(?:\?.*)?$', photo_url):
raise InvalidURL("Invalid photo URL")
self.user_repository.edit_user(user_id, filtered_update_data)
try:
self.user_repository.edit_user(user_id, filtered_update_data)
except Exception as e:
self.user_repository.rollback()
raise e

def login(self, auth_code: str):
access_token = self._get_access_token(auth_code)
Expand Down
Loading