]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed regression whereby composite() with
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 14 Feb 2011 17:51:53 +0000 (12:51 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 14 Feb 2011 17:51:53 +0000 (12:51 -0500)
Column objects placed inline would fail
to initialize.  The Column objects can now
be inline with the composite() or external
and pulled in via name or object ref.
[ticket:2058]

CHANGES
lib/sqlalchemy/ext/declarative.py
lib/sqlalchemy/orm/descriptor_props.py
test/ext/test_declarative.py

diff --git a/CHANGES b/CHANGES
index 16c678868076b3bd4284ae4ace0739b1d7d18484..4d4ac726d1c5f8f878fa9bc26989b50d1282f999 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -35,6 +35,14 @@ CHANGES
     FROM clauses (like when you use union() or 
     from_self()) when generating a cache key.
 
+- declarative
+  - Fixed regression whereby composite() with 
+    Column objects placed inline would fail
+    to initialize.  The Column objects can now
+    be inline with the composite() or external
+    and pulled in via name or object ref. 
+    [ticket:2058]
+
 0.7.0b1
 =======
 - Detailed descriptions of each change below are 
index f80562b32aed589b1d84ff1f3704e9f79394a8ab..00c4aec3f62ae5cf81b9cd85d66beeb3b142e976 100755 (executable)
@@ -977,16 +977,17 @@ def _as_declarative(cls, classname, dict_):
     our_stuff.sort(key=lambda key: our_stuff[key]._creation_order)
 
     # extract columns from the class dict
-    cols = []
+    cols = set()
     for key, c in our_stuff.iteritems():
         if isinstance(c, (ColumnProperty, CompositeProperty)):
             for col in c.columns:
-                if isinstance(col, Column) and col.table is None:
+                if isinstance(col, Column) and \
+                    col.table is None:
                     _undefer_column_name(key, col)
-                    cols.append(col)
+                    cols.add(col)
         elif isinstance(c, Column):
             _undefer_column_name(key, c)
-            cols.append(c)
+            cols.add(c)
             # if the column is the same name as the key, 
             # remove it from the explicit properties dict.
             # the normal rules for assigning column-based properties
@@ -994,6 +995,7 @@ def _as_declarative(cls, classname, dict_):
             # in multi-column ColumnProperties.
             if key == c.key:
                 del our_stuff[key]
+    cols = sorted(cols, key=lambda c:c._creation_order)
 
     table = None
     if '__table__' not in dict_:
index 49f310787de1c2a017e7ab983c02ddf20445f436..d8a4bc8cf791cfe9de8144f4fc9dc81cd73272eb 100644 (file)
@@ -164,6 +164,10 @@ class CompositeProperty(DescriptorProperty):
                 prop = attr.property
             props.append(prop)
 
+    @property
+    def columns(self):
+        return [a for a in self.attrs if isinstance(a, schema.Column)]
+
     def _setup_arguments_on_columns(self):
         """Propagate configuration arguments made on this composite
         to the target columns, for those that apply.
index 9d75333c85242a46a39a60937f7262e75b4d371b..32eae69a9ee8e2fcb14655c8da1a3bd30b917c27 100644 (file)
@@ -10,7 +10,8 @@ from sqlalchemy import MetaData, Integer, String, ForeignKey, \
 from test.lib.schema import Table, Column
 from sqlalchemy.orm import relationship, create_session, class_mapper, \
     joinedload, configure_mappers, backref, clear_mappers, \
-    polymorphic_union, deferred, column_property
+    polymorphic_union, deferred, column_property, composite,\
+    Session
 from test.lib.testing import eq_
 from sqlalchemy.util import classproperty
 from test.orm._base import ComparableEntity, MappedTest
@@ -895,6 +896,66 @@ class DeclarativeTest(DeclarativeTestBase):
 
         self.assert_sql_count(testing.db, go, 1)
 
+    def test_composite_inline(self):
+        class AddressComposite(ComparableEntity):
+            def __init__(self, street, state):
+                self.street = street
+                self.state = state
+            def __composite_values__(self):
+                return [self.street, self.state]
+
+        class User(Base, ComparableEntity):
+            __tablename__ = 'user'
+            id = Column(Integer, primary_key=True, 
+                            test_needs_autoincrement=True)
+            address = composite(AddressComposite, 
+                Column('street', String(50)),
+                Column('state', String(2)),
+            )
+
+        Base.metadata.create_all()
+        sess = Session()
+        sess.add(User(
+                address=AddressComposite('123 anywhere street', 
+                                'MD')
+                ))
+        sess.commit()
+        eq_(
+            sess.query(User).all(), 
+            [User(address=AddressComposite('123 anywhere street', 
+                                'MD'))]
+        )
+
+    def test_composite_separate(self):
+        class AddressComposite(ComparableEntity):
+            def __init__(self, street, state):
+                self.street = street
+                self.state = state
+            def __composite_values__(self):
+                return [self.street, self.state]
+
+        class User(Base, ComparableEntity):
+            __tablename__ = 'user'
+            id = Column(Integer, primary_key=True, 
+                            test_needs_autoincrement=True)
+            street = Column(String(50))
+            state = Column(String(2))
+            address = composite(AddressComposite, 
+                street, state)
+
+        Base.metadata.create_all()
+        sess = Session()
+        sess.add(User(
+                address=AddressComposite('123 anywhere street', 
+                                'MD')
+                ))
+        sess.commit()
+        eq_(
+            sess.query(User).all(), 
+            [User(address=AddressComposite('123 anywhere street', 
+                                'MD'))]
+        )
+
     def test_mapping_to_join(self):
         users = Table('users', Base.metadata,
             Column('id', Integer, primary_key=True)