Commits

Anonymous committed c56397b

Copied `DeclarativeReflectedBase` from the examples to `sqlalchemy.ext.declarative` and fixed an override issue. Added tests.

  • Participants
  • Parent commits 913e3f4

Comments (0)

Files changed (3)

File examples/declarative_reflection/declarative_reflection.py

                     autoload_replace=False,
                     autoload=True, 
                     autoload_with=engine,
-                    schema=table.schema)
+                    schema=table.schema,
+                    *[ _ for _ in table.c ])
             klass.__mapper__ = mapper(*args, **kw)
 
 if __name__ == '__main__':
     ])
     s.commit()
     for f in s.query(Foo):
-        print f.data, ",".join([b.data for b in f.bars])
+        print f.data, ",".join([b.data for b in f.bars])

File lib/sqlalchemy/ext/declarative.py

 
 
 __all__ = 'declarative_base', 'synonym_for', \
-            'comparable_using', 'instrument_declarative'
+            'comparable_using', 'instrument_declarative', \
+            'DeclarativeReflectedBase'
 
 def instrument_declarative(cls, registry, metadata):
     """Given a class, configure the class declaratively,
     if column.name is None:
         column.name = key
 
+
+class DeclarativeReflectedBase(object):
+    _mapper_args = []
+
+    @classmethod
+    def __mapper_cls__(cls, *args, **kw):
+        """Declarative will use this function in lieu of 
+        calling mapper() directly.
+        
+        Collect each series of arguments and invoke
+        them when prepare() is called.
+        """
+
+        cls._mapper_args.append((args, kw))
+
+    @classmethod
+    def prepare(cls, engine):
+        """Reflect all the tables and map !"""
+        while cls._mapper_args:
+            args, kw  = cls._mapper_args.pop()
+            klass = args[0]
+            # autoload Table, which is already
+            # present in the metadata.  This
+            # will fill in db-loaded columns
+            # into the existing Table object.
+            if args[1] is not None:
+                table = args[1]
+                Table(table.name, 
+                    cls.metadata, 
+                    extend_existing=True,
+                    autoload_replace=False,
+                    autoload=True, 
+                    autoload_with=engine,
+                    schema=table.schema,
+                    *[ _ for _ in table.c ])
+            klass.__mapper__ = mapper(*args, **kw)
+
+
 class ConcreteBase(object):
     """A helper class for 'concrete' declarative mappings.
     

File test/ext/test_declarative.py

     def test_relationship_primryjoin(self):
         self._test_relationship(True)
 
+
+class ReflectionTest(fixtures.TestBase):
+    """Tests the declarative reflection example"""
+    
+    __requires__ = 'sqlite',
+    
+    @classmethod
+    def setup_class(cls):
+        cls.engine = sa.create_engine('sqlite://')
+    
+    @classmethod
+    def teardown_class(cls):
+        cls.engine.dispose()
+    
+    def test_override_declarative_reflection(self):
+        """Ensures that a primary key can be overriden on a reflected Column"""
+        
+        meta = MetaData(bind = self.engine)
+        tbl = Table('sqla_test__no_pkey',
+                    meta,
+                    Column('emp_id', Integer()),
+                    Column('name', String(20)),
+                    Column('is_active', Integer()))
+        meta.create_all()
+        
+        Base = decl.declarative_base(cls=decl.DeclarativeReflectedBase)        
+        class Override(Base):
+            __tablename__ = 'sqla_test__no_pkey'
+            emp_id = Column(Integer(), primary_key=True)
+        
+        Base.prepare(self.engine)