summaryrefslogtreecommitdiff
path: root/test/ext/test_associationproxy.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2017-04-27 11:24:41 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2017-04-28 10:14:09 -0400
commit36275b0c2d8d3501bc0023e80d8433c0d54c0d9a (patch)
treeb558f1d4df1daf6854d013abf13c0200b5c68cd4 /test/ext/test_associationproxy.py
parentcedb11925fc7dd652f479370b59c38324e0e3951 (diff)
downloadsqlalchemy-36275b0c2d8d3501bc0023e80d8433c0d54c0d9a.tar.gz
Call proxied collection before invoking creator in associationlist.append()
Improved the association proxy list collection so that premature autoflush against a newly created association object can be prevented in the case where ``list.append()`` is being used, and a lazy load would be invoked when the association proxy accesses the endpoint collection. The endpoint collection is now accessed first before the creator is invoked to produce the association object. Change-Id: I008a6dbdfe5b1c0dfd02189c3d954d83a65f3fc5 Fixes: #3941
Diffstat (limited to 'test/ext/test_associationproxy.py')
-rw-r--r--test/ext/test_associationproxy.py100
1 files changed, 99 insertions, 1 deletions
diff --git a/test/ext/test_associationproxy.py b/test/ext/test_associationproxy.py
index 018c2bc2a..c3891408a 100644
--- a/test/ext/test_associationproxy.py
+++ b/test/ext/test_associationproxy.py
@@ -50,6 +50,103 @@ class ObjectCollection(object):
return iter(self.values)
+class AutoFlushTest(fixtures.TablesTest):
+ @classmethod
+ def define_tables(cls, metadata):
+ Table(
+ 'parent', metadata,
+ Column('id', Integer, primary_key=True,
+ test_needs_autoincrement=True))
+ Table(
+ 'association', metadata,
+ Column('parent_id', ForeignKey('parent.id'), primary_key=True),
+ Column('child_id', ForeignKey('child.id'), primary_key=True),
+ Column('name', String(50))
+ )
+ Table(
+ 'child', metadata,
+ Column('id', Integer, primary_key=True,
+ test_needs_autoincrement=True),
+ Column('name', String(50))
+ )
+
+ def _fixture(self, collection_class, is_dict=False):
+ class Parent(object):
+ collection = association_proxy("_collection", "child")
+
+ class Child(object):
+ def __init__(self, name):
+ self.name = name
+
+ class Association(object):
+ if is_dict:
+ def __init__(self, key, child):
+ self.child = child
+ else:
+ def __init__(self, child):
+ self.child = child
+
+ mapper(Parent, self.tables.parent, properties={
+ "_collection": relationship(Association,
+ collection_class=collection_class,
+ backref="parent")
+ })
+ mapper(Association, self.tables.association, properties={
+ "child": relationship(Child, backref="association")
+ })
+ mapper(Child, self.tables.child)
+
+ return Parent, Child, Association
+
+ def _test_premature_flush(self, collection_class, fn, is_dict=False):
+ Parent, Child, Association = self._fixture(
+ collection_class, is_dict=is_dict)
+
+ session = Session(testing.db, autoflush=True, expire_on_commit=True)
+
+ p1 = Parent()
+ c1 = Child('c1')
+ c2 = Child('c2')
+ session.add(p1)
+ session.add(c1)
+ session.add(c2)
+
+ fn(p1.collection, c1)
+ session.commit()
+
+ fn(p1.collection, c2)
+ session.commit()
+
+ is_(c1.association[0].parent, p1)
+ is_(c2.association[0].parent, p1)
+
+ session.close()
+
+ def test_list_append(self):
+ self._test_premature_flush(
+ list, lambda collection, obj: collection.append(obj))
+
+ def test_list_extend(self):
+ self._test_premature_flush(
+ list, lambda collection, obj: collection.extend([obj]))
+
+ def test_set_add(self):
+ self._test_premature_flush(
+ set, lambda collection, obj: collection.add(obj))
+
+ def test_set_extend(self):
+ self._test_premature_flush(
+ set, lambda collection, obj: collection.update([obj]))
+
+ def test_dict_set(self):
+ def set_(collection, obj):
+ collection[obj.name] = obj
+
+ self._test_premature_flush(
+ collections.attribute_mapped_collection('name'),
+ set_, is_dict=True)
+
+
class _CollectionOperations(fixtures.TestBase):
def setup(self):
collection_class = self.collection_class
@@ -84,7 +181,7 @@ class _CollectionOperations(fixtures.TestBase):
self.name = name
mapper(Parent, parents_table, properties={
- '_children': relationship(Child, lazy='joined',
+ '_children': relationship(Child, lazy='joined', backref='parent',
collection_class=collection_class)})
mapper(Child, children_table)
@@ -260,6 +357,7 @@ class _CollectionOperations(fixtures.TestBase):
assert True
+
class DefaultTest(_CollectionOperations):
collection_class = None