rb-commons 0.5.18__py3-none-any.whl → 0.5.20__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.
@@ -12,6 +12,16 @@ from rb_commons.orm.exceptions import DatabaseException, InternalException
12
12
 
13
13
  ModelType = TypeVar('ModelType', bound=declarative_base())
14
14
 
15
+ class QJSON:
16
+ def __init__(self, field: str, key: str, operator: str, value: Any):
17
+ self.field = field
18
+ self.key = key
19
+ self.operator = operator
20
+ self.value = value
21
+
22
+ def __repr__(self):
23
+ return f"QJSON(field={self.field}, key={self.key}, op={self.operator}, value={self.value})"
24
+
15
25
  class Q:
16
26
  """Boolean logic container that can be combined with `&`, `|`, and `~`."""
17
27
 
@@ -124,7 +134,10 @@ class BaseManager(Generic[ModelType]):
124
134
  return current.is_(None) if value else current.isnot(None)
125
135
  raise ValueError(f"Unsupported operator in lookup: {lookup}")
126
136
 
127
- def _q_to_expr(self, q: Q):
137
+ def _q_to_expr(self, q: Union[Q, QJSON]):
138
+ if isinstance(q, QJSON):
139
+ return self._parse_qjson(q)
140
+
128
141
  clauses: List[Any] = [self._parse_lookup(k, v) for k, v in q.lookups.items()]
129
142
  for child in q.children:
130
143
  clauses.append(self._q_to_expr(child))
@@ -135,6 +148,29 @@ class BaseManager(Generic[ModelType]):
135
148
  )
136
149
  return ~combined if q.negated else combined
137
150
 
151
+ def _parse_qjson(self, qjson: QJSON):
152
+ col = getattr(self.model, qjson.field, None)
153
+ if col is None:
154
+ raise ValueError(f"Invalid JSON field: {qjson.field}")
155
+
156
+ json_expr = col[qjson.key].astext
157
+
158
+ if qjson.operator == "eq":
159
+ return json_expr == str(qjson.value)
160
+ if qjson.operator == "ne":
161
+ return json_expr != str(qjson.value)
162
+ if qjson.operator == "contains":
163
+ return json_expr.ilike(f"%{qjson.value}%")
164
+ if qjson.operator == "startswith":
165
+ return json_expr.ilike(f"{qjson.value}%")
166
+ if qjson.operator == "endswith":
167
+ return json_expr.ilike(f"%{qjson.value}")
168
+ if qjson.operator == "in":
169
+ if not isinstance(qjson.value, (list, tuple, set)):
170
+ raise ValueError(f"{qjson.field}[{qjson.key}]__in requires an iterable")
171
+ return json_expr.in_(qjson.value)
172
+ raise ValueError(f"Unsupported QJSON operator: {qjson.operator}")
173
+
138
174
  def _loader_from_path(self, path: str) -> Load:
139
175
  """
140
176
  Turn 'attributes.attribute.attribute_group' into
@@ -173,25 +209,31 @@ class BaseManager(Generic[ModelType]):
173
209
  return self
174
210
 
175
211
  def filter(self, *expressions: Any, **lookups: Any) -> "BaseManager[ModelType]":
176
- """Add **AND** constraints (default behaviour).
212
+ """Add **AND** constraints (default behaviour)."""
177
213
 
178
- * `expressions` can be raw SQLAlchemy clauses **or** `Q` objects.
179
- * `lookups` are Django‑style keyword filters.
180
- """
181
214
  self._filtered = True
182
215
  for expr in expressions:
183
- self.filters.append(self._q_to_expr(expr) if isinstance(expr, Q) else expr)
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)
184
220
  for k, v in lookups.items():
185
221
  self.filters.append(self._parse_lookup(k, v))
186
222
  return self
187
223
 
188
224
  def or_filter(self, *expressions: Any, **lookups: Any) -> "BaseManager[ModelType]":
189
225
  """Add one OR group (shortcut for `filter(Q() | Q())`)."""
226
+
190
227
  or_clauses: List[Any] = []
191
228
  for expr in expressions:
192
- or_clauses.append(self._q_to_expr(expr) if isinstance(expr, Q) else expr)
229
+ if isinstance(expr, Q) or isinstance(expr, QJSON):
230
+ or_clauses.append(self._q_to_expr(expr))
231
+ else:
232
+ or_clauses.append(expr)
233
+
193
234
  for k, v in lookups.items():
194
235
  or_clauses.append(self._parse_lookup(k, v))
236
+
195
237
  if or_clauses:
196
238
  self._filtered = True
197
239
  self.filters.append(or_(*or_clauses))
rb_commons/schemes/jwt.py CHANGED
@@ -36,7 +36,7 @@ class Claims(BaseModel):
36
36
  except ValueError as e:
37
37
  raise ValueError(f"Invalid user_id format: {e}")
38
38
 
39
- if raw_claims["x-customer-id"]:
39
+ if raw_claims["x-customer-id"] and raw_claims["x-customer-id"] is not None:
40
40
  try:
41
41
  raw_claims["x-customer-id"] = int(raw_claims["x-customer-id"])
42
42
  except ValueError as e:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rb-commons
3
- Version: 0.5.18
3
+ Version: 0.5.20
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,16 +13,16 @@ 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=VMu3v-JzSVZ9pN2d4ZcAF6qZyqmBeXZ62kiHUY73v20,17163
16
+ rb_commons/orm/managers.py,sha256=czc2czBswfVjm51vYvMEupDGxniinAYMqkTXbiMEC7Y,18660
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
20
20
  rb_commons/schemes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- rb_commons/schemes/jwt.py,sha256=5J-VTAgRWnRrOU6cuumc8eDJQDyTm5y8cn-kLSLan_g,2453
21
+ rb_commons/schemes/jwt.py,sha256=yeMe_HACL_tdtmfpMMkLJY8_9ZaWiXEtMGLd-bq634s,2497
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.18.dist-info/METADATA,sha256=K4LUgXImE93aU2C4Sl9t0ttSj-WP3TLsTPV1hl9Ziws,6571
26
- rb_commons-0.5.18.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
27
- rb_commons-0.5.18.dist-info/top_level.txt,sha256=HPx_WAYo3_fbg1WCeGHsz3wPGio1ucbnrlm2lmqlJog,11
28
- rb_commons-0.5.18.dist-info/RECORD,,
25
+ rb_commons-0.5.20.dist-info/METADATA,sha256=vl5IGgRH6CTF2qtk3DoyCHfoCeAmiCtXu0a4O-1qOwc,6571
26
+ rb_commons-0.5.20.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
+ rb_commons-0.5.20.dist-info/top_level.txt,sha256=HPx_WAYo3_fbg1WCeGHsz3wPGio1ucbnrlm2lmqlJog,11
28
+ rb_commons-0.5.20.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5