def test_relationship(self): pjoin = polymorphic_union( {"manager": managers_table, "engineer": engineers_table}, "type", "pjoin", ) mapper( Company, companies, properties={"employees": relationship(Employee)}, ) 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", ) session = create_session() c = Company() c.employees.append(Manager("Tom", "knows how to manage things")) c.employees.append(Engineer("Kurt", "knows how to hack")) session.add(c) session.flush() session.expunge_all() def go(): c2 = session.query(Company).get(c.id) assert set([repr(x) for x in c2.employees]) == set( [ "Engineer Kurt knows how to hack", "Manager Tom knows how to manage things", ] ) self.assert_sql_count(testing.db, go, 2) session.expunge_all() def go(): c2 = ( session.query(Company) .options(joinedload(Company.employees)) .get(c.id) ) assert set([repr(x) for x in c2.employees]) == set( [ "Engineer Kurt knows how to hack", "Manager Tom knows how to manage things", ] ) self.assert_sql_count(testing.db, go, 1)
def _get_polymorphics(cls): people, engineers, managers, boss = \ cls.tables.people, cls.tables.engineers, \ cls.tables.managers, cls.tables.boss person_join = polymorphic_union({ 'engineer':people.join(engineers), 'manager':people.join(managers)}, None, 'pjoin') manager_join = people.join(managers).outerjoin(boss) person_with_polymorphic = ( [Person, Manager, Engineer], person_join) manager_with_polymorphic = ('*', manager_join) return person_with_polymorphic,\ manager_with_polymorphic
def test_explicit(self): engineers = Table( 'engineers', Base.metadata, Column('id', Integer, primary_key=True, test_needs_autoincrement=True), Column('name', String(50)), Column('primary_language', String(50))) managers = Table('managers', Base.metadata, Column('id', Integer, primary_key=True, test_needs_autoincrement=True), Column('name', String(50)), Column('golf_swing', String(50)) ) boss = Table('boss', Base.metadata, Column('id', Integer, primary_key=True, test_needs_autoincrement=True), Column('name', String(50)), Column('golf_swing', String(50)) ) punion = polymorphic_union({ 'engineer': engineers, 'manager': managers, 'boss': boss}, 'type', 'punion') class Employee(Base, fixtures.ComparableEntity): __table__ = punion __mapper_args__ = {'polymorphic_on': punion.c.type} class Engineer(Employee): __table__ = engineers __mapper_args__ = {'polymorphic_identity': 'engineer', 'concrete': True} class Manager(Employee): __table__ = managers __mapper_args__ = {'polymorphic_identity': 'manager', 'concrete': True} class Boss(Manager): __table__ = boss __mapper_args__ = {'polymorphic_identity': 'boss', 'concrete': True} self._roundtrip(Employee, Manager, Engineer, Boss)
def _get_polymorphics(cls): people, engineers, managers, boss = ( cls.tables.people, cls.tables.engineers, cls.tables.managers, cls.tables.boss, ) person_join = polymorphic_union( { "engineer": people.join(engineers), "manager": people.join(managers), }, None, "pjoin", ) manager_join = people.join(managers).outerjoin(boss) person_with_polymorphic = ([Person, Manager, Engineer], person_join) manager_with_polymorphic = ("*", manager_join) return person_with_polymorphic, manager_with_polymorphic
def test_keys(self): pjoin = polymorphic_union( {"refugee": refugees_table, "office": offices_table}, "type", "pjoin", ) class Location(object): pass class Refugee(Location): pass class Office(Location): pass location_mapper = mapper( Location, pjoin, polymorphic_on=pjoin.c.type, polymorphic_identity="location", ) office_mapper = mapper( Office, offices_table, inherits=location_mapper, concrete=True, polymorphic_identity="office", ) refugee_mapper = mapper( Refugee, refugees_table, inherits=location_mapper, concrete=True, polymorphic_identity="refugee", ) sess = create_session() eq_(sess.query(Refugee).get(1).name, "refugee1") eq_(sess.query(Refugee).get(2).name, "refugee2") eq_(sess.query(Office).get(1).name, "office1") eq_(sess.query(Office).get(2).name, "office2")
def test_basic(self): pjoin = polymorphic_union( {"manager": managers_table, "engineer": engineers_table}, "type", "pjoin", ) 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", ) session = create_session() session.add(Manager("Tom", "knows how to manage things")) session.add(Engineer("Kurt", "knows how to hack")) session.flush() session.expunge_all() assert set([repr(x) for x in session.query(Employee)]) == set( [ "Engineer Kurt knows how to hack", "Manager Tom knows how to manage things", ] ) assert set([repr(x) for x in session.query(Manager)]) == set( ["Manager Tom knows how to manage things"] ) assert set([repr(x) for x in session.query(Engineer)]) == set( ["Engineer Kurt knows how to hack"] ) manager = session.query(Manager).one() session.expire(manager, ["manager_data"]) eq_(manager.manager_data, "knows how to manage things")
def _get_polymorphics(cls): people, engineers, managers, boss = ( cls.tables.people, cls.tables.engineers, cls.tables.managers, cls.tables.boss, ) person_join = polymorphic_union( util.OrderedDict( [ ("engineer", people.join(engineers)), ("manager", people.join(managers)), ] ), None, "pjoin", ) manager_join = people.join(managers).outerjoin(boss) person_with_polymorphic = ([Person, Manager, Engineer], person_join) manager_with_polymorphic = ("*", manager_join) return person_with_polymorphic, manager_with_polymorphic
def test_roundtrip(self): parent_table = {"a": ta, "b": tb, "c": tc}[parent] child_table = {"a": ta, "b": tb, "c": tc}[child] remote_side = None if direction == MANYTOONE: foreign_keys = [parent_table.c.child_id] elif direction == ONETOMANY: foreign_keys = [child_table.c.parent_id] atob = ta.c.id == tb.c.id btoc = tc.c.id == tb.c.id if direction == ONETOMANY: relationshipjoin = parent_table.c.id == child_table.c.parent_id elif direction == MANYTOONE: relationshipjoin = parent_table.c.child_id == child_table.c.id if parent is child: remote_side = [child_table.c.id] abcjoin = polymorphic_union( { "a": ta.select( tb.c.id == None, # noqa from_obj=[ta.outerjoin(tb, onclause=atob)], ), "b": ta.join(tb, onclause=atob).outerjoin( tc, onclause=btoc).select( tc.c.id == None).reduce_columns(), # noqa "c": tc.join(tb, onclause=btoc).join(ta, onclause=atob), }, "type", "abcjoin", ) bcjoin = polymorphic_union( { "b": ta.join(tb, onclause=atob).outerjoin( tc, onclause=btoc).select( tc.c.id == None).reduce_columns(), # noqa "c": tc.join(tb, onclause=btoc).join(ta, onclause=atob), }, "type", "bcjoin", ) class A(object): def __init__(self, name): self.a_data = name class B(A): pass class C(B): pass mapper( A, ta, polymorphic_on=abcjoin.c.type, with_polymorphic=("*", abcjoin), polymorphic_identity="a", ) mapper( B, tb, polymorphic_on=bcjoin.c.type, with_polymorphic=("*", bcjoin), polymorphic_identity="b", inherits=A, inherit_condition=atob, ) mapper( C, tc, polymorphic_identity="c", inherits=B, inherit_condition=btoc, ) parent_mapper = class_mapper({ta: A, tb: B, tc: C}[parent_table]) child_mapper = class_mapper({ta: A, tb: B, tc: C}[child_table]) parent_class = parent_mapper.class_ child_class = child_mapper.class_ parent_mapper.add_property( "collection", relationship( child_mapper, primaryjoin=relationshipjoin, foreign_keys=foreign_keys, order_by=child_mapper.c.id, remote_side=remote_side, uselist=True, ), ) sess = create_session() parent_obj = parent_class("parent1") child_obj = child_class("child1") somea = A("somea") someb = B("someb") somec = C("somec") # print "APPENDING", parent.__class__.__name__ , "TO", # child.__class__.__name__ sess.add(parent_obj) parent_obj.collection.append(child_obj) if direction == ONETOMANY: child2 = child_class("child2") parent_obj.collection.append(child2) sess.add(child2) elif direction == MANYTOONE: parent2 = parent_class("parent2") parent2.collection.append(child_obj) sess.add(parent2) sess.add(somea) sess.add(someb) sess.add(somec) sess.flush() sess.expunge_all() # assert result via direct get() of parent object result = sess.query(parent_class).get(parent_obj.id) assert result.id == parent_obj.id assert result.collection[0].id == child_obj.id if direction == ONETOMANY: assert result.collection[1].id == child2.id elif direction == MANYTOONE: result2 = sess.query(parent_class).get(parent2.id) assert result2.id == parent2.id assert result2.collection[0].id == child_obj.id sess.expunge_all() # assert result via polymorphic load of parent object result = sess.query(A).filter_by(id=parent_obj.id).one() assert result.id == parent_obj.id assert result.collection[0].id == child_obj.id if direction == ONETOMANY: assert result.collection[1].id == child2.id elif direction == MANYTOONE: result2 = sess.query(A).filter_by(id=parent2.id).one() assert result2.id == parent2.id assert result2.collection[0].id == child_obj.id
def setup_mappers(cls): parent, child, direction = cls.parent, cls.child, cls.direction ta, tb, tc = cls.tables("a", "b", "c") parent_table = {"a": ta, "b": tb, "c": tc}[parent] child_table = {"a": ta, "b": tb, "c": tc}[child] remote_side = None if direction == MANYTOONE: foreign_keys = [parent_table.c.child_id] elif direction == ONETOMANY: foreign_keys = [child_table.c.parent_id] atob = ta.c.id == tb.c.id btoc = tc.c.id == tb.c.id if direction == ONETOMANY: relationshipjoin = parent_table.c.id == child_table.c.parent_id elif direction == MANYTOONE: relationshipjoin = parent_table.c.child_id == child_table.c.id if parent is child: remote_side = [child_table.c.id] abcjoin = polymorphic_union( { "a": ta.select().where(tb.c.id == None) # noqa .select_from(ta.outerjoin(tb, onclause=atob)).subquery(), "b": ta.join(tb, onclause=atob).outerjoin( tc, onclause=btoc).select().where( tc.c.id == None).reduce_columns().subquery(), # noqa "c": tc.join(tb, onclause=btoc).join(ta, onclause=atob), }, "type", "abcjoin", ) bcjoin = polymorphic_union( { "b": ta.join(tb, onclause=atob).outerjoin( tc, onclause=btoc).select().where( tc.c.id == None).reduce_columns().subquery(), # noqa "c": tc.join(tb, onclause=btoc).join(ta, onclause=atob), }, "type", "bcjoin", ) class A(cls.Comparable): def __init__(self, name): self.a_data = name class B(A): pass class C(B): pass cls.mapper_registry.map_imperatively( A, ta, polymorphic_on=abcjoin.c.type, with_polymorphic=("*", abcjoin), polymorphic_identity="a", ) cls.mapper_registry.map_imperatively( B, tb, polymorphic_on=bcjoin.c.type, with_polymorphic=("*", bcjoin), polymorphic_identity="b", inherits=A, inherit_condition=atob, ) cls.mapper_registry.map_imperatively( C, tc, polymorphic_identity="c", with_polymorphic=("*", tc.join(tb, btoc).join(ta, atob)), inherits=B, inherit_condition=btoc, ) parent_mapper = class_mapper({ta: A, tb: B, tc: C}[parent_table]) child_mapper = class_mapper({ta: A, tb: B, tc: C}[child_table]) parent_mapper.add_property( "collection", relationship( child_mapper, primaryjoin=relationshipjoin, foreign_keys=foreign_keys, order_by=child_mapper.c.id, remote_side=remote_side, uselist=True, ), )
def test_without_default_polymorphic(self): Employee, Engineer, Manager = self.classes( "Employee", "Engineer", "Manager" ) (Hacker,) = self.classes("Hacker") (employees_table,) = self.tables("employees") engineers_table, managers_table = self.tables("engineers", "managers") (hackers_table,) = self.tables("hackers") pjoin = polymorphic_union( { "employee": employees_table, "manager": managers_table, "engineer": engineers_table, "hacker": hackers_table, }, "type", "pjoin", ) pjoin2 = polymorphic_union( {"engineer": engineers_table, "hacker": hackers_table}, "type", "pjoin2", ) employee_mapper = self.mapper_registry.map_imperatively( Employee, employees_table, polymorphic_identity="employee" ) self.mapper_registry.map_imperatively( Manager, managers_table, inherits=employee_mapper, concrete=True, polymorphic_identity="manager", ) engineer_mapper = self.mapper_registry.map_imperatively( Engineer, engineers_table, inherits=employee_mapper, concrete=True, polymorphic_identity="engineer", ) self.mapper_registry.map_imperatively( Hacker, hackers_table, inherits=engineer_mapper, concrete=True, polymorphic_identity="hacker", ) session = fixture_session() jdoe = Employee("Jdoe") tom = Manager("Tom", "knows how to manage things") jerry = Engineer("Jerry", "knows how to program") hacker = Hacker("Kurt", "Badass", "knows how to hack") session.add_all((jdoe, tom, jerry, hacker)) session.flush() with expect_deprecated_20(with_polymorphic_dep): eq_( len( session.connection() .execute( session.query(Employee) .with_polymorphic("*", pjoin, pjoin.c.type) .statement ) .fetchall() ), 4, ) eq_(session.get(Employee, jdoe.employee_id), jdoe) eq_(session.get(Engineer, jerry.employee_id), jerry) with expect_deprecated_20(with_polymorphic_dep): eq_( set( [ repr(x) for x in session.query(Employee).with_polymorphic( "*", pjoin, pjoin.c.type ) ] ), set( [ "Employee Jdoe", "Engineer Jerry knows how to program", "Manager Tom knows how to manage things", "Hacker Kurt 'Badass' knows how to hack", ] ), ) eq_( set([repr(x) for x in session.query(Manager)]), set(["Manager Tom knows how to manage things"]), ) with expect_deprecated_20(with_polymorphic_dep): eq_( set( [ repr(x) for x in session.query(Engineer).with_polymorphic( "*", pjoin2, pjoin2.c.type ) ] ), set( [ "Engineer Jerry knows how to program", "Hacker Kurt 'Badass' knows how to hack", ] ), ) eq_( set([repr(x) for x in session.query(Hacker)]), set(["Hacker Kurt 'Badass' knows how to hack"]), ) # test adaption of the column by wrapping the query in a # subquery with testing.expect_deprecated( r"The Query.from_self\(\) method", with_polymorphic_dep ): eq_( len( session.connection() .execute( session.query(Engineer) .with_polymorphic("*", pjoin2, pjoin2.c.type) .from_self() .statement ) .fetchall() ), 2, ) with testing.expect_deprecated( r"The Query.from_self\(\) method", with_polymorphic_dep ): eq_( set( [ repr(x) for x in session.query(Engineer) .with_polymorphic("*", pjoin2, pjoin2.c.type) .from_self() ] ), set( [ "Engineer Jerry knows how to program", "Hacker Kurt 'Badass' knows how to hack", ] ), )
# just Collections that have additional data. # :C0103: Tables and mappers are constants but SQLAlchemy/TurboGears convention # is not to name them with all uppercase # pylint: disable-msg=C0103 CollectionTable = Table('collection', metadata, autoload=True) BranchTable = Table('branch', metadata, autoload=True) ReposTable = Table('repos', metadata, autoload=True) CollectionJoin = polymorphic_union ( {'b' : select((CollectionTable.join( BranchTable, CollectionTable.c.id == BranchTable.c.collectionid),)), 'c' : select((CollectionTable,), not_(CollectionTable.c.id.in_(select( (CollectionTable.c.id,), CollectionTable.c.id == BranchTable.c.collectionid) ))) }, 'kind', 'CollectionJoin' ) # # CollectionTable that shows number of packages in a collection # CollectionPackageTable = Table('collectionpackage', metadata, Column('id', Integer, primary_key=True), Column('statuscode', Integer, ForeignKey('collectionstatuscode.statuscodeid')), autoload=True) #
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 pjoin = polymorphic_union({ 'manager':managers_table, 'engineer':engineers_table }, 'type', 'pjoin') 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') session = sessionmaker(engine)() m1 = Manager("pointy haired boss", "manager1") e1 = Engineer("wally", "engineer1")
def initMappings(): a = sqlalchemy s = Schema def eventstampedMapper(class_, local_table, **kwargs): props = kwargs.setdefault('properties', {}) props['creationEvent'] = orm.relation(Event) props['eventId'] = local_table.c.event_id return orm.mapper(class_, local_table, **kwargs) orm.mapper(Event, s.event, properties={ 'eventId' : s.event.c.event_id, 'eventTimestamp' : s.event.c.event_timestamp, }) transactionMapper = eventstampedMapper( Transaction, s.statementItem, properties={ 'date' : s.statementItem.c.dtposted, 'amount' : s.statementItem.c.trnamt, }) isLikelyInvoiceable = a.exists([1], s.statementItem.c.memo.ilike(s.likelyInvoiceable.c.pattern)) \ .correlate(s.statementItem) \ .label('isLikelyInvoiceable') isInvoiceable = a.exists([1], s.statementItem.c.fitid == s.invoiceableItem.c.fitid) \ .label('isInvoiceable') isLikelyPayment = ((s.statementItem.c.trnamt > 0) & (s.statementItem.c.trnamt <= MAXIMUM_LIKELY_PAYMENT)) \ .label('isLikelyPayment') isPayment = a.exists([1], s.statementItem.c.fitid == s.paymentStatementEvidence.c.fitid) \ .label('isPayment') transactionListSelect = a.select([ s.statementItem, isLikelyInvoiceable, isInvoiceable, isLikelyPayment, isPayment, ]).alias('transactionSelect') global transactionListMapper transactionListMapper = orm.mapper(Transaction, transactionListSelect, properties={ 'date' : s.statementItem.c.dtposted, 'amount' : s.statementItem.c.trnamt, }, non_primary=True) eventstampedMapper(ImportedStatement, s.importedStatement, properties={ 'beginDate' : s.importedStatement.c.begin_date, 'endDate' : s.importedStatement.c.end_date, }) orm.mapper(Person, s.person, properties={ 'personId' : s.person.c.person_id, 'givenName' : s.person.c.given_name, 'familyName' : s.person.c.family_name, 'tenancies' : orm.relation(Tenancy, backref='person', cascade='all, delete-orphan'), 'payments' : orm.relation(Payment, backref='personFrom', cascade='all, delete-orphan'), 'invoices' : orm.relation(Invoice, backref='personTo', cascade='all, delete-orphan'), }) eventstampedMapper(Tenancy, s.personTenancy, properties={ 'tenancyId' : s.personTenancy.c.tenancy_id, 'personId' : s.personTenancy.c.person_id, 'dateMovedIn' : s.personTenancy.c.date_moved_in, 'dateMovedOut' : s.personTenancy.c.date_moved_out, }) paymentJoin = orm.polymorphic_union( { 'paymentWithStatementEvidence' : s.personPayment.join(s.paymentStatementEvidence), 'paymentWithOtherEvidence' : s.personPayment.join(s.paymentOtherEvidence), }, None, 'paymentjoin') paymentMapper = eventstampedMapper(Payment, s.personPayment, polymorphic_on=s.personPayment.c.evidence_type, properties={ 'paymentId' : s.personPayment.c.payment_id, 'personId' : s.personPayment.c.person_id, 'paymentDate' : s.personPayment.c.payment_date, 'evidenceType' : s.personPayment.c.evidence_type, }) orm.mapper(PaymentWithStatementEvidence, s.paymentStatementEvidence, inherits=paymentMapper, polymorphic_identity='statement', properties={ 'transaction' : orm.relation(Transaction) }) orm.mapper(PaymentWithOtherEvidence, s.paymentOtherEvidence, inherits=paymentMapper, polymorphic_identity='other') eventstampedMapper(InvoiceableItem, s.invoiceableItem, properties={ 'transaction' : orm.relation(Transaction), }) eventstampedMapper(Invoice, s.personInvoice, properties={ 'invoiceId' : s.personInvoice.c.invoice_id, 'personId' : s.personInvoice.c.person_id, 'invoiceDate' : s.personInvoice.c.invoice_date, 'amount' : s.personInvoice.c.amount, }) orm.mapper(LikelyInvoiceable, s.likelyInvoiceable) orm.compile_mappers()
productFilter=release.product, versionFilter=release.version, searchOtherShipped=True) if similar: # The release has been marked as shipped (this build or an other) # Store this information to disable the button to avoid two builds of # the same version marked as shipped release.ReleaseMarkedAsShipped = True return releases release_union = polymorphic_union( { 'firefox': FirefoxRelease.__table__, 'fennec': FennecRelease.__table__, 'devedition': DeveditionRelease.__table__, 'thunderbird': ThunderbirdRelease.__table__ }, 'product', 'release') class ProductReleasesView(object): view = release_union @classmethod def getOrderByList(cls, orderByDict): lst = [] for k, v in orderByDict.iteritems(): column = getattr(cls.view.c, k) direction = getattr(column, v) lst.append(direction())
# Search if we don't have a build (same version + product) already shipped similar = getReleases(shipped=True, productFilter=release.product, versionFilter=release.version, searchOtherShipped=True) if similar: # The release has been marked as shipped (this build or an other) # Store this information to disable the button to avoid two builds of # the same version marked as shipped release.ReleaseMarkedAsShipped = True return releases release_union = polymorphic_union({ 'firefox': FirefoxRelease.__table__, 'fennec': FennecRelease.__table__, 'devedition': DeveditionRelease.__table__, 'thunderbird': ThunderbirdRelease.__table__ }, 'product', 'release') class ProductReleasesView(object): view = release_union @classmethod def getOrderByList(cls, orderByDict): lst = [] for k, v in orderByDict.iteritems(): column = getattr(cls.view.c, k) direction = getattr(column, v) lst.append(direction())
def test_relationship(self): Employee, Engineer, Manager = self.classes( "Employee", "Engineer", "Manager" ) (Company,) = self.classes("Company") (companies,) = self.tables("companies") engineers_table, managers_table = self.tables("engineers", "managers") pjoin = polymorphic_union( {"manager": managers_table, "engineer": engineers_table}, "type", "pjoin", ) self.mapper_registry.map_imperatively( Company, companies, properties={"employees": relationship(Employee)}, ) employee_mapper = self.mapper_registry.map_imperatively( Employee, pjoin, polymorphic_on=pjoin.c.type ) self.mapper_registry.map_imperatively( Manager, managers_table, inherits=employee_mapper, concrete=True, polymorphic_identity="manager", ) self.mapper_registry.map_imperatively( Engineer, engineers_table, inherits=employee_mapper, concrete=True, polymorphic_identity="engineer", ) session = fixture_session() c = Company() c.employees.append(Manager("Sally", "knows how to manage things")) c.employees.append(Engineer("Karina", "knows how to hack")) session.add(c) session.flush() session.expunge_all() def go(): c2 = session.get(Company, c.id) assert set([repr(x) for x in c2.employees]) == set( [ "Engineer Karina knows how to hack", "Manager Sally knows how to manage things", ] ) self.assert_sql_count(testing.db, go, 2) session.expunge_all() def go(): c2 = session.get( Company, c.id, options=[joinedload(Company.employees)] ) assert set([repr(x) for x in c2.employees]) == set( [ "Engineer Karina knows how to hack", "Manager Sally knows how to manage things", ] ) self.assert_sql_count(testing.db, go, 1)
def two_pjoin_fixture(self): Employee, Engineer, Manager = self.classes( "Employee", "Engineer", "Manager" ) (Hacker,) = self.classes("Hacker") (employees_table,) = self.tables("employees") engineers_table, managers_table = self.tables("engineers", "managers") (hackers_table,) = self.tables("hackers") pjoin = polymorphic_union( { "employee": employees_table, "manager": managers_table, "engineer": engineers_table, "hacker": hackers_table, }, "type", "pjoin", ) pjoin2 = polymorphic_union( {"engineer": engineers_table, "hacker": hackers_table}, "type", "pjoin2", ) employee_mapper = self.mapper_registry.map_imperatively( Employee, employees_table, polymorphic_identity="employee" ) self.mapper_registry.map_imperatively( Manager, managers_table, inherits=employee_mapper, concrete=True, polymorphic_identity="manager", ) engineer_mapper = self.mapper_registry.map_imperatively( Engineer, engineers_table, inherits=employee_mapper, concrete=True, polymorphic_identity="engineer", ) self.mapper_registry.map_imperatively( Hacker, hackers_table, inherits=engineer_mapper, concrete=True, polymorphic_identity="hacker", ) session = fixture_session(expire_on_commit=False) jdoe = Employee("Jdoe") sally = Manager("Sally", "knows how to manage things") jenn = Engineer("Jenn", "knows how to program") hacker = Hacker("Karina", "Badass", "knows how to hack") session.add_all((jdoe, sally, jenn, hacker)) session.commit() return ( session, Employee, Engineer, Manager, Hacker, pjoin, pjoin2, jdoe, sally, jenn, hacker, )
def test_multi_level_with_base(self): Employee, Engineer, Manager = self.classes( "Employee", "Engineer", "Manager" ) employees_table, engineers_table, managers_table = self.tables( "employees", "engineers", "managers" ) (hackers_table,) = self.tables("hackers") (Hacker,) = self.classes("Hacker") pjoin = polymorphic_union( { "employee": employees_table, "manager": managers_table, "engineer": engineers_table, "hacker": hackers_table, }, "type", "pjoin", ) pjoin2 = polymorphic_union( {"engineer": engineers_table, "hacker": hackers_table}, "type", "pjoin2", ) employee_mapper = self.mapper_registry.map_imperatively( Employee, employees_table, with_polymorphic=("*", pjoin), polymorphic_on=pjoin.c.type, ) self.mapper_registry.map_imperatively( Manager, managers_table, inherits=employee_mapper, concrete=True, polymorphic_identity="manager", ) engineer_mapper = self.mapper_registry.map_imperatively( Engineer, engineers_table, with_polymorphic=("*", pjoin2), polymorphic_on=pjoin2.c.type, inherits=employee_mapper, concrete=True, polymorphic_identity="engineer", ) self.mapper_registry.map_imperatively( Hacker, hackers_table, inherits=engineer_mapper, concrete=True, polymorphic_identity="hacker", ) session = fixture_session() sally = Manager("Sally", "knows how to manage things") jenn = Engineer("Jenn", "knows how to program") hacker = Hacker("Karina", "Badass", "knows how to hack") session.add_all((sally, jenn, hacker)) session.flush() def go(): eq_(jenn.name, "Jenn") eq_(hacker.nickname, "Badass") self.assert_sql_count(testing.db, go, 0) session.expunge_all() # check that we aren't getting a cartesian product in the raw # SQL. this requires that Engineer's polymorphic discriminator # is not rendered in the statement which is only against # Employee's "pjoin" assert ( len( session.connection() .execute(session.query(Employee).statement) .fetchall() ) == 3 ) assert set([repr(x) for x in session.query(Employee)]) == set( [ "Engineer Jenn knows how to program", "Manager Sally knows how to manage things", "Hacker Karina 'Badass' knows how to hack", ] ) assert set([repr(x) for x in session.query(Manager)]) == set( ["Manager Sally knows how to manage things"] ) assert set([repr(x) for x in session.query(Engineer)]) == set( [ "Engineer Jenn knows how to program", "Hacker Karina 'Badass' knows how to hack", ] ) assert set([repr(x) for x in session.query(Hacker)]) == set( ["Hacker Karina 'Badass' knows how to hack"] )
def test_multi_level_no_base_w_hybrid(self): Employee, Engineer, Manager = self.classes( "Employee", "Engineer", "Manager" ) (Hacker,) = self.classes("Hacker") engineers_table, managers_table = self.tables("engineers", "managers") (hackers_table,) = self.tables("hackers") pjoin = polymorphic_union( { "manager": managers_table, "engineer": engineers_table, "hacker": hackers_table, }, "type", "pjoin", ) test_calls = mock.Mock() class ManagerWHybrid(Employee): def __init__(self, name, manager_data): self.name = name self.manager_data = manager_data @hybrid_property def engineer_info(self): test_calls.engineer_info_instance() return self.manager_data @engineer_info.expression def engineer_info(cls): test_calls.engineer_info_class() return cls.manager_data employee_mapper = self.mapper_registry.map_imperatively( Employee, pjoin, polymorphic_on=pjoin.c.type ) self.mapper_registry.map_imperatively( ManagerWHybrid, managers_table, inherits=employee_mapper, concrete=True, polymorphic_identity="manager", ) self.mapper_registry.map_imperatively( Engineer, engineers_table, inherits=employee_mapper, concrete=True, polymorphic_identity="engineer", ) session = fixture_session() sally = ManagerWHybrid("Sally", "mgrdata") # mapping did not impact the engineer_info # hybrid in any way eq_(test_calls.mock_calls, []) eq_(sally.engineer_info, "mgrdata") eq_(test_calls.mock_calls, [mock.call.engineer_info_instance()]) session.add(sally) session.commit() session.close() Sally = ( session.query(ManagerWHybrid) .filter(ManagerWHybrid.engineer_info == "mgrdata") .one() ) eq_( test_calls.mock_calls, [ mock.call.engineer_info_instance(), mock.call.engineer_info_class(), ], ) eq_(Sally.engineer_info, "mgrdata")
def test_multi_level_no_base(self): Employee, Engineer, Manager = self.classes( "Employee", "Engineer", "Manager" ) (Hacker,) = self.classes("Hacker") engineers_table, managers_table = self.tables("engineers", "managers") (hackers_table,) = self.tables("hackers") 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 = self.mapper_registry.map_imperatively( Employee, pjoin, polymorphic_on=pjoin.c.type ) self.mapper_registry.map_imperatively( Manager, managers_table, inherits=employee_mapper, concrete=True, polymorphic_identity="manager", ) engineer_mapper = self.mapper_registry.map_imperatively( Engineer, engineers_table, with_polymorphic=("*", pjoin2), polymorphic_on=pjoin2.c.type, inherits=employee_mapper, concrete=True, polymorphic_identity="engineer", ) self.mapper_registry.map_imperatively( Hacker, hackers_table, inherits=engineer_mapper, concrete=True, polymorphic_identity="hacker", ) session = fixture_session() sally = Manager("Sally", "knows how to manage things") assert_raises_message( AttributeError, "does not implement attribute .?'type' at the instance level.", setattr, sally, "type", "sometype", ) jenn = Engineer("Jenn", "knows how to program") hacker = Hacker("Karina", "Badass", "knows how to hack") assert_raises_message( AttributeError, "does not implement attribute .?'type' at the instance level.", setattr, hacker, "type", "sometype", ) session.add_all((sally, jenn, hacker)) session.flush() # ensure "readonly" on save logic didn't pollute the # expired_attributes collection assert ( "nickname" not in attributes.instance_state(jenn).expired_attributes ) assert "name" not in attributes.instance_state(jenn).expired_attributes assert ( "name" not in attributes.instance_state(hacker).expired_attributes ) assert ( "nickname" not in attributes.instance_state(hacker).expired_attributes ) def go(): eq_(jenn.name, "Jenn") eq_(hacker.nickname, "Badass") self.assert_sql_count(testing.db, go, 0) session.expunge_all() assert ( repr( session.query(Employee).filter(Employee.name == "Sally").one() ) == "Manager Sally knows how to manage things" ) assert ( repr(session.query(Manager).filter(Manager.name == "Sally").one()) == "Manager Sally knows how to manage things" ) assert set([repr(x) for x in session.query(Employee).all()]) == set( [ "Engineer Jenn knows how to program", "Manager Sally knows how to manage things", "Hacker Karina 'Badass' knows how to hack", ] ) assert set([repr(x) for x in session.query(Manager).all()]) == set( ["Manager Sally knows how to manage things"] ) assert set([repr(x) for x in session.query(Engineer).all()]) == set( [ "Engineer Jenn knows how to program", "Hacker Karina 'Badass' knows how to hack", ] ) assert set([repr(x) for x in session.query(Hacker).all()]) == set( ["Hacker Karina 'Badass' knows how to hack"] )
autoload=True) logJoin = polymorphic_union( { 'pkglog': select((LogTable.join(PackageLogTable, LogTable.c.id == PackageLogTable.c.logid), literal_column("'pkglog'").label('kind'))), 'pkglistlog': select((LogTable.join(PackageListingLogTable, LogTable.c.id == PackageListingLogTable.c.logid), literal_column("'pkglistlog'").label('kind'))), 'personpkglistacllog': select((LogTable.join( PersonPackageListingAclLogTable, LogTable.c.id == PersonPackageListingAclLogTable.c.logid), literal_column("'personpkglistacllog'").label('kind'))), 'grouppkglistacllog': select((LogTable.join( GroupPackageListingAclLogTable, LogTable.c.id == GroupPackageListingAclLogTable.c.logid), literal_column("'grouppkglistacllog'").label('kind'))), 'log': select((LogTable, literal_column("'log'").label('kind')), not_( LogTable.c.id.in_( select((LogTable.c.id, ), LogTable.c.id == PackageListingLogTable.c.logid)))) }, None) #
def setup_mapper(self): ''' Initializes and assign a mapper to the entity. At this point the mapper will usually have no property as they are added later. ''' if self.entity.mapper: return # for now we don't support the "abstract" parent class in a concrete # inheritance scenario as demonstrated in # sqlalchemy/test/orm/inheritance/concrete.py # this should be added along other kwargs = {} if self.order_by: kwargs['order_by'] = self.translate_order_by(self.order_by) if self.version_id_col: kwargs['version_id_col'] = self.get_column(self.version_id_col) if self.inheritance in ('single', 'concrete', 'multi'): if self.parent and \ (self.inheritance != 'concrete' or self.polymorphic): # non-polymorphic concrete doesn't need this kwargs['inherits'] = self.parent.mapper if self.inheritance == 'multi' and self.parent: kwargs['inherit_condition'] = self.join_condition if self.polymorphic: if self.children: if self.inheritance == 'concrete': keys = [(self.identity, self.entity.table)] keys.extend([(child._descriptor.identity, child.table) for child in self._get_children()]) # Having the same alias name for an entity and one of # its child (which is a parent itself) shouldn't cause # any problem because the join shouldn't be used at # the same time. But in reality, some versions of SA # do misbehave on this. Since it doesn't hurt to have # different names anyway, here they go. pjoin = polymorphic_union( dict(keys), self.polymorphic, 'pjoin_%s' % self.identity) kwargs['with_polymorphic'] = ('*', pjoin) kwargs['polymorphic_on'] = \ getattr(pjoin.c, self.polymorphic) elif not self.parent: kwargs['polymorphic_on'] = \ self.get_column(self.polymorphic) if self.children or self.parent: kwargs['polymorphic_identity'] = self.identity if self.parent and self.inheritance == 'concrete': kwargs['concrete'] = True if self.parent and self.inheritance == 'single': args = [] else: args = [self.entity.table] # let user-defined kwargs override Elixir-generated ones, though that's # not very usefull since most of them expect Column instances. kwargs.update(self.mapper_options) #TODO: document this! if 'primary_key' in kwargs: cols = self.entity.table.c kwargs['primary_key'] = [getattr(cols, colname) for colname in kwargs['primary_key']] # do the mapping if self.session is None: self.entity.mapper = mapper(self.entity, *args, **kwargs) elif isinstance(self.session, ScopedSession): session_mapper = session_mapper_factory(self.session) self.entity.mapper = session_mapper(self.entity, *args, **kwargs) else: raise Exception("Failed to map entity '%s' with its table or " "selectable. You can only bind an Entity to a " "ScopedSession object or None for manual session " "management." % self.entity.__name__)
def test_multi_level_no_base_w_hybrid(self): pjoin = polymorphic_union( { "manager": managers_table, "engineer": engineers_table, "hacker": hackers_table, }, "type", "pjoin", ) test_calls = mock.Mock() class ManagerWHybrid(Employee): def __init__(self, name, manager_data): self.name = name self.manager_data = manager_data @hybrid_property def engineer_info(self): test_calls.engineer_info_instance() return self.manager_data @engineer_info.expression def engineer_info(cls): test_calls.engineer_info_class() return cls.manager_data employee_mapper = mapper(Employee, pjoin, polymorphic_on=pjoin.c.type) mapper( ManagerWHybrid, managers_table, inherits=employee_mapper, concrete=True, polymorphic_identity="manager", ) mapper( Engineer, engineers_table, inherits=employee_mapper, concrete=True, polymorphic_identity="engineer", ) session = create_session() tom = ManagerWHybrid("Tom", "mgrdata") # mapping did not impact the engineer_info # hybrid in any way eq_(test_calls.mock_calls, []) eq_(tom.engineer_info, "mgrdata") eq_(test_calls.mock_calls, [mock.call.engineer_info_instance()]) session.add(tom) session.flush() session.close() tom = ( session.query(ManagerWHybrid) .filter(ManagerWHybrid.engineer_info == "mgrdata") .one() ) eq_( test_calls.mock_calls, [ mock.call.engineer_info_instance(), mock.call.engineer_info_class(), ], ) eq_(tom.engineer_info, "mgrdata")
def test_roundtrip(self): if with_polymorphic == "unions": if include_base: person_join = polymorphic_union( { "engineer": people.join(engineers), "manager": people.join(managers), "person": people.select(people.c.type == "person").subquery(), }, None, "pjoin", ) else: person_join = polymorphic_union( { "engineer": people.join(engineers), "manager": people.join(managers), }, None, "pjoin", ) manager_join = people.join(managers).outerjoin(boss) person_with_polymorphic = ["*", person_join] manager_with_polymorphic = ["*", manager_join] elif with_polymorphic == "joins": person_join = (people.outerjoin(engineers).outerjoin( managers).outerjoin(boss)) manager_join = people.join(managers).outerjoin(boss) person_with_polymorphic = ["*", person_join] manager_with_polymorphic = ["*", manager_join] elif with_polymorphic == "auto": person_with_polymorphic = "*" manager_with_polymorphic = "*" else: person_with_polymorphic = None manager_with_polymorphic = None if redefine_colprop: person_mapper = mapper( Person, people, with_polymorphic=person_with_polymorphic, polymorphic_on=people.c.type, polymorphic_identity="person", properties={"person_name": people.c.name}, ) else: person_mapper = mapper( Person, people, with_polymorphic=person_with_polymorphic, polymorphic_on=people.c.type, polymorphic_identity="person", ) mapper( Engineer, engineers, inherits=person_mapper, polymorphic_identity="engineer", ) mapper( Manager, managers, inherits=person_mapper, with_polymorphic=manager_with_polymorphic, polymorphic_identity="manager", ) mapper(Boss, boss, inherits=Manager, polymorphic_identity="boss") mapper( Company, companies, properties={ "employees": relationship( Person, lazy=lazy_relationship, cascade="all, delete-orphan", backref="company", order_by=people.c.person_id, ) }, ) if redefine_colprop: person_attribute_name = "person_name" else: person_attribute_name = "name" employees = [ Manager(status="AAB", manager_name="manager1", **{person_attribute_name: "pointy haired boss"}), Engineer(status="BBA", engineer_name="engineer1", primary_language="java", **{person_attribute_name: "dilbert"}), ] if include_base: employees.append(Person(**{person_attribute_name: "joesmith"})) employees += [ Engineer(status="CGG", engineer_name="engineer2", primary_language="python", **{person_attribute_name: "wally"}), Manager(status="ABA", manager_name="manager2", **{person_attribute_name: "jsmith"}), ] pointy = employees[0] jsmith = employees[-1] dilbert = employees[1] session = create_session() c = Company(name="company1") c.employees = employees session.add(c) session.flush() session.expunge_all() eq_(session.query(Person).get(dilbert.person_id), dilbert) session.expunge_all() eq_( session.query(Person).filter( Person.person_id == dilbert.person_id).one(), dilbert, ) session.expunge_all() def go(): cc = session.query(Company).get(c.company_id) eq_(cc.employees, employees) if not lazy_relationship: if with_polymorphic != "none": self.assert_sql_count(testing.db, go, 1) else: self.assert_sql_count(testing.db, go, 5) else: if with_polymorphic != "none": self.assert_sql_count(testing.db, go, 2) else: self.assert_sql_count(testing.db, go, 6) # test selecting from the query, using the base # mapped table (people) as the selection criterion. # in the case of the polymorphic Person query, # the "people" selectable should be adapted to be "person_join" eq_( session.query(Person).filter( getattr(Person, person_attribute_name) == "dilbert").first(), dilbert, ) assert (session.query(Person).filter( getattr(Person, person_attribute_name) == "dilbert").first().person_id) eq_( session.query(Engineer).filter( getattr(Person, person_attribute_name) == "dilbert").first(), dilbert, ) # test selecting from the query, joining against # an alias of the base "people" table. test that # the "palias" alias does *not* get sucked up # into the "person_join" conversion. palias = people.alias("palias") dilbert = session.query(Person).get(dilbert.person_id) is_( dilbert, session.query(Person).filter( (palias.c.name == "dilbert") & (palias.c.person_id == Person.person_id)).first(), ) is_( dilbert, session.query(Engineer).filter( (palias.c.name == "dilbert") & (palias.c.person_id == Person.person_id)).first(), ) is_( dilbert, session.query(Person).filter( (Engineer.engineer_name == "engineer1") & (engineers.c.person_id == people.c.person_id)).first(), ) is_( dilbert, session.query(Engineer).filter( Engineer.engineer_name == "engineer1")[0], ) session.flush() session.expunge_all() def go(): session.query(Person).filter( getattr(Person, person_attribute_name) == "dilbert").first() self.assert_sql_count(testing.db, go, 1) session.expunge_all() dilbert = (session.query(Person).filter( getattr(Person, person_attribute_name) == "dilbert").first()) def go(): # assert that only primary table is queried for # already-present-in-session d = (session.query(Person).filter( getattr(Person, person_attribute_name) == "dilbert").first()) self.assert_sql_count(testing.db, go, 1) # test standalone orphans daboss = Boss(status="BBB", manager_name="boss", golf_swing="fore", **{person_attribute_name: "daboss"}) session.add(daboss) assert_raises(sa_exc.DBAPIError, session.flush) c = session.query(Company).first() daboss.company = c manager_list = [e for e in c.employees if isinstance(e, Manager)] session.flush() session.expunge_all() eq_( session.query(Manager).order_by(Manager.person_id).all(), manager_list, ) c = session.query(Company).first() session.delete(c) session.flush() eq_(select([func.count("*")]).select_from(people).scalar(), 0)
def test_without_default_polymorphic(self): pjoin = polymorphic_union( { "employee": employees_table, "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, employees_table, polymorphic_identity="employee" ) 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() jdoe = Employee("Jdoe") tom = Manager("Tom", "knows how to manage things") jerry = Engineer("Jerry", "knows how to program") hacker = Hacker("Kurt", "Badass", "knows how to hack") session.add_all((jdoe, tom, jerry, hacker)) session.flush() eq_( len( testing.db.execute( session.query(Employee) .with_polymorphic("*", pjoin, pjoin.c.type) .with_labels() .statement ).fetchall() ), 4, ) eq_(session.query(Employee).get(jdoe.employee_id), jdoe) eq_(session.query(Engineer).get(jerry.employee_id), jerry) eq_( set( [ repr(x) for x in session.query(Employee).with_polymorphic( "*", pjoin, pjoin.c.type ) ] ), set( [ "Employee Jdoe", "Engineer Jerry knows how to program", "Manager Tom knows how to manage things", "Hacker Kurt 'Badass' knows how to hack", ] ), ) eq_( set([repr(x) for x in session.query(Manager)]), set(["Manager Tom knows how to manage things"]), ) eq_( set( [ repr(x) for x in session.query(Engineer).with_polymorphic( "*", pjoin2, pjoin2.c.type ) ] ), set( [ "Engineer Jerry knows how to program", "Hacker Kurt 'Badass' knows how to hack", ] ), ) eq_( set([repr(x) for x in session.query(Hacker)]), set(["Hacker Kurt 'Badass' knows how to hack"]), ) # test adaption of the column by wrapping the query in a # subquery eq_( len( testing.db.execute( session.query(Engineer) .with_polymorphic("*", pjoin2, pjoin2.c.type) .from_self() .statement ).fetchall() ), 2, ) eq_( set( [ repr(x) for x in session.query(Engineer) .with_polymorphic("*", pjoin2, pjoin2.c.type) .from_self() ] ), set( [ "Engineer Jerry knows how to program", "Hacker Kurt 'Badass' knows how to hack", ] ), )
logJoin = polymorphic_union( { "pkglog": select( ( LogTable.join(PackageLogTable, LogTable.c.id == PackageLogTable.c.logid), literal_column("'pkglog'").label("kind"), ) ), "pkglistlog": select( ( LogTable.join(PackageListingLogTable, LogTable.c.id == PackageListingLogTable.c.logid), literal_column("'pkglistlog'").label("kind"), ) ), "personpkglistacllog": select( ( LogTable.join( PersonPackageListingAclLogTable, LogTable.c.id == PersonPackageListingAclLogTable.c.logid ), literal_column("'personpkglistacllog'").label("kind"), ) ), "grouppkglistacllog": select( ( LogTable.join(GroupPackageListingAclLogTable, LogTable.c.id == GroupPackageListingAclLogTable.c.logid), literal_column("'grouppkglistacllog'").label("kind"), ) ), "log": select( (LogTable, literal_column("'log'").label("kind")), not_(LogTable.c.id.in_(select((LogTable.c.id,), LogTable.c.id == PackageListingLogTable.c.logid))), ), }, None, )
def test_polymorphic_backref(self): """test multiple backrefs to the same polymorphically-loading attribute.""" A, C, B, c_table, b_table, a_table, Dest, dest_table = ( self.classes.A, self.classes.C, self.classes.B, self.tables.c_table, self.tables.b_table, self.tables.a_table, self.classes.Dest, self.tables.dest_table, ) ajoin = polymorphic_union( {"a": a_table, "b": b_table, "c": c_table}, "type", "ajoin" ) mapper( A, a_table, with_polymorphic=("*", ajoin), polymorphic_on=ajoin.c.type, polymorphic_identity="a", properties={ "some_dest": relationship(Dest, back_populates="many_a") }, ) mapper( B, b_table, inherits=A, concrete=True, polymorphic_identity="b", properties={ "some_dest": relationship(Dest, back_populates="many_a") }, ) mapper( C, c_table, inherits=A, concrete=True, polymorphic_identity="c", properties={ "some_dest": relationship(Dest, back_populates="many_a") }, ) mapper( Dest, dest_table, properties={ "many_a": relationship( A, back_populates="some_dest", order_by=ajoin.c.id ) }, ) sess = sessionmaker()() dest1 = Dest(name="c1") dest2 = Dest(name="c2") a1 = A(some_dest=dest1, aname="a1", id=1) a2 = A(some_dest=dest2, aname="a2", id=2) b1 = B(some_dest=dest1, bname="b1", id=3) b2 = B(some_dest=dest1, bname="b2", id=4) c1 = C(some_dest=dest1, cname="c1", id=5) c2 = C(some_dest=dest2, cname="c2", id=6) eq_([a2, c2], dest2.many_a) eq_([a1, b1, b2, c1], dest1.many_a) sess.add_all([dest1, dest2]) sess.commit() assert sess.query(Dest).filter(Dest.many_a.contains(a2)).one() is dest2 assert sess.query(Dest).filter(Dest.many_a.contains(b1)).one() is dest1 assert sess.query(Dest).filter(Dest.many_a.contains(c2)).one() is dest2 eq_(dest2.many_a, [a2, c2]) eq_(dest1.many_a, [a1, b1, b2, c1]) sess.expire_all() def go(): eq_( [ Dest( many_a=[ A(aname="a1"), B(bname="b1"), B(bname="b2"), C(cname="c1"), ] ), Dest(many_a=[A(aname="a2"), C(cname="c2")]), ], sess.query(Dest) .options(joinedload(Dest.many_a)) .order_by(Dest.id) .all(), ) self.assert_sql_count(testing.db, go, 1)
def _setup_mapping(self, use_unions, use_joins): ( Publication, Issue, Location, LocationName, PageSize, Magazine, Page, MagazinePage, ClassifiedPage, ) = self.classes( "Publication", "Issue", "Location", "LocationName", "PageSize", "Magazine", "Page", "MagazinePage", "ClassifiedPage", ) mapper(Publication, self.tables.publication) mapper( Issue, self.tables.issue, properties={ "publication": relationship( Publication, backref=backref("issues", cascade="all, delete-orphan"), ) }, ) mapper(LocationName, self.tables.location_name) mapper( Location, self.tables.location, properties={ "issue": relationship( Issue, backref=backref( "locations", lazy="joined", cascade="all, delete-orphan", ), ), "name": relationship(LocationName), }, ) mapper(PageSize, self.tables.page_size) mapper( Magazine, self.tables.magazine, properties={ "location": relationship(Location, backref=backref("magazine", uselist=False)), "size": relationship(PageSize), }, ) if use_unions: page_join = polymorphic_union( { "m": self.tables.page.join(self.tables.magazine_page), "c": self.tables.page.join(self.tables.magazine_page).join( self.tables.classified_page), "p": self.tables.page.select().where( self.tables.page.c.type == "p").subquery(), }, None, "page_join", ) page_mapper = mapper( Page, self.tables.page, with_polymorphic=("*", page_join), polymorphic_on=page_join.c.type, polymorphic_identity="p", ) elif use_joins: page_join = self.tables.page.outerjoin( self.tables.magazine_page).outerjoin( self.tables.classified_page) page_mapper = mapper( Page, self.tables.page, with_polymorphic=("*", page_join), polymorphic_on=self.tables.page.c.type, polymorphic_identity="p", ) else: page_mapper = mapper( Page, self.tables.page, polymorphic_on=self.tables.page.c.type, polymorphic_identity="p", ) if use_unions: magazine_join = polymorphic_union( { "m": self.tables.page.join(self.tables.magazine_page), "c": self.tables.page.join(self.tables.magazine_page).join( self.tables.classified_page), }, None, "page_join", ) magazine_page_mapper = mapper( MagazinePage, self.tables.magazine_page, with_polymorphic=("*", magazine_join), inherits=page_mapper, polymorphic_identity="m", properties={ "magazine": relationship( Magazine, backref=backref("pages", order_by=magazine_join.c.page_no), ) }, ) elif use_joins: magazine_join = self.tables.page.join( self.tables.magazine_page).outerjoin( self.tables.classified_page) magazine_page_mapper = mapper( MagazinePage, self.tables.magazine_page, with_polymorphic=("*", magazine_join), inherits=page_mapper, polymorphic_identity="m", properties={ "magazine": relationship( Magazine, backref=backref("pages", order_by=self.tables.page.c.page_no), ) }, ) else: magazine_page_mapper = mapper( MagazinePage, self.tables.magazine_page, inherits=page_mapper, polymorphic_identity="m", properties={ "magazine": relationship( Magazine, backref=backref("pages", order_by=self.tables.page.c.page_no), ) }, ) mapper( ClassifiedPage, self.tables.classified_page, inherits=magazine_page_mapper, polymorphic_identity="c", primary_key=[self.tables.page.c.id], )
def test_roundtrip(self): publication_mapper = mapper(Publication, self.tables.publication) issue_mapper = mapper( Issue, self.tables.issue, properties={ "publication": relationship( Publication, backref=backref("issues", cascade="all, delete-orphan"), ) }, ) location_name_mapper = mapper(LocationName, self.tables.location_name) location_mapper = mapper( Location, self.tables.location, properties={ "issue": relationship( Issue, backref=backref( "locations", lazy="joined", cascade="all, delete-orphan", ), ), "_name": relationship(LocationName), }, ) page_size_mapper = mapper(PageSize, self.tables.page_size) magazine_mapper = mapper( Magazine, self.tables.magazine, properties={ "location": relationship( Location, backref=backref("magazine", uselist=False) ), "size": relationship(PageSize), }, ) if use_unions: page_join = polymorphic_union( { "m": self.tables.page.join(self.tables.magazine_page), "c": self.tables.page.join(self.tables.magazine_page).join( self.tables.classified_page ), "p": self.tables.page.select( self.tables.page.c.type == "p" ).subquery(), }, None, "page_join", ) page_mapper = mapper( Page, self.tables.page, with_polymorphic=("*", page_join), polymorphic_on=page_join.c.type, polymorphic_identity="p", ) elif use_joins: page_join = self.tables.page.outerjoin( self.tables.magazine_page ).outerjoin(self.tables.classified_page) page_mapper = mapper( Page, self.tables.page, with_polymorphic=("*", page_join), polymorphic_on=self.tables.page.c.type, polymorphic_identity="p", ) else: page_mapper = mapper( Page, self.tables.page, polymorphic_on=self.tables.page.c.type, polymorphic_identity="p", ) if use_unions: magazine_join = polymorphic_union( { "m": self.tables.page.join(self.tables.magazine_page), "c": self.tables.page.join(self.tables.magazine_page).join( self.tables.classified_page ), }, None, "page_join", ) magazine_page_mapper = mapper( MagazinePage, self.tables.magazine_page, with_polymorphic=("*", magazine_join), inherits=page_mapper, polymorphic_identity="m", properties={ "magazine": relationship( Magazine, backref=backref( "pages", order_by=magazine_join.c.page_no ), ) }, ) elif use_joins: magazine_join = self.tables.page.join( self.tables.magazine_page ).outerjoin(self.tables.classified_page) magazine_page_mapper = mapper( MagazinePage, self.tables.magazine_page, with_polymorphic=("*", magazine_join), inherits=page_mapper, polymorphic_identity="m", properties={ "magazine": relationship( Magazine, backref=backref( "pages", order_by=self.tables.page.c.page_no ), ) }, ) else: magazine_page_mapper = mapper( MagazinePage, self.tables.magazine_page, inherits=page_mapper, polymorphic_identity="m", properties={ "magazine": relationship( Magazine, backref=backref( "pages", order_by=self.tables.page.c.page_no ), ) }, ) classified_page_mapper = mapper( ClassifiedPage, self.tables.classified_page, inherits=magazine_page_mapper, polymorphic_identity="c", primary_key=[self.tables.page.c.id], ) session = create_session() pub = Publication(name="Test") issue = Issue(issue=46, publication=pub) location = Location(ref="ABC", name="London", issue=issue) page_size = PageSize(name="A4", width=210, height=297) magazine = Magazine(location=location, size=page_size) page = ClassifiedPage(magazine=magazine, page_no=1) page2 = MagazinePage(magazine=magazine, page_no=2) page3 = ClassifiedPage(magazine=magazine, page_no=3) session.add(pub) session.flush() print([x for x in session]) session.expunge_all() session.flush() session.expunge_all() p = session.query(Publication).filter(Publication.name == "Test").one() print(p.issues[0].locations[0].magazine.pages) print([page, page2, page3]) assert repr(p.issues[0].locations[0].magazine.pages) == repr( [page, page2, page3] ), repr(p.issues[0].locations[0].magazine.pages)
def test_multi_level_no_base(self): 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, with_polymorphic=("*", 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() tom = Manager("Tom", "knows how to manage things") assert_raises_message( AttributeError, "does not implement attribute .?'type' at the instance level.", setattr, tom, "type", "sometype", ) jerry = Engineer("Jerry", "knows how to program") hacker = Hacker("Kurt", "Badass", "knows how to hack") assert_raises_message( AttributeError, "does not implement attribute .?'type' at the instance level.", setattr, hacker, "type", "sometype", ) session.add_all((tom, jerry, hacker)) session.flush() # ensure "readonly" on save logic didn't pollute the # expired_attributes collection assert ( "nickname" not in attributes.instance_state(jerry).expired_attributes ) assert ( "name" not in attributes.instance_state(jerry).expired_attributes ) assert ( "name" not in attributes.instance_state(hacker).expired_attributes ) assert ( "nickname" not in attributes.instance_state(hacker).expired_attributes ) def go(): eq_(jerry.name, "Jerry") eq_(hacker.nickname, "Badass") self.assert_sql_count(testing.db, go, 0) session.expunge_all() assert ( repr(session.query(Employee).filter(Employee.name == "Tom").one()) == "Manager Tom knows how to manage things" ) assert ( repr(session.query(Manager).filter(Manager.name == "Tom").one()) == "Manager Tom knows how to manage things" ) 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", ] ) assert set([repr(x) for x in session.query(Hacker).all()]) == set( ["Hacker Kurt 'Badass' knows how to hack"] )
def test_roundtrip(self): parent_table = {"a": ta, "b": tb, "c": tc}[parent] child_table = {"a": ta, "b": tb, "c": tc}[child] remote_side = None if direction == MANYTOONE: foreign_keys = [parent_table.c.child_id] elif direction == ONETOMANY: foreign_keys = [child_table.c.parent_id] atob = ta.c.id == tb.c.id btoc = tc.c.id == tb.c.id if direction == ONETOMANY: relationshipjoin = parent_table.c.id == child_table.c.parent_id elif direction == MANYTOONE: relationshipjoin = parent_table.c.child_id == child_table.c.id if parent is child: remote_side = [child_table.c.id] abcjoin = polymorphic_union( { "a": ta.select( tb.c.id == None, # noqa from_obj=[ta.outerjoin(tb, onclause=atob)], ), "b": ta.join(tb, onclause=atob) .outerjoin(tc, onclause=btoc) .select(tc.c.id == None) .reduce_columns(), # noqa "c": tc.join(tb, onclause=btoc).join(ta, onclause=atob), }, "type", "abcjoin", ) bcjoin = polymorphic_union( { "b": ta.join(tb, onclause=atob) .outerjoin(tc, onclause=btoc) .select(tc.c.id == None) .reduce_columns(), # noqa "c": tc.join(tb, onclause=btoc).join(ta, onclause=atob), }, "type", "bcjoin", ) class A(object): def __init__(self, name): self.a_data = name class B(A): pass class C(B): pass mapper( A, ta, polymorphic_on=abcjoin.c.type, with_polymorphic=("*", abcjoin), polymorphic_identity="a", ) mapper( B, tb, polymorphic_on=bcjoin.c.type, with_polymorphic=("*", bcjoin), polymorphic_identity="b", inherits=A, inherit_condition=atob, ) mapper( C, tc, polymorphic_identity="c", inherits=B, inherit_condition=btoc, ) parent_mapper = class_mapper({ta: A, tb: B, tc: C}[parent_table]) child_mapper = class_mapper({ta: A, tb: B, tc: C}[child_table]) parent_class = parent_mapper.class_ child_class = child_mapper.class_ parent_mapper.add_property( "collection", relationship( child_mapper, primaryjoin=relationshipjoin, foreign_keys=foreign_keys, order_by=child_mapper.c.id, remote_side=remote_side, uselist=True, ), ) sess = create_session() parent_obj = parent_class("parent1") child_obj = child_class("child1") somea = A("somea") someb = B("someb") somec = C("somec") # print "APPENDING", parent.__class__.__name__ , "TO", # child.__class__.__name__ sess.add(parent_obj) parent_obj.collection.append(child_obj) if direction == ONETOMANY: child2 = child_class("child2") parent_obj.collection.append(child2) sess.add(child2) elif direction == MANYTOONE: parent2 = parent_class("parent2") parent2.collection.append(child_obj) sess.add(parent2) sess.add(somea) sess.add(someb) sess.add(somec) sess.flush() sess.expunge_all() # assert result via direct get() of parent object result = sess.query(parent_class).get(parent_obj.id) assert result.id == parent_obj.id assert result.collection[0].id == child_obj.id if direction == ONETOMANY: assert result.collection[1].id == child2.id elif direction == MANYTOONE: result2 = sess.query(parent_class).get(parent2.id) assert result2.id == parent2.id assert result2.collection[0].id == child_obj.id sess.expunge_all() # assert result via polymorphic load of parent object result = sess.query(A).filter_by(id=parent_obj.id).one() assert result.id == parent_obj.id assert result.collection[0].id == child_obj.id if direction == ONETOMANY: assert result.collection[1].id == child2.id elif direction == MANYTOONE: result2 = sess.query(A).filter_by(id=parent2.id).one() assert result2.id == parent2.id assert result2.collection[0].id == child_obj.id
def test_multi_level_with_base(self): pjoin = polymorphic_union( { "employee": employees_table, "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, employees_table, with_polymorphic=("*", 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, with_polymorphic=("*", 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() tom = Manager("Tom", "knows how to manage things") jerry = Engineer("Jerry", "knows how to program") hacker = Hacker("Kurt", "Badass", "knows how to hack") session.add_all((tom, jerry, hacker)) session.flush() def go(): eq_(jerry.name, "Jerry") eq_(hacker.nickname, "Badass") self.assert_sql_count(testing.db, go, 0) session.expunge_all() # check that we aren't getting a cartesian product in the raw # SQL. this requires that Engineer's polymorphic discriminator # is not rendered in the statement which is only against # Employee's "pjoin" assert ( len( testing.db.execute( session.query(Employee).with_labels().statement ).fetchall() ) == 3 ) assert set([repr(x) for x in session.query(Employee)]) == 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)]) == set( ["Manager Tom knows how to manage things"] ) assert set([repr(x) for x in session.query(Engineer)]) == set( [ "Engineer Jerry knows how to program", "Hacker Kurt 'Badass' knows how to hack", ] ) assert set([repr(x) for x in session.query(Hacker)]) == set( ["Hacker Kurt 'Badass' knows how to hack"] )
def test_insert_order(self): """test that classes of multiple types mix up mapper inserts so that insert order of individual tables is maintained""" person_join = polymorphic_union( { "engineer": people.join(engineers), "manager": people.join(managers), "person": people.select(people.c.type == "person"), }, None, "pjoin", ) person_mapper = mapper( Person, people, with_polymorphic=("*", person_join), polymorphic_on=person_join.c.type, polymorphic_identity="person", ) mapper( Engineer, engineers, inherits=person_mapper, polymorphic_identity="engineer", ) mapper( Manager, managers, inherits=person_mapper, polymorphic_identity="manager", ) mapper( Company, companies, properties={ "employees": relationship( Person, backref="company", order_by=person_join.c.person_id ) }, ) session = create_session() c = Company(name="company1") c.employees.append( Manager( status="AAB", manager_name="manager1", name="pointy haired boss", ) ) c.employees.append( Engineer( status="BBA", engineer_name="engineer1", primary_language="java", name="dilbert", ) ) c.employees.append(Person(status="HHH", name="joesmith")) c.employees.append( Engineer( status="CGG", engineer_name="engineer2", primary_language="python", name="wally", ) ) c.employees.append( Manager(status="ABA", manager_name="manager2", name="jsmith") ) session.add(c) session.flush() session.expunge_all() eq_(session.query(Company).get(c.company_id), c)
def test_roundtrip(self): if with_polymorphic == "unions": if include_base: person_join = polymorphic_union( { "engineer": people.join(engineers), "manager": people.join(managers), "person": people.select(people.c.type == "person"), }, None, "pjoin", ) else: person_join = polymorphic_union( { "engineer": people.join(engineers), "manager": people.join(managers), }, None, "pjoin", ) manager_join = people.join(managers).outerjoin(boss) person_with_polymorphic = ["*", person_join] manager_with_polymorphic = ["*", manager_join] elif with_polymorphic == "joins": person_join = ( people.outerjoin(engineers).outerjoin(managers).outerjoin(boss) ) manager_join = people.join(managers).outerjoin(boss) person_with_polymorphic = ["*", person_join] manager_with_polymorphic = ["*", manager_join] elif with_polymorphic == "auto": person_with_polymorphic = "*" manager_with_polymorphic = "*" else: person_with_polymorphic = None manager_with_polymorphic = None if redefine_colprop: person_mapper = mapper( Person, people, with_polymorphic=person_with_polymorphic, polymorphic_on=people.c.type, polymorphic_identity="person", properties={"person_name": people.c.name}, ) else: person_mapper = mapper( Person, people, with_polymorphic=person_with_polymorphic, polymorphic_on=people.c.type, polymorphic_identity="person", ) mapper( Engineer, engineers, inherits=person_mapper, polymorphic_identity="engineer", ) mapper( Manager, managers, inherits=person_mapper, with_polymorphic=manager_with_polymorphic, polymorphic_identity="manager", ) mapper(Boss, boss, inherits=Manager, polymorphic_identity="boss") mapper( Company, companies, properties={ "employees": relationship( Person, lazy=lazy_relationship, cascade="all, delete-orphan", backref="company", order_by=people.c.person_id, ) }, ) if redefine_colprop: person_attribute_name = "person_name" else: person_attribute_name = "name" employees = [ Manager( status="AAB", manager_name="manager1", **{person_attribute_name: "pointy haired boss"} ), Engineer( status="BBA", engineer_name="engineer1", primary_language="java", **{person_attribute_name: "dilbert"} ), ] if include_base: employees.append(Person(**{person_attribute_name: "joesmith"})) employees += [ Engineer( status="CGG", engineer_name="engineer2", primary_language="python", **{person_attribute_name: "wally"} ), Manager( status="ABA", manager_name="manager2", **{person_attribute_name: "jsmith"} ), ] pointy = employees[0] jsmith = employees[-1] dilbert = employees[1] session = create_session() c = Company(name="company1") c.employees = employees session.add(c) session.flush() session.expunge_all() eq_(session.query(Person).get(dilbert.person_id), dilbert) session.expunge_all() eq_( session.query(Person) .filter(Person.person_id == dilbert.person_id) .one(), dilbert, ) session.expunge_all() def go(): cc = session.query(Company).get(c.company_id) eq_(cc.employees, employees) if not lazy_relationship: if with_polymorphic != "none": self.assert_sql_count(testing.db, go, 1) else: self.assert_sql_count(testing.db, go, 5) else: if with_polymorphic != "none": self.assert_sql_count(testing.db, go, 2) else: self.assert_sql_count(testing.db, go, 6) # test selecting from the query, using the base # mapped table (people) as the selection criterion. # in the case of the polymorphic Person query, # the "people" selectable should be adapted to be "person_join" eq_( session.query(Person) .filter(getattr(Person, person_attribute_name) == "dilbert") .first(), dilbert, ) assert ( session.query(Person) .filter(getattr(Person, person_attribute_name) == "dilbert") .first() .person_id ) eq_( session.query(Engineer) .filter(getattr(Person, person_attribute_name) == "dilbert") .first(), dilbert, ) # test selecting from the query, joining against # an alias of the base "people" table. test that # the "palias" alias does *not* get sucked up # into the "person_join" conversion. palias = people.alias("palias") dilbert = session.query(Person).get(dilbert.person_id) is_( dilbert, session.query(Person) .filter( (palias.c.name == "dilbert") & (palias.c.person_id == Person.person_id) ) .first(), ) is_( dilbert, session.query(Engineer) .filter( (palias.c.name == "dilbert") & (palias.c.person_id == Person.person_id) ) .first(), ) is_( dilbert, session.query(Person) .filter( (Engineer.engineer_name == "engineer1") & (engineers.c.person_id == people.c.person_id) ) .first(), ) is_( dilbert, session.query(Engineer).filter( Engineer.engineer_name == "engineer1" )[0], ) session.flush() session.expunge_all() def go(): session.query(Person).filter( getattr(Person, person_attribute_name) == "dilbert" ).first() self.assert_sql_count(testing.db, go, 1) session.expunge_all() dilbert = ( session.query(Person) .filter(getattr(Person, person_attribute_name) == "dilbert") .first() ) def go(): # assert that only primary table is queried for # already-present-in-session d = ( session.query(Person) .filter(getattr(Person, person_attribute_name) == "dilbert") .first() ) self.assert_sql_count(testing.db, go, 1) # test standalone orphans daboss = Boss( status="BBB", manager_name="boss", golf_swing="fore", **{person_attribute_name: "daboss"} ) session.add(daboss) assert_raises(sa_exc.DBAPIError, session.flush) c = session.query(Company).first() daboss.company = c manager_list = [e for e in c.employees if isinstance(e, Manager)] session.flush() session.expunge_all() eq_( session.query(Manager).order_by(Manager.person_id).all(), manager_list, ) c = session.query(Company).first() session.delete(c) session.flush() eq_(select([func.count("*")]).select_from(people).scalar(), 0)
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 pjoin = polymorphic_union( { 'manager': managers_table, 'engineer': engineers_table }, 'type', 'pjoin') 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')
def test_merge_w_relationship(self): A, C, B, c_table, b_table, a_table, Dest, dest_table = ( self.classes.A, self.classes.C, self.classes.B, self.tables.c_table, self.tables.b_table, self.tables.a_table, self.classes.Dest, self.tables.dest_table, ) ajoin = polymorphic_union( {"a": a_table, "b": b_table, "c": c_table}, "type", "ajoin" ) mapper( A, a_table, with_polymorphic=("*", ajoin), polymorphic_on=ajoin.c.type, polymorphic_identity="a", properties={ "some_dest": relationship(Dest, back_populates="many_a") }, ) mapper( B, b_table, inherits=A, concrete=True, polymorphic_identity="b", properties={ "some_dest": relationship(Dest, back_populates="many_a") }, ) mapper( C, c_table, inherits=A, concrete=True, polymorphic_identity="c", properties={ "some_dest": relationship(Dest, back_populates="many_a") }, ) mapper( Dest, dest_table, properties={ "many_a": relationship( A, back_populates="some_dest", order_by=ajoin.c.id ) }, ) assert C.some_dest.property.parent is class_mapper(C) assert B.some_dest.property.parent is class_mapper(B) assert A.some_dest.property.parent is class_mapper(A) sess = sessionmaker()() dest1 = Dest(name="d1") dest2 = Dest(name="d2") a1 = A(some_dest=dest2, aname="a1") b1 = B(some_dest=dest1, bname="b1") c1 = C(some_dest=dest2, cname="c1") sess.add_all([dest1, dest2, c1, a1, b1]) sess.commit() sess2 = sessionmaker()() merged_c1 = sess2.merge(c1) eq_(merged_c1.some_dest.name, "d2") eq_(merged_c1.some_dest_id, c1.some_dest_id)
def setup_mapper(self): ''' Initializes and assign a mapper to the entity. At this point the mapper will usually have no property as they are added later. ''' if self.entity.mapper: return # for now we don't support the "abstract" parent class in a concrete # inheritance scenario as demonstrated in # sqlalchemy/test/orm/inheritance/concrete.py # this should be added along other kwargs = self.mapper_options if self.order_by: kwargs['order_by'] = self.translate_order_by(self.order_by) if self.version_id_col: kwargs['version_id_col'] = self.get_column(self.version_id_col) if self.inheritance in ('single', 'concrete', 'multi'): if self.parent and \ not (self.inheritance == 'concrete' and not self.polymorphic): kwargs['inherits'] = self.parent.mapper if self.inheritance == 'multi' and self.parent: col_pairs = zip(self.primary_keys, self.parent._descriptor.primary_keys) kwargs['inherit_condition'] = \ and_(*[pc == c for c, pc in col_pairs]) if self.polymorphic: if self.children: if self.inheritance == 'concrete': keys = [(self.identity, self.entity.table)] keys.extend([(child._descriptor.identity, child.table) for child in self._get_children()]) #XXX: we might need to change the alias name so that # children (which are parent themselves) don't end up # with the same alias than their parent? pjoin = polymorphic_union( dict(keys), self.polymorphic, 'pjoin') kwargs['with_polymorphic'] = ('*', pjoin) kwargs['polymorphic_on'] = \ getattr(pjoin.c, self.polymorphic) elif not self.parent: kwargs['polymorphic_on'] = \ self.get_column(self.polymorphic) #TODO: this is an optimization, and it breaks the multi # table polymorphic inheritance test with a relation. # So I turn it off for now. We might want to provide an # option to turn it on. # if self.inheritance == 'multi': # children = self._get_children() # join = self.entity.table # for child in children: # join = join.outerjoin(child.table) # kwargs['select_table'] = join if self.children or self.parent: kwargs['polymorphic_identity'] = self.identity if self.parent and self.inheritance == 'concrete': kwargs['concrete'] = True #TODO: document this! if 'primary_key' in kwargs: cols = self.entity.table.c kwargs['primary_key'] = [getattr(cols, colname) for colname in kwargs['primary_key']] if self.parent and self.inheritance == 'single': args = [] else: args = [self.entity.table] # do the mapping if self.session is None: self.entity.mapper = mapper(self.entity, *args, **kwargs) elif isinstance(self.session, ScopedSession): self.entity.mapper = self.session.mapper(self.entity, *args, **kwargs) else: raise Exception("Failed to map entity '%s' with its table or " "selectable" % self.entity.__name__)