From 50e5619a48b584872a4ddf8b6003cfce80d0cf1b Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Mon, 29 May 2006 17:21:41 +0000 Subject: [PATCH] more polymorphic adjustments to circular dependency sort --- doc/build/content/dbengine.txt | 2 +- lib/sqlalchemy/orm/mapper.py | 10 +++++++--- lib/sqlalchemy/orm/properties.py | 10 +++------- lib/sqlalchemy/orm/unitofwork.py | 20 ++++++++++++++------ 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/doc/build/content/dbengine.txt b/doc/build/content/dbengine.txt index 2193ab6b5d..715e274fad 100644 --- a/doc/build/content/dbengine.txt +++ b/doc/build/content/dbengine.txt @@ -192,7 +192,7 @@ To get at the actual `Connection` object which is used by implicit executions, c conn1 = db.contextual_connection() conn2 = db.contextual_connection() - >>> assert conn1 is conn2 + >>> assert conn1.connection is conn2.connection True When the `plain` strategy is used, the `contextual_connection()` method is synonymous with the `connect()` method; both return a distinct connection from the pool. diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 07e4f503d3..11806ea8f5 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -231,7 +231,7 @@ class Mapper(object): if self.columntoproperty.has_key(column): continue if not self.columns.has_key(column.key): - self.columns[column.key] = column + self.columns[column.key] = self.select_table.corresponding_column(column, keys_ok=True, raiseerr=True) prop = self.props.get(column.key, None) if prop is None: @@ -291,7 +291,11 @@ class Mapper(object): return self.inherits.base_mapper() else: return self - + + def _inherits(self, mapper): + """returns True if the given mapper and this mapper are in the same inheritance hierarchy""" + return self.base_mapper() is mapper.base_mapper() + def add_polymorphic_mapping(self, key, class_or_mapper, entity_name=None): if isinstance(class_or_mapper, type): class_or_mapper = class_mapper(class_or_mapper, entity_name=entity_name) @@ -338,7 +342,7 @@ class Mapper(object): self.props[key] = prop if isinstance(prop, ColumnProperty): - self.columns[key] = prop.columns[0] + self.columns[key] = self.select_table.corresponding_column(prop.columns[0], keys_ok=True, raiseerr=True) for col in prop.columns: proplist = self.columntoproperty.setdefault(col, []) proplist.append(prop) diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index 9f8883a310..8c38b897fe 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -150,12 +150,9 @@ class PropertyLoader(mapper.MapperProperty): private = property(lambda s:s.cascade.delete_orphan) - def cascade_iterator(self, type, object, recursive=None): + def cascade_iterator(self, type, object, recursive): if not type in self.cascade: return - if recursive is None: - recursive = sets.Set() - childlist = sessionlib.global_attributes.get_history(object, self.key, passive=True) for c in childlist.added_items() + childlist.deleted_items() + childlist.unchanged_items(): @@ -163,7 +160,7 @@ class PropertyLoader(mapper.MapperProperty): if c not in recursive: recursive.add(c) yield c - for c2 in self.mapper.cascade_iterator(type, c, recursive): + for c2 in self.mapper.primary_mapper().cascade_iterator(type, c, recursive): yield c2 def copy(self): @@ -247,10 +244,9 @@ class PropertyLoader(mapper.MapperProperty): def _get_direction(self): """determines our 'direction', i.e. do we represent one to many, many to many, etc.""" - if self.secondaryjoin is not None: return sync.MANYTOMANY - elif self.parent.mapped_table is self.target: + elif self.parent.mapped_table is self.target or self.parent.select_table is self.target: if self.foreignkey.primary_key: return sync.MANYTOONE else: diff --git a/lib/sqlalchemy/orm/unitofwork.py b/lib/sqlalchemy/orm/unitofwork.py index 1ebf9cd698..3927b949e8 100644 --- a/lib/sqlalchemy/orm/unitofwork.py +++ b/lib/sqlalchemy/orm/unitofwork.py @@ -761,8 +761,9 @@ class UOWTask(object): for dep in task.dependencies: if not dependency_in_cycles(dep): extradeplist.append(dep) - l = deps_by_targettask.setdefault(dep.targettask, []) - l.append(dep) + for t in dep.targettask.polymorphic_tasks(): + l = deps_by_targettask.setdefault(t, []) + l.append(dep) for t in cycles: for task in t.polymorphic_tasks(): @@ -771,8 +772,10 @@ class UOWTask(object): object_to_original_task[obj] = task #print "OBJ", repr(obj), "TASK", repr(task) + for dep in deps_by_targettask.get(task, []): # is this dependency involved in one of the cycles ? + #print "DEP iterate", dep.processor.key if not dependency_in_cycles(dep): continue #print "DEP", dep.processor.key @@ -790,8 +793,9 @@ class UOWTask(object): for o in childlist: if o is None or not childtask.contains_object(o, polymorphic=True): continue - #print "CHILD", o + #print "parent/child", obj, o whosdep = dep.whose_dependent_on_who(obj, o) + #print "WHOSEDEP", dep.processor.key, dep.processor.direction, whosdep if whosdep is not None: tuples.append(whosdep) # create a UOWDependencyProcessor representing this pair of objects. @@ -820,13 +824,17 @@ class UOWTask(object): def make_task_tree(node, parenttask): """takes a dependency-sorted tree of objects and creates a tree of UOWTasks""" - #print "MAKETASKTREE", node.item + #print "MAKETASKTREE", node.item, parenttask t = get_object_task(node.item) for n in node.children: t2 = make_task_tree(n, t) - - can_add_to_parent = t.mapper is parenttask.mapper + + # this flag is attempting to coalesce non-dependent operations into lists, instead of + # individual tasks, to produce more of a "batching" effect. great when it works, + # but easily breakable...so its at False for now + can_add_to_parent = False #parenttask.mapper._inherits(t.mapper) + original_task = object_to_original_task[node.item] #print "ORIG TASK", original_task if original_task.contains_object(node.item, polymorphic=False): -- 2.47.2