fastapi-sqlalchemy-toolkit 0.7.16__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.16 → fastapi_sqlalchemy_toolkit-0.7.18}/PKG-INFO +1 -1
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/fastapi_sqlalchemy_toolkit/model_manager.py +50 -3
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/pyproject.toml +1 -1
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/.flake8 +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/.github/workflows/docker-test.yml +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/.github/workflows/python-publish.yml +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/.gitignore +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/.pylintrc +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/AUTHORS +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/LICENSE +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/Makefile +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/README.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/benefits.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/db_validation.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/extension.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/filtering.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/index.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/benefits.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/db_validation.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/extension.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/filtering.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/index.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/sorting.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/transactions.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/usage.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/utils.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/sorting.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/transactions.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/usage.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/utils.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/.env +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/__init__.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/api/__init__.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/api/api.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/api/deps.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/api/endpoints/__init__.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/api/endpoints/child.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/config.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/db.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/main.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/managers.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/models.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/schemas.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/fastapi_sqlalchemy_toolkit/__init__.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/fastapi_sqlalchemy_toolkit/filters.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/fastapi_sqlalchemy_toolkit/ordering.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/fastapi_sqlalchemy_toolkit/utils.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/mkdocs.yml +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/requirements/base.txt +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/requirements/docs.txt +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/requirements/lint.txt +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/requirements/test.txt +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/Dockerfile +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/__init__.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/conftest.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/db.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/docker-compose.yml +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/models.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.16 → 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:
|
|
@@ -1075,10 +1081,16 @@ class ModelManager(Generic[ModelT, CreateSchemaT, UpdateSchemaT]):
|
|
|
1075
1081
|
Проверить, не нарушаются ли UniqueConstraint модели.
|
|
1076
1082
|
"""
|
|
1077
1083
|
for unique_constraint in self.unique_constraints:
|
|
1084
|
+
null_found = False
|
|
1078
1085
|
query = {}
|
|
1079
1086
|
for field in unique_constraint:
|
|
1080
|
-
if in_obj[field] is
|
|
1081
|
-
|
|
1087
|
+
if in_obj[field] is None:
|
|
1088
|
+
null_found = True
|
|
1089
|
+
break
|
|
1090
|
+
|
|
1091
|
+
query[field] = in_obj[field]
|
|
1092
|
+
if null_found:
|
|
1093
|
+
continue
|
|
1082
1094
|
if query:
|
|
1083
1095
|
object_exists = await self.exists(
|
|
1084
1096
|
session, **query, where=(self.model.id != in_obj.get("id"))
|
|
@@ -1113,7 +1125,7 @@ class ModelManager(Generic[ModelT, CreateSchemaT, UpdateSchemaT]):
|
|
|
1113
1125
|
continue
|
|
1114
1126
|
attrs_to_check = {column.name: in_obj[column.name]}
|
|
1115
1127
|
object_exists = await self.exists(
|
|
1116
|
-
session
|
|
1128
|
+
session,
|
|
1117
1129
|
**attrs_to_check,
|
|
1118
1130
|
where=(self.model.id != in_obj.get("id")),
|
|
1119
1131
|
)
|
|
@@ -1126,6 +1138,41 @@ class ModelManager(Generic[ModelT, CreateSchemaT, UpdateSchemaT]):
|
|
|
1126
1138
|
),
|
|
1127
1139
|
)
|
|
1128
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
|
+
|
|
1129
1176
|
async def handle_m2m_fields(self, session: AsyncSession, in_obj: ModelDict) -> None:
|
|
1130
1177
|
for field in in_obj:
|
|
1131
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.16 → 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.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/db_validation.md
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/docs/ru/extension.md
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.16 → 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.16 → 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.16 → 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.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/__init__.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/api/__init__.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/api/api.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.16 → 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.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/config.py
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/main.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/managers.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/examples/app/models.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.16 → 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.16 → fastapi_sqlalchemy_toolkit-0.7.18}/requirements/base.txt
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/requirements/docs.txt
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/requirements/lint.txt
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.16 → 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.16 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/docker-compose.yml
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.16 → fastapi_sqlalchemy_toolkit-0.7.18}/tests/test_public_methods.py
RENAMED
|
File without changes
|