from sqlalchemy.orm import mapper, object_mapper
from sqlalchemy.orm.mapper import _state_mapper
from sqlalchemy.orm import util as mapperutil
+from sqlalchemy.orm import interfaces
__all__ = ['Query', 'QueryContext']
mapper = start
alias = self._aliases
for key in util.to_list(keys):
- prop = mapper.get_property(key, resolve_synonyms=True)
+ if isinstance(key, interfaces.PropComparator):
+ prop = key.property
+ else:
+ prop = mapper.get_property(key, resolve_synonyms=True)
+
if prop._is_self_referential() and not create_aliases:
raise exceptions.InvalidRequestError("Self-referential query on '%s' property requires create_aliases=True argument." % str(prop))
return q
def join(self, prop, id=None, aliased=False, from_joinpoint=False):
- """create a join of this ``Query`` object's criterion
- to a relationship and return the newly resulting ``Query``.
-
- 'prop' may be a string property name or a list of string
- property names.
+ """Create a join against this ``Query`` object's criterion
+ and apply generatively, retunring the newly resulting ``Query``.
+
+ 'prop' may be one of:
+ * a string property name, i.e. "rooms"
+ * a class-mapped attribute, i.e. Houses.rooms
+ * a list containing a combination of any of the above.
+
+ e.g.::
+
+ session.query(Company).join('employees')
+ session.query(Company).join(['employees', 'tasks'])
+ session.query(Houses).join([Colonials.rooms, Room.closets])
+
"""
return self._join(prop, id=id, outerjoin=False, aliased=aliased, from_joinpoint=from_joinpoint)
def outerjoin(self, prop, id=None, aliased=False, from_joinpoint=False):
- """create a left outer join of this ``Query`` object's criterion
- to a relationship and return the newly resulting ``Query``.
-
- 'prop' may be a string property name or a list of string
- property names.
+ """Create a left outer join against this ``Query`` object's criterion
+ and apply generatively, retunring the newly resulting ``Query``.
+
+ 'prop' may be one of:
+ * a string property name, i.e. "rooms"
+ * a class-mapped attribute, i.e. Houses.rooms
+ * a list containing a combination of any of the above.
+
+ e.g.::
+
+ session.query(Company).outerjoin('employees')
+ session.query(Company).outerjoin(['employees', 'tasks'])
+ session.query(Houses).outerjoin([Colonials.rooms, Room.closets])
+
"""
return self._join(prop, id=id, outerjoin=True, aliased=aliased, from_joinpoint=from_joinpoint)
class Boss(Manager):
pass
+class Machine(fixtures.Base):
+ pass
+
class Paperwork(fixtures.Base):
pass
keep_mappers = True
def define_tables(self, metadata):
- global companies, people, engineers, managers, boss, paperwork
+ global companies, people, engineers, managers, boss, paperwork, machines
companies = Table('companies', metadata,
Column('company_id', Integer, Sequence('company_id_seq', optional=True), primary_key=True),
Column('engineer_name', String(50)),
Column('primary_language', String(50)),
)
-
+
+ machines = Table('machines', metadata,
+ Column('machine_id', Integer, primary_key=True),
+ Column('name', String(50)),
+ Column('engineer_id', Integer, ForeignKey('engineers.person_id')))
+
managers = Table('managers', metadata,
Column('person_id', Integer, ForeignKey('people.person_id'), primary_key=True),
Column('status', String(30)),
'employees':relation(Person)
})
+ mapper(Machine, machines)
+
# testing a order_by here as well; the surrogate mapper has to adapt it
mapper(Person, people, select_table=person_join, polymorphic_on=people.c.type, polymorphic_identity='person', order_by=people.c.person_id,
properties={
'paperwork':relation(Paperwork)
})
- mapper(Engineer, engineers, inherits=Person, polymorphic_identity='engineer')
+ mapper(Engineer, engineers, inherits=Person, polymorphic_identity='engineer', properties={
+ 'machines':relation(Machine)
+ })
mapper(Manager, managers, select_table=manager_join, inherits=Person, polymorphic_identity='manager')
mapper(Boss, boss, inherits=Manager, polymorphic_identity='boss')
mapper(Paperwork, paperwork)
e1 = Engineer(name="dilbert", engineer_name="dilbert", primary_language="java", status="regular engineer", paperwork=[
Paperwork(description="tps report #1"),
Paperwork(description="tps report #2")
+ ], machines=[
+ Machine(name='IBM ThinkPad'),
+ Machine(name='IPhone'),
])
e2 = Engineer(name="wally", engineer_name="wally", primary_language="c++", status="regular engineer", paperwork=[
Paperwork(description="tps report #3"),
Paperwork(description="tps report #4")
+ ], machines=[
+ Machine(name="Commodore 64")
])
b1 = Boss(name="pointy haired boss", golf_swing="fore", manager_name="pointy", status="da boss", paperwork=[
Paperwork(description="review #1"),
e3 = Engineer(name="vlad", engineer_name="vlad", primary_language="cobol", status="elbonian engineer", paperwork=[
Paperwork(description='elbonian missive #3')
+ ], machines=[
+ Machine(name="Commodore 64"),
+ Machine(name="IBM 3270")
])
+
c2.employees = [e3]
sess = create_session()
sess.save(c1)
self.assertEquals(sess.query(Company).join('employees', aliased=True).filter(Person.name=='vlad').one(), c2)
+ def test_join_to_subclass(self):
+ sess = create_session()
+
+ self.assertEquals(sess.query(Person).join(Engineer.machines).all(), [e1, e2, e3])
+
+ self.assertEquals(sess.query(Person).join(Engineer.machines).filter(Machine.name.ilike("%ibm%")).all(), [e1, e3])
+
+ self.assertEquals(sess.query(Company).join(['employees', Engineer.machines]).all(), [c1, c2])
+
+ self.assertEquals(sess.query(Company).join(['employees', Engineer.machines]).filter(Machine.name.ilike("%thinkpad%")).all(), [c1])
+
def test_join_through_polymorphic(self):
sess = create_session()