@@ -200,7 +200,7 @@ def __init__(self, client, entity,
200200
201201 self .setAttributes (attributes )
202202 self .setAggregate (aggregate )
203- self .conditions = dict ()
203+ self .conditions = []
204204 self .addConditions (conditions )
205205 self .includes = set ()
206206 self .addIncludes (includes )
@@ -276,7 +276,7 @@ def _dosubst(self, obj, subst, addas=True):
276276 def _get_subst (self ):
277277 if self ._subst is None :
278278 joinattrs = ( self ._order_attrs |
279- set ( self .conditions . keys ()) |
279+ self ._conditions_attrs |
280280 set (self .attributes ) )
281281 self ._subst = self ._makesubst (joinattrs )
282282 return self ._subst
@@ -417,7 +417,7 @@ def setOrder(self, order):
417417 for (pattr , attrInfo , rclass ) in self ._attrpath (item .attr ):
418418 if attrInfo .relType == "ONE" :
419419 if (not attrInfo .notNullable and
420- pattr not in self .conditions and
420+ pattr not in self ._conditions_attrs and
421421 pattr not in self .join_specs ):
422422 sl = 3 if self ._init else 2
423423 warn (QueryNullableOrderWarning (pattr ),
@@ -445,34 +445,45 @@ def addConditions(self, conditions):
445445 """Add conditions to the constraints to build the WHERE clause from.
446446
447447 :param conditions: the conditions to restrict the search
448- result. This must be a mapping of attribute names to
449- conditions on that attribute. The latter may either be a
450- string with a single condition or a list of strings to add
451- more then one condition on a single attribute. The
452- attribute name (the key of the condition) can be wrapped
453- with a JPQL function (such as "UPPER(title)"). If the
454- query already has a condition on a given attribute, the
455- previous condition(s) will be retained and the new
456- condition(s) added to that.
457- :type conditions: :class:`dict`
458- :raise ValueError: if any key in `conditions` is not valid.
448+ result. This must be a list of tuples with a pair of an
449+ attribute name and a condition on that attribute
450+ respectively. The attribute name may be wrapped with a
451+ JPQL function (such as "UPPER(title)").
452+
453+ For backward compatibility with previous versions, this
454+ may alternatively be a mapping of attribute names to a
455+ (lists of) conditions.
456+ :type conditions: :class:`list` of :class:`tuple` or :class:`dict`
457+ :raise ValueError: if any attribute in `conditions` is not valid.
459458
460459 .. versionchanged:: 0.20.0
461460 allow a JPQL function in the attribute.
461+
462+ .. versionchanged:: 2.0.0
463+ expect a :class:`list` of :class:`tuple` in the
464+ `conditions` argument.
465+ .. deprecated:: 2.0.0
466+ accept a :class:`dict` in the `conditions` argument.
462467 """
463468 if conditions :
464469 self ._subst = None
465- for k in conditions .keys ():
466- if isinstance (conditions [k ], str ):
467- conds = [conditions [k ]]
468- else :
469- conds = conditions [k ]
470- for rhs in conds :
471- item = ConditionItem (k , rhs )
472- for (pattr , attrInfo , rclass ) in self ._attrpath (item .attr ):
473- pass
474- l = self .conditions .setdefault (item .attr , [])
475- l .append (item )
470+
471+ if isinstance (conditions , Mapping ):
472+ # Convert the conditions argument to a list of tuples.
473+ conds = []
474+ for obj ,v in conditions .items ():
475+ if isinstance (v , str ):
476+ conds .append ( (obj ,v ) )
477+ else :
478+ for rhs in v :
479+ conds .append ( (obj ,rhs ) )
480+ conditions = conds
481+
482+ for obj ,rhs in conditions :
483+ item = ConditionItem (obj , rhs )
484+ for (pattr , attrInfo , rclass ) in self ._attrpath (item .attr ):
485+ pass
486+ self .conditions .append (item )
476487
477488 def addIncludes (self , includes ):
478489 """Add related objects to build the INCLUDE clause from.
@@ -512,6 +523,10 @@ def setLimit(self, limit):
512523 def _order_attrs (self ):
513524 return { item .attr for item in self .order }
514525
526+ @property
527+ def _conditions_attrs (self ):
528+ return { item .attr for item in self .conditions }
529+
515530 @property
516531 def select_clause (self ):
517532 """The SELECT clause of the query.
@@ -564,11 +579,9 @@ def where_clause(self):
564579 """
565580 if self .conditions :
566581 subst = self ._get_subst ()
567- conds = []
568- for a in sorted (self .conditions .keys ()):
569- attr = self ._dosubst (a , subst , False )
570- for c in self .conditions [a ]:
571- conds .append (c .formatstr % attr )
582+ sortkey = lambda item : item .attr
583+ conds = [ item .formatstr % self ._dosubst (item .attr , subst , False )
584+ for item in sorted (self .conditions , key = sortkey ) ]
572585 return "WHERE " + " AND " .join (conds )
573586 else :
574587 return None
@@ -645,9 +658,7 @@ def copy(self):
645658 q .attributes = list (self .attributes )
646659 q .aggregate = self .aggregate
647660 q .order = self .order .copy ()
648- q .conditions = dict ()
649- for k , v in self .conditions .items ():
650- q .conditions [k ] = self .conditions [k ].copy ()
661+ q .conditions = self .conditions .copy ()
651662 q .includes = self .includes .copy ()
652663 q .limit = self .limit
653664 q .join_specs = self .join_specs .copy ()
0 commit comments