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 CHANGED
@@ -5,4 +5,4 @@ This file contains the Version info for this package.
5
5
  # SPDX-FileCopyrightText: 2023-present Robin van der Noord <robinvandernoord@gmail.com>
6
6
  #
7
7
  # SPDX-License-Identifier: MIT
8
- __version__ = "3.8.5"
8
+ __version__ = "3.9.1"
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 rows.
2233
+ Querybuilder is truthy if it has any conditions.
2225
2234
  """
2226
- return self.count() > 0
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 = {str(fields[0]): Relationship(fields[0], condition=condition, join=method)}
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 = {str(k): r.clone(join=method) for k, r in relationships.items()}
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
- join.append(other.on(relation.condition(model, other)))
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,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: TypeDAL
3
- Version: 3.8.5
3
+ Version: 3.9.1
4
4
  Summary: Typing support for PyDAL
5
5
  Project-URL: Documentation, https://typedal.readthedocs.io/
6
6
  Project-URL: Issues, https://github.com/trialandsuccess/TypeDAL/issues
@@ -1,9 +1,9 @@
1
- typedal/__about__.py,sha256=bvQs_IhdRXwl5i7SVQ_hGOKt-LVVmnzTgIq29Sdi698,206
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=3puxKj57FvZjR4JUt2926e9eSPnOSaE9hbe2w2M7PyM,101411
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.8.5.dist-info/METADATA,sha256=z0OMhwDSKy8WskcYeYwrLtaGHv7GZzET7qENGoiv4PY,10463
17
- typedal-3.8.5.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
18
- typedal-3.8.5.dist-info/entry_points.txt,sha256=m1wqcc_10rHWPdlQ71zEkmJDADUAnZtn7Jac_6mbyUc,44
19
- typedal-3.8.5.dist-info/RECORD,,
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,,