Hi there,

I've been playing with concrete inheritance a bit these days (trying
to implement it into Elixir). I've run into several problems, which
might be known limitations, but I'd like to know for sure or be shown
what I've done wrong...

The two problems I get involve a chain of classes inheriting from one
another: class C inherits from class B which inherits from class A.
The first problem is that I can get a polymorphic load starting from
class B. I'd like it to return instances of class C, along with the
instances from class B. Querying class A works as expected though
(return instances of A, B and C).
See multi_level_concrete.py for what I tried. (It's a
hacked/standalone version of the unit tests found in SA itself). FWIW,
I run them with nosetest.

The second (probably related) problem is that I can't get
relationships to work polymorphically. I'd like to have a relationship
to the B class. Since I've read in the doc that the relation is not
inherited automatically, I tried duplicating manually, but then it
doesn't work polymorphically... Anyway, see concrete_with_relations.py
for my experimentations.

Thanks in advance for any pointer on this,
-- 
Gaƫtan de Menten
http://openhex.org

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

from sqlalchemy import *
from sqlalchemy.orm import *

metadata = MetaData('sqlite:///')

companies = Table('companies', metadata,
   Column('id', Integer, primary_key=True),
   Column('name', String(50)))

managers_table = Table('managers', metadata,
    Column('employee_id', Integer, primary_key=True),
    Column('name', String(50)),
    Column('manager_data', String(50)),
    Column('company_id', Integer, ForeignKey('companies.id'))
)

engineers_table = Table('engineers', metadata,
    Column('employee_id', Integer, primary_key=True),
    Column('name', String(50)),
    Column('engineer_info', String(50)),
    Column('company_id', Integer, ForeignKey('companies.id'))
)

hackers_table = Table('hackers', metadata,
    Column('employee_id', Integer, primary_key=True),
    Column('name', String(50)),
    Column('engineer_info', String(50)),
    Column('company_id', Integer, ForeignKey('companies.id')),
    Column('nickname', String(50))
)

metadata.create_all()
#metadata.bind.echo = True

def test_relation_1():
    class Company(object):
        def __init__(self, name):
            self.name = name

    class Employee(object):
        def __init__(self, name):
            self.name = name
        def __repr__(self):
            return self.__class__.__name__ + " " + self.name

    class Manager(Employee):
        def __init__(self, name, manager_data):
            self.name = name
            self.manager_data = manager_data
        def __repr__(self):
            return self.__class__.__name__ + " " + self.name + " " +  self.manager_data

    class Engineer(Employee):
        def __init__(self, name, engineer_info):
            self.name = name
            self.engineer_info = engineer_info
        def __repr__(self):
            return self.__class__.__name__ + " " + self.name + " " +  self.engineer_info

    class Hacker(Engineer):
        def __init__(self, name, nickname, engineer_info):
            self.name = name
            self.nickname = nickname
            self.engineer_info = engineer_info
        def __repr__(self):
            return self.__class__.__name__ + " " + self.name + " '" + \
                   self.nickname + "' " +  self.engineer_info
    pjoin = polymorphic_union({
        'manager':managers_table,
        'engineer':engineers_table,
        'hacker':hackers_table
    }, 'type', 'pjoin')

    mapper(Company, companies, properties={
        'engineers':relation(Engineer, lazy=False, enable_typechecks=False)
    })
    employee_mapper = mapper(Employee, pjoin, polymorphic_on=pjoin.c.type)
    manager_mapper = mapper(Manager, managers_table, inherits=employee_mapper, concrete=True, polymorphic_identity='manager')
    engineer_mapper = mapper(Engineer, engineers_table,
            inherits=employee_mapper, concrete=True,
            polymorphic_identity='engineer',
            properties={'company': relation(Company)})
    hacker_mapper = mapper(Hacker, hackers_table, inherits=engineer_mapper,
                           concrete=True, polymorphic_identity='hacker',
                           properties={'company': relation(Company)})

    session = create_session()
    c = Company('Super')
    session.save(Manager('Tom', 'knows how to manage things'))
    c.engineers.append(Engineer('Jerry', 'knows how to program'))
    c.engineers.append(Hacker('Kurt', 'Badass', 'knows how to hack'))
    assert len(c.engineers) == 2
    session.save(c)
    session.flush()
    session.clear()

    assert set([repr(x) for x in session.query(Employee).all()]) == \
           set(["Engineer Jerry knows how to program", "Manager Tom knows how to manage things", "Hacker Kurt 'Badass' knows how to hack"])
    assert set([repr(x) for x in session.query(Manager).all()]) == set(["Manager Tom knows how to manage things"])
    res = session.query(Company).one().engineers
    print res
    assert set([repr(x) for x in res]) == \
           set(["Engineer Jerry knows how to program", "Hacker Kurt 'Badass' knows how to hack"])

