fastapi-basekit 0.4.3__tar.gz → 0.5.2__tar.gz
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-0.4.3 → fastapi_basekit-0.5.2}/PKG-INFO +3 -3
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/beanie/controller/base.py +1 -1
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/beanie/repository/base.py +76 -12
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/beanie/service/base.py +60 -26
- fastapi_basekit-0.5.2/fastapi_basekit/aio/controller/base.py +438 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/sqlalchemy/controller/base.py +1 -1
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/sqlalchemy/repository/base.py +93 -16
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/sqlalchemy/service/base.py +48 -10
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/sqlmodel/repository/base.py +120 -22
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/sqlmodel/service/base.py +36 -11
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/exceptions/handler.py +15 -0
- fastapi_basekit-0.5.2/fastapi_basekit/py.typed +1 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/servicios/thrid/jwt.py +42 -7
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit.egg-info/PKG-INFO +3 -3
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit.egg-info/SOURCES.txt +21 -1
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit.egg-info/requires.txt +2 -2
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/pyproject.toml +4 -3
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_action_param_leak.py +41 -2
- fastapi_basekit-0.5.2/tests/test_beanie_repository_regression.py +295 -0
- fastapi_basekit-0.5.2/tests/test_beanie_service_regression.py +244 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_exception_handlers.py +30 -0
- fastapi_basekit-0.5.2/tests/test_generics_optional_and_cache.py +99 -0
- fastapi_basekit-0.5.2/tests/test_generics_wiring.py +100 -0
- fastapi_basekit-0.5.2/tests/test_jwt_config_robustness.py +61 -0
- fastapi_basekit-0.5.2/tests/test_params_classification.py +193 -0
- fastapi_basekit-0.5.2/tests/test_params_coercion_matrix.py +110 -0
- fastapi_basekit-0.5.2/tests/test_params_coercion_unit.py +165 -0
- fastapi_basekit-0.5.2/tests/test_params_http_matrix_beanie.py +109 -0
- fastapi_basekit-0.5.2/tests/test_params_http_matrix_sqlalchemy.py +114 -0
- fastapi_basekit-0.5.2/tests/test_params_rich_type_coercion.py +79 -0
- fastapi_basekit-0.5.2/tests/test_path_filter_mixin_compat.py +179 -0
- fastapi_basekit-0.5.2/tests/test_post_process_list_hook.py +154 -0
- fastapi_basekit-0.5.2/tests/test_pulbot_cbv_pattern_beanie.py +146 -0
- fastapi_basekit-0.5.2/tests/test_repo_signature_aliases.py +74 -0
- fastapi_basekit-0.5.2/tests/test_sqlalchemy_repository_regression.py +173 -0
- fastapi_basekit-0.5.2/tests/test_sqlalchemy_service_regression.py +154 -0
- fastapi_basekit-0.5.2/tests/test_sqlmodel_filter_operators.py +92 -0
- fastapi_basekit-0.5.2/tests/test_typed_filter_coercion.py +114 -0
- fastapi_basekit-0.4.3/fastapi_basekit/aio/controller/base.py +0 -301
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/LICENSE +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/README.md +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/beanie/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/beanie/controller/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/beanie/repository/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/beanie/service/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/controller/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/permissions/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/permissions/base.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/sqlalchemy/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/sqlalchemy/controller/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/sqlalchemy/repository/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/sqlalchemy/service/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/sqlalchemy/session.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/sqlmodel/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/sqlmodel/controller/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/sqlmodel/controller/base.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/sqlmodel/repository/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/sqlmodel/service/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/cli/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/cli/main.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/exceptions/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/exceptions/api_exceptions.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/exceptions/domain.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/openapi.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/schema/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/schema/base.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/schema/jwt.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/schema/schema.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/servicios/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/servicios/thrid/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/cookiecutter.json +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/hooks/post_gen_project.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/hooks/pre_gen_project.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/.env.example +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/.gitignore +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/Dockerfile +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/LICENSE +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/Makefile +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/README.md +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/alembic/env.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/alembic/script.py.mako +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/alembic.ini +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/api/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/api/v1/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/api/v1/endpoints/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/api/v1/endpoints/auth/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/api/v1/endpoints/auth/auth.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/api/v1/endpoints/user/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/api/v1/endpoints/user/user.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/api/v1/routers.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/config/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/config/database.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/config/settings.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/main.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/middleware/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/middleware/auth.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/middleware/permissions.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/models/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/models/auth.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/models/base.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/models/enums.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/models/types.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/permissions/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/permissions/user.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/repositories/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/repositories/user/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/repositories/user/repository.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/schemas/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/schemas/auth.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/schemas/base.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/schemas/user.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/scripts/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/scripts/init.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/scripts/init_admin.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/services/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/services/auth_service.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/services/dependency.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/services/user_service.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/utils/__init__.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/utils/exception_handlers.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/app/utils/security.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/docker-compose.yml +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/pytest.ini +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/templates/project/{{cookiecutter.project_slug}}/requirements.txt +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit.egg-info/dependency_links.txt +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit.egg-info/entry_points.txt +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit.egg-info/top_level.txt +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/setup.cfg +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_api_exceptions.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_base_response.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_base_service.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_beanie_aggregation_hooks.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_beanie_aggregation_integration.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_beanie_keyset_pagination.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_beanie_service_mutable_defaults.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_controller_auto_permissions.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_crud_beanie_controller.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_crud_controller.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_crud_sqlmodel_repository_service.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_filter_operators.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_jwt_service.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_openapi_simplify.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_sql_queryset_override.py +0 -0
- {fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/tests/test_sqlalchemy_base_service_order.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fastapi-basekit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: Utilities and base classes for FastAPI async projects (Beanie, SQLAlchemy or SQLModel)
|
|
5
5
|
Author-email: Jerson Moreno <jerson.ml820@hotmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -23,7 +23,7 @@ Provides-Extra: beanie
|
|
|
23
23
|
Requires-Dist: beanie<3,>=2.0; extra == "beanie"
|
|
24
24
|
Provides-Extra: sqlalchemy
|
|
25
25
|
Requires-Dist: SQLAlchemy[asyncio]<3,>=2.0.30; extra == "sqlalchemy"
|
|
26
|
-
Requires-Dist: psycopg2>=2.9.0; extra == "sqlalchemy"
|
|
26
|
+
Requires-Dist: psycopg2-binary>=2.9.0; extra == "sqlalchemy"
|
|
27
27
|
Provides-Extra: sqlmodel
|
|
28
28
|
Requires-Dist: sqlmodel>=0.0.37; extra == "sqlmodel"
|
|
29
29
|
Provides-Extra: init
|
|
@@ -37,7 +37,7 @@ Requires-Dist: mike>=2.1.0; extra == "docs"
|
|
|
37
37
|
Provides-Extra: all
|
|
38
38
|
Requires-Dist: beanie<3,>=2.0; extra == "all"
|
|
39
39
|
Requires-Dist: SQLAlchemy[asyncio]<3,>=2.0.30; extra == "all"
|
|
40
|
-
Requires-Dist: psycopg2>=2.9.0; extra == "all"
|
|
40
|
+
Requires-Dist: psycopg2-binary>=2.9.0; extra == "all"
|
|
41
41
|
Requires-Dist: sqlmodel>=0.0.37; extra == "all"
|
|
42
42
|
Requires-Dist: cookiecutter>=2.5.0; extra == "all"
|
|
43
43
|
Requires-Dist: mkdocs>=1.6.0; extra == "all"
|
{fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/beanie/controller/base.py
RENAMED
|
@@ -19,7 +19,7 @@ class BeanieBaseController(BaseController):
|
|
|
19
19
|
async def list(self):
|
|
20
20
|
"""Lista documentos con paginación usando Beanie."""
|
|
21
21
|
await self.prepare_action("list")
|
|
22
|
-
params = self._params(
|
|
22
|
+
params = self._params()
|
|
23
23
|
items, total = await self.service.list(**params)
|
|
24
24
|
count = params.get("count") or 0
|
|
25
25
|
page = params.get("page") or 1
|
{fastapi_basekit-0.4.3 → fastapi_basekit-0.5.2}/fastapi_basekit/aio/beanie/repository/base.py
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import Any, Dict, List, Optional, Type, Union
|
|
2
|
+
from typing import Any, Dict, Generic, List, Optional, Type, TypeVar, Union
|
|
3
3
|
from typing import get_args, get_origin
|
|
4
4
|
import re
|
|
5
5
|
|
|
@@ -11,10 +11,31 @@ from beanie.operators import Or, RegEx
|
|
|
11
11
|
|
|
12
12
|
logger = logging.getLogger(__name__)
|
|
13
13
|
|
|
14
|
+
#: Tipo del Document Beanie que gestiona el repositorio. Parametrízalo al
|
|
15
|
+
#: declarar la subclase — ``class UserRepository(BaseRepository[User])`` — para
|
|
16
|
+
#: que ``get_by_id``/``create``/``update``/``list_all`` devuelvan el Document
|
|
17
|
+
#: tipado (autocompletado + mypy para consumidores e IAs).
|
|
18
|
+
ModelT = TypeVar("ModelT", bound=Document)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class BaseRepository(Generic[ModelT]):
|
|
22
|
+
"""Repositorio base para Beanie ODM (MongoDB), parametrizado por el modelo.
|
|
23
|
+
|
|
24
|
+
OJO — las firmas difieren del repo SQLAlchemy (misma clase, distinto ORM):
|
|
25
|
+
- get por id: `get_by_id(id)` (SQL usa `get(id)`)
|
|
26
|
+
- update: `update(obj, data)` — el 1er arg es el **Document**, no el
|
|
27
|
+
id (SQL usa `update(id, dict)`). Fetch primero con
|
|
28
|
+
`get_by_id`, luego `update(obj, data)`.
|
|
29
|
+
- delete: `delete(obj)` — recibe el Document (SQL usa `delete(id)`).
|
|
30
|
+
- create: `create(obj | dict)`.
|
|
31
|
+
Listado: `build_list_queryset(...)`→FindMany + `paginate(...)`, o
|
|
32
|
+
`build_list_pipeline(...)` + `paginate_pipeline(...)` para joins (`$lookup`).
|
|
33
|
+
Preferí llamar el SERVICE (API unificada) en vez del repo directo; llamar
|
|
34
|
+
`get_by_id` directo bypassea el scoping de `get_filters()`.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
model: Type[ModelT]
|
|
14
38
|
|
|
15
|
-
class BaseRepository:
|
|
16
|
-
model: Type[Document]
|
|
17
|
-
|
|
18
39
|
def _parse_order_field(self, order_by: str) -> tuple[str, int, bool]:
|
|
19
40
|
"""Parse order_by string into components.
|
|
20
41
|
|
|
@@ -194,6 +215,19 @@ class BaseRepository:
|
|
|
194
215
|
exprs.append(field_attr.id == _coerce_objectid(v))
|
|
195
216
|
continue
|
|
196
217
|
|
|
218
|
+
# Clave no resoluble (typo, campo inexistente, nesting mal escrito).
|
|
219
|
+
# Se descarta — pero se AVISA: si la clave venía de `get_filters`
|
|
220
|
+
# (scoping por tenant/owner), su desaparición silenciosa deja el
|
|
221
|
+
# listado sin filtrar → fuga cross-tenant (IDOR). El warning hace
|
|
222
|
+
# visible la pérdida en logs/Sentry en vez de fallar en silencio.
|
|
223
|
+
logger.warning(
|
|
224
|
+
"build_filter_query: filtro '%s' descartado (no resuelve a "
|
|
225
|
+
"ningún campo de %s). Si era un filtro de scoping, el listado "
|
|
226
|
+
"queda SIN ese filtro.",
|
|
227
|
+
k,
|
|
228
|
+
getattr(self.model, "__name__", self.model),
|
|
229
|
+
)
|
|
230
|
+
|
|
197
231
|
# Raw MongoDB filters go first so Beanie processes them as a dict condition
|
|
198
232
|
query_args: list = ([raw_filters] if raw_filters else []) + exprs
|
|
199
233
|
query = self.model.find(*query_args, **self._get_query_kwargs(**kwargs))
|
|
@@ -207,6 +241,17 @@ class BaseRepository:
|
|
|
207
241
|
async def paginate(
|
|
208
242
|
self, query: FindMany[Document], page: int, count: int, order_by: Optional[List[tuple]] = None
|
|
209
243
|
) -> tuple[List[Document], int]:
|
|
244
|
+
"""MOTOR DE PAGINACIÓN (FindMany) — NO LO REIMPLEMENTES.
|
|
245
|
+
|
|
246
|
+
Único loop de paginación offset (count + skip/limit). Para personalizar
|
|
247
|
+
el listado, override el HOOK correcto, no copies skip/limit/count:
|
|
248
|
+
- query/filtros/scoping/orden → `build_list_queryset` (o `build_filter_query`)
|
|
249
|
+
- join `$lookup` / shape plano → `use_aggregation=True` + `build_list_pipeline`
|
|
250
|
+
- filtros por usuario/acción → `Service.get_filters`
|
|
251
|
+
- orden por defecto → `Service.get_order`
|
|
252
|
+
- enriquecer items de la página→ `Service.post_process_list`
|
|
253
|
+
- scroll infinito / cursor → `paginate_keyset` (método+endpoint aparte)
|
|
254
|
+
"""
|
|
210
255
|
# Apply ordering if provided and not already applied
|
|
211
256
|
if order_by:
|
|
212
257
|
query = query.sort(order_by)
|
|
@@ -379,7 +424,13 @@ class BaseRepository:
|
|
|
379
424
|
count: int,
|
|
380
425
|
validate: bool = True,
|
|
381
426
|
) -> tuple[List[Any], int]:
|
|
382
|
-
"""
|
|
427
|
+
"""MOTOR DE PAGINACIÓN (aggregation `$facet`) — NO LO REIMPLEMENTES.
|
|
428
|
+
|
|
429
|
+
Ejecuta el pipeline con paginación `$facet`. Para un listado agregado
|
|
430
|
+
NO copies este `$facet`/skip/limit: override `Service.build_list_pipeline`
|
|
431
|
+
(agrega `$lookup`/`$project`/`$group`) y activa `use_aggregation=True`;
|
|
432
|
+
este método le pone la paginación. Si la proyección no es el modelo,
|
|
433
|
+
`aggregation_validate=False`.
|
|
383
434
|
|
|
384
435
|
Args:
|
|
385
436
|
pipeline: Pipeline stages (without the final `$facet`).
|
|
@@ -471,7 +522,7 @@ class BaseRepository:
|
|
|
471
522
|
self,
|
|
472
523
|
obj_id: Union[str, ObjectId],
|
|
473
524
|
**kwargs,
|
|
474
|
-
) -> Optional[
|
|
525
|
+
) -> Optional[ModelT]:
|
|
475
526
|
if not isinstance(obj_id, ObjectId):
|
|
476
527
|
obj_id = ObjectId(obj_id)
|
|
477
528
|
return await self.model.find_one(
|
|
@@ -479,12 +530,19 @@ class BaseRepository:
|
|
|
479
530
|
**self._get_query_kwargs(**kwargs),
|
|
480
531
|
)
|
|
481
532
|
|
|
533
|
+
async def get(
|
|
534
|
+
self, obj_id: Union[str, ObjectId], **kwargs
|
|
535
|
+
) -> Optional[ModelT]:
|
|
536
|
+
"""Alias de `get_by_id(id)` — nombre unificado con los repos SQL
|
|
537
|
+
(`get`) para que las lecturas por id sean portables entre ORMs."""
|
|
538
|
+
return await self.get_by_id(obj_id, **kwargs)
|
|
539
|
+
|
|
482
540
|
async def get_by_field(
|
|
483
541
|
self,
|
|
484
542
|
field_name: str,
|
|
485
543
|
value: Any,
|
|
486
544
|
**kwargs,
|
|
487
|
-
) -> Optional[
|
|
545
|
+
) -> Optional[ModelT]:
|
|
488
546
|
if not hasattr(self.model, field_name):
|
|
489
547
|
raise AttributeError(
|
|
490
548
|
f"{self.model.__name__} no tiene el campo '{field_name}'"
|
|
@@ -498,7 +556,7 @@ class BaseRepository:
|
|
|
498
556
|
self,
|
|
499
557
|
filters: Dict[str, Any],
|
|
500
558
|
**kwargs,
|
|
501
|
-
) -> Optional[
|
|
559
|
+
) -> Optional[ModelT]:
|
|
502
560
|
exprs = [
|
|
503
561
|
getattr(self.model, f) == v
|
|
504
562
|
for f, v in filters.items()
|
|
@@ -513,21 +571,27 @@ class BaseRepository:
|
|
|
513
571
|
async def list_all(
|
|
514
572
|
self,
|
|
515
573
|
**kwargs,
|
|
516
|
-
) -> List[
|
|
574
|
+
) -> List[ModelT]:
|
|
517
575
|
query = self.model.find_all(**self._get_query_kwargs(**kwargs))
|
|
518
576
|
return await query.to_list()
|
|
519
577
|
|
|
520
|
-
async def create(self, obj: Union[
|
|
578
|
+
async def create(self, obj: Union[ModelT, Dict[str, Any]]) -> ModelT:
|
|
521
579
|
if isinstance(obj, dict):
|
|
522
580
|
obj = self.model(**obj)
|
|
523
581
|
await obj.insert()
|
|
524
582
|
return obj
|
|
525
583
|
|
|
526
|
-
async def update(self, obj:
|
|
584
|
+
async def update(self, obj: ModelT, data: Dict[str, Any]) -> ModelT:
|
|
585
|
+
"""Actualiza un Document Beanie ya cargado.
|
|
586
|
+
|
|
587
|
+
Divergencia con SQL: acá el 1er arg es el **Document** (no el id) y SÍ
|
|
588
|
+
setea ``None``. El repo SQLAlchemy usa ``update(id, dict)`` y omite
|
|
589
|
+
``None``. Ver la tabla en el CLAUDE.md de la lib.
|
|
590
|
+
"""
|
|
527
591
|
for key, value in data.items():
|
|
528
592
|
setattr(obj, key, value)
|
|
529
593
|
await obj.save()
|
|
530
594
|
return obj
|
|
531
595
|
|
|
532
|
-
async def delete(self, obj:
|
|
596
|
+
async def delete(self, obj: ModelT) -> None:
|
|
533
597
|
await obj.delete()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any, Dict, List, Optional, Union
|
|
1
|
+
from typing import Any, Dict, Generic, List, Optional, Tuple, Union
|
|
2
2
|
|
|
3
3
|
from beanie import Document
|
|
4
4
|
from beanie.odm.queries.find import FindMany
|
|
@@ -6,17 +6,25 @@ from fastapi import Request
|
|
|
6
6
|
from pydantic import BaseModel
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
from ...beanie.repository.base import BaseRepository
|
|
9
|
+
from ...beanie.repository.base import BaseRepository, ModelT
|
|
10
10
|
from ....exceptions.api_exceptions import (
|
|
11
11
|
NotFoundException,
|
|
12
12
|
DatabaseIntegrityException,
|
|
13
13
|
)
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
class BaseService:
|
|
17
|
-
"""Servicio base específico para Beanie ODM (async).
|
|
16
|
+
class BaseService(Generic[ModelT]):
|
|
17
|
+
"""Servicio base específico para Beanie ODM (async), parametrizado.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Declara el modelo vía el genérico para tipar el CRUD::
|
|
20
|
+
|
|
21
|
+
class UserService(BaseService[User]):
|
|
22
|
+
repository: UserRepository
|
|
23
|
+
|
|
24
|
+
Así ``retrieve``/``create``/``update`` devuelven ``User``.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
repository: BaseRepository[ModelT]
|
|
20
28
|
search_fields: List[str] = []
|
|
21
29
|
duplicate_check_fields: List[str] = []
|
|
22
30
|
kwargs_query: Dict[str, Union[str, int]] = {}
|
|
@@ -74,7 +82,7 @@ class BaseService:
|
|
|
74
82
|
filters = filters or {}
|
|
75
83
|
return filters
|
|
76
84
|
|
|
77
|
-
async def retrieve(self, id: str):
|
|
85
|
+
async def retrieve(self, id: str) -> ModelT:
|
|
78
86
|
kwargs = self.get_kwargs_query()
|
|
79
87
|
obj = await self.repository.get_by_id(id, **kwargs)
|
|
80
88
|
if not obj:
|
|
@@ -133,7 +141,7 @@ class BaseService:
|
|
|
133
141
|
count: int = 25,
|
|
134
142
|
filters: Optional[Dict[str, Any]] = None,
|
|
135
143
|
order_by: Optional[str] = None, # Dynamic ordering (e.g., "-created_at" or "tool__name")
|
|
136
|
-
):
|
|
144
|
+
) -> Tuple[List[ModelT], int]:
|
|
137
145
|
kwargs = self.get_kwargs_query()
|
|
138
146
|
applied_filters = self.get_filters(filters)
|
|
139
147
|
|
|
@@ -159,34 +167,60 @@ class BaseService:
|
|
|
159
167
|
order_by=order_str,
|
|
160
168
|
**kwargs,
|
|
161
169
|
)
|
|
162
|
-
|
|
170
|
+
items, total = await self.repository.paginate_pipeline(
|
|
163
171
|
pipeline,
|
|
164
172
|
page=page,
|
|
165
173
|
count=count,
|
|
166
174
|
validate=self.aggregation_validate,
|
|
167
175
|
)
|
|
176
|
+
else:
|
|
177
|
+
# FindMany path
|
|
178
|
+
order_list = None
|
|
179
|
+
if order_str:
|
|
180
|
+
direction = -1 if order_str.startswith("-") else 1
|
|
181
|
+
field = order_str.lstrip("-")
|
|
182
|
+
order_list = [(field, direction)]
|
|
168
183
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
184
|
+
query = self.build_list_queryset(
|
|
185
|
+
search=search,
|
|
186
|
+
search_fields=self.search_fields,
|
|
187
|
+
filters=applied_filters,
|
|
188
|
+
order_by=order_list,
|
|
189
|
+
**kwargs,
|
|
190
|
+
)
|
|
191
|
+
items, total = await self.repository.paginate(
|
|
192
|
+
query, page, count, order_by=order_list
|
|
193
|
+
)
|
|
175
194
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
)
|
|
195
|
+
items = await self.post_process_list(items)
|
|
196
|
+
return items, total
|
|
197
|
+
|
|
198
|
+
async def post_process_list(self, items: List[ModelT]) -> List[ModelT]:
|
|
199
|
+
"""Hook: transforma/enriquece los items DE UNA PÁGINA ya paginada.
|
|
200
|
+
|
|
201
|
+
Este es el método para "hacer algo custom con los resultados" SIN
|
|
202
|
+
reescribir la paginación ni overridear `list()`. Corre después de
|
|
203
|
+
`paginate`/`paginate_pipeline`, sobre los items de la página actual
|
|
204
|
+
(no toda la colección), así que es seguro para un enrich con un `await`
|
|
205
|
+
extra por página (agrega un contador, resuelve un campo derivado, etc.).
|
|
206
|
+
|
|
207
|
+
Default: devuelve los items sin cambios. Ejemplo::
|
|
208
|
+
|
|
209
|
+
async def post_process_list(self, items):
|
|
210
|
+
ids = [c.id for c in items]
|
|
211
|
+
counts = await self.conv_repo.count_by_customer_ids(ids)
|
|
212
|
+
for c in items:
|
|
213
|
+
c.conversation_count = counts.get(c.id, 0)
|
|
214
|
+
return items
|
|
215
|
+
|
|
216
|
+
NO cambies el `total` acá (es el de la query completa). NO filtres items
|
|
217
|
+
(eso va en `get_filters`/`build_list_*`, o el total quedaría mal).
|
|
218
|
+
"""
|
|
219
|
+
return items
|
|
186
220
|
|
|
187
221
|
async def create(
|
|
188
222
|
self, payload: BaseModel, check_fields: Optional[List[str]] = None
|
|
189
|
-
) ->
|
|
223
|
+
) -> ModelT:
|
|
190
224
|
data = (
|
|
191
225
|
payload.model_dump() if not isinstance(payload, dict) else payload
|
|
192
226
|
)
|
|
@@ -205,7 +239,7 @@ class BaseService:
|
|
|
205
239
|
else created
|
|
206
240
|
)
|
|
207
241
|
|
|
208
|
-
async def update(self, id: str, data: BaseModel) ->
|
|
242
|
+
async def update(self, id: str, data: BaseModel) -> ModelT:
|
|
209
243
|
kwargs = self.get_kwargs_query()
|
|
210
244
|
obj = await self.repository.get_by_id(id, **kwargs)
|
|
211
245
|
if not obj:
|