sqlobjects 1.4.0__tar.gz → 1.5.0__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 (80) hide show
  1. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/CHANGELOG.md +6 -0
  2. {sqlobjects-1.4.0/sqlobjects.egg-info → sqlobjects-1.5.0}/PKG-INFO +1 -1
  3. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/pyproject.toml +1 -1
  4. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/cascade.py +37 -2
  5. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/model.py +9 -2
  6. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/queryset.py +3 -2
  7. {sqlobjects-1.4.0 → sqlobjects-1.5.0/sqlobjects.egg-info}/PKG-INFO +1 -1
  8. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/LICENSE +0 -0
  9. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/README.md +0 -0
  10. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/docs/rules/01-database-session-guide.md +0 -0
  11. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/docs/rules/02-model-definition-guide.md +0 -0
  12. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/docs/rules/03-query-operations-guide.md +0 -0
  13. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/docs/rules/04-crud-operations-guide.md +0 -0
  14. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/docs/rules/05-relationships-guide.md +0 -0
  15. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/docs/rules/06-validation-signals-guide.md +0 -0
  16. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/docs/rules/07-performance-guide.md +0 -0
  17. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/docs/rules/README.md +0 -0
  18. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/setup.cfg +0 -0
  19. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/__init__.py +0 -0
  20. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/_install_rules.py +0 -0
  21. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/contrib/__init__.py +0 -0
  22. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/contrib/asgi.py +0 -0
  23. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/contrib/fastapi.py +0 -0
  24. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/database/__init__.py +0 -0
  25. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/database/config.py +0 -0
  26. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/database/manager.py +0 -0
  27. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/exceptions.py +0 -0
  28. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/expressions/__init__.py +0 -0
  29. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/expressions/aggregate.py +0 -0
  30. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/expressions/base.py +0 -0
  31. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/expressions/cte.py +0 -0
  32. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/expressions/explain.py +0 -0
  33. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/expressions/function.py +0 -0
  34. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/expressions/mixins.py +0 -0
  35. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/expressions/scalar.py +0 -0
  36. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/expressions/subquery.py +0 -0
  37. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/expressions/terminal.py +0 -0
  38. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/expressions/window.py +0 -0
  39. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/fields/__init__.py +0 -0
  40. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/fields/core.py +0 -0
  41. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/fields/functions.py +0 -0
  42. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/fields/proxies.py +0 -0
  43. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/fields/relations/__init__.py +0 -0
  44. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/fields/relations/descriptors.py +0 -0
  45. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/fields/relations/managers.py +0 -0
  46. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/fields/relations/prefetch.py +0 -0
  47. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/fields/relations/strategies.py +0 -0
  48. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/fields/relations/utils.py +0 -0
  49. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/fields/shortcuts.py +0 -0
  50. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/fields/types/__init__.py +0 -0
  51. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/fields/types/base.py +0 -0
  52. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/fields/types/comparators.py +0 -0
  53. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/fields/types/registry.py +0 -0
  54. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/fields/utils.py +0 -0
  55. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/internal/__init__.py +0 -0
  56. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/internal/operations.py +0 -0
  57. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/internal/results.py +0 -0
  58. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/metadata.py +0 -0
  59. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/mixins.py +0 -0
  60. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/objects/__init__.py +0 -0
  61. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/objects/bulk.py +0 -0
  62. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/objects/core.py +0 -0
  63. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/objects/upsert.py +0 -0
  64. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/queries/__init__.py +0 -0
  65. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/queries/builder.py +0 -0
  66. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/queries/dialect.py +0 -0
  67. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/queries/executor.py +0 -0
  68. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/session.py +0 -0
  69. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/signals.py +0 -0
  70. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/utils/__init__.py +0 -0
  71. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/utils/inspect.py +0 -0
  72. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/utils/naming.py +0 -0
  73. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/utils/pattern.py +0 -0
  74. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects/validators.py +0 -0
  75. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects.egg-info/SOURCES.txt +0 -0
  76. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects.egg-info/dependency_links.txt +0 -0
  77. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects.egg-info/entry_points.txt +0 -0
  78. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects.egg-info/requires.txt +0 -0
  79. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/sqlobjects.egg-info/top_level.txt +0 -0
  80. {sqlobjects-1.4.0 → sqlobjects-1.5.0}/tests/test_config.py +0 -0
@@ -1,3 +1,9 @@
1
+ ## 1.5.0 (2026-03-16)
2
+
3
+ ### Feat
4
+
5
+ - **cascade**: unify cascade strategy with auto-detection for Model.delete()
6
+
1
7
  ## 1.4.0 (2026-03-11)
2
8
 
3
9
  ### Feat
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlobjects
3
- Version: 1.4.0
3
+ Version: 1.5.0
4
4
  Summary: Django-style async ORM library based on SQLAlchemy with chainable queries, Q objects, and relationship loading
5
5
  Author-email: XtraVisions <gitadmin@xtravisions.com>, Chen Hao <chenhao@xtravisions.com>
6
6
  Maintainer-email: XtraVisions <gitadmin@xtravisions.com>, Chen Hao <chenhao@xtravisions.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sqlobjects"
3
- version = "1.4.0"
3
+ version = "1.5.0"
4
4
  description = "Django-style async ORM library based on SQLAlchemy with chainable queries, Q objects, and relationship loading"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -28,6 +28,7 @@ __all__ = [
28
28
  "normalize_onupdate",
29
29
  "normalize_cascade",
30
30
  "has_cascade_delete_relations",
31
+ "has_delete_signals",
31
32
  ]
