diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2017-04-27 11:24:41 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2017-04-28 10:14:09 -0400 |
| commit | 36275b0c2d8d3501bc0023e80d8433c0d54c0d9a (patch) | |
| tree | b558f1d4df1daf6854d013abf13c0200b5c68cd4 /test/ext/test_associationproxy.py | |
| parent | cedb11925fc7dd652f479370b59c38324e0e3951 (diff) | |
| download | sqlalchemy-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.py | 100 |
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 |
