-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12 from nickatnight/nickatnight-GH-9
[GH-9] Add repository and interfaces
- Loading branch information
Showing
16 changed files
with
209 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
{{ cookiecutter.project_slug }}/{{ cookiecutter.backend_container_name }}/src/core/enums.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
class SortOrder: | ||
ASC = "asc" | ||
DESC = "desc" |
7 changes: 7 additions & 0 deletions
7
...iecutter.project_slug }}/{{ cookiecutter.backend_container_name }}/src/core/exceptions.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
|
||
class {{ cookiecutter.project_name|title|replace(' ', '') }}Exception(Exception): | ||
pass | ||
|
||
|
||
class ObjectNotFound({{ cookiecutter.project_name|title|replace(' ', '') }}Exception): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
34 changes: 34 additions & 0 deletions
34
...er.project_slug }}/{{ cookiecutter.backend_container_name }}/src/interfaces/repository.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from abc import ABCMeta, abstractmethod | ||
from typing import Generic, Optional, TypeVar, List | ||
|
||
|
||
T = TypeVar("T") | ||
|
||
|
||
class IRepository(Generic[T], metaclass=ABCMeta): | ||
"""Class representing the repository interface.""" | ||
|
||
@abstractmethod | ||
async def create(self, obj_in: T, **kwargs: int) -> T: | ||
"""Create new entity and returns the saved instance.""" | ||
raise NotImplementedError | ||
|
||
@abstractmethod | ||
async def update(self, instance: T, obj_in: T) -> T: | ||
"""Updates an entity and returns the saved instance.""" | ||
raise NotImplementedError | ||
|
||
@abstractmethod | ||
async def get(self, **kwargs: int) -> T: | ||
"""Get and return one instance by filter.""" | ||
raise NotImplementedError | ||
|
||
@abstractmethod | ||
async def delete(self, **kwargs: int) -> None: | ||
"""Delete one instance by filter.""" | ||
raise NotImplementedError | ||
|
||
@abstractmethod | ||
async def all(self, skip: int = 0, limit: int = 50, sort_field: Optional[str] = None, sort_order: Optional[str] = None) -> List[T]: | ||
"""Delete one instance by filter.""" | ||
raise NotImplementedError |
43 changes: 0 additions & 43 deletions
43
...}}/{{ cookiecutter.backend_container_name }}/src/migrations/versions/3577cec8a2bb_init.py
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
103 changes: 103 additions & 0 deletions
103
....project_slug }}/{{ cookiecutter.backend_container_name }}/src/repositories/sqlalchemy.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import logging | ||
from typing import Optional, Type, TypeVar, List | ||
|
||
from sqlalchemy.ext.asyncio import AsyncSession | ||
from sqlmodel import SQLModel, select | ||
|
||
from src.core.exceptions import ObjectNotFound | ||
from src.interfaces.repository import IRepository | ||
|
||
ModelType = TypeVar("ModelType", bound=SQLModel) | ||
logger: logging.Logger = logging.getLogger(__name__) | ||
|
||
|
||
class SQLAlchemyRepository(IRepository[ModelType]): | ||
|
||
def __init__(self, model: Type[ModelType], db: AsyncSession) -> None: | ||
self.model = model | ||
self.db = db | ||
|
||
async def create(self, obj_in: ModelType, **kwargs: int) -> ModelType: | ||
logger.info(f"Inserting new object[{obj_in.__class__.__name__}]") | ||
|
||
db_obj = self.model.from_orm(obj_in) | ||
add = kwargs.get("add", True) | ||
flush = kwargs.get("flush", True) | ||
commit = kwargs.get("commit", True) | ||
|
||
if add: | ||
self.db.add(db_obj) | ||
|
||
# Navigate these with caution | ||
if add and commit: | ||
try: | ||
await self.db.commit() | ||
await self.db.refresh(db_obj) | ||
except Exception as exc: | ||
logger.error(exc) | ||
await self.db.rollback() | ||
|
||
elif add and flush: | ||
await self.db.flush() | ||
|
||
return db_obj | ||
|
||
async def get(self, **kwargs: int) -> ModelType: | ||
logger.info(f"Fetching [{self.model}] object by [{kwargs}]") | ||
|
||
query = select(self.model).filter_by(**kwargs) | ||
response = await self.db.execute(query) | ||
scalar: Optional[ModelType] = response.scalar_one_or_none() | ||
|
||
if not scalar: | ||
raise ObjectNotFound(f"Object with [{kwargs}] not found.") | ||
|
||
return scalar | ||
|
||
async def update(self, obj_current: ModelType, obj_in: ModelType) -> ModelType: | ||
logger.info(f"Updating [{self.model}] object with [{obj_in}]") | ||
|
||
update_data = obj_in.dict( | ||
exclude_unset=True | ||
) # This tells Pydantic to not include the values that were not sent | ||
|
||
for field in update_data: | ||
setattr(obj_current, field, update_data[field]) | ||
|
||
self.db.add(obj_current) | ||
await self.db.commit() | ||
await self.db.refresh(obj_current) | ||
|
||
return obj_current | ||
|
||
async def delete(self, **kwargs: int) -> None: | ||
obj = self.get(**kwargs) | ||
|
||
await self.db.delete(obj) | ||
await self.db.commit() | ||
|
||
async def all( | ||
self, | ||
skip: int = 0, | ||
limit: int = 100, | ||
sort_field: Optional[str] = None, | ||
sort_order: Optional[str] = None, | ||
) -> List[ModelType]: | ||
columns = self.model.__table__.columns # type: ignore | ||
|
||
if not sort_field: | ||
sort_field = "created_at" | ||
|
||
if not sort_order: | ||
sort_order = "desc" | ||
|
||
order_by = getattr(columns[sort_field], sort_order)() | ||
query = ( | ||
select(self.model) | ||
.offset(skip) | ||
.limit(limit) | ||
.order_by(order_by) | ||
) | ||
|
||
response = await self.db.execute(query) | ||
return response.scalars().all() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,4 +8,8 @@ class IMemeCreate(MemeBase): | |
|
||
|
||
class IMemeRead(MemeBase): | ||
id: UUID | ||
ref_id: UUID | ||
|
||
|
||
class IMemeUpdate(MemeBase): | ||
pass |