32
33
 
33
34
 
@@ -130,6 +131,30 @@ def has_cascade_delete_relations(model_class) -> bool:
130
131
  return False
131
132
 
132
133
 
134
+ def has_delete_signals(model_class) -> bool:
135
+ """Check if model class has delete signal handlers defined.
136
+
137
+ Args:
138
+ model_class: Model class to check
139
+
140
+ Returns:
141
+ True if model has before_delete/after_delete handlers, False otherwise
142
+ """
143
+ from .signals import SignalMixin
144
+
145
+ if not issubclass(model_class, SignalMixin):
146
+ return False
147
+
148
+ for method_name in ("before_delete", "after_delete"):
149
+ method = getattr(model_class, method_name, None)
150
+ if method is None:
151
+ continue
152
+ # Must be defined on the model itself, not inherited from SignalMixin
153
+ if method_name in model_class.__dict__:
154
+ return True
155
+ return False
156
+
157
+
133
158
  def normalize_cascade(cascade: CascadeType) -> str:
134
159
  """Normalize cascade parameter to SQLAlchemy string format."""
135
160
  if cascade is None:
@@ -344,7 +369,7 @@ class CascadeExecutor:
344
369
  return instance
345
370
 
346
371
  async def execute_delete_operation(
347
- self, target, cascade_strategy: str = "full", session: "AsyncSession | None" = None
372
+ self, target, cascade_strategy: str = "auto", session: "AsyncSession | None" = None
348
373
  ) -> int:
349
374
  """Execute delete operation with cascade handling."""
350
375
  if session is None:
@@ -355,7 +380,8 @@ class CascadeExecutor:
355
380
  return await self._execute_queryset_delete(target, cascade_strategy, session)
356
381
 
357
382
  # Handle single instance deletion
358
- await self._delete_related_objects(target, session)
383
+ if has_cascade_delete_relations(target.__class__):
384
+ await self._delete_related_objects(target, session)
359
385
  await target._delete_internal(session=session) # noqa
360
386
  return 1
361
387
 
@@ -478,6 +504,15 @@ class CascadeExecutor:
478
504
 
479
505
  async def _execute_queryset_delete(self, queryset, cascade_strategy: str, session: "AsyncSession") -> int:
480
506
  """Execute QuerySet delete with different cascade strategies."""
507
+ if cascade_strategy == "auto":
508
+ model_class = queryset._model_class
509
+ if has_delete_signals(model_class):
510
+ cascade_strategy = "full"
511
+ elif has_cascade_delete_relations(model_class):
512
+ cascade_strategy = "fast"
513
+ else:
514
+ cascade_strategy = "none"
515
+
481
516
  if cascade_strategy == "full":
482
517
  return await self._delete_with_full_cascade(queryset, session)
483
518
  elif cascade_strategy == "fast":
@@ -278,11 +278,14 @@ class ModelMixin(DataConversionMixin, SignalMixin):
278
278
  return await self._save_internal(validate=validate, session=session)
279
279
 
280
280
  @emit_signals(Operation.DELETE)
281
- async def delete(self, cascade: bool = True):
281
+ async def delete(self, cascade: bool | None = None):
282
282
  """Delete this model instance from the database with cascade support.
283
283
 
284
284
  Args:
285
- cascade: Whether to handle cascade deletion (default: True)
285
+ cascade: Whether to handle cascade deletion.
286
+ None (default): auto-detect based on model relationships
287
+ True: force cascade handling
288
+ False: skip cascade, direct delete
286
289
 
287
290
  Raises:
288
291
  PrimaryKeyError: If instance has no primary key values or delete fails
@@ -292,6 +295,10 @@ class ModelMixin(DataConversionMixin, SignalMixin):
292
295
 
293
296
  session = self.get_session()
294
297
 
298
+ # Auto-detect cascade need when not explicitly specified
299
+ if cascade is None:
300
+ cascade = self._has_on_delete_relations()
301
+
295
302
  # Use cascade executor for cascade operations
296
303
  if cascade:
297
304
  executor = CascadeExecutor()
@@ -1221,12 +1221,13 @@ class QuerySet(Generic[T]):
1221
1221
  return await executor.execute_update_operation(self, values)
1222
1222
 
1223
1223
  @emit_signals(Operation.DELETE, is_bulk=True)
1224
- async def delete(self, cascade: str = "full") -> int:
1224
+ async def delete(self, cascade: str = "auto") -> int:
1225
1225
  """Perform bulk delete on objects matching query conditions.
1226
1226
 
1227
1227
  Args:
1228
1228
  cascade: Cascade deletion strategy
1229
- - "full" (default): Complete cascade deletion with full ORM functionality
1229
+ - "auto" (default): Automatically choose based on model relationships
1230
+ - "full": Complete cascade deletion with full ORM functionality
1230
1231
  - "fast": Fast cascade deletion with minimal ORM processing
1231
1232
  - "none": Direct SQL deletion without ORM cascade processing
1232
1233
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlobjects
3
- Version: 1.4.0
3
+ Version: 1.5.0
4
4
  Summary: Django-style async ORM library based on SQLAlchemy with chainable queries, Q objects, and relationship loading
5
5
  Author-email: XtraVisions <gitadmin@xtravisions.com>, Chen Hao <chenhao@xtravisions.com>
6
6
  Maintainer-email: XtraVisions <gitadmin@xtravisions.com>, Chen Hao <chenhao@xtravisions.com>
File without changes
File without changes
File without changes