def test_relation_2():
    metadata.drop_all()
    metadata.create_all()

    class Company(object):
        def __init__(self, name):
            self.name = name

    class Employee(object):
        def __init__(self, name):
            self.name = name
        def __repr__(self):
            return self.__class__.__name__ + " " + self.name

    class Manager(Employee):
        def __init__(self, name, manager_data):
            self.name = name
            self.manager_data = manager_data
        def __repr__(self):
            return self.__class__.__name__ + " " + self.name + " " +  self.manager_data

    class Engineer(Employee):
        def __init__(self, name, engineer_info):
            self.name = name
            self.engineer_info = engineer_info
        def __repr__(self):
            return self.__class__.__name__ + " " + self.name + " " +  self.engineer_info

    class Hacker(Engineer):
        def __init__(self, name, nickname, engineer_info):
            self.name = name
            self.nickname = nickname
            self.engineer_info = engineer_info
        def __repr__(self):
            return self.__class__.__name__ + " " + self.name + " '" + \
                   self.nickname + "' " +  self.engineer_info
    pjoin = polymorphic_union({
        'manager':managers_table,
        'engineer':engineers_table,
        'hacker':hackers_table
    }, 'type', 'pjoin')

    mapper(Company, companies, properties={
        'engineers': relation(Engineer, lazy=False, enable_typechecks=False, backref='company')
    })
    employee_mapper = mapper(Employee, pjoin, polymorphic_on=pjoin.c.type)
    manager_mapper = mapper(Manager, managers_table, inherits=employee_mapper, concrete=True, polymorphic_identity='manager')
    engineer_mapper = mapper(Engineer, engineers_table,
            inherits=employee_mapper, concrete=True,
            polymorphic_identity='engineer')
    hacker_mapper = mapper(Hacker, hackers_table, inherits=engineer_mapper,
                           concrete=True, polymorphic_identity='hacker')

    session = create_session()
    c = Company('Super')
    session.save(Manager('Tom', 'knows how to manage things'))
    c.engineers.append(Engineer('Jerry', 'knows how to program'))
    c.engineers.append(Hacker('Kurt', 'Badass', 'knows how to hack'))
    session.save(c)
    session.flush()
    session.clear()

    assert set([repr(x) for x in session.query(Employee).all()]) == \
           set(["Engineer Jerry knows how to program", "Manager Tom knows how to manage things", "Hacker Kurt 'Badass' knows how to hack"])
    assert set([repr(x) for x in session.query(Manager).all()]) == set(["Manager Tom knows how to manage things"])
    res = session.query(Company).one().engineers
    print res
    assert set([repr(x) for x in res]) == \
           set(["Engineer Jerry knows how to program", "Hacker Kurt 'Badass' knows how to hack"])


from sqlalchemy import *
from sqlalchemy.orm import *

metadata = MetaData('sqlite:///')

companies = Table('companies', metadata,
   Column('id', Integer, primary_key=True),
   Column('name', String(50)))

managers_table = Table('managers', metadata,
    Column('employee_id', Integer, primary_key=True),
    Column('name', String(50)),
    Column('manager_data', String(50)),
    Column('company_id', Integer, ForeignKey('companies.id'))
)

engineers_table = Table('engineers', metadata,
    Column('employee_id', Integer, primary_key=True),
    Column('name', String(50)),
    Column('engineer_info', String(50)),
    Column('company_id', Integer, ForeignKey('companies.id'))
)

hackers_table = Table('hackers', metadata,
    Column('employee_id', Integer, primary_key=True),
    Column('name', String(50)),
    Column('engineer_info', String(50)),
    Column('company_id', Integer, ForeignKey('companies.id')),
    Column('nickname', String(50))
)

metadata.create_all()
#metadata.bind.echo = True

class Company(object):
    def __init__(self, name):
        self.name = name


