summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2007-01-13 01:39:15 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2007-01-13 01:39:15 +0000
commit5b4871f4364c7b93de010097aa8f4008f69bddd4 (patch)
treef1febf6ffff2881ea0be5f5a627e6b3f392bfe49 /lib/sqlalchemy
parent29dd5916496ac93bd81a7f2986563ff6160e0a51 (diff)
downloadsqlalchemy-5b4871f4364c7b93de010097aa8f4008f69bddd4.tar.gz
- basic idea of "session.merge()" actually implemented. needs more testing.
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/orm/interfaces.py5
-rw-r--r--lib/sqlalchemy/orm/properties.py18
-rw-r--r--lib/sqlalchemy/orm/session.py40
3 files changed, 41 insertions, 22 deletions
diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py
index 0c0ad2a72..4e9fe55f4 100644
--- a/lib/sqlalchemy/orm/interfaces.py
+++ b/lib/sqlalchemy/orm/interfaces.py
@@ -55,7 +55,10 @@ class MapperProperty(object):
This flag is used to indicate that the MapperProperty can define attribute instrumentation
for the class at the class level (as opposed to the individual instance level.)"""
return self.parent._is_primary_mapper()
-
+ def merge(self, session, source, dest):
+ """merges the attribute represented by this MapperProperty from source to destination object"""
+ raise NotImplementedError()
+
class StrategizedProperty(MapperProperty):
"""a MapperProperty which uses selectable strategies to affect loading behavior.
There is a single default strategy selected, and alternate strategies can be selected
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index cdab5464a..888ac0442 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -39,6 +39,8 @@ class SynonymProperty(MapperProperty):
return s
return getattr(obj, self.name)
setattr(self.parent.class_, self.key, SynonymProp())
+ def merge(self, session, source, dest):
+ pass
class ColumnProperty(StrategizedProperty):
"""describes an object attribute that corresponds to a table column."""
@@ -60,6 +62,8 @@ class ColumnProperty(StrategizedProperty):
setattr(object, self.key, value)
def get_history(self, obj, passive=False):
return sessionlib.attribute_manager.get_history(obj, self.key, passive=passive)
+ def merge(self, session, source, dest):
+ setattr(dest, self.key, getattr(source, self.key, None))
ColumnProperty.logger = logging.class_logger(ColumnProperty)
@@ -118,6 +122,20 @@ class PropertyLoader(StrategizedProperty):
def __str__(self):
return self.__class__.__name__ + " " + str(self.parent) + "->" + self.key + "->" + str(self.mapper)
+
+ def merge(self, session, source, dest):
+ if not "merge" in self.cascade:
+ return
+ childlist = sessionlib.attribute_manager.get_history(source, self.key, passive=True)
+ if childlist is None:
+ return
+ if self.uselist:
+ # sets a blank list according to the correct list class
+ dest_list = getattr(self.parent.class_, self.key).initialize(dest)
+ for current in list(childlist):
+ dest_list.append(session.merge(current))
+ else:
+ setattr(dest, self.key, session.merge(current))
def cascade_iterator(self, type, object, recursive, halt_on=None):
if not type in self.cascade:
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index 113341e17..829220688 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -324,29 +324,27 @@ class Session(object):
self.uow.register_deleted(c)
def merge(self, object, entity_name=None):
- """merge the object into a newly loaded or existing instance from this Session.
+ """copy the state of the given object onto the persistent object with the same identifier.
- note: this method is currently not completely implemented."""
- instance = None
- for obj in [object] + list(_object_mapper(object).cascade_iterator('merge', object)):
- key = getattr(obj, '_instance_key', None)
- if key is None:
- mapper = _object_mapper(object)
- ident = mapper.identity(object)
- for k in ident:
- if k is None:
- raise exceptions.InvalidRequestError("Instance '%s' does not have a full set of identity values, and does not represent a saved entity in the database. Use the add() method to add unsaved instances to this Session." % repr(obj))
- key = mapper.identity_key(ident)
- u = self.uow
- if u.identity_map.has_key(key):
- # TODO: copy the state of the given object into this one. tricky !
- inst = u.identity_map[key]
+ If there is no persistent instance currently associated with the session, it will be loaded.
+ Return the persistent instance. If the given instance is unsaved, save a copy of and return it as
+ a newly persistent instance. The given instance does not become associated with the session.
+ This operation cascades to associated instances if the association is mapped with cascade="merge".
+ """
+ mapper = _object_mapper(object)
+ key = getattr(object, '_instance_key', None)
+ if key is None:
+ merged = mapper._create_instance(self)
+ else:
+ if key in self.identity_map:
+ merged = self.identity_map[key]
else:
- inst = self.get(object.__class__, key[1])
- if obj is object:
- instance = inst
-
- return instance
+ merged = self.get(mapper.class_, key[1])
+ for prop in mapper.props.values():
+ prop.merge(self, object, merged)
+ if key is None:
+ self.save(merged)
+ return merged
def _save_impl(self, object, **kwargs):
if hasattr(object, '_instance_key'):