summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/mapper.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2005-11-17 04:14:23 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2005-11-17 04:14:23 +0000
commitb5d506a9c20a74a27e21778d6e156b1c7c35d478 (patch)
tree6a4b641c75611fbbbe39381f7bed782ec9101e5b /lib/sqlalchemy/mapper.py
parent3a7631ab1a622a7dabc5404c0e027f2a067e17ee (diff)
downloadsqlalchemy-b5d506a9c20a74a27e21778d6e156b1c7c35d478.tar.gz
workin out the lazy/eager thing
Diffstat (limited to 'lib/sqlalchemy/mapper.py')
-rw-r--r--lib/sqlalchemy/mapper.py58
1 files changed, 16 insertions, 42 deletions
diff --git a/lib/sqlalchemy/mapper.py b/lib/sqlalchemy/mapper.py
index a46f47b96..d3fb1c019 100644
--- a/lib/sqlalchemy/mapper.py
+++ b/lib/sqlalchemy/mapper.py
@@ -986,10 +986,7 @@ class PropertyLoader(MapperProperty):
def execute(self, instance, row, identitykey, imap, isnew):
if self._is_primary():
return
- if self.uselist:
- setattr(instance, self.key, [])
- else:
- setattr(instance, self.key, None)
+ objectstore.global_attributes.create_history(instance, self.key, self.uselist)
class LazyLoader(PropertyLoader):
def init(self, key, parent):
@@ -997,30 +994,8 @@ class LazyLoader(PropertyLoader):
(self.lazywhere, self.lazybinds) = create_lazy_clause(self.parent.table, self.primaryjoin, self.secondaryjoin, self.foreignkey)
def _set_class_attribute(self, class_, key):
- # sets an attribute on the mapped class, which will call setup_loader off this object when the attribute is first accessed.
- # setup_loader then creates a "lazyload" callable that is called second.
- # this "early setup" is so that an object that wasnt even loaded from the DB can still "lazy load" its properties,
- # in the case that those properties are saved in some other way to the DB in the same transaction that this object
- # is also saved.
- #
- # hey and it also removes the callable from being attached to the object instance itself- objects with lazy
- # laoders can be pickled !
- #
- # test case: make two mappers, A and B. A has a "one-to-many" relation to B, B has a "one-to-one" relation
- # to A. create a new object for "A", call it "Ao".
- #
- # then, create a new object for B, call it "Bo". attach "Ao" to it as its "one-to-one". then commit. Ao is saved, Bo
- # is saved with its relation to Ao. Now, Ao's list of B's should have Bo in it, or be able to lazy load. since it wasnt
- # loaded from a loadfromrow type of call, the lazy loader must be attached at the object-construction level, not the
- # result-processing level.
- #
- # problem: if you make Ao, then randomly try to access its child list, then that child list gets executed with nothing,
- # and still puts the object into an invalid state. Or, if you get Ao from the DB, access its child list, then later
- # save an object via the "reverse" relationship; Ao's child list is still invalid.
- #
- # when users create a bi-directional dependency, we might want to put a "loadalways" or "live" flag or something on a property
- # loader, so that one of the props can be more "read-only" and always read from the DB when its accessed.
- objectstore.uow().register_attribute(class_, key, uselist = self.uselist, deleteremoved = self.private, live=self.live, create_prop=lambda i: self.setup_loader(i))
+ # establish a class-level lazy loader on our class
+ objectstore.global_attributes.register_attribute(class_, key, uselist = self.uselist, deleteremoved = self.private, live=self.live, callable_=lambda i: self.setup_loader(i))
def setup_loader(self, instance):
def lazyload():
@@ -1051,10 +1026,15 @@ class LazyLoader(PropertyLoader):
def execute(self, instance, row, identitykey, imap, isnew):
if isnew:
- if not self._is_primary:
- objectstore.uow().register_callable(obj, self.key, self.setup_loader(obj), self.uselist)
+ # new object instance being loaded from a result row
+ if not self._is_primary():
+ # we are not the primary manager for this attribute on this class - set up a per-instance lazyloader,
+ # which will override the class-level behavior
+ objectstore.global_attributes.create_history(instance, self.key, self.uselist, callable_=self.setup_loader(instance))
else:
- objectstore.uow().attributes.reset_history(instance, self.key)
+ # we are the primary manager for this attribute on this class - reset its per-instance attribute state,
+ # so that the class-level lazy loader is executed when next referenced on this instance
+ objectstore.global_attributes.reset_history(instance, self.key)
def create_lazy_clause(table, primaryjoin, secondaryjoin, foreignkey):
binds = {}
@@ -1131,20 +1111,14 @@ class EagerLoader(PropertyLoader):
def execute(self, instance, row, identitykey, imap, isnew):
"""receive a row. tell our mapper to look for a new object instance in the row, and attach
it to a list on the parent instance."""
+ if isnew:
+ h = objectstore.global_attributes.create_history(instance, self.key, self.uselist)
+
if not self.uselist:
- # TODO: check for multiple values on single-element child element ?
- instance.__dict__[self.key] = self.mapper._instance(row, imap)
- #setattr(instance, self.key, self.mapper._instance(row, imap))
+ h.setattr(self.mapper._instance(row, imap))
return
elif isnew:
- result_list = getattr(instance, self.key)
- result_list[:] = []
- result_list.commit()
- ## TODO: whats this about ?
- #result_list = []
- #setattr(instance, self.key, result_list)
- #result_list = getattr(instance, self.key)
- #result_list.commit()
+ result_list = h
else:
result_list = getattr(instance, self.key)