fastapi-sqlalchemy-toolkit 0.7.17__tar.gz → 0.7.18__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_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/PKG-INFO +1 -1
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/fastapi_sqlalchemy_toolkit/model_manager.py +42 -1
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/pyproject.toml +1 -1
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/.flake8 +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/.github/workflows/docker-test.yml +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/.github/workflows/python-publish.yml +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/.gitignore +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/.pylintrc +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/AUTHORS +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/LICENSE +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/Makefile +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/README.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/benefits.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/db_validation.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/extension.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/filtering.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/index.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/benefits.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/db_validation.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/extension.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/filtering.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/index.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/sorting.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/transactions.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/usage.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/utils.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/sorting.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/transactions.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/usage.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/utils.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/.env +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/__init__.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/api/__init__.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/api/api.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/api/deps.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/api/endpoints/__init__.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/api/endpoints/child.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/config.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/db.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/main.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/managers.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/models.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/schemas.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/fastapi_sqlalchemy_toolkit/__init__.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/fastapi_sqlalchemy_toolkit/filters.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/fastapi_sqlalchemy_toolkit/ordering.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/fastapi_sqlalchemy_toolkit/utils.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/mkdocs.yml +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/requirements/base.txt +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/requirements/docs.txt +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/requirements/lint.txt +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/requirements/test.txt +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/Dockerfile +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/__init__.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/conftest.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/db.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/docker-compose.yml +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/models.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/test_public_methods.py +0 -0
|
@@ -7,10 +7,12 @@ from fastapi_pagination.bases import BasePage
|
|
|
7
7
|
from fastapi_pagination.ext.sqlalchemy import paginate
|
|
8
8
|
from pydantic import BaseModel
|
|
9
9
|
from sqlalchemy import (
|
|
10
|
+
Index,
|
|
10
11
|
Integer,
|
|
11
12
|
Row,
|
|
12
13
|
String,
|
|
13
14
|
UniqueConstraint,
|
|
15
|
+
and_,
|
|
14
16
|
delete,
|
|
15
17
|
func,
|
|
16
18
|
insert,
|
|
@@ -65,6 +67,7 @@ class ModelManager(Generic[ModelT, CreateSchemaT, UpdateSchemaT]):
|
|
|
65
67
|
self.fk_name_to_model: dict[str, type[ModelT]] = {}
|
|
66
68
|
|
|
67
69
|
self.unique_constraints: List[List[str]] = []
|
|
70
|
+
self.unique_indexes: List[Index] = []
|
|
68
71
|
|
|
69
72
|
if hasattr(self.model, "__table_args__"):
|
|
70
73
|
for table_arg in self.model.__table_args__:
|
|
@@ -73,6 +76,8 @@ class ModelManager(Generic[ModelT, CreateSchemaT, UpdateSchemaT]):
|
|
|
73
76
|
self.unique_constraints.append(table_arg.columns.keys())
|
|
74
77
|
else:
|
|
75
78
|
self.unique_constraints.append(table_arg._pending_colargs)
|
|
79
|
+
elif isinstance(table_arg, Index) and table_arg.unique is True:
|
|
80
|
+
self.unique_indexes.append(table_arg)
|
|
76
81
|
|
|
77
82
|
self.reverse_relationships: dict[str, type[ModelT]] = {}
|
|
78
83
|
self.m2m_relationships: dict[str, type[ModelT]] = {}
|
|
@@ -865,6 +870,7 @@ class ModelManager(Generic[ModelT, CreateSchemaT, UpdateSchemaT]):
|
|
|
865
870
|
await self.handle_m2m_fields(session, in_obj)
|
|
866
871
|
await self.validate_unique_fields(session, in_obj, db_obj=db_obj)
|
|
867
872
|
await self.validate_unique_constraints(session, in_obj)
|
|
873
|
+
await self.validate_unique_indexes(session, in_obj)
|
|
868
874
|
return in_obj
|
|
869
875
|
|
|
870
876
|
def get_select(self, base_stmt: Select | None = None, **_kwargs: Any) -> Select:
|
|
@@ -1119,7 +1125,7 @@ class ModelManager(Generic[ModelT, CreateSchemaT, UpdateSchemaT]):
|
|
|
1119
1125
|
continue
|
|
1120
1126
|
attrs_to_check = {column.name: in_obj[column.name]}
|
|
1121
1127
|
object_exists = await self.exists(
|
|
1122
|
-
session
|
|
1128
|
+
session,
|
|
1123
1129
|
**attrs_to_check,
|
|
1124
1130
|
where=(self.model.id != in_obj.get("id")),
|
|
1125
1131
|
)
|
|
@@ -1132,6 +1138,41 @@ class ModelManager(Generic[ModelT, CreateSchemaT, UpdateSchemaT]):
|
|
|
1132
1138
|
),
|
|
1133
1139
|
)
|
|
1134
1140
|
|
|
1141
|
+
async def validate_unique_indexes(
|
|
1142
|
+
self, session: AsyncSession, in_obj: ModelDict
|
|
1143
|
+
) -> None:
|
|
1144
|
+
"""
|
|
1145
|
+
Валидирует соблюдение уникальности индексов
|
|
1146
|
+
"""
|
|
1147
|
+
for index in self.unique_indexes:
|
|
1148
|
+
condition = (
|
|
1149
|
+
index.dialect_options["postgresql"].get("where")
|
|
1150
|
+
if index.dialect_options.get("postgresql")
|
|
1151
|
+
else None
|
|
1152
|
+
)
|
|
1153
|
+
filters = []
|
|
1154
|
+
|
|
1155
|
+
for column in index.columns:
|
|
1156
|
+
try:
|
|
1157
|
+
filters.append(column == in_obj[column.name])
|
|
1158
|
+
except KeyError:
|
|
1159
|
+
if column.nullable:
|
|
1160
|
+
filters.append(column.is_(None))
|
|
1161
|
+
|
|
1162
|
+
object_exists = await self.exists(
|
|
1163
|
+
session,
|
|
1164
|
+
where=and_(*filters, condition, self.model.id != in_obj.get("id")),
|
|
1165
|
+
)
|
|
1166
|
+
if object_exists:
|
|
1167
|
+
raise HTTPException(
|
|
1168
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
1169
|
+
detail=(
|
|
1170
|
+
f"{self.model.__tablename__} с такими "
|
|
1171
|
+
+ ", ".join([column.name for column in index.columns])
|
|
1172
|
+
+ " уже существует."
|
|
1173
|
+
),
|
|
1174
|
+
)
|
|
1175
|
+
|
|
1135
1176
|
async def handle_m2m_fields(self, session: AsyncSession, in_obj: ModelDict) -> None:
|
|
1136
1177
|
for field in in_obj:
|
|
1137
1178
|
if field in self.m2m_relationships:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/db_validation.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/db_validation.md
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/extension.md
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/filtering.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/transactions.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/transactions.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/__init__.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/api/__init__.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/api/api.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/api/deps.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/config.py
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/main.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/managers.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/models.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/schemas.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/requirements/base.txt
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/requirements/docs.txt
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/requirements/lint.txt
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/requirements/test.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/docker-compose.yml
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.17 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/test_public_methods.py
RENAMED
|
File without changes
|