diff --git a/orator/orm/builder.py b/orator/orm/builder.py index 72a7441e..2fd75de2 100644 --- a/orator/orm/builder.py +++ b/orator/orm/builder.py @@ -827,8 +827,8 @@ def _add_has_where(self, has_query, relation, operator, count, boolean): if isinstance(count, basestring) and count.isdigit(): count = QueryExpression(count) - return self.where( - QueryExpression("(%s)" % has_query.to_sql()), operator, count, boolean + return self._query.where_expression( + has_query._query, operator, count, boolean ) def _merge_model_defined_relation_wheres_to_has_query(self, has_query, relation): @@ -843,9 +843,7 @@ def _merge_model_defined_relation_wheres_to_has_query(self, has_query, relation) """ relation_query = relation.get_base_query() - has_query.merge_wheres(relation_query.wheres, relation_query.get_bindings()) - - self._query.add_binding(has_query.get_query().get_bindings(), "where") + has_query.merge_wheres(relation_query.wheres) def _get_has_relation_query(self, relation): """ diff --git a/orator/query/builder.py b/orator/query/builder.py index 2b5d0f08..1e930c42 100644 --- a/orator/query/builder.py +++ b/orator/query/builder.py @@ -506,6 +506,44 @@ def _where_sub(self, column, operator, query, boolean): return self + def where_expression(self, left_expression, operator, right_expression, boolean="and"): + type = "expression" + + bindings = [] + + if isinstance(left_expression, QueryBuilder): + self.merge_bindings(left_expression) + bindings += left_expression.get_bindings() + left_expression = QueryExpression('(%s)' % left_expression.to_sql()) + elif not isinstance(left_expression, QueryExpression): + if not isinstance(left_expression, list): + bindings.append(left_expression) + else: + bindings += left_expression + + if isinstance(right_expression, QueryBuilder): + self.merge_bindings(right_expression) + bindings += right_expression.get_bindings() + right_expression = QueryExpression('(%s)' % right_expression.to_sql()) + elif not isinstance(right_expression, QueryExpression): + if not isinstance(right_expression, list): + bindings.append(right_expression) + else: + bindings += right_expression + + self.wheres.append( + { + "type": type, + "lhs": left_expression, + "operator": operator, + "rhs": right_expression, + "boolean": boolean, + "bindings": bindings, + } + ) + + return self + def where_exists(self, query, boolean="and", negate=False): """ Add an exists clause to the query. diff --git a/orator/query/grammars/grammar.py b/orator/query/grammars/grammar.py index ffd1d74d..249a71de 100644 --- a/orator/query/grammars/grammar.py +++ b/orator/query/grammars/grammar.py @@ -157,6 +157,21 @@ def _where_sub(self, query, where): return "%s %s (%s)" % (self.wrap(where["column"]), where["operator"], select) + def _where_expression(self, query, where): + lhs = where["lhs"] + rhs = where["rhs"] + if isinstance(lhs, list): + lhs = '(%s)' % self.parameterize(lhs) + else: + lhs = self.parameter(lhs) + + if isinstance(rhs, list): + rhs = '(%s)' % self.parameterize(rhs) + else: + rhs = self.parameter(rhs) + + return "%s %s %s" % (lhs, where["operator"], rhs) + def _where_basic(self, query, where): value = self.parameter(where["value"])