[Checkins] SVN: megrok.rdb/trunk/src/megrok/rdb/ added polymorphic support to megrok.rdb, see plock for example

Jordan Baker jbb at scryent.com
Wed May 20 16:37:17 EDT 2009


Log message for revision 100175:
  added polymorphic support to megrok.rdb, see plock for example

Changed:
  U   megrok.rdb/trunk/src/megrok/rdb/__init__.py
  U   megrok.rdb/trunk/src/megrok/rdb/directive.py
  U   megrok.rdb/trunk/src/megrok/rdb/meta.py
  U   megrok.rdb/trunk/src/megrok/rdb/setup.py
  A   megrok.rdb/trunk/src/megrok/rdb/sorted_inheritance.py
  A   megrok.rdb/trunk/src/megrok/rdb/tests/polymorphic.py
  U   megrok.rdb/trunk/src/megrok/rdb/tests/test_rdb.py

-=-
Modified: megrok.rdb/trunk/src/megrok/rdb/__init__.py
===================================================================
--- megrok.rdb/trunk/src/megrok/rdb/__init__.py	2009-05-20 13:14:59 UTC (rev 100174)
+++ megrok.rdb/trunk/src/megrok/rdb/__init__.py	2009-05-20 20:37:16 UTC (rev 100175)
@@ -1,7 +1,8 @@
 from megrok.rdb.components import Model, Container, QueryContainer
 from megrok.rdb.schema import Fields
 from megrok.rdb.directive import (key, metadata, tablename, reflected,
-                                  tableargs)
+                                  tableargs, polymorphic_on, inherits,
+                                  polymorphic_identity)
 from megrok.rdb.setup import setupDatabase
 from megrok.rdb.interfaces import IDatabaseSetupEvent
 from megrok.rdb.prop import locatedproperty

Modified: megrok.rdb/trunk/src/megrok/rdb/directive.py
===================================================================
--- megrok.rdb/trunk/src/megrok/rdb/directive.py	2009-05-20 13:14:59 UTC (rev 100174)
+++ megrok.rdb/trunk/src/megrok/rdb/directive.py	2009-05-20 20:37:16 UTC (rev 100175)
@@ -21,6 +21,24 @@
     scope = CLASS_OR_MODULE
     store = ONCE
 
+class inherits(Directive):
+    scope = CLASS
+    store = ONCE
+    default = None
+
+class polymorphic_on(Directive):
+    scope = CLASS
+    store = ONCE
+    default = None
+    
+    def factory(self, table, column):
+        return table, column
+
+class polymorphic_identity(Directive):
+    scope = CLASS
+    store = ONCE
+    default = None
+
 class tableargs(Directive):
     scope = CLASS
     store = ONCE

Modified: megrok.rdb/trunk/src/megrok/rdb/meta.py
===================================================================
--- megrok.rdb/trunk/src/megrok/rdb/meta.py	2009-05-20 13:14:59 UTC (rev 100174)
+++ megrok.rdb/trunk/src/megrok/rdb/meta.py	2009-05-20 20:37:16 UTC (rev 100175)
@@ -14,8 +14,11 @@
     martian.directive(rdb.metadata)
     martian.directive(rdb.reflected)
     martian.directive(rdb.tableargs)
+    martian.directive(rdb.inherits)
+    martian.directive(rdb.polymorphic_identity)
+    martian.directive(rdb.polymorphic_on)
     
-    def execute(self, class_, tablename, metadata, reflected, tableargs, **kw):
+    def execute(self, class_, tablename, metadata, reflected, tableargs, inherits, polymorphic_identity, polymorphic_on, **kw):
         class_.__tablename__ = tablename
         if tableargs is not None:
             class_.__table_args__ = tableargs
@@ -23,7 +26,14 @@
         if reflected:
             if not hasattr(metadata, '_reflected_registry'):
                 metadata._reflected_registry = {}
-            metadata._reflected_registry[class_] = None
+
+            metadata._reflected_registry[class_] = dict(
+                inherits=inherits,
+                polymorphic_on=polymorphic_on,
+                polymorphic_identity=polymorphic_identity,
+                )
+
+
             # if this table is reflected, don't instrument now but
             # manually map later
             return True

Modified: megrok.rdb/trunk/src/megrok/rdb/setup.py
===================================================================
--- megrok.rdb/trunk/src/megrok/rdb/setup.py	2009-05-20 13:14:59 UTC (rev 100174)
+++ megrok.rdb/trunk/src/megrok/rdb/setup.py	2009-05-20 20:37:16 UTC (rev 100175)
@@ -1,7 +1,6 @@
 from zope import component
 from zope.event import notify
 
-from sqlalchemy.orm import mapper
 from sqlalchemy.ext.declarative import instrument_declarative
 from sqlalchemy.schema import Table
 
@@ -40,9 +39,28 @@
     metadata.reflect(bind=engine)
     if not hasattr(metadata, '_decl_registry'):
         metadata._decl_registry = {}
