rb-commons 0.5.18__py3-none-any.whl → 0.5.19__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.
- rb_commons/orm/managers.py +49 -7
- {rb_commons-0.5.18.dist-info → rb_commons-0.5.19.dist-info}/METADATA +1 -1
- {rb_commons-0.5.18.dist-info → rb_commons-0.5.19.dist-info}/RECORD +5 -5
- {rb_commons-0.5.18.dist-info → rb_commons-0.5.19.dist-info}/WHEEL +1 -1
- {rb_commons-0.5.18.dist-info → rb_commons-0.5.19.dist-info}/top_level.txt +0 -0
rb_commons/orm/managers.py
CHANGED
@@ -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
|
-
|
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
|
-
|
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))
|
@@ -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=
|
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
|
@@ -22,7 +22,7 @@ rb_commons/schemes/jwt.py,sha256=5J-VTAgRWnRrOU6cuumc8eDJQDyTm5y8cn-kLSLan_g,245
|
|
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.
|
26
|
-
rb_commons-0.5.
|
27
|
-
rb_commons-0.5.
|
28
|
-
rb_commons-0.5.
|
25
|
+
rb_commons-0.5.19.dist-info/METADATA,sha256=BjA7S-dZXfP3gExEwuqyNqmZbYuGx1cb_d1Ww3MjhRA,6571
|
26
|
+
rb_commons-0.5.19.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
27
|
+
rb_commons-0.5.19.dist-info/top_level.txt,sha256=HPx_WAYo3_fbg1WCeGHsz3wPGio1ucbnrlm2lmqlJog,11
|
28
|
+
rb_commons-0.5.19.dist-info/RECORD,,
|
File without changes
|