summaryrefslogtreecommitdiff
path: root/doc/build/orm
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2018-12-12 12:51:20 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2018-12-12 12:54:56 -0500
commiteb73b1a1cdb72e76bda65df2dd024e3efa7a254b (patch)
treed311aec472a7b30296bc89f2dc184e5b5d1f845d /doc/build/orm
parent560452acd292c8a9a57db032378a6342f16448c6 (diff)
downloadsqlalchemy-eb73b1a1cdb72e76bda65df2dd024e3efa7a254b.tar.gz
Document and support nested composites
Composites can behave in a "nested" fashion by defining the class in that way. To make the constructor more convenient, a callable can be passed to :func:`.composite` instead of the class itself. This works now, so add a test to ensure this pattern remains available. Change-Id: Ia009f274fca7269f41d6d824e0f70b6fb0ada081 (cherry picked from commit d4a130bb1b92869efe33675262c7b1fde364e477)
Diffstat (limited to 'doc/build/orm')
-rw-r--r--doc/build/orm/composites.rst70
1 files changed, 70 insertions, 0 deletions
diff --git a/doc/build/orm/composites.rst b/doc/build/orm/composites.rst
index 04f9b5110..fbbef1293 100644
--- a/doc/build/orm/composites.rst
+++ b/doc/build/orm/composites.rst
@@ -148,3 +148,73 @@ the same expression that the base "greater than" does::
end = composite(Point, x2, y2,
comparator_factory=PointComparator)
+Nesting Composites
+-------------------
+
+Composite objects can be defined to work in simple nested schemes, by
+redefining behaviors within the composite class to work as desired, then
+mapping the composite class to the full length of individual columns normally.
+Typically, it is convenient to define separate constructors for user-defined
+use and generate-from-row use. Below we reorganize the ``Vertex`` class to
+itself be a composite object, which is then mapped to a class ``HasVertex``::
+
+ from sqlalchemy.orm import composite
+
+ class Point(object):
+ def __init__(self, x, y):
+ self.x = x
+ self.y = y
+
+ def __composite_values__(self):
+ return self.x, self.y
+
+ def __repr__(self):
+ return "Point(x=%r, y=%r)" % (self.x, self.y)
+
+ def __eq__(self, other):
+ return isinstance(other, Point) and \
+ other.x == self.x and \
+ other.y == self.y
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ class Vertex(object):
+ def __init__(self, start, end):
+ self.start = start
+ self.end = end
+
+ @classmethod
+ def _generate(self, x1, y1, x2, y2):
+ """generate a Vertex from a row"""
+ return Vertex(
+ Point(x1, y1),
+ Point(x2, y2)
+ )
+
+ def __composite_values__(self):
+ return \
+ self.start.__composite_values__() + \
+ self.end.__composite_values__()
+
+ class HasVertex(Base):
+ __tablename__ = 'has_vertex'
+ id = Column(Integer, primary_key=True)
+ x1 = Column(Integer)
+ y1 = Column(Integer)
+ x2 = Column(Integer)
+ y2 = Column(Integer)
+
+ vertex = composite(Vertex._generate, x1, y1, x2, y2)
+
+We can then use the above mapping as::
+
+ hv = HasVertex(vertex=Vertex(Point(1, 2), Point(3, 4)))
+
+ s.add(hv)
+ s.commit()
+
+ hv = s.query(HasVertex).filter(
+ HasVertex.vertex == Vertex(Point(1, 2), Point(3, 4))).first()
+ print(hv.vertex.start)
+ print(hv.vertex.end) \ No newline at end of file