-    # now declaratively set up any reflected classes
-    for class_ in metadata._reflected_registry.keys():
+
+    # XXX should sort by the inheritance tree
+    for class_ in sorted(metadata._reflected_registry.keys(), key=lambda a: getattr(a, 'megrok.rdb.directive.inherits', 0)):
+        class_args = metadata._reflected_registry[class_]
+        polymorphic_on = class_args['polymorphic_on']
+        polymorphic_identity = class_args['polymorphic_identity']
+        inherits = class_args['inherits']
+        mapper_args = getattr(class_, '__mapper_args__', {})
+
+        if polymorphic_on:
+            tablename, column = polymorphic_on
+            mapper_args['polymorphic_on'] = getattr(metadata.tables[tablename].c, column)
+        if polymorphic_identity:
+            mapper_args['polymorphic_identity'] = polymorphic_identity
+        if inherits:
+            mapper_args['inherits'] = inherits
+                    
+        if mapper_args:
+            class_.__mapper_args__ = mapper_args
+
         instrument_declarative(class_, metadata._decl_registry, metadata)
+
     # XXX thread safety?
     metadata._reflected_completed = True
 

Added: megrok.rdb/trunk/src/megrok/rdb/sorted_inheritance.py
===================================================================
--- megrok.rdb/trunk/src/megrok/rdb/sorted_inheritance.py	                        (rev 0)
+++ megrok.rdb/trunk/src/megrok/rdb/sorted_inheritance.py	2009-05-20 20:37:16 UTC (rev 100175)
@@ -0,0 +1,37 @@
+# faasen's proof of concept of a sorting by inheritance
+class C(object):
+    pass
+
+class B(C):
+    pass
+
+class A(B):
+    pass
+
+d = {
+    A: B,
+    B: C,
+    C: None,
+    }
+
+l = [A, B, C]
+
+def sorted_inheritance(x, y):
+    if x is y:
+        return 0
+    if inherits(x, y):
+        return 1
+    else:
+        return -1
+
+def inherits(x, y):
+    if x is y:
+        return True
+    potential_base = d[x]
+    if potential_base is None:
+        return False
+    if potential_base is y:
+        return True
+    return inherits(potential_base, y)
+
+print sorted(l, cmp=sorted_inheritance)

Added: megrok.rdb/trunk/src/megrok/rdb/tests/polymorphic.py
===================================================================
--- megrok.rdb/trunk/src/megrok/rdb/tests/polymorphic.py	                        (rev 0)
+++ megrok.rdb/trunk/src/megrok/rdb/tests/polymorphic.py	2009-05-20 20:37:16 UTC (rev 100175)
@@ -0,0 +1,81 @@
+import unittest
+
+import grok.testing
+
+from megrok import rdb
+
+metadata = rdb.MetaData()
+rdb.metadata(metadata)
+
+class Polymorphic(unittest.TestCase):
+    def setUp(self):
+        grok.testing.grok('megrok.rdb.meta')
+        from megrok.rdb.testing import configureEngine
+        engine = configureEngine()
+
+        from sqlalchemy.sql import text
+        conn = engine.connect()
+        s = text('''
+            create table content (
+                id integer,
+                type char(50),
+                primary key (id))
+        ''')
+        result = conn.execute(s)
+        s = text('''
+           create table person (
+             id integer,
+             name char(50),
+             FOREIGN KEY(id) REFERENCES content (id)
+             )
+        ''')
+        result = conn.execute(s)
+        x = conn.execute
+        x('INSERT INTO content VALUES (1, "person")')
+        x('INSERT INTO person VALUES (1, "Bob")')
+        x('INSERT INTO content VALUES (2, "content")')
+
+    def test_polymorphic_reflection(self):
+        """
+        Could test basic attributes being set but this integration test
+        ensures it continues to work with SQLAlchemy.
+        """
+
+        class Content(rdb.Model):
+            rdb.reflected()
+            rdb.polymorphic_on(table='content', column='type')
+            rdb.polymorphic_identity('content')
+
+        class Person(Content):
+            rdb.tablename('person')
+            rdb.reflected()
+            rdb.inherits(Content)
+            rdb.polymorphic_identity('person')
+
+        grok.testing.grok_component('Content', Content)
+        grok.testing.grok_component('Person', Person)
+
+        # this has to be called after classes are grokked
+        rdb.setupDatabase(metadata)
+        session = rdb.Session()
+        
+        results = session.query(Content).all()
+
+        assert results
+        assert isinstance(results[0], Person)
+        # a Person has a name
+        assert results[0].name == 'Bob'
+        
+        assert isinstance(results[1], Content)
+        # Content does not have a name
+        assert not hasattr(results[1], 'name')
+        
+    def test_polymorphic_declarative(self):
+        """
+        Test that non-reflected works
+        """
+        assert "I am broken!"
+
+def suite():
+    return unittest.makeSuite(Polymorphic)
+

Modified: megrok.rdb/trunk/src/megrok/rdb/tests/test_rdb.py
===================================================================
--- megrok.rdb/trunk/src/megrok/rdb/tests/test_rdb.py	2009-05-20 13:14:59 UTC (rev 100174)
+++ megrok.rdb/trunk/src/megrok/rdb/tests/test_rdb.py	2009-05-20 20:37:16 UTC (rev 100175)
@@ -8,7 +8,7 @@
     
 from z3c.saconfig.interfaces import IEngineFactory, IScopedSession
 
-from megrok.rdb.tests import tableargs
+from megrok.rdb.tests import tableargs, polymorphic
 
 def moduleSetUp(test):
     # using zope.testing.module.setUp to work around
@@ -61,4 +61,5 @@
         optionflags=optionflags,
         ))
     suite.addTest(tableargs.suite())
+    suite.addTest(polymorphic.suite())
     return suite



More information about the Checkins mailing list