fastapi-basekit 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastapi_basekit/__init__.py +8 -0
- fastapi_basekit/aio/__init__.py +1 -0
- fastapi_basekit/aio/beanie/__init__.py +6 -0
- fastapi_basekit/aio/beanie/controller/base.py +21 -0
- fastapi_basekit/aio/beanie/repository/__init__.py +1 -0
- fastapi_basekit/aio/beanie/repository/base.py +129 -0
- fastapi_basekit/aio/beanie/service/base.py +115 -0
- fastapi_basekit/aio/controller/__init__.py +0 -0
- fastapi_basekit/aio/controller/base.py +131 -0
- fastapi_basekit/aio/permissions/__init__.py +0 -0
- fastapi_basekit/aio/permissions/base.py +10 -0
- fastapi_basekit/aio/sqlalchemy/__init__.py +6 -0
- fastapi_basekit/aio/sqlalchemy/controller/base.py +68 -0
- fastapi_basekit/aio/sqlalchemy/repository/__init__.py +1 -0
- fastapi_basekit/aio/sqlalchemy/repository/base.py +208 -0
- fastapi_basekit/aio/sqlalchemy/service/__init__.py +1 -0
- fastapi_basekit/aio/sqlalchemy/service/base.py +134 -0
- fastapi_basekit/exceptions/__init__.py +0 -0
- fastapi_basekit/exceptions/api_exceptions.py +119 -0
- fastapi_basekit/exceptions/handler.py +97 -0
- fastapi_basekit/schema/__init__.py +0 -0
- fastapi_basekit/schema/base.py +25 -0
- fastapi_basekit/schema/jwt.py +6 -0
- fastapi_basekit/schema/schema.py +17 -0
- fastapi_basekit/servicios/__init__.py +1 -0
- fastapi_basekit/servicios/thrid/__init__.py +1 -0
- fastapi_basekit/servicios/thrid/jwt.py +76 -0
- fastapi_basekit-0.1.0.dist-info/METADATA +356 -0
- fastapi_basekit-0.1.0.dist-info/RECORD +31 -0
- fastapi_basekit-0.1.0.dist-info/WHEEL +5 -0
- fastapi_basekit-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__all__ = ["controller", "beanie", "sqlalchemy"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import ClassVar, Type
|
|
2
|
+
|
|
3
|
+
from fastapi import Depends
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
from ...controller.base import BaseController
|
|
7
|
+
from ..service.base import BaseService
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class BeanieBaseController(BaseController):
|
|
11
|
+
"""BaseController para Beanie ODM (async).
|
|
12
|
+
|
|
13
|
+
Hereda el comportamiento del controlador base y conecta con
|
|
14
|
+
`Beanie` a través de su `BaseService` sin requerir `db` explícito.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
service: BaseService = Depends()
|
|
18
|
+
schema_class: ClassVar[Type[BaseModel]]
|
|
19
|
+
|
|
20
|
+
# No es necesario sobreescribir métodos CRUD; el base usa
|
|
21
|
+
# `self.service` con la firma de Beanie (sin `db`).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
from typing import Any, Dict, List, Optional, Type, Union
|
|
2
|
+
|
|
3
|
+
from bson import ObjectId
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
from beanie import Document
|
|
6
|
+
from beanie.odm.queries.find import FindMany
|
|
7
|
+
from beanie.operators import Or, RegEx
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class BaseRepository:
|
|
11
|
+
model: Type[Document]
|
|
12
|
+
|
|
13
|
+
def _get_query_kwargs(
|
|
14
|
+
self,
|
|
15
|
+
fetch_links: bool = False,
|
|
16
|
+
nesting_depths_per_field: Optional[Dict[str, int]] = None,
|
|
17
|
+
projection: Optional[Union[List[str], Type[BaseModel]]] = None,
|
|
18
|
+
):
|
|
19
|
+
kwargs = {
|
|
20
|
+
"fetch_links": fetch_links,
|
|
21
|
+
"nesting_depths_per_field": (
|
|
22
|
+
nesting_depths_per_field if fetch_links else None
|
|
23
|
+
),
|
|
24
|
+
}
|
|
25
|
+
if projection is not None:
|
|
26
|
+
kwargs["projection"] = projection
|
|
27
|
+
return kwargs
|
|
28
|
+
|
|
29
|
+
def build_filter_query(
|
|
30
|
+
self,
|
|
31
|
+
search: Optional[str],
|
|
32
|
+
search_fields: List[str],
|
|
33
|
+
filters: dict = None,
|
|
34
|
+
**kwargs,
|
|
35
|
+
) -> FindMany[Document]:
|
|
36
|
+
exprs = []
|
|
37
|
+
|
|
38
|
+
if search and search_fields:
|
|
39
|
+
exprs.append(
|
|
40
|
+
Or(
|
|
41
|
+
*[
|
|
42
|
+
RegEx(
|
|
43
|
+
getattr(self.model, f),
|
|
44
|
+
f".*{search}.*",
|
|
45
|
+
options="i",
|
|
46
|
+
)
|
|
47
|
+
for f in search_fields
|
|
48
|
+
]
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
for k, v in (filters or {}).items():
|
|
53
|
+
if hasattr(self.model, k):
|
|
54
|
+
exprs.append(getattr(self.model, k) == v)
|
|
55
|
+
|
|
56
|
+
query = self.model.find(*exprs, **self._get_query_kwargs(**kwargs))
|
|
57
|
+
return query
|
|
58
|
+
|
|
59
|
+
async def paginate(
|
|
60
|
+
self, query: FindMany[Document], page: int, count: int
|
|
61
|
+
) -> tuple[List[Document], int]:
|
|
62
|
+
total = await query.count()
|
|
63
|
+
items = await query.skip(count * (page - 1)).limit(count).to_list()
|
|
64
|
+
return items, total
|
|
65
|
+
|
|
66
|
+
async def get_by_id(
|
|
67
|
+
self,
|
|
68
|
+
obj_id: Union[str, ObjectId],
|
|
69
|
+
**kwargs,
|
|
70
|
+
) -> Optional[Document]:
|
|
71
|
+
if not isinstance(obj_id, ObjectId):
|
|
72
|
+
obj_id = ObjectId(obj_id)
|
|
73
|
+
return await self.model.find_one(
|
|
74
|
+
self.model.id == obj_id,
|
|
75
|
+
**self._get_query_kwargs(**kwargs),
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
async def get_by_field(
|
|
79
|
+
self,
|
|
80
|
+
field_name: str,
|
|
81
|
+
value: Any,
|
|
82
|
+
**kwargs,
|
|
83
|
+
) -> Optional[Document]:
|
|
84
|
+
if not hasattr(self.model, field_name):
|
|
85
|
+
raise AttributeError(
|
|
86
|
+
f"{self.model.__name__} no tiene el campo '{field_name}'"
|
|
87
|
+
)
|
|
88
|
+
return await self.model.find_one(
|
|
89
|
+
getattr(self.model, field_name) == value,
|
|
90
|
+
**self._get_query_kwargs(**kwargs),
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
async def get_by_fields(
|
|
94
|
+
self,
|
|
95
|
+
filters: Dict[str, Any],
|
|
96
|
+
**kwargs,
|
|
97
|
+
) -> Optional[Document]:
|
|
98
|
+
exprs = [
|
|
99
|
+
getattr(self.model, f) == v
|
|
100
|
+
for f, v in filters.items()
|
|
101
|
+
if hasattr(self.model, f)
|
|
102
|
+
]
|
|
103
|
+
if not exprs:
|
|
104
|
+
return None
|
|
105
|
+
return await self.model.find_one(
|
|
106
|
+
*exprs, **self._get_query_kwargs(**kwargs)
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
async def list_all(
|
|
110
|
+
self,
|
|
111
|
+
**kwargs,
|
|
112
|
+
) -> List[Document]:
|
|
113
|
+
query = self.model.find_all(**self._get_query_kwargs(**kwargs))
|
|
114
|
+
return await query.to_list()
|
|
115
|
+
|
|
116
|
+
async def create(self, obj: Union[Document, Dict[str, Any]]) -> Document:
|
|
117
|
+
if isinstance(obj, dict):
|
|
118
|
+
obj = self.model(**obj)
|
|
119
|
+
await obj.insert()
|
|
120
|
+
return obj
|
|
121
|
+
|
|
122
|
+
async def update(self, obj: Document, data: Dict[str, Any]) -> Document:
|
|
123
|
+
for key, value in data.items():
|
|
124
|
+
setattr(obj, key, value)
|
|
125
|
+
await obj.save()
|
|
126
|
+
return obj
|
|
127
|
+
|
|
128
|
+
async def delete(self, obj: Document) -> None:
|
|
129
|
+
await obj.delete()
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
from typing import Any, Dict, List, Optional, Union
|
|
2
|
+
|
|
3
|
+
from fastapi import Request
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
from ...beanie.repository.base import BaseRepository
|
|
8
|
+
from ....exceptions.api_exceptions import (
|
|
9
|
+
NotFoundException,
|
|
10
|
+
DatabaseIntegrityException,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BaseService:
|
|
15
|
+
"""Servicio base específico para Beanie ODM (async)."""
|
|
16
|
+
|
|
17
|
+
repository: BaseRepository
|
|
18
|
+
search_fields: List[str] = []
|
|
19
|
+
duplicate_check_fields: List[str] = []
|
|
20
|
+
kwargs_query: Dict[str, Union[str, int]] = {}
|
|
21
|
+
action: str = ""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self, repository: BaseRepository, request: Optional[Request] = None
|
|
25
|
+
):
|
|
26
|
+
self.repository = repository
|
|
27
|
+
self.request = request
|
|
28
|
+
endpoint_func = (
|
|
29
|
+
self.request.scope.get("endpoint") if self.request else None
|
|
30
|
+
)
|
|
31
|
+
self.action = endpoint_func.__name__ if endpoint_func else None
|
|
32
|
+
|
|
33
|
+
async def _check_duplicate(self, data: Dict[str, Any], fields: List[str]):
|
|
34
|
+
filters = {f: data[f] for f in fields if f in data}
|
|
35
|
+
if not filters:
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
existing = await self.repository.get_by_fields(filters)
|
|
39
|
+
if existing:
|
|
40
|
+
raise DatabaseIntegrityException(
|
|
41
|
+
message="Registro ya existe",
|
|
42
|
+
data=filters,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def get_kwargs_query(self) -> Dict[str, Any]:
|
|
46
|
+
return self.kwargs_query
|
|
47
|
+
|
|
48
|
+
def get_filters(
|
|
49
|
+
self,
|
|
50
|
+
filters: Optional[Dict[str, Any]] = None,
|
|
51
|
+
) -> Dict[str, Any]:
|
|
52
|
+
filters = filters or {}
|
|
53
|
+
return filters
|
|
54
|
+
|
|
55
|
+
async def retrieve(self, id: str):
|
|
56
|
+
kwargs = self.get_kwargs_query()
|
|
57
|
+
obj = await self.repository.get_by_id(id, **kwargs)
|
|
58
|
+
if not obj:
|
|
59
|
+
raise NotFoundException(f"id={id} no encontrado")
|
|
60
|
+
return obj
|
|
61
|
+
|
|
62
|
+
async def list(
|
|
63
|
+
self,
|
|
64
|
+
search: Optional[str] = None,
|
|
65
|
+
page: int = 1,
|
|
66
|
+
count: int = 25,
|
|
67
|
+
filters: Optional[Dict[str, Any]] = None,
|
|
68
|
+
):
|
|
69
|
+
kwargs = self.get_kwargs_query()
|
|
70
|
+
applied_filters = self.get_filters(filters)
|
|
71
|
+
query = self.repository.build_filter_query(
|
|
72
|
+
search=search,
|
|
73
|
+
search_fields=self.search_fields,
|
|
74
|
+
filters=applied_filters,
|
|
75
|
+
**kwargs,
|
|
76
|
+
)
|
|
77
|
+
return await self.repository.paginate(query, page, count)
|
|
78
|
+
|
|
79
|
+
async def create(
|
|
80
|
+
self, payload: BaseModel, check_fields: Optional[List[str]] = None
|
|
81
|
+
) -> Any:
|
|
82
|
+
data = (
|
|
83
|
+
payload.model_dump() if not isinstance(payload, dict) else payload
|
|
84
|
+
)
|
|
85
|
+
fields = (
|
|
86
|
+
check_fields
|
|
87
|
+
if check_fields is not None
|
|
88
|
+
else self.duplicate_check_fields
|
|
89
|
+
)
|
|
90
|
+
if fields:
|
|
91
|
+
await self._check_duplicate(data, fields)
|
|
92
|
+
created = await self.repository.create(data)
|
|
93
|
+
kwargs = self.get_kwargs_query()
|
|
94
|
+
return (
|
|
95
|
+
await self.repository.get_by_id(created.id, **kwargs)
|
|
96
|
+
if kwargs
|
|
97
|
+
else created
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
async def update(self, id: str, data: BaseModel) -> Any:
|
|
101
|
+
kwargs = self.get_kwargs_query()
|
|
102
|
+
obj = await self.repository.get_by_id(id, **kwargs)
|
|
103
|
+
if not obj:
|
|
104
|
+
raise NotFoundException(f"id={id} no encontrado")
|
|
105
|
+
if isinstance(data, BaseModel):
|
|
106
|
+
data = data.model_dump(exclude_unset=True)
|
|
107
|
+
updated = await self.repository.update(obj, data)
|
|
108
|
+
return updated
|
|
109
|
+
|
|
110
|
+
async def delete(self, id: str) -> str:
|
|
111
|
+
obj = await self.repository.get_by_id(id)
|
|
112
|
+
if not obj:
|
|
113
|
+
raise NotFoundException(f"id={id} no encontrado")
|
|
114
|
+
await self.repository.delete(obj)
|
|
115
|
+
return "deleted"
|
|
File without changes
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
from typing import Any, ClassVar, Dict, List, Optional, Type
|
|
2
|
+
from fastapi import Depends, Request
|
|
3
|
+
from pydantic import BaseModel, TypeAdapter
|
|
4
|
+
|
|
5
|
+
from ..permissions.base import BasePermission
|
|
6
|
+
|
|
7
|
+
from ...schema.base import BasePaginationResponse, BaseResponse
|
|
8
|
+
from ...exceptions.api_exceptions import PermissionException
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BaseController:
|
|
12
|
+
"""Montar rutas CRUD genericas y captura errores de negocio."""
|
|
13
|
+
|
|
14
|
+
service = Depends()
|
|
15
|
+
schema_class: ClassVar[Type[BaseModel]]
|
|
16
|
+
action: ClassVar[Optional[str]] = None
|
|
17
|
+
request: Request
|
|
18
|
+
|
|
19
|
+
def __init__(self) -> None:
|
|
20
|
+
endpoint_func = (
|
|
21
|
+
self.request.scope.get("endpoint") if self.request else None
|
|
22
|
+
)
|
|
23
|
+
self.action = endpoint_func.__name__ if endpoint_func else None
|
|
24
|
+
|
|
25
|
+
def get_schema_class(self) -> Type[BaseModel]:
|
|
26
|
+
assert self.schema_class is not None, (
|
|
27
|
+
"'%s' should either include a `schema_class` attribute, "
|
|
28
|
+
"or override the `get_serializer_class()` method."
|
|
29
|
+
% self.__class__.__name__
|
|
30
|
+
)
|
|
31
|
+
return self.schema_class
|
|
32
|
+
|
|
33
|
+
async def check_permissions_class(self):
|
|
34
|
+
permissions = self.check_permissions()
|
|
35
|
+
if permissions:
|
|
36
|
+
for permission in permissions:
|
|
37
|
+
obj = permission()
|
|
38
|
+
check = await obj.has_permission(self.request)
|
|
39
|
+
if not check:
|
|
40
|
+
raise PermissionException(obj.message_exception)
|
|
41
|
+
|
|
42
|
+
def check_permissions(self) -> List[Type[BasePermission]]:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
async def list(self):
|
|
46
|
+
params = self._params()
|
|
47
|
+
items, total = await self.service.list(**params)
|
|
48
|
+
pagination = {
|
|
49
|
+
"page": params.get("page"),
|
|
50
|
+
"count": params.get("count"),
|
|
51
|
+
"total": total,
|
|
52
|
+
}
|
|
53
|
+
return self.format_response(data=items, pagination=pagination)
|
|
54
|
+
|
|
55
|
+
async def retrieve(self, id: str):
|
|
56
|
+
item = await self.service.retrieve(id)
|
|
57
|
+
return self.format_response(data=item)
|
|
58
|
+
|
|
59
|
+
async def create(self, validated_data: Any):
|
|
60
|
+
result = await self.service.create(validated_data)
|
|
61
|
+
return self.format_response(result, message="Creado exitosamente")
|
|
62
|
+
|
|
63
|
+
async def update(self, id: str, validated_data: Any):
|
|
64
|
+
result = await self.service.update(id, validated_data)
|
|
65
|
+
return self.format_response(result, message="Actualizado exitosamente")
|
|
66
|
+
|
|
67
|
+
async def delete(self, id: str):
|
|
68
|
+
await self.service.delete(id)
|
|
69
|
+
return self.format_response(None, message="Eliminado exitosamente")
|
|
70
|
+
|
|
71
|
+
def format_response(
|
|
72
|
+
self,
|
|
73
|
+
data: Any,
|
|
74
|
+
pagination: Optional[Dict[str, Any]] = None,
|
|
75
|
+
message: Optional[str] = None,
|
|
76
|
+
status: str = "success",
|
|
77
|
+
) -> BaseModel:
|
|
78
|
+
schema = self.get_schema_class()
|
|
79
|
+
|
|
80
|
+
if isinstance(data, list):
|
|
81
|
+
data_dicts = [self.to_dict(item) for item in data]
|
|
82
|
+
adapter = TypeAdapter(List[schema])
|
|
83
|
+
data_parsed = adapter.validate_python(data_dicts)
|
|
84
|
+
elif self.service.repository and isinstance(
|
|
85
|
+
data, self.service.repository.model
|
|
86
|
+
):
|
|
87
|
+
data_parsed = self.to_dict(data)
|
|
88
|
+
data_parsed = schema.model_validate(data_parsed)
|
|
89
|
+
elif isinstance(data, dict):
|
|
90
|
+
data_parsed = schema.model_validate(data)
|
|
91
|
+
else:
|
|
92
|
+
data_parsed = data
|
|
93
|
+
|
|
94
|
+
if pagination:
|
|
95
|
+
return BasePaginationResponse(
|
|
96
|
+
data=data_parsed,
|
|
97
|
+
pagination=pagination,
|
|
98
|
+
message=message or "Operación exitosa",
|
|
99
|
+
status=status,
|
|
100
|
+
)
|
|
101
|
+
else:
|
|
102
|
+
return BaseResponse(
|
|
103
|
+
data=data_parsed,
|
|
104
|
+
message=message or "Operación exitosa",
|
|
105
|
+
status=status,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
def _params(self) -> Dict[str, Any]:
|
|
109
|
+
query_params = self.request.query_params if self.request else {}
|
|
110
|
+
|
|
111
|
+
page = int(query_params.get("page", 1))
|
|
112
|
+
count = int(query_params.get("count", 10))
|
|
113
|
+
search = query_params.get("search")
|
|
114
|
+
|
|
115
|
+
filters = {
|
|
116
|
+
k: v
|
|
117
|
+
for k, v in query_params.items()
|
|
118
|
+
if k not in ["page", "count", "search"]
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
"page": page,
|
|
123
|
+
"count": count,
|
|
124
|
+
"search": search,
|
|
125
|
+
"filters": filters,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
def to_dict(self, obj: Any):
|
|
129
|
+
if hasattr(obj, "model_dump"):
|
|
130
|
+
return obj.model_dump()
|
|
131
|
+
return obj
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from fastapi import Request
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class BasePermission:
|
|
5
|
+
message_exception: str = "Permiso denegado"
|
|
6
|
+
"""Clase base de permisos, para extender según lógica."""
|
|
7
|
+
|
|
8
|
+
async def has_permission(self, request: Request) -> bool:
|
|
9
|
+
"""Sobreescribir con la lógica de permiso."""
|
|
10
|
+
return True
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from typing import Any, ClassVar, List, Optional, Type
|
|
2
|
+
|
|
3
|
+
from fastapi import Depends
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
6
|
+
|
|
7
|
+
from ...controller.base import BaseController
|
|
8
|
+
from ..service.base import BaseService
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SQLAlchemyBaseController(BaseController):
|
|
12
|
+
"""BaseController para SQLAlchemy (AsyncSession).
|
|
13
|
+
|
|
14
|
+
- Acepta `db: AsyncSession` en operaciones CRUD.
|
|
15
|
+
- Construye y pasa parámetros específicos (joins, order_by, use_or).
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
service: BaseService = Depends()
|
|
19
|
+
schema_class: ClassVar[Type[BaseModel]]
|
|
20
|
+
|
|
21
|
+
async def list(
|
|
22
|
+
self,
|
|
23
|
+
db: AsyncSession,
|
|
24
|
+
*,
|
|
25
|
+
use_or: bool = False,
|
|
26
|
+
joins: Optional[List[str]] = None,
|
|
27
|
+
order_by: Optional[Any] = None,
|
|
28
|
+
):
|
|
29
|
+
params = self._params()
|
|
30
|
+
service_params = {
|
|
31
|
+
"page": params.get("page"),
|
|
32
|
+
"count": params.get("count"),
|
|
33
|
+
"filters": params.get("filters"),
|
|
34
|
+
"use_or": use_or,
|
|
35
|
+
"joins": joins,
|
|
36
|
+
"order_by": order_by,
|
|
37
|
+
}
|
|
38
|
+
items, total = await self.service.list(db, **service_params)
|
|
39
|
+
pagination = {
|
|
40
|
+
"page": params.get("page"),
|
|
41
|
+
"count": params.get("count"),
|
|
42
|
+
"total": total,
|
|
43
|
+
}
|
|
44
|
+
return self.format_response(data=items, pagination=pagination)
|
|
45
|
+
|
|
46
|
+
async def retrieve(
|
|
47
|
+
self, db: AsyncSession, id: str, *, joins: Optional[List[str]] = None
|
|
48
|
+
):
|
|
49
|
+
item = await self.service.retrieve(db, id, joins=joins)
|
|
50
|
+
return self.format_response(data=item)
|
|
51
|
+
|
|
52
|
+
async def create(
|
|
53
|
+
self,
|
|
54
|
+
db: AsyncSession,
|
|
55
|
+
validated_data: Any,
|
|
56
|
+
*,
|
|
57
|
+
check_fields: Optional[List[str]] = None,
|
|
58
|
+
):
|
|
59
|
+
result = await self.service.create(db, validated_data, check_fields)
|
|
60
|
+
return self.format_response(result, message="Creado exitosamente")
|
|
61
|
+
|
|
62
|
+
async def update(self, db: AsyncSession, id: str, validated_data: Any):
|
|
63
|
+
result = await self.service.update(db, id, validated_data)
|
|
64
|
+
return self.format_response(result, message="Actualizado exitosamente")
|
|
65
|
+
|
|
66
|
+
async def delete(self, db: AsyncSession, id: str):
|
|
67
|
+
await self.service.delete(db, id)
|
|
68
|
+
return self.format_response(None, message="Eliminado exitosamente")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|