summaryrefslogtreecommitdiff
path: root/examples/polymorph/polymorph.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2006-05-25 14:20:23 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2006-05-25 14:20:23 +0000
commitbb79e2e871d0a4585164c1a6ed626d96d0231975 (patch)
tree6d457ba6c36c408b45db24ec3c29e147fe7504ff /examples/polymorph/polymorph.py
parent4fc3a0648699c2b441251ba4e1d37a9107bd1986 (diff)
downloadsqlalchemy-bb79e2e871d0a4585164c1a6ed626d96d0231975.tar.gz
merged 0.2 branch into trunk; 0.1 now in sqlalchemy/branches/rel_0_1
Diffstat (limited to 'examples/polymorph/polymorph.py')
-rw-r--r--examples/polymorph/polymorph.py177
1 files changed, 71 insertions, 106 deletions
diff --git a/examples/polymorph/polymorph.py b/examples/polymorph/polymorph.py
index d105a64ea..76a03b99d 100644
--- a/examples/polymorph/polymorph.py
+++ b/examples/polymorph/polymorph.py
@@ -1,145 +1,110 @@
from sqlalchemy import *
-import sys
+import sys, sets
-# this example illustrates how to create a relationship to a list of objects,
-# where each object in the list has a different type. The typed objects will
-# extend from a common base class, although this same approach can be used
-# with
+# this example illustrates a polymorphic load of two classes, where each class has a very
+# different set of properties
-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)
+metadata = BoundMetaData('sqlite://', echo='debug')
# a table to store companies
-companies = Table('companies', db,
+companies = Table('companies', metadata,
Column('company_id', Integer, primary_key=True),
- Column('name', String(50))).create()
+ Column('name', String(50)))
# we will define an inheritance relationship between the table "people" and "engineers",
# and a second inheritance relationship between the table "people" and "managers"
-people = Table('people', db,
+people = Table('people', metadata,
Column('person_id', Integer, primary_key=True),
Column('company_id', Integer, ForeignKey('companies.company_id')),
- Column('name', String(50))).create()
+ Column('name', String(50)),
+ Column('type', String(30)))
-engineers = Table('engineers', db,
+engineers = Table('engineers', metadata,
Column('person_id', Integer, ForeignKey('people.person_id'), primary_key=True),
- Column('special_description', String(50))).create()
+ Column('status', String(30)),
+ Column('engineer_name', String(50)),
+ Column('primary_language', String(50)),
+ )
-managers = Table('managers', db,
+managers = Table('managers', metadata,
Column('person_id', Integer, ForeignKey('people.person_id'), primary_key=True),
- Column('description', String(50))).create()
+ Column('status', String(30)),
+ Column('manager_name', String(50))
+ )
+
+metadata.create_all()
-
# create our classes. The Engineer and Manager classes extend from Person.
class Person(object):
+ def __init__(self, **kwargs):
+ for key, value in kwargs.iteritems():
+ setattr(self, key, value)
def __repr__(self):
return "Ordinary person %s" % self.name
class Engineer(Person):
def __repr__(self):
- return "Engineer %s, description %s" % (self.name, self.special_description)
+ return "Engineer %s, status %s, engineer_name %s, primary_language %s" % (self.name, self.status, self.engineer_name, self.primary_language)
class Manager(Person):
def __repr__(self):
- return "Manager %s, description %s" % (self.name, self.description)
+ return "Manager %s, status %s, manager_name %s" % (self.name, self.status, self.manager_name)
class Company(object):
+ def __init__(self, **kwargs):
+ for key, value in kwargs.iteritems():
+ setattr(self, key, value)
def __repr__(self):
return "Company %s" % self.name
-# next we assign Person mappers. Since these are the first mappers we are
-# creating for these classes, they automatically become the "primary mappers", which
-# define the dependency relationships between the classes, so we do a straight
-# inheritance setup, i.e. no modifications to how objects are loaded or anything like that.
-assign_mapper(Person, people)
-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.
-# 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
-# columns in the Selectable must have unique names. Dont worry about mappers at this point,
-# just worry about making a query where if you were to view the results, you could tell everything
-# you need to know from each row how to construct an object instance from it. this is the
-# essence of "resultset-based-mapping", which is the core ideology of SQLAlchemy.
-#
-person_join = select(
- [people, managers.c.description,column("'manager'").label('type')],
- people.c.person_id==managers.c.person_id).union_all(
- select(
- [people, engineers.c.special_description.label('description'), column("'engineer'").label('type')],
- people.c.person_id==engineers.c.person_id)).alias('pjoin')
-
-
-# lets print out what this Selectable looks like. The mapper is going to take the selectable and
-# Select off of it, with the flag "use_labels" which indicates to prefix column names with the table
-# name. So here is what our mapper will see:
-print "Person selectable:", str(person_join.select(use_labels=True)), "\n"
-
-
-# MapperExtension object.
-class PersonLoader(MapperExtension):
- def create_instance(self, mapper, row, imap, class_):
- if row['pjoin_type'] =='engineer':
- e = Engineer()
- e.special_description = row['pjoin_description']
- return e
- elif row['pjoin_type'] =='manager':
- return Manager()
- else:
- return Person()
-ext = PersonLoader()
-
-# set up the polymorphic mapper, which maps the person_join we set up to
-# 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, lazy=False, private=True)
-})
-c = Company(name='company1')
-c.employees.append(Manager(name='pointy haired boss', description='manager1'))
-c.employees.append(Engineer(name='dilbert', special_description='engineer1'))
-c.employees.append(Engineer(name='wally', special_description='engineer2'))
-c.employees.append(Manager(name='jsmith', description='manager2'))
-objectstore.commit()
+# create a union that represents both types of joins.
+person_join = polymorphic_union(
+ {
+ 'engineer':people.join(engineers),
+ 'manager':people.join(managers),
+ 'person':people.select(people.c.type=='person'),
+ }, None, 'pjoin')
-objectstore.clear()
+#person_mapper = mapper(Person, people, select_table=person_join, polymorphic_on=person_join.c.type, polymorphic_identity='person')
+person_mapper = mapper(Person, people, select_table=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')
-c = Company.get(1)
-for e in c.employees:
- print e, e._instance_key
+mapper(Company, companies, properties={
+ 'employees': relation(Person, lazy=False, private=True, backref='company')
+})
+session = create_session(echo_uow=False)
+c = Company(name='company1')
+c.employees.append(Manager(name='pointy haired boss', status='AAB', manager_name='manager1'))
+c.employees.append(Engineer(name='dilbert', status='BBA', engineer_name='engineer1', primary_language='java'))
+c.employees.append(Person(name='joesmith', status='HHH'))
+c.employees.append(Engineer(name='wally', status='CGG', engineer_name='engineer2', primary_language='python'))
+c.employees.append(Manager(name='jsmith', status='ABA', manager_name='manager2'))
+session.save(c)
+print session.new
+session.flush()
+#sys.exit()
+session.clear()
+
+c = session.query(Company).get(1)
+for e in c.employees:
+ print e, e._instance_key, e.company
+assert sets.Set([e.name for e in c.employees]) == sets.Set(['pointy haired boss', 'dilbert', 'joesmith', 'wally', 'jsmith'])
print "\n"
-dilbert = Engineer.mapper.get_by(name='dilbert')
-dilbert.special_description = 'hes dibert!'
-objectstore.commit()
+dilbert = session.query(Person).get_by(name='dilbert')
+dilbert2 = session.query(Engineer).get_by(name='dilbert')
+assert dilbert is dilbert2
+
+dilbert.engineer_name = 'hes dibert!'
-objectstore.clear()
-c = Company.get(1)
+session.flush()
+session.clear()
+
+c = session.query(Company).get(1)
for e in c.employees:
print e, e._instance_key
-objectstore.delete(c)
-objectstore.commit()
-
+session.delete(c)
+session.flush()
-managers.drop()
-engineers.drop()
-people.drop()
-companies.drop()
+metadata.drop_all()