TypeDAL 3.8.5__py3-none-any.whl → 3.9.0__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.
Potentially problematic release.
This version of TypeDAL might be problematic. Click here for more details.
- typedal/__about__.py +1 -1
- typedal/core.py +31 -9
- {typedal-3.8.5.dist-info → typedal-3.9.0.dist-info}/METADATA +1 -1
- {typedal-3.8.5.dist-info → typedal-3.9.0.dist-info}/RECORD +6 -6
- {typedal-3.8.5.dist-info → typedal-3.9.0.dist-info}/WHEEL +0 -0
- {typedal-3.8.5.dist-info → typedal-3.9.0.dist-info}/entry_points.txt +0 -0
typedal/__about__.py
CHANGED
typedal/core.py
CHANGED
|
@@ -130,6 +130,7 @@ class Relationship(typing.Generic[To_Type]):
|
|
|
130
130
|
_type: To_Type
|
|
131
131
|
table: Type["TypedTable"] | type | str
|
|
132
132
|
condition: Condition
|
|
133
|
+
condition_and: Condition
|
|
133
134
|
on: OnQuery
|
|
134
135
|
multiple: bool
|
|
135
136
|
join: JOIN_OPTIONS
|
|
@@ -140,6 +141,7 @@ class Relationship(typing.Generic[To_Type]):
|
|
|
140
141
|
condition: Condition = None,
|
|
141
142
|
join: JOIN_OPTIONS = None,
|
|
142
143
|
on: OnQuery = None,
|
|
144
|
+
condition_and: Condition = None,
|
|
143
145
|
):
|
|
144
146
|
"""
|
|
145
147
|
Should not be called directly, use relationship() instead!
|
|
@@ -152,6 +154,7 @@ class Relationship(typing.Generic[To_Type]):
|
|
|
152
154
|
self.condition = condition
|
|
153
155
|
self.join = "left" if on else join # .on is always left join!
|
|
154
156
|
self.on = on
|
|
157
|
+
self.condition_and = condition_and
|
|
155
158
|
|
|
156
159
|
if args := typing.get_args(_type):
|
|
157
160
|
self.table = unwrap_type(args[0])
|
|
@@ -172,6 +175,7 @@ class Relationship(typing.Generic[To_Type]):
|
|
|
172
175
|
update.get("condition") or self.condition,
|
|
173
176
|
update.get("join") or self.join,
|
|
174
177
|
update.get("on") or self.on,
|
|
178
|
+
update.get("condition_and") or self.condition_and,
|
|
175
179
|
)
|
|
176
180
|
|
|
177
181
|
def __repr__(self) -> str:
|
|
@@ -180,6 +184,10 @@ class Relationship(typing.Generic[To_Type]):
|
|
|
180
184
|
"""
|
|
181
185
|
if callback := self.condition or self.on:
|
|
182
186
|
src_code = inspect.getsource(callback).strip()
|
|
187
|
+
|
|
188
|
+
if c_and := self.condition_and:
|
|
189
|
+
and_code = inspect.getsource(c_and).strip()
|
|
190
|
+
src_code += " AND " + and_code
|
|
183
191
|
else:
|
|
184
192
|
cls_name = self._type if isinstance(self._type, str) else self._type.__name__ # type: ignore
|
|
185
193
|
src_code = f"to {cls_name} (missing condition)"
|
|
@@ -1050,11 +1058,12 @@ class TableMeta(type):
|
|
|
1050
1058
|
method: JOIN_OPTIONS = None,
|
|
1051
1059
|
on: OnQuery | list[Expression] | Expression = None,
|
|
1052
1060
|
condition: Condition = None,
|
|
1061
|
+
condition_and: Condition = None,
|
|
1053
1062
|
) -> "QueryBuilder[T_MetaInstance]":
|
|
1054
1063
|
"""
|
|
1055
1064
|
See QueryBuilder.join!
|
|
1056
1065
|
"""
|
|
1057
|
-
return QueryBuilder(self).join(*fields, on=on, condition=condition, method=method)
|
|
1066
|
+
return QueryBuilder(self).join(*fields, on=on, condition=condition, method=method, condition_and=condition_and)
|
|
1058
1067
|
|
|
1059
1068
|
def collect(self: Type[T_MetaInstance], verbose: bool = False) -> "TypedRows[T_MetaInstance]":
|
|
1060
1069
|
"""
|
|
@@ -2317,6 +2326,7 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2317
2326
|
method: JOIN_OPTIONS = None,
|
|
2318
2327
|
on: OnQuery | list[Expression] | Expression = None,
|
|
2319
2328
|
condition: Condition = None,
|
|
2329
|
+
condition_and: Condition = None,
|
|
2320
2330
|
) -> "QueryBuilder[T_MetaInstance]":
|
|
2321
2331
|
"""
|
|
2322
2332
|
Include relationship fields in the result.
|
|
@@ -2326,8 +2336,13 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2326
2336
|
|
|
2327
2337
|
By default, the `method` defined in the relationship is used.
|
|
2328
2338
|
This can be overwritten with the `method` keyword argument (left or inner)
|
|
2339
|
+
|
|
2340
|
+
`condition_and` can be used to add extra conditions to an inner join.
|
|
2329
2341
|
"""
|
|
2330
2342
|
# todo: allow limiting amount of related rows returned for join?
|
|
2343
|
+
# todo: it would be nice if 'fields' could be an actual relationship
|
|
2344
|
+
# (Article.tags = list[Tag]) and you could change the .condition and .on
|
|
2345
|
+
# this could deprecate condition_and
|
|
2331
2346
|
|
|
2332
2347
|
relationships = self.model.get_relationships()
|
|
2333
2348
|
|
|
@@ -2340,7 +2355,9 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2340
2355
|
if isinstance(condition, pydal.objects.Query):
|
|
2341
2356
|
condition = as_lambda(condition)
|
|
2342
2357
|
|
|
2343
|
-
relationships = {
|
|
2358
|
+
relationships = {
|
|
2359
|
+
str(fields[0]): Relationship(fields[0], condition=condition, join=method, condition_and=condition_and)
|
|
2360
|
+
}
|
|
2344
2361
|
elif on:
|
|
2345
2362
|
if len(fields) != 1:
|
|
2346
2363
|
raise ValueError("join(field, on=...) can only be used with exactly one field!")
|
|
@@ -2350,15 +2367,17 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2350
2367
|
|
|
2351
2368
|
if isinstance(on, list):
|
|
2352
2369
|
on = as_lambda(on)
|
|
2353
|
-
relationships = {str(fields[0]): Relationship(fields[0], on=on, join=method)}
|
|
2370
|
+
relationships = {str(fields[0]): Relationship(fields[0], on=on, join=method, condition_and=condition_and)}
|
|
2354
2371
|
|
|
2355
2372
|
else:
|
|
2356
2373
|
if fields:
|
|
2357
2374
|
# join on every relationship
|
|
2358
|
-
relationships = {str(k): relationships[str(k)] for k in fields}
|
|
2375
|
+
relationships = {str(k): relationships[str(k)].clone(condition_and=condition_and) for k in fields}
|
|
2359
2376
|
|
|
2360
2377
|
if method:
|
|
2361
|
-
relationships = {
|
|
2378
|
+
relationships = {
|
|
2379
|
+
str(k): r.clone(join=method, condition_and=condition_and) for k, r in relationships.items()
|
|
2380
|
+
}
|
|
2362
2381
|
|
|
2363
2382
|
return self._extend(relationships=relationships)
|
|
2364
2383
|
|
|
@@ -2579,7 +2598,6 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2579
2598
|
|
|
2580
2599
|
metadata["relationships"] = set(self.relationships.keys())
|
|
2581
2600
|
|
|
2582
|
-
# query = self._update_query_for_inner(db, model, query)
|
|
2583
2601
|
join = []
|
|
2584
2602
|
for key, relation in self.relationships.items():
|
|
2585
2603
|
if not relation.condition or relation.join != "inner":
|
|
@@ -2587,7 +2605,11 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2587
2605
|
|
|
2588
2606
|
other = relation.get_table(db)
|
|
2589
2607
|
other = other.with_alias(f"{key}_{hash(relation)}")
|
|
2590
|
-
|
|
2608
|
+
condition = relation.condition(model, other)
|
|
2609
|
+
if callable(relation.condition_and):
|
|
2610
|
+
condition &= relation.condition_and(model, other)
|
|
2611
|
+
|
|
2612
|
+
join.append(other.on(condition))
|
|
2591
2613
|
|
|
2592
2614
|
if limitby := select_kwargs.pop("limitby", ()):
|
|
2593
2615
|
|
|
@@ -2637,12 +2659,12 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2637
2659
|
# .on not given, generate it:
|
|
2638
2660
|
other = other.with_alias(f"{key}_{hash(relation)}")
|
|
2639
2661
|
condition = typing.cast(Query, relation.condition(model, other))
|
|
2662
|
+
if callable(relation.condition_and):
|
|
2663
|
+
condition &= relation.condition_and(model, other)
|
|
2640
2664
|
left.append(other.on(condition))
|
|
2641
2665
|
else:
|
|
2642
2666
|
# else: inner join (handled earlier)
|
|
2643
2667
|
other = other.with_alias(f"{key}_{hash(relation)}") # only for replace
|
|
2644
|
-
# other = other.with_alias(f"{key}_{hash(relation)}")
|
|
2645
|
-
# query &= relation.condition(model, other)
|
|
2646
2668
|
|
|
2647
2669
|
# if no fields of 'other' are included, add other.ALL
|
|
2648
2670
|
# else: only add other.id if missing
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
typedal/__about__.py,sha256=
|
|
1
|
+
typedal/__about__.py,sha256=ZuJhJWjiRvul81lGSU613j5iNkWmLFCmfexofoyuMao,206
|
|
2
2
|
typedal/__init__.py,sha256=QQpLiVl9w9hm2LBxey49Y_tCF_VB2bScVaS_mCjYy54,366
|
|
3
3
|
typedal/caching.py,sha256=SMcJsahLlZ79yykWCveERFx1ZJUNEKhA9SPmCTIuLp8,11798
|
|
4
4
|
typedal/cli.py,sha256=wzyId6YwRyqfuJ2byxvl6YecDNaKpkLmo-R5HvRuTok,19265
|
|
5
5
|
typedal/config.py,sha256=0qy1zrTUdtmXPM9jHzFnSR1DJsqGJqcdG6pvhzKQHe0,11625
|
|
6
|
-
typedal/core.py,sha256=
|
|
6
|
+
typedal/core.py,sha256=LQi-aE0j3n_JjSeYmUmZ1XhW4snt7SrxPSZ3DY_WV-k,102403
|
|
7
7
|
typedal/fields.py,sha256=A4qt0aK4F_-UeOY-xJ0ObVY-tFEoLFy7TYRMHnp4g6o,6516
|
|
8
8
|
typedal/for_py4web.py,sha256=d07b8hL_PvNDUS26Z5fDH2OxWb-IETBuAFPSzrRwm04,1285
|
|
9
9
|
typedal/for_web2py.py,sha256=xn7zo6ImsmTkH6LacbjLQl2oqyBvP0zLqRxEJvMQk1w,1929
|
|
@@ -13,7 +13,7 @@ typedal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
13
13
|
typedal/types.py,sha256=1FIgv1s0be0E8r5Wd9E1nvDvK4ETV8u2NlfI7_P6UUY,6752
|
|
14
14
|
typedal/web2py_py4web_shared.py,sha256=VK9T8P5UwVLvfNBsY4q79ANcABv-jX76YKADt1Zz_co,1539
|
|
15
15
|
typedal/serializers/as_json.py,sha256=ffo152W-sARYXym4BzwX709rrO2-QwKk2KunWY8RNl4,2229
|
|
16
|
-
typedal-3.
|
|
17
|
-
typedal-3.
|
|
18
|
-
typedal-3.
|
|
19
|
-
typedal-3.
|
|
16
|
+
typedal-3.9.0.dist-info/METADATA,sha256=GJ6GuOyCvWzkkQiZ3p8UVKoAxMtmZfCpQtxQeig7J3Y,10463
|
|
17
|
+
typedal-3.9.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
18
|
+
typedal-3.9.0.dist-info/entry_points.txt,sha256=m1wqcc_10rHWPdlQ71zEkmJDADUAnZtn7Jac_6mbyUc,44
|
|
19
|
+
typedal-3.9.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|