fastapi-sqlalchemy-toolkit 0.7.14__tar.gz → 0.7.16__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.
Files changed (59) hide show
  1. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/PKG-INFO +1 -1
  2. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/fastapi_sqlalchemy_toolkit/model_manager.py +17 -58
  3. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/pyproject.toml +1 -1
  4. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/.flake8 +0 -0
  5. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/.github/workflows/docker-test.yml +0 -0
  6. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/.github/workflows/python-publish.yml +0 -0
  7. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/.gitignore +0 -0
  8. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/.pylintrc +0 -0
  9. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/AUTHORS +0 -0
  10. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/LICENSE +0 -0
  11. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/Makefile +0 -0
  12. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/README.md +0 -0
  13. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/benefits.md +0 -0
  14. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/db_validation.md +0 -0
  15. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/extension.md +0 -0
  16. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/filtering.md +0 -0
  17. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/index.md +0 -0
  18. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/benefits.md +0 -0
  19. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/db_validation.md +0 -0
  20. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/extension.md +0 -0
  21. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/filtering.md +0 -0
  22. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/index.md +0 -0
  23. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/sorting.md +0 -0
  24. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/transactions.md +0 -0
  25. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/usage.md +0 -0
  26. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/utils.md +0 -0
  27. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/sorting.md +0 -0
  28. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/transactions.md +0 -0
  29. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/usage.md +0 -0
  30. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/utils.md +0 -0
  31. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/.env +0 -0
  32. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/__init__.py +0 -0
  33. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/api/__init__.py +0 -0
  34. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/api/api.py +0 -0
  35. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/api/deps.py +0 -0
  36. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/api/endpoints/__init__.py +0 -0
  37. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/api/endpoints/child.py +0 -0
  38. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/config.py +0 -0
  39. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/db.py +0 -0
  40. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/main.py +0 -0
  41. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/managers.py +0 -0
  42. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/models.py +0 -0
  43. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/schemas.py +0 -0
  44. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/fastapi_sqlalchemy_toolkit/__init__.py +0 -0
  45. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/fastapi_sqlalchemy_toolkit/filters.py +0 -0
  46. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/fastapi_sqlalchemy_toolkit/ordering.py +0 -0
  47. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/fastapi_sqlalchemy_toolkit/utils.py +0 -0
  48. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/mkdocs.yml +0 -0
  49. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/requirements/base.txt +0 -0
  50. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/requirements/docs.txt +0 -0
  51. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/requirements/lint.txt +0 -0
  52. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/requirements/test.txt +0 -0
  53. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/tests/Dockerfile +0 -0
  54. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/tests/__init__.py +0 -0
  55. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/tests/conftest.py +0 -0
  56. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/tests/db.py +0 -0
  57. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/tests/docker-compose.yml +0 -0
  58. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/tests/models.py +0 -0
  59. {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/tests/test_public_methods.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi_sqlalchemy_toolkit
3
- Version: 0.7.14
3
+ Version: 0.7.16
4
4
  Summary: FastAPI SQLAlchemy Toolkit
5
5
  Project-URL: Homepage, https://github.com/e-kondr01/fastapi-sqlalchemy-toolkit
6
6
  Author-email: Egor Kondrashov <e.kondr01@gmail.com>
@@ -38,7 +38,7 @@ ModelDict = dict[str, Any]
38
38
 
39
39
  def sqlalchemy_model_to_dict(model: DeclarativeBase) -> dict:
40
40
  db_obj_dict = model.__dict__.copy()
41
- del db_obj_dict["_sa_instance_state"]
41
+ db_obj_dict.pop("_sa_instance_state", None)
42
42
  return db_obj_dict
43
43
 
44
44
 
@@ -65,27 +65,14 @@ class ModelManager(Generic[ModelT, CreateSchemaT, UpdateSchemaT]):
65
65
  self.fk_name_to_model: dict[str, type[ModelT]] = {}
66
66
 
67
67
  self.unique_constraints: List[List[str]] = []
68
- self.nullable_unique_constraints: List[List[str]] = []
69
68
 
70
69
  if hasattr(self.model, "__table_args__"):
71
70
  for table_arg in self.model.__table_args__:
72
71
  if isinstance(table_arg, UniqueConstraint):
73
- # Проверяем наличие атрибута postgresql_nulls_not_distinct
74
- # и его значение
75
- if table_arg.dialect_kwargs.get("postgresql_nulls_not_distinct"):
76
- if table_arg.columns.keys():
77
- self.nullable_unique_constraints.append(
78
- table_arg.columns.keys()
79
- )
80
- else:
81
- self.nullable_unique_constraints.append(
82
- table_arg._pending_colargs
83
- )
72
+ if table_arg.columns.keys():
73
+ self.unique_constraints.append(table_arg.columns.keys())
84
74
  else:
85
- if table_arg.columns.keys():
86
- self.unique_constraints.append(table_arg.columns.keys())
87
- else:
88
- self.unique_constraints.append(table_arg._pending_colargs)
75
+ self.unique_constraints.append(table_arg._pending_colargs)
89
76
 
90
77
  self.reverse_relationships: dict[str, type[ModelT]] = {}
91
78
  self.m2m_relationships: dict[str, type[ModelT]] = {}
@@ -878,7 +865,6 @@ class ModelManager(Generic[ModelT, CreateSchemaT, UpdateSchemaT]):
878
865
  await self.handle_m2m_fields(session, in_obj)
879
866
  await self.validate_unique_fields(session, in_obj, db_obj=db_obj)
880
867
  await self.validate_unique_constraints(session, in_obj)
881
- await self.validate_nullable_unique_constraints(session, in_obj)
882
868
  return in_obj
883
869
 
884
870
  def get_select(self, base_stmt: Select | None = None, **_kwargs: Any) -> Select:
@@ -1093,47 +1079,20 @@ class ModelManager(Generic[ModelT, CreateSchemaT, UpdateSchemaT]):
1093
1079
  for field in unique_constraint:
1094
1080
  if in_obj[field] is not None:
1095
1081
  query[field] = in_obj[field]
1096
- object_exists = await self.exists(
1097
- session, **query, where=(self.model.id != in_obj.get("id"))
1098
- )
1099
- if object_exists:
1100
- conflicting_fields = ", ".join(unique_constraint)
1101
- raise HTTPException(
1102
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
1103
- detail=(
1104
- f"{self.model.__tablename__} с такими "
1105
- + conflicting_fields
1106
- + " уже существует."
1107
- ),
1108
- )
1109
-
1110
- async def validate_nullable_unique_constraints(
1111
- self, session: AsyncSession, in_obj: ModelDict
1112
- ) -> None:
1113
- """
1114
- Проверяет, не нарушаются ли nullable UniqueConstraint модели.
1115
- Поля со значением NULL игнорируются при проверке и не считаются дублированием.
1116
- """
1117
- for unique_constraint in self.nullable_unique_constraints:
1118
- query = {}
1119
- if any(in_obj[field] is None for field in unique_constraint):
1120
- continue
1121
-
1122
- for field in unique_constraint:
1123
- query[field] = in_obj[field]
1124
- object_exists = await self.exists(
1125
- session, **query, where=(self.model.id != in_obj.get("id"))
1126
- )
1127
- if object_exists:
1128
- conflicting_fields = ", ".join(unique_constraint)
1129
- raise HTTPException(
1130
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
1131
- detail=(
1132
- f"{self.model.__tablename__} с такими "
1133
- + conflicting_fields
1134
- + " уже существует."
1135
- ),
1082
+ if query:
1083
+ object_exists = await self.exists(
1084
+ session, **query, where=(self.model.id != in_obj.get("id"))
1136
1085
  )
1086
+ if object_exists:
1087
+ conflicting_fields = ", ".join(unique_constraint)
1088
+ raise HTTPException(
1089
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
1090
+ detail=(
1091
+ f"{self.model.__tablename__} с такими "
1092
+ + conflicting_fields
1093
+ + " уже существует."
1094
+ ),
1095
+ )
1137
1096
 
1138
1097
  async def validate_unique_fields(
1139
1098
  self,
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "fastapi_sqlalchemy_toolkit"
7
- version = "0.7.14"
7
+ version = "0.7.16"
8
8
  authors = [
9
9
  { name="Egor Kondrashov", email="e.kondr01@gmail.com" },
10
10
  ]