def test_multi_level_1():
    class Employee(object):
        def __init__(self, name):
            self.name = name
        def __repr__(self):
            return self.__class__.__name__ + " " + self.name

    class Manager(Employee):
        def __init__(self, name, manager_data):
            self.name = name
            self.manager_data = manager_data
        def __repr__(self):
            return self.__class__.__name__ + " " + self.name + " " +  self.manager_data

    class Engineer(Employee):
        def __init__(self, name, engineer_info):
            self.name = name
            self.engineer_info = engineer_info
        def __repr__(self):
            return self.__class__.__name__ + " " + self.name + " " +  self.engineer_info

    class Hacker(Engineer):
        def __init__(self, name, nickname, engineer_info):
            self.name = name
            self.nickname = nickname
            self.engineer_info = engineer_info
        def __repr__(self):
            return self.__class__.__name__ + " " + self.name + " '" + \
                   self.nickname + "' " +  self.engineer_info

    pjoin = polymorphic_union({
        'manager': managers_table,
        'engineer': engineers_table,
        'hacker': hackers_table
    }, 'type', 'pjoin')

    pjoin2 = polymorphic_union({
        'engineer': engineers_table,
        'hacker': hackers_table
    }, 'type', 'pjoin2')

    employee_mapper = mapper(Employee, pjoin, polymorphic_on=pjoin.c.type)
    manager_mapper = mapper(Manager, managers_table, inherits=employee_mapper, concrete=True, polymorphic_identity='manager')
    engineer_mapper = mapper(Engineer, engineers_table,
            inherits=employee_mapper, concrete=True,
            polymorphic_identity='engineer')
    hacker_mapper = mapper(Hacker, hackers_table, inherits=engineer_mapper,
                           concrete=True, polymorphic_identity='hacker')

    session = create_session()
    session.save(Manager('Tom', 'knows how to manage things'))
    session.save(Engineer('Jerry', 'knows how to program'))
    session.save(Hacker('Kurt', 'Badass', 'knows how to hack'))
    session.flush()
    session.clear()

    assert set([repr(x) for x in session.query(Employee).all()]) == \
           set(["Engineer Jerry knows how to program", "Manager Tom knows how to manage things", "Hacker Kurt 'Badass' knows how to hack"])
    assert set([repr(x) for x in session.query(Manager).all()]) == set(["Manager Tom knows how to manage things"])
    assert set([repr(x) for x in session.query(Engineer).all()]) == \
           set(["Engineer Jerry knows how to program", "Hacker Kurt 'Badass' knows how to hack"])

def test_multi_level_2():
    metadata.drop_all()
    metadata.create_all()

    class Employee(object):
        def __init__(self, name):
            self.name = name
        def __repr__(self):
            return self.__class__.__name__ + " " + self.name

    class Manager(Employee):
        def __init__(self, name, manager_data):
            self.name = name
            self.manager_data = manager_data
        def __repr__(self):
            return self.__class__.__name__ + " " + self.name + " " +  self.manager_data

    class Engineer(Employee):
        def __init__(self, name, engineer_info):
            self.name = name
            self.engineer_info = engineer_info
        def __repr__(self):
            return self.__class__.__name__ + " " + self.name + " " +  self.engineer_info

    class Hacker(Engineer):
        def __init__(self, name, nickname, engineer_info):
            self.name = name
            self.nickname = nickname
            self.engineer_info = engineer_info
        def __repr__(self):
            return self.__class__.__name__ + " " + self.name + " '" + \
                   self.nickname + "' " +  self.engineer_info
    
    pjoin = polymorphic_union({
        'manager': managers_table,
        'engineer': engineers_table,
        'hacker': hackers_table
    }, 'type', 'pjoin')

    pjoin2 = polymorphic_union({
        'engineer': engineers_table,
        'hacker': hackers_table
    }, 'type', 'pjoin2')

    employee_mapper = mapper(Employee, pjoin, polymorphic_on=pjoin.c.type)
    manager_mapper = mapper(Manager, managers_table, inherits=employee_mapper, concrete=True, polymorphic_identity='manager')
    engineer_mapper = mapper(Engineer, pjoin2, polymorphic_on=pjoin2.c.type,
            inherits=employee_mapper, concrete=True,
            polymorphic_identity='engineer')
    hacker_mapper = mapper(Hacker, hackers_table, inherits=engineer_mapper,
                           concrete=True, polymorphic_identity='hacker')

    session = create_session()
    session.save(Manager('Tom', 'knows how to manage things'))
    session.save(Engineer('Jerry', 'knows how to program'))
    session.save(Hacker('Kurt', 'Badass', 'knows how to hack'))
    session.flush()
    session.clear()

    assert set([repr(x) for x in session.query(Employee).all()]) == \
           set(["Engineer Jerry knows how to program", "Manager Tom knows how to manage things", "Hacker Kurt 'Badass' knows how to hack"])
    assert set([repr(x) for x in session.query(Manager).all()]) == set(["Manager Tom knows how to manage things"])
    assert set([repr(x) for x in session.query(Engineer).all()]) == \
           set(["Engineer Jerry knows how to program", "Hacker Kurt 'Badass' knows how to hack"])

Reply via email to