summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/future
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2019-12-01 17:24:27 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2020-05-24 11:54:08 -0400
commitdce8c7a125cb99fad62c76cd145752d5afefae36 (patch)
tree352dfa2c38005207ca64f45170bbba2c0f8c927e /lib/sqlalchemy/future
parent1502b5b3e4e4b93021eb927a6623f288ef006ba6 (diff)
downloadsqlalchemy-dce8c7a125cb99fad62c76cd145752d5afefae36.tar.gz
Unify Query and select() , move all processing to compile phase
Convert Query to do virtually all compile state computation in the _compile_context() phase, and organize it all such that a plain select() construct may also be used as the source of information in order to generate ORM query state. This makes it such that Query is not needed except for its additional methods like from_self() which are all to be deprecated. The construction of ORM state will occur beyond the caching boundary when the new execution model is integrated. future select() gains a working join() and filter_by() method. as we continue to rebase and merge each commit in the steps, callcounts continue to bump around. will have to look at the final result when it's all in. References: #5159 References: #4705 References: #4639 References: #4871 References: #5010 Change-Id: I19e05b3424b07114cce6c439b05198ac47f7ac10
Diffstat (limited to 'lib/sqlalchemy/future')
-rw-r--r--lib/sqlalchemy/future/__init__.py4
-rw-r--r--lib/sqlalchemy/future/selectable.py144
2 files changed, 146 insertions, 2 deletions
diff --git a/lib/sqlalchemy/future/__init__.py b/lib/sqlalchemy/future/__init__.py
index 635afa78c..6a3581599 100644
--- a/lib/sqlalchemy/future/__init__.py
+++ b/lib/sqlalchemy/future/__init__.py
@@ -11,7 +11,7 @@
from .engine import Connection # noqa
from .engine import create_engine # noqa
from .engine import Engine # noqa
-from ..sql.selectable import Select
+from .selectable import Select # noqa
from ..util.langhelpers import public_factory
-select = public_factory(Select._create_select, ".future.select")
+select = public_factory(Select._create_future_select, ".future.select")
diff --git a/lib/sqlalchemy/future/selectable.py b/lib/sqlalchemy/future/selectable.py
new file mode 100644
index 000000000..2b76245e0
--- /dev/null
+++ b/lib/sqlalchemy/future/selectable.py
@@ -0,0 +1,144 @@
+from ..sql import coercions
+from ..sql import roles
+from ..sql.base import _generative
+from ..sql.selectable import GenerativeSelect
+from ..sql.selectable import Select as _LegacySelect
+from ..sql.selectable import SelectState
+from ..sql.util import _entity_namespace_key
+
+
+class Select(_LegacySelect):
+ _is_future = True
+ _setup_joins = ()
+ _legacy_setup_joins = ()
+
+ @classmethod
+ def _create_select(cls, *entities):
+ raise NotImplementedError("use _create_future_select")
+
+ @classmethod
+ def _create_future_select(cls, *entities):
+ r"""Construct a new :class:`_expression.Select` using the 2.
+ x style API.
+
+ .. versionadded:: 2.0 - the :func:`_future.select` construct is
+ the same construct as the one returned by
+ :func:`_expression.select`, except that the function only
+ accepts the "columns clause" entities up front; the rest of the
+ state of the SELECT should be built up using generative methods.
+
+ Similar functionality is also available via the
+ :meth:`_expression.FromClause.select` method on any
+ :class:`_expression.FromClause`.
+
+ .. seealso::
+
+ :ref:`coretutorial_selecting` - Core Tutorial description of
+ :func:`_expression.select`.
+
+ :param \*entities:
+ Entities to SELECT from. For Core usage, this is typically a series
+ of :class:`_expression.ColumnElement` and / or
+ :class:`_expression.FromClause`
+ objects which will form the columns clause of the resulting
+ statement. For those objects that are instances of
+ :class:`_expression.FromClause` (typically :class:`_schema.Table`
+ or :class:`_expression.Alias`
+ objects), the :attr:`_expression.FromClause.c`
+ collection is extracted
+ to form a collection of :class:`_expression.ColumnElement` objects.
+
+ This parameter will also accept :class:`_expression.TextClause`
+ constructs as
+ given, as well as ORM-mapped classes.
+
+ """
+
+ self = cls.__new__(cls)
+ self._raw_columns = [
+ coercions.expect(roles.ColumnsClauseRole, ent, apply_plugins=self)
+ for ent in entities
+ ]
+
+ GenerativeSelect.__init__(self)
+
+ return self
+
+ def filter(self, *criteria):
+ """A synonym for the :meth:`_future.Select.where` method."""
+
+ return self.where(*criteria)
+
+ def _filter_by_zero(self):
+ if self._setup_joins:
+ meth = SelectState.get_plugin_classmethod(
+ self, "determine_last_joined_entity"
+ )
+ _last_joined_entity = meth(self)
+ if _last_joined_entity is not None:
+ return _last_joined_entity
+
+ if self._from_obj:
+ return self._from_obj[0]
+
+ return self._raw_columns[0]
+
+ def filter_by(self, **kwargs):
+ r"""apply the given filtering criterion as a WHERE clause
+ to this select.
+
+ """
+ from_entity = self._filter_by_zero()
+
+ clauses = [
+ _entity_namespace_key(from_entity, key) == value
+ for key, value in kwargs.items()
+ ]
+ return self.filter(*clauses)
+
+ @_generative
+ def join(self, target, onclause=None, isouter=False, full=False):
+ r"""Create a SQL JOIN against this :class:`_expresson.Select`
+ object's criterion
+ and apply generatively, returning the newly resulting
+ :class:`_expression.Select`.
+
+
+ """
+ target = coercions.expect(
+ roles.JoinTargetRole, target, apply_plugins=self
+ )
+ self._setup_joins += (
+ (target, onclause, None, {"isouter": isouter, "full": full}),
+ )
+
+ @_generative
+ def join_from(
+ self, from_, target, onclause=None, isouter=False, full=False
+ ):
+ r"""Create a SQL JOIN against this :class:`_expresson.Select`
+ object's criterion
+ and apply generatively, returning the newly resulting
+ :class:`_expression.Select`.
+
+
+ """
+
+ target = coercions.expect(
+ roles.JoinTargetRole, target, apply_plugins=self
+ )
+ from_ = coercions.expect(
+ roles.FromClauseRole, from_, apply_plugins=self
+ )
+
+ self._setup_joins += (
+ (target, onclause, from_, {"isouter": isouter, "full": full}),
+ )
+
+ def outerjoin(self, target, onclause=None, full=False):
+ """Create a left outer join.
+
+
+
+ """
+ return self.join(target, onclause=onclause, isouter=True, full=full,)