summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES8
-rwxr-xr-xlib/sqlalchemy/ext/declarative.py10
-rw-r--r--lib/sqlalchemy/orm/descriptor_props.py4
-rw-r--r--test/ext/test_declarative.py63
4 files changed, 80 insertions, 5 deletions
diff --git a/CHANGES b/CHANGES
index 16c678868..4d4ac726d 100644
--- 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
diff --git a/lib/sqlalchemy/ext/declarative.py b/lib/sqlalchemy/ext/declarative.py
index f80562b32..00c4aec3f 100755
--- a/lib/sqlalchemy/ext/declarative.py
+++ b/lib/sqlalchemy/ext/declarative.py
@@ -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_:
diff --git a/lib/sqlalchemy/orm/descriptor_props.py b/lib/sqlalchemy/orm/descriptor_props.py
index 49f310787..d8a4bc8cf 100644
--- a/lib/sqlalchemy/orm/descriptor_props.py
+++ b/lib/sqlalchemy/orm/descriptor_props.py
@@ -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.
diff --git a/test/ext/test_declarative.py b/test/ext/test_declarative.py
index 9d75333c8..32eae69a9 100644
--- a/test/ext/test_declarative.py
+++ b/test/ext/test_declarative.py
@@ -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)