summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2006-03-06 03:10:46 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2006-03-06 03:10:46 +0000
commit1644a44628f6a09bb992752bf266994afe0e98df (patch)
tree515a7c6709fe292af63319d6e1e2ba04349b0bf5
parenta0079b6831aef2b604859f89f07772e65c04d5d4 (diff)
downloadsqlalchemy-1644a44628f6a09bb992752bf266994afe0e98df.tar.gz
a mapper with inheritance will place itself as "dependent" on the inherited mapper; even though this is not usually needed, it allows certain exotic combinations of mapper setups to work (i.e. the one in the polymorph example)
-rw-r--r--examples/polymorph/polymorph.py42
-rw-r--r--lib/sqlalchemy/mapping/mapper.py10
-rw-r--r--lib/sqlalchemy/mapping/objectstore.py1
-rw-r--r--lib/sqlalchemy/sql.py1
4 files changed, 34 insertions, 20 deletions
diff --git a/examples/polymorph/polymorph.py b/examples/polymorph/polymorph.py
index b19038016..7200aa016 100644
--- a/examples/polymorph/polymorph.py
+++ b/examples/polymorph/polymorph.py
@@ -6,7 +6,8 @@ import sys
# extend from a common base class, although this same approach can be used
# with
-db = create_engine('sqlite://', echo=True, echo_uow=False)
+#db = create_engine('sqlite://', echo=True, echo_uow=False)
+db = create_engine('postgres://user=scott&password=tiger&host=127.0.0.1&database=test', echo=True, echo_uow=False)
# a table to store companies
companies = Table('companies', db,
@@ -52,9 +53,10 @@ assign_mapper(Engineer, engineers, inherits=Person.mapper)
assign_mapper(Manager, managers, inherits=Person.mapper)
# next, we define a query that is going to load Managers and Engineers in one shot.
-# this query is tricky since the managers and engineers tables contain the same "description" column,
-# so we set up a full blown select() statement that uses aliases for the description
-# column. The select() statement is also given an alias 'pjoin', since the mapper requires
+# we will use a UNION ALL with an extra hardcoded column to indicate the type of object.
+# this can also be done via several LEFT OUTER JOINS but a UNION is more appropriate
+# since they are distinct result sets.
+# The select() statement is also given an alias 'pjoin', since the mapper requires
# that all Selectables have a name.
#
# TECHNIQUE - when you want to load a certain set of objects from a in one query, all the
@@ -65,7 +67,7 @@ assign_mapper(Manager, managers, inherits=Person.mapper)
#
person_join = select(
[people, managers.c.description,column("'manager'").label('type')],
- people.c.person_id==managers.c.person_id).union(
+ people.c.person_id==managers.c.person_id).union_all(
select(
[people, engineers.c.description, column("'engineer'").label('type')],
people.c.person_id==engineers.c.person_id)).alias('pjoin')
@@ -89,20 +91,24 @@ class PersonLoader(MapperExtension):
ext = PersonLoader()
# set up the polymorphic mapper, which maps the person_join we set up to
-# the Person class, using an instance of PersonLoader. Note that even though
-# this mapper is against Person, its not going to screw up the normal operation
-# of the Person object since its not the "primary" mapper. In reality, we could even
-# make this mapper against some other class we dont care about since the creation of
-# objects is hardcoded.
+# the Person class, using an instance of PersonLoader.
people_mapper = mapper(Person, person_join, extension=ext)
+# create a mapper for Company. the 'employees' relationship points to
+# our new people_mapper.
+#
+# the dependency relationships which take effect on commit (i.e. the order of
+# inserts/deletes) will be established against the Person class's primary
+# mapper, and when the Engineer and
+# Manager objects are found in the 'employees' list, the primary mappers
+# for those subclasses will register
+# themselves as dependent on the Person mapper's save operations.
+# (translation: it'll work)
+# TODO: get the eager loading to work (the compound select alias doesnt like being aliased itself)
assign_mapper(Company, companies, properties={
- 'employees': relation(people_mapper),
- 'engineers': relation(Engineer, private=True),
- 'managers':relation(Manager, private=True)
+ 'employees': relation(people_mapper, private=True)
})
-
c = Company(name='company1')
c.employees.append(Manager(name='pointy haired boss', description='manager1'))
c.employees.append(Engineer(name='dilbert', description='engineer1'))
@@ -128,4 +134,10 @@ for e in c.employees:
print e, e._instance_key
objectstore.delete(c)
-objectstore.commit() \ No newline at end of file
+objectstore.commit()
+
+
+managers.drop()
+engineers.drop()
+people.drop()
+companies.drop()
diff --git a/lib/sqlalchemy/mapping/mapper.py b/lib/sqlalchemy/mapping/mapper.py
index 7b4595fb0..330c75c31 100644
--- a/lib/sqlalchemy/mapping/mapper.py
+++ b/lib/sqlalchemy/mapping/mapper.py
@@ -67,9 +67,11 @@ class Mapper(object):
self.table = sql.join(inherits.table, table, inherit_condition)
self._synchronizer = sync.ClauseSynchronizer(self, self, sync.ONETOMANY)
self._synchronizer.compile(self.table.onclause, inherits.tables, TableFinder(table))
+ self.inherits = inherits
else:
self.primarytable = self.table
self._synchronizer = None
+ self.inherits = None
# locate all tables contained within the "table" passed in, which
# may be a join or other construct
@@ -670,13 +672,15 @@ class Mapper(object):
except KeyError:
return False
- def register_dependencies(self, *args, **kwargs):
+ def register_dependencies(self, uowcommit, *args, **kwargs):
"""called by an instance of objectstore.UOWTransaction to register
which mappers are dependent on which, as well as DependencyProcessor
objects which will process lists of objects in between saves and deletes."""
for prop in self.props.values():
- prop.register_dependencies(*args, **kwargs)
-
+ prop.register_dependencies(uowcommit, *args, **kwargs)
+ if self.inherits is not None:
+ uowcommit.register_dependency(self.inherits, self)
+
def register_deleted(self, obj, uow):
for prop in self.props.values():
prop.register_deleted(obj, uow)
diff --git a/lib/sqlalchemy/mapping/objectstore.py b/lib/sqlalchemy/mapping/objectstore.py
index d0e1573c6..d2aca8b06 100644
--- a/lib/sqlalchemy/mapping/objectstore.py
+++ b/lib/sqlalchemy/mapping/objectstore.py
@@ -534,7 +534,6 @@ class UOWTransaction(object):
def register_dependency(self, mapper, dependency):
"""called by mapper.PropertyLoader to register the objects handled by
one mapper being dependent on the objects handled by another."""
-
# correct for primary mapper (the mapper offcially associated with the class)
self.dependencies[(mapper._primary_mapper(), dependency._primary_mapper())] = True
self.__modified = True
diff --git a/lib/sqlalchemy/sql.py b/lib/sqlalchemy/sql.py
index a6ddf8cb9..d4312a151 100644
--- a/lib/sqlalchemy/sql.py
+++ b/lib/sqlalchemy/sql.py
@@ -1211,7 +1211,6 @@ class Select(SelectBaseMixin, FromClause):
self.visit_select(cs)
for s in cs.selects:
s.parens = False
- print "BUT", id(cs), cs.parens
def visit_column(self, c):pass
def visit_table(self, c):pass
def visit_select(self, select):