rb-commons 0.5.3__py3-none-any.whl → 0.5.5__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.
@@ -5,7 +5,7 @@ from typing import TypeVar, Type, Generic, Optional, List, Dict, Literal, Union,
5
5
  from sqlalchemy import select, delete, update, and_, func, desc, inspect, or_
6
6
  from sqlalchemy.exc import IntegrityError, SQLAlchemyError, NoResultFound
7
7
  from sqlalchemy.ext.asyncio import AsyncSession
8
- from sqlalchemy.orm import declarative_base, InstrumentedAttribute, selectinload, RelationshipProperty
8
+ from sqlalchemy.orm import declarative_base, InstrumentedAttribute, selectinload, RelationshipProperty, Load
9
9
 
10
10
  from rb_commons.http.exceptions import NotFoundException
11
11
  from rb_commons.orm.exceptions import DatabaseException, InternalException
@@ -135,6 +135,27 @@ class BaseManager(Generic[ModelType]):
135
135
  )
136
136
  return ~combined if q.negated else combined
137
137
 
138
+ def _loader_from_path(self, path: str) -> Load:
139
+ """
140
+ Turn 'attributes.attribute.attribute_group' into
141
+ selectinload(Product.attributes)
142
+ .selectinload(Attribute.attribute)
143
+ .selectinload(ProductAttributeGroup.attribute_group)
144
+ """
145
+ parts = path.split(".")
146
+ current_model = self.model
147
+ loader = None
148
+
149
+ for segment in parts:
150
+ attr = getattr(current_model, segment, None)
151
+ if attr is None or not hasattr(attr, "property"):
152
+ raise ValueError(f"Invalid relationship path: {path!r}")
153
+
154
+ loader = selectinload(attr) if loader is None else loader.selectinload(attr)
155
+ current_model = attr.property.mapper.class_ # step down the graph
156
+
157
+ return loader
158
+
138
159
  def order_by(self, *columns: Any):
139
160
  """Collect ORDER BY clauses.
140
161
  """
@@ -249,12 +270,18 @@ class BaseManager(Generic[ModelType]):
249
270
  self._reset_state()
250
271
  return result.scalars().first()
251
272
 
252
-
253
- async def count(self) -> int:
273
+ async def count(self) -> int | None:
254
274
  self._ensure_filtered()
255
- query = select(func.count()).select_from(self.model).filter(and_(*self.filters))
256
- result = await self.session.execute(query)
257
- return result.scalar_one()
275
+
276
+ stmt = select(func.count(self.model.id)).select_from(self.model)
277
+ if self.filters:
278
+ stmt = stmt.where(and_(*self.filters))
279
+
280
+ try:
281
+ result = await self.session.execute(stmt)
282
+ return int(result.scalar_one())
283
+ finally:
284
+ self._reset_state()
258
285
 
259
286
  async def paginate(self, limit=10, offset=0, load_all_relations=False):
260
287
  self._ensure_filtered()
@@ -368,7 +395,11 @@ class BaseManager(Generic[ModelType]):
368
395
  stmt = select(self.model).filter_by(id=pk)
369
396
  if load_relations:
370
397
  for rel in load_relations:
371
- stmt = stmt.options(selectinload(getattr(self.model, rel)))
398
+ loader = (
399
+ self._loader_from_path(rel) if "." in rel
400
+ else selectinload(getattr(self.model, rel))
401
+ )
402
+ stmt = stmt.options(loader)
372
403
  result = await self.session.execute(stmt)
373
404
  instance = result.scalar_one_or_none()
374
405
  if instance is None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rb-commons
3
- Version: 0.5.3
3
+ Version: 0.5.5
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
@@ -11,7 +11,7 @@ rb_commons/http/consul.py,sha256=Ioq72VD1jGwoC96set7n2SgxN40olzI-myA2lwKkYi4,186
11
11
  rb_commons/http/exceptions.py,sha256=EGRMr1cRgiJ9Q2tkfANbf0c6-zzXf1CD6J3cmCaT_FA,1885
12
12
  rb_commons/orm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  rb_commons/orm/exceptions.py,sha256=1aMctiEwrPjyehoXVX1l6ML5ZOhmDkmBISzlTD5ey1Y,509
14
- rb_commons/orm/managers.py,sha256=gTe2oL-DBFM2zaZU92Rl4PEL7qYvU8B64mAYYNFRpmM,15456
14
+ rb_commons/orm/managers.py,sha256=mKpsN1OrPUDxF12KyZleZNMD7vBBQ503pWclIYjGWFE,16565
15
15
  rb_commons/orm/services.py,sha256=71eRcJ4TxZvzNz-hLXo12X4U7PGK54ZfbLAb27AjZi8,1589
16
16
  rb_commons/permissions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  rb_commons/permissions/role_permissions.py,sha256=HL50s5RHW1nk2U3-YTESg0EDGkJDu1vN4QchcfK-L5g,988
@@ -20,7 +20,7 @@ rb_commons/schemes/jwt.py,sha256=F66JJDhholuOPPzlKeoC6f1TL4gXg4oRUrV5yheNpyo,167
20
20
  rb_commons/schemes/pagination.py,sha256=8VZW1wZGJIPR9jEBUgppZUoB4uqP8ORudHkMwvEJSxg,1866
21
21
  rb_commons/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  rb_commons/utils/media.py,sha256=KNY_9SdRa3Rp7d3B1tZaXkhmzVa65RcS62BYwZP1bVM,332
23
- rb_commons-0.5.3.dist-info/METADATA,sha256=_WkjUP_eAPiat0t-NHTeBT085dnAxSs3HBh5dpT4SwA,6570
24
- rb_commons-0.5.3.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
25
- rb_commons-0.5.3.dist-info/top_level.txt,sha256=HPx_WAYo3_fbg1WCeGHsz3wPGio1ucbnrlm2lmqlJog,11
26
- rb_commons-0.5.3.dist-info/RECORD,,
23
+ rb_commons-0.5.5.dist-info/METADATA,sha256=Q6QZet60caB50aSvjYzEeWzCDvftwoSEW4NH0ofmjRg,6570
24
+ rb_commons-0.5.5.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
25
+ rb_commons-0.5.5.dist-info/top_level.txt,sha256=HPx_WAYo3_fbg1WCeGHsz3wPGio1ucbnrlm2lmqlJog,11
26
+ rb_commons-0.5.5.dist-info/RECORD,,