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 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.0"
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 = {str(fields[0]): Relationship(fields[0], condition=condition, join=method)}
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 = {str(k): r.clone(join=method) for k, r in relationships.items()}
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
- join.append(other.on(relation.condition(model, other)))
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,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: TypeDAL
3
- Version: 3.8.5
3
+ Version: 3.9.0
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=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=3puxKj57FvZjR4JUt2926e9eSPnOSaE9hbe2w2M7PyM,101411
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.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.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,,