rb-commons 0.7.1__py3-none-any.whl → 0.7.3__py3-none-any.whl

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.
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import re
4
4
  import uuid
5
5
  from typing import TypeVar, Type, Generic, Optional, List, Dict, Literal, Union, Sequence, Any, Iterable
6
- from sqlalchemy import select, delete, update, and_, func, desc, inspect, or_, asc
6
+ from sqlalchemy import select, delete, update, and_, func, desc, inspect, or_, asc, true
7
7
  from sqlalchemy.exc import IntegrityError, SQLAlchemyError
8
8
  from sqlalchemy.ext.asyncio import AsyncSession
9
9
  from sqlalchemy.orm import declarative_base, selectinload, RelationshipProperty, Load
@@ -151,9 +151,13 @@ class BaseManager(Generic[ModelType]):
151
151
  def _parse_lookup(self, lookup: str, value: Any):
152
152
  parts, operator, rel_attr, col_attr = self._parse_lookup_meta(lookup)
153
153
  expr = self._build_comparison(col_attr, operator, value)
154
+
154
155
  if rel_attr:
155
- prop = rel_attr.property
156
- return prop.uselist and rel_attr.any(expr) or rel_attr.has(expr)
156
+ if rel_attr.property.uselist:
157
+ return rel_attr.any(expr)
158
+ else:
159
+ return rel_attr.has(expr)
160
+
157
161
  return expr
158
162
 
159
163
  def _q_to_expr(self, q: Union[Q, QJSON]):
@@ -163,11 +167,14 @@ class BaseManager(Generic[ModelType]):
163
167
  clauses: List[Any] = [self._parse_lookup(k, v) for k, v in q.lookups.items()]
164
168
  for child in q.children:
165
169
  clauses.append(self._q_to_expr(child))
166
- combined = (
167
- True
168
- if not clauses
169
- else (or_(*clauses) if q._operator == "OR" else and_(*clauses))
170
- )
170
+
171
+ if not clauses:
172
+ combined = true()
173
+ elif q._operator == "OR":
174
+ combined = or_(*clauses)
175
+ else:
176
+ combined = and_(*clauses)
177
+
171
178
  return ~combined if q.negated else combined
172
179
 
173
180
  def _parse_qjson(self, qjson: QJSON):
@@ -247,6 +254,49 @@ class BaseManager(Generic[ModelType]):
247
254
  self.filters.append(or_(*or_clauses))
248
255
  return self
249
256
 
257
+ def exclude(self, *expressions: Any, **lookups: Any) -> "BaseManager[ModelType]":
258
+ """
259
+ Exclude records that match the given conditions.
260
+ This is the opposite of filter() - it adds NOT conditions.
261
+
262
+ Args:
263
+ *expressions: Q objects, QJSON objects, or SQLAlchemy expressions
264
+ **lookups: Field lookups (same format as filter())
265
+
266
+ Returns:
267
+ BaseManager instance for method chaining
268
+
269
+ Example:
270
+ # Exclude users with specific names
271
+ manager.exclude(name="John", email__contains="test")
272
+
273
+ # Exclude using Q objects
274
+ manager.exclude(Q(age__lt=18) | Q(status="inactive"))
275
+
276
+ # Exclude using QJSON
277
+ manager.exclude(QJSON("metadata", "type", "eq", "archived"))
278
+ """
279
+ self._filtered = True
280
+
281
+ for k, v in lookups.items():
282
+ root = k.split("__", 1)[0]
283
+ if hasattr(self.model, root):
284
+ attr = getattr(self.model, root)
285
+ if hasattr(attr, "property") and isinstance(attr.property, RelationshipProperty):
286
+ self._joins.add(root)
287
+
288
+ lookup_expr = self._parse_lookup(k, v)
289
+ self.filters.append(~lookup_expr)
290
+
291
+ for expr in expressions:
292
+ if isinstance(expr, Q) or isinstance(expr, QJSON):
293
+ q_expr = self._q_to_expr(expr)
294
+ self.filters.append(~q_expr)
295
+ else:
296
+ self.filters.append(~expr)
297
+
298
+ return self
299
+
250
300
  def limit(self, value: int) -> "BaseManager[ModelType]":
251
301
  self._limit = value
252
302
  return self
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rb-commons
3
- Version: 0.7.1
3
+ Version: 0.7.3
4
4
  Summary: Commons of project and simplified orm based on sqlalchemy.
5
5
  Home-page: https://github.com/RoboSell-organization/rb-commons
6
6
  Author: Abdulvoris
@@ -13,7 +13,7 @@ rb_commons/http/consul.py,sha256=Ioq72VD1jGwoC96set7n2SgxN40olzI-myA2lwKkYi4,186
13
13
  rb_commons/http/exceptions.py,sha256=EGRMr1cRgiJ9Q2tkfANbf0c6-zzXf1CD6J3cmCaT_FA,1885
14
14
  rb_commons/orm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  rb_commons/orm/exceptions.py,sha256=1aMctiEwrPjyehoXVX1l6ML5ZOhmDkmBISzlTD5ey1Y,509
16
- rb_commons/orm/managers.py,sha256=5ud5TWpR4D-1W9R1TYuK1MDcimFxZeJUwXTcbAqWPEM,19627
16
+ rb_commons/orm/managers.py,sha256=041roR5ViDlY6e4kOQEGeOuRTirS3pakzatMn1Py-GU,21256
17
17
  rb_commons/orm/services.py,sha256=71eRcJ4TxZvzNz-hLXo12X4U7PGK54ZfbLAb27AjZi8,1589
18
18
  rb_commons/permissions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  rb_commons/permissions/role_permissions.py,sha256=4dV89z6ggzLqCCiFYlMp7kQVJRESu6MHpkT5ZNjLo6A,1096
@@ -22,7 +22,7 @@ rb_commons/schemes/jwt.py,sha256=ZKLJ5D3fcEmEKySjzbxEgUcza4K-oPoHr14_Z0r9Yic,249
22
22
  rb_commons/schemes/pagination.py,sha256=8VZW1wZGJIPR9jEBUgppZUoB4uqP8ORudHkMwvEJSxg,1866
23
23
  rb_commons/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  rb_commons/utils/media.py,sha256=J2Zi0J28DhcVQVzt-myNNVuzj9Msaetul53VjZtdDdc,820
25
- rb_commons-0.7.1.dist-info/METADATA,sha256=BW48hhEBVyZksP6lhZGyBgtGgYGW23pZSuw7QwGQ3ro,6570
26
- rb_commons-0.7.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
- rb_commons-0.7.1.dist-info/top_level.txt,sha256=HPx_WAYo3_fbg1WCeGHsz3wPGio1ucbnrlm2lmqlJog,11
28
- rb_commons-0.7.1.dist-info/RECORD,,
25
+ rb_commons-0.7.3.dist-info/METADATA,sha256=5GCH4rFktZE2zHbYDBS7T6NaaQJRoo-jFeEM0QDsJ7Q,6570
26
+ rb_commons-0.7.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
+ rb_commons-0.7.3.dist-info/top_level.txt,sha256=HPx_WAYo3_fbg1WCeGHsz3wPGio1ucbnrlm2lmqlJog,11
28
+ rb_commons-0.7.3.dist-info/RECORD,,