rb-commons 0.5.22__py3-none-any.whl → 0.5.24__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.
@@ -86,6 +86,7 @@ class BaseManager(Generic[ModelType]):
86
86
  self._filtered: bool = False
87
87
  self._limit: Optional[int] = None
88
88
  self._order_by: List[Any] = []
89
+ self._joins: set[str] = set()
89
90
 
90
91
  async def _smart_commit(self, instance: Optional[ModelType] = None) -> Optional[ModelType]:
91
92
  if not self.session.in_transaction():
@@ -96,19 +97,28 @@ class BaseManager(Generic[ModelType]):
96
97
  return None
97
98
 
98
99
  def _parse_lookup(self, lookup: str, value: Any):
100
+ root = lookup.split("__", 1)[0]
101
+
102
+ if hasattr(self.model, root):
103
+ attr0 = getattr(self.model, root)
104
+ if hasattr(attr0, "property") and isinstance(attr0.property, RelationshipProperty):
105
+ self._joins.add(root)
106
+ parts = lookup.split("__")
107
+
99
108
  parts = lookup.split("__")
100
109
  operator = "eq"
101
110
  if parts[-1] in {"eq", "ne", "gt", "lt", "gte", "lte", "in", "contains", "null"}:
102
111
  operator = parts.pop()
103
112
 
104
113
  current: Union[Type[ModelType], InstrumentedAttribute] = self.model
105
- # walk relationships
114
+ path_parts = []
106
115
  for field in parts:
107
116
  attr = getattr(current, field, None)
108
117
  if attr is None:
109
118
  raise ValueError(f"Invalid filter field: {'.'.join(parts)}")
110
119
  if hasattr(attr, "property") and isinstance(attr.property, RelationshipProperty):
111
120
  current = attr.property.mapper.class_
121
+ path_parts.append(field)
112
122
  else:
113
123
  current = attr
114
124
 
@@ -208,17 +218,21 @@ class BaseManager(Generic[ModelType]):
208
218
 
209
219
  return self
210
220
 
211
- def filter(self, *expressions: Any, **lookups: Any) -> "BaseManager[ModelType]":
212
- """Add **AND** constraints (default behaviour)."""
213
-
221
+ def filter(self, *expressions: Any, **lookups: Any) -> "BaseManager":
214
222
  self._filtered = True
215
- for expr in expressions:
216
- if isinstance(expr, Q) or isinstance(expr, QJSON):
217
- self.filters.append(self._q_to_expr(expr))
218
- else:
219
- self.filters.append(expr)
223
+
220
224
  for k, v in lookups.items():
225
+ root = k.split("__", 1)[0]
226
+ if hasattr(self.model, root):
227
+ attr = getattr(self.model, root)
228
+ if hasattr(attr, "property") and isinstance(attr.property, RelationshipProperty):
229
+ self._joins.add(root)
230
+
221
231
  self.filters.append(self._parse_lookup(k, v))
232
+
233
+ for expr in expressions:
234
+ self.filters.append(self._q_to_expr(expr) if isinstance(expr, Q) else expr)
235
+
222
236
  return self
223
237
 
224
238
  def or_filter(self, *expressions: Any, **lookups: Any) -> "BaseManager[ModelType]":
@@ -273,9 +287,23 @@ class BaseManager(Generic[ModelType]):
273
287
  self.filters.clear()
274
288
  self._filtered = False
275
289
  self._limit = None
290
+ self._joins.clear()
276
291
 
277
292
  async def all(self, load_all_relations: bool = False):
278
293
  stmt = select(self.model)
294
+
295
+ for rel_path in self._joins:
296
+ rel_model = self.model
297
+ join_attr = None
298
+
299
+ for part in rel_path.split("__"):
300
+ join_attr = getattr(rel_model, part)
301
+ if not hasattr(join_attr, "property"):
302
+ raise ValueError(f"Invalid join path: {rel_path}")
303
+ rel_model = join_attr.property.mapper.class_
304
+
305
+ stmt = stmt.join(join_attr)
306
+
279
307
  if self.filters:
280
308
  stmt = stmt.filter(and_(*self.filters))
281
309
  if self._order_by:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rb-commons
3
- Version: 0.5.22
3
+ Version: 0.5.24
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=mWLwcJmdQJxtmjQ4ZWCTQRvBF_ukborgyqGW70oodgA,18794
16
+ rb_commons/orm/managers.py,sha256=wFYZx6RxsB58p2_nJStS8BLiiW4pGYF-zgQ3X9R8esM,19767
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.5.22.dist-info/METADATA,sha256=a_gA3J0YHykn1itXgtZvolgR73tRAh9mq1mElTlQasY,6571
26
- rb_commons-0.5.22.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
- rb_commons-0.5.22.dist-info/top_level.txt,sha256=HPx_WAYo3_fbg1WCeGHsz3wPGio1ucbnrlm2lmqlJog,11
28
- rb_commons-0.5.22.dist-info/RECORD,,
25
+ rb_commons-0.5.24.dist-info/METADATA,sha256=SXvgYuSQpp5vNxAunOl9g76z8OHHDwKwPpzxYyJDNcY,6571
26
+ rb_commons-0.5.24.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
+ rb_commons-0.5.24.dist-info/top_level.txt,sha256=HPx_WAYo3_fbg1WCeGHsz3wPGio1ucbnrlm2lmqlJog,11
28
+ rb_commons-0.5.24.dist-info/RECORD,,