From f05e742839d052889fb5036a91df874b919b5a58 Mon Sep 17 00:00:00 2001 From: Aron Podrigal Date: Sun, 26 May 2019 16:12:20 -0700 Subject: [PATCH 1/2] `QueryBuilder.from_sub()` to select from SubQuery expression. --- orator/query/builder.py | 25 ++++++++++++++++++++++++- tests/query/test_query_builder.py | 14 ++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/orator/query/builder.py b/orator/query/builder.py index 6e8aaa6c..9c7e2e59 100644 --- a/orator/query/builder.py +++ b/orator/query/builder.py @@ -63,7 +63,7 @@ def __init__(self, connection, grammar, processor): self._processor = processor self._connection = connection self._bindings = OrderedDict() - for type in ["select", "join", "where", "having", "order"]: + for type in ["select", "from", "join", "where", "having", "order"]: self._bindings[type] = [] self.aggregate_ = None @@ -188,8 +188,31 @@ def from_(self, table): :return: The current QueryBuilder instance :rtype: QueryBuilder """ + self.set_bindings([], "from") self.from__ = table + return self + + def from_sub(self, query, as_): + """ + Set the query target table to a subquery + + :param query: The QueryBuilder to set as from expression + :type query: QueryBuilder + + :param as_: The alias name for the subquery + :type as_: str + + :return: The current QueryBuilder instance + :rtype: QueryBuilder + """ + if not isinstance(query, QueryBuilder): + raise ArgumentError("From expression must be a QueryBuilder") + + bindings = query.get_bindings() + query = "(%s) AS %s" % (query.to_sql(), self._grammar.wrap(as_)) + self.set_bindings(bindings, "from") + self.from__ = QueryExpression(query) return self def join(self, table, one=None, operator=None, two=None, type="inner", where=False): diff --git a/tests/query/test_query_builder.py b/tests/query/test_query_builder.py index 26c1c5e3..ff2a06a9 100644 --- a/tests/query/test_query_builder.py +++ b/tests/query/test_query_builder.py @@ -1618,6 +1618,20 @@ def test_sub_select(self): self.assertEqual(expected_sql, builder.to_sql()) self.assertEqual(expected_bindings, builder.get_bindings()) + def test_from_sub_query(self): + builder = self.get_builder() + marker = builder.get_grammar().get_marker() + expected_sql = ( + 'SELECT "foo", "bar" FROM ' + '(SELECT "a" AS "foo", "b" AS "bar" FROM "one" WHERE "key" = %s ORDER BY "foo" ASC) AS "two" ' + 'WHERE "foo" = %s ORDER BY "bar" DESC' % (marker, marker) + ) + expected_bindings = ['innerval', 'outerval'] + inner_query = builder.new_query().from_('one').select('a as foo', 'b as bar').where('key', '=', 'innerval').order_by('foo', 'asc') + builder.select('foo', 'bar').from_sub(inner_query, 'two').where('foo', '=', 'outerval').order_by('bar', 'desc') + self.assertEqual(expected_sql, builder.to_sql()) + self.assertEqual(expected_bindings, builder.get_bindings()) + def test_chunk(self): builder = self.get_builder() results = [{"foo": "bar"}, {"foo": "baz"}, {"foo": "bam"}, {"foo": "boom"}] From 42a0029c1ec710d0ccfd8fcd751b2dac96d0ebe9 Mon Sep 17 00:00:00 2001 From: Aron Podrigal Date: Sun, 26 May 2019 16:46:04 -0700 Subject: [PATCH 2/2] Fixed formatting --- tests/query/test_query_builder.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/query/test_query_builder.py b/tests/query/test_query_builder.py index ff2a06a9..faf4fc1f 100644 --- a/tests/query/test_query_builder.py +++ b/tests/query/test_query_builder.py @@ -1626,9 +1626,18 @@ def test_from_sub_query(self): '(SELECT "a" AS "foo", "b" AS "bar" FROM "one" WHERE "key" = %s ORDER BY "foo" ASC) AS "two" ' 'WHERE "foo" = %s ORDER BY "bar" DESC' % (marker, marker) ) - expected_bindings = ['innerval', 'outerval'] - inner_query = builder.new_query().from_('one').select('a as foo', 'b as bar').where('key', '=', 'innerval').order_by('foo', 'asc') - builder.select('foo', 'bar').from_sub(inner_query, 'two').where('foo', '=', 'outerval').order_by('bar', 'desc') + expected_bindings = ["innerval", "outerval"] + inner_query = ( + builder.new_query() + .from_("one") + .select("a as foo", "b as bar") + .where("key", "=", "innerval") + .order_by("foo", "asc") + ) + builder.from_sub(inner_query, "two").select("foo", "bar").where( + "foo", "=", "outerval" + ).order_by("bar", "desc") + self.assertEqual(expected_sql, builder.to_sql()) self.assertEqual(expected_bindings, builder.get_bindings())