summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/ext
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/ext')
-rw-r--r--lib/sqlalchemy/ext/hybrid.py149
1 files changed, 0 insertions, 149 deletions
diff --git a/lib/sqlalchemy/ext/hybrid.py b/lib/sqlalchemy/ext/hybrid.py
index cfc6bd73b..de9ab52be 100644
--- a/lib/sqlalchemy/ext/hybrid.py
+++ b/lib/sqlalchemy/ext/hybrid.py
@@ -657,155 +657,6 @@ measurement, currencies and encrypted passwords.
<https://techspot.zzzeek.org/2011/10/29/value-agnostic-types-part-ii/>`_ -
on the techspot.zzzeek.org blog
-.. _hybrid_transformers:
-
-Building Transformers
-----------------------
-
-A *transformer* is an object which can receive a :class:`_query.Query`
-object and
-return a new one. The :class:`_query.Query` object includes a method
-:meth:`.with_transformation` that returns a new :class:`_query.Query`
-transformed by
-the given function.
-
-We can combine this with the :class:`.Comparator` class to produce one type
-of recipe which can both set up the FROM clause of a query as well as assign
-filtering criterion.
-
-Consider a mapped class ``Node``, which assembles using adjacency list into a
-hierarchical tree pattern::
-
- from sqlalchemy import Column, Integer, ForeignKey
- from sqlalchemy.orm import relationship
- from sqlalchemy.ext.declarative import declarative_base
- Base = declarative_base()
-
- class Node(Base):
- __tablename__ = 'node'
- id = Column(Integer, primary_key=True)
- parent_id = Column(Integer, ForeignKey('node.id'))
- parent = relationship("Node", remote_side=id)
-
-Suppose we wanted to add an accessor ``grandparent``. This would return the
-``parent`` of ``Node.parent``. When we have an instance of ``Node``, this is
-simple::
-
- from sqlalchemy.ext.hybrid import hybrid_property
-
- class Node(Base):
- # ...
-
- @hybrid_property
- def grandparent(self):
- return self.parent.parent
-
-For the expression, things are not so clear. We'd need to construct a
-:class:`_query.Query` where we :meth:`_query.Query.join` twice along
-``Node.parent`` to get to the ``grandparent``. We can instead return a
-transforming callable that we'll combine with the :class:`.Comparator` class to
-receive any :class:`_query.Query` object, and return a new one that's joined to
-the ``Node.parent`` attribute and filtered based on the given criterion::
-
- from sqlalchemy.ext.hybrid import Comparator
-
- class GrandparentTransformer(Comparator):
- def operate(self, op, other, **kwargs):
- def transform(q):
- cls = self.__clause_element__()
- parent_alias = aliased(cls)
- return q.join(parent_alias, cls.parent).filter(
- op(parent_alias.parent, other, **kwargs)
- )
-
- return transform
-
- Base = declarative_base()
-
- class Node(Base):
- __tablename__ = 'node'
- id = Column(Integer, primary_key=True)
- parent_id = Column(Integer, ForeignKey('node.id'))
- parent = relationship("Node", remote_side=id)
-
- @hybrid_property
- def grandparent(self):
- return self.parent.parent
-
- @grandparent.comparator
- def grandparent(cls):
- return GrandparentTransformer(cls)
-
-The ``GrandparentTransformer`` overrides the core :meth:`.Operators.operate`
-method at the base of the :class:`.Comparator` hierarchy to return a query-
-transforming callable, which then runs the given comparison operation in a
-particular context. Such as, in the example above, the ``operate`` method is
-called, given the :attr:`.Operators.eq` callable as well as the right side of
-the comparison ``Node(id=5)``. A function ``transform`` is then returned which
-will transform a :class:`_query.Query` first to join to ``Node.parent``,
-then to
-compare ``parent_alias`` using :attr:`.Operators.eq` against the left and right
-sides, passing into :meth:`_query.Query.filter`:
-
-.. sourcecode:: pycon+sql
-
- >>> from sqlalchemy.orm import Session
- >>> session = Session()
- {sql}>>> session.query(Node).\
- ... with_transformation(Node.grandparent==Node(id=5)).\
- ... all()
- SELECT node.id AS node_id, node.parent_id AS node_parent_id
- FROM node JOIN node AS node_1 ON node_1.id = node.parent_id
- WHERE :param_1 = node_1.parent_id
- {stop}
-
-We can modify the pattern to be more verbose but flexible by separating the
-"join" step from the "filter" step. The tricky part here is ensuring that
-successive instances of ``GrandparentTransformer`` use the same
-:class:`.AliasedClass` object against ``Node``. Below we use a simple
-memoizing approach that associates a ``GrandparentTransformer`` with each
-class::
-
- class Node(Base):
-
- # ...
-
- @grandparent.comparator
- def grandparent(cls):
- # memoize a GrandparentTransformer
- # per class
- if '_gp' not in cls.__dict__:
- cls._gp = GrandparentTransformer(cls)
- return cls._gp
-
- class GrandparentTransformer(Comparator):
-
- def __init__(self, cls):
- self.parent_alias = aliased(cls)
-
- @property
- def join(self):
- def go(q):
- return q.join(self.parent_alias, Node.parent)
- return go
-
- def operate(self, op, other, **kwargs):
- return op(self.parent_alias.parent, other, **kwargs)
-
-.. sourcecode:: pycon+sql
-
- {sql}>>> session.query(Node).\
- ... with_transformation(Node.grandparent.join).\
- ... filter(Node.grandparent==Node(id=5))
- SELECT node.id AS node_id, node.parent_id AS node_parent_id
- FROM node JOIN node AS node_1 ON node_1.id = node.parent_id
- WHERE :param_1 = node_1.parent_id
- {stop}
-
-The "transformer" pattern is an experimental pattern that starts to make usage
-of some functional programming paradigms. While it's only recommended for
-advanced and/or patient developers, there's probably a whole lot of amazing
-things it can be used for.
""" # noqa