From: Patrick Hayes Date: Thu, 24 Oct 2019 14:11:52 +0000 (-0400) Subject: Add public accessor `is_single_entity` to Query X-Git-Tag: rel_1_4_0b1~650^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e55e749e182e257fcc60db383751d5afbe52ddfb;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Add public accessor `is_single_entity` to Query Added accessor :attr:`.Query.is_single_entity` to :class:`.Query`, which will indicate if the results returned by this :class:`.Query` will be a list of ORM entities, or a tuple of entities or column expressions. SQLAlchemy hopes to improve upon the behavior of single entity / tuples in future releases such that the behavior would be explicit up front, however this attribute should be helpful with the current behavior. Pull request courtesy Patrick Hayes. Fixes: #4934 Closes: #4935 Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/4935 Pull-request-sha: 98f72b40a896761a65b048cc3722ff2dac4cf2b1 Change-Id: If5db5db3ea46a93406d76ef90b5b588149ba2986 --- diff --git a/doc/build/changelog/unreleased_13/4934.rst b/doc/build/changelog/unreleased_13/4934.rst new file mode 100644 index 0000000000..3f279a4308 --- /dev/null +++ b/doc/build/changelog/unreleased_13/4934.rst @@ -0,0 +1,11 @@ +.. change:: + :tags: orm, usecase + :tickets: 4934 + + Added accessor :meth:`.Query.is_single_entity` to :class:`.Query`, which + will indicate if the results returned by this :class:`.Query` will be a + list of ORM entities, or a tuple of entities or column expressions. + SQLAlchemy hopes to improve upon the behavior of single entity / tuples in + future releases such that the behavior would be explicit up front, however + this attribute should be helpful with the current behavior. Pull request + courtesy Patrick Hayes. diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py index 8de7d5a8b8..25ba8a3986 100644 --- a/lib/sqlalchemy/orm/loading.py +++ b/lib/sqlalchemy/orm/loading.py @@ -42,11 +42,7 @@ def instances(query, cursor, context): filtered = query._has_mapper_entities - single_entity = ( - not query._only_return_tuples - and len(query._entities) == 1 - and query._entities[0].supports_single_entity - ) + single_entity = query.is_single_entity if filtered: if single_entity: diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index 92f9ee9525..1a36349f3a 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -640,14 +640,40 @@ class Query(Generative): @_generative def only_return_tuples(self, value): - """When set to True, the query results will always be a tuple, - specifically for single element queries. The default is False. + """When set to True, the query results will always be a tuple. - . .. versionadded:: 1.2.5 + This is specifically for single element queries. The default is False. + + .. versionadded:: 1.2.5 + + .. seealso:: + + :meth:`.Query.is_single_entity` """ self._only_return_tuples = value + @property + def is_single_entity(self): + """Indicates if this :class:`.Query` returns tuples or single entities. + + Returns True if this query returns a single entity for each instance + in its result list, and False if this query returns a tuple of entities + for each result. + + .. versionadded:: 1.3.11 + + .. seealso:: + + :meth:`.Query.only_return_tuples` + + """ + return ( + not self._only_return_tuples + and len(self._entities) == 1 + and self._entities[0].supports_single_entity + ) + @_generative def enable_eagerloads(self, value): """Control whether or not eager joins and subqueries are diff --git a/test/orm/test_query.py b/test/orm/test_query.py index d2c4f5bc7b..cdbeba1382 100644 --- a/test/orm/test_query.py +++ b/test/orm/test_query.py @@ -55,7 +55,9 @@ from sqlalchemy.sql import operators from sqlalchemy.testing import AssertsCompiledSQL from sqlalchemy.testing import fixtures from sqlalchemy.testing import is_ +from sqlalchemy.testing import is_false from sqlalchemy.testing import is_not_ +from sqlalchemy.testing import is_true from sqlalchemy.testing import mock from sqlalchemy.testing.assertions import assert_raises from sqlalchemy.testing.assertions import assert_raises_message @@ -96,32 +98,38 @@ class MiscTest(QueryTest): class OnlyReturnTuplesTest(QueryTest): def test_single_entity_false(self): User = self.classes.User - row = create_session().query(User).only_return_tuples(False).first() + query = create_session().query(User).only_return_tuples(False) + is_true(query.is_single_entity) + row = query.first() assert isinstance(row, User) def test_single_entity_true(self): User = self.classes.User - row = create_session().query(User).only_return_tuples(True).first() + query = create_session().query(User).only_return_tuples(True) + is_false(query.is_single_entity) + row = query.first() assert isinstance(row, collections_abc.Sequence) def test_multiple_entity_false(self): User = self.classes.User - row = ( + query = ( create_session() .query(User.id, User) .only_return_tuples(False) - .first() ) + is_false(query.is_single_entity) + row = query.first() assert isinstance(row, collections_abc.Sequence) def test_multiple_entity_true(self): User = self.classes.User - row = ( + query = ( create_session() .query(User.id, User) .only_return_tuples(True) - .first() ) + is_false(query.is_single_entity) + row = query.first() assert isinstance(row, collections_abc.Sequence)