TypeDAL 3.8.5__py3-none-any.whl → 3.9.1__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 +43 -11
- {typedal-3.8.5.dist-info → typedal-3.9.1.dist-info}/METADATA +1 -1
- {typedal-3.8.5.dist-info → typedal-3.9.1.dist-info}/RECORD +6 -6
- {typedal-3.8.5.dist-info → typedal-3.9.1.dist-info}/WHEEL +0 -0
- {typedal-3.8.5.dist-info → typedal-3.9.1.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
|
"""
|
|
@@ -2221,9 +2230,19 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2221
2230
|
|
|
2222
2231
|
def __bool__(self) -> bool:
|
|
2223
2232
|
"""
|
|
2224
|
-
Querybuilder is truthy if it has
|
|
2233
|
+
Querybuilder is truthy if it has any conditions.
|
|
2225
2234
|
"""
|
|
2226
|
-
|
|
2235
|
+
table = self.model._ensure_table_defined()
|
|
2236
|
+
default_query = typing.cast(Query, table.id > 0)
|
|
2237
|
+
return any(
|
|
2238
|
+
[
|
|
2239
|
+
self.query != default_query,
|
|
2240
|
+
self.select_args,
|
|
2241
|
+
self.select_kwargs,
|
|
2242
|
+
self.relationships,
|
|
2243
|
+
self.metadata,
|
|
2244
|
+
]
|
|
2245
|
+
)
|
|
2227
2246
|
|
|
2228
2247
|
def _extend(
|
|
2229
2248
|
self,
|
|
@@ -2317,6 +2336,7 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2317
2336
|
method: JOIN_OPTIONS = None,
|
|
2318
2337
|
on: OnQuery | list[Expression] | Expression = None,
|
|
2319
2338
|
condition: Condition = None,
|
|
2339
|
+
condition_and: Condition = None,
|
|
2320
2340
|
) -> "QueryBuilder[T_MetaInstance]":
|
|
2321
2341
|
"""
|
|
2322
2342
|
Include relationship fields in the result.
|
|
@@ -2326,8 +2346,13 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2326
2346
|
|
|
2327
2347
|
By default, the `method` defined in the relationship is used.
|
|
2328
2348
|
This can be overwritten with the `method` keyword argument (left or inner)
|
|
2349
|
+
|
|
2350
|
+
`condition_and` can be used to add extra conditions to an inner join.
|
|
2329
2351
|
"""
|
|
2330
2352
|
# todo: allow limiting amount of related rows returned for join?
|
|
2353
|
+
# todo: it would be nice if 'fields' could be an actual relationship
|
|
2354
|
+
# (Article.tags = list[Tag]) and you could change the .condition and .on
|
|
2355
|
+
# this could deprecate condition_and
|
|
2331
2356
|
|
|
2332
2357
|
relationships = self.model.get_relationships()
|
|
2333
2358
|
|
|
@@ -2340,7 +2365,9 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2340
2365
|
if isinstance(condition, pydal.objects.Query):
|
|
2341
2366
|
condition = as_lambda(condition)
|
|
2342
2367
|
|
|
2343
|
-
relationships = {
|
|
2368
|
+
relationships = {
|
|
2369
|
+
str(fields[0]): Relationship(fields[0], condition=condition, join=method, condition_and=condition_and)
|
|
2370
|
+
}
|
|
2344
2371
|
elif on:
|
|
2345
2372
|
if len(fields) != 1:
|
|
2346
2373
|
raise ValueError("join(field, on=...) can only be used with exactly one field!")
|
|
@@ -2350,15 +2377,17 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2350
2377
|
|
|
2351
2378
|
if isinstance(on, list):
|
|
2352
2379
|
on = as_lambda(on)
|
|
2353
|
-
relationships = {str(fields[0]): Relationship(fields[0], on=on, join=method)}
|
|
2380
|
+
relationships = {str(fields[0]): Relationship(fields[0], on=on, join=method, condition_and=condition_and)}
|
|
2354
2381
|
|
|
2355
2382
|
else:
|
|
2356
2383
|
if fields:
|
|
2357
2384
|
# join on every relationship
|
|
2358
|
-
relationships = {str(k): relationships[str(k)] for k in fields}
|
|
2385
|
+
relationships = {str(k): relationships[str(k)].clone(condition_and=condition_and) for k in fields}
|
|
2359
2386
|
|
|
2360
2387
|
if method:
|
|
2361
|
-
relationships = {
|
|
2388
|
+
relationships = {
|
|
2389
|
+
str(k): r.clone(join=method, condition_and=condition_and) for k, r in relationships.items()
|
|
2390
|
+
}
|
|
2362
2391
|
|
|
2363
2392
|
return self._extend(relationships=relationships)
|
|
2364
2393
|
|
|
@@ -2579,7 +2608,6 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2579
2608
|
|
|
2580
2609
|
metadata["relationships"] = set(self.relationships.keys())
|
|
2581
2610
|
|
|
2582
|
-
# query = self._update_query_for_inner(db, model, query)
|
|
2583
2611
|
join = []
|
|
2584
2612
|
for key, relation in self.relationships.items():
|
|
2585
2613
|
if not relation.condition or relation.join != "inner":
|
|
@@ -2587,7 +2615,11 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2587
2615
|
|
|
2588
2616
|
other = relation.get_table(db)
|
|
2589
2617
|
other = other.with_alias(f"{key}_{hash(relation)}")
|
|
2590
|
-
|
|
2618
|
+
condition = relation.condition(model, other)
|
|
2619
|
+
if callable(relation.condition_and):
|
|
2620
|
+
condition &= relation.condition_and(model, other)
|
|
2621
|
+
|
|
2622
|
+
join.append(other.on(condition))
|
|
2591
2623
|
|
|
2592
2624
|
if limitby := select_kwargs.pop("limitby", ()):
|
|
2593
2625
|
|
|
@@ -2637,12 +2669,12 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2637
2669
|
# .on not given, generate it:
|
|
2638
2670
|
other = other.with_alias(f"{key}_{hash(relation)}")
|
|
2639
2671
|
condition = typing.cast(Query, relation.condition(model, other))
|
|
2672
|
+
if callable(relation.condition_and):
|
|
2673
|
+
condition &= relation.condition_and(model, other)
|
|
2640
2674
|
left.append(other.on(condition))
|
|
2641
2675
|
else:
|
|
2642
2676
|
# else: inner join (handled earlier)
|
|
2643
2677
|
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
2678
|
|
|
2647
2679
|
# if no fields of 'other' are included, add other.ALL
|
|
2648
2680
|
# else: only add other.id if missing
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
typedal/__about__.py,sha256=
|
|
1
|
+
typedal/__about__.py,sha256=B3nvfsy5sqV1qvJD-USMBUZp7Yxt_MntWJjHQpKTRp4,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=OBokUmNBvm83REIEKUjjIXna5UWSXC5H8M82LiAag0M,102729
|
|
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.1.dist-info/METADATA,sha256=Sq9mjfjvP1QgHSkb5HMpTkmsoxqyAZe7vFHTU-KXeQc,10463
|
|
17
|
+
typedal-3.9.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
18
|
+
typedal-3.9.1.dist-info/entry_points.txt,sha256=m1wqcc_10rHWPdlQ71zEkmJDADUAnZtn7Jac_6mbyUc,44
|
|
19
|
+
typedal-3.9.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|