예제 #1
0
    def flush(self, session, objects=None):
        # this context will track all the objects we want to save/update/delete,
        # and organize a hierarchical dependency structure.  it also handles
        # communication with the mappers and relationships to fire off SQL
        # and synchronize attributes between related objects.
        echo = logging.is_info_enabled(self.logger)

        flush_context = UOWTransaction(self, session)

        # create the set of all objects we want to operate upon
        if objects is not None:
            # specific list passed in
            objset = util.Set(objects)
        else:
            # or just everything
            objset = util.Set(self.identity_map.values()).union(self.new)

        # detect persistent objects that have changes
        dirty = self.locate_dirty()

        # store objects whose fate has been decided
        processed = util.Set()

        # put all saves/updates into the flush context.  detect orphans and throw them into deleted.
        for obj in self.new.union(dirty).intersection(objset).difference(
                self.deleted):
            if obj in processed:
                continue
            if object_mapper(obj)._is_orphan(obj):
                for c in [obj] + list(
                        object_mapper(obj).cascade_iterator('delete', obj)):
                    if c in processed:
                        continue
                    flush_context.register_object(c, isdelete=True)
                    processed.add(c)
            else:
                flush_context.register_object(obj)
                processed.add(obj)

        # put all remaining deletes into the flush context.
        for obj in self.deleted:
            if (objset is not None and not obj in objset) or obj in processed:
                continue
            flush_context.register_object(obj, isdelete=True)

        trans = session.create_transaction(autoflush=False)
        flush_context.transaction = trans
        try:
            flush_context.execute()
        except:
            trans.rollback()
            raise
        trans.commit()

        flush_context.post_exec()
예제 #2
0
    def flush(self, session, objects=None):
        # this context will track all the objects we want to save/update/delete,
        # and organize a hierarchical dependency structure.  it also handles
        # communication with the mappers and relationships to fire off SQL
        # and synchronize attributes between related objects.
        echo = logging.is_info_enabled(self.logger)

        flush_context = UOWTransaction(self, session)

        # create the set of all objects we want to operate upon
        if objects is not None:
            # specific list passed in
            objset = util.Set(objects)
        else:
            # or just everything
            objset = util.Set(self.identity_map.values()).union(self.new)

        # detect persistent objects that have changes
        dirty = self.locate_dirty()

        # store objects whose fate has been decided
        processed = util.Set()


        # put all saves/updates into the flush context.  detect orphans and throw them into deleted.
        for obj in self.new.union(dirty).intersection(objset).difference(self.deleted):
            if obj in processed:
                continue
            if object_mapper(obj)._is_orphan(obj):
                for c in [obj] + list(object_mapper(obj).cascade_iterator('delete', obj)):
                    if c in processed:
                        continue
                    flush_context.register_object(c, isdelete=True)
                    processed.add(c)
            else:
                flush_context.register_object(obj)
                processed.add(obj)

        # put all remaining deletes into the flush context.
        for obj in self.deleted:
            if (objset is not None and not obj in objset) or obj in processed:
                continue
            flush_context.register_object(obj, isdelete=True)

        trans = session.create_transaction(autoflush=False)
        flush_context.transaction = trans
        try:
            flush_context.execute()
        except:
            trans.rollback()
            raise
        trans.commit()

        flush_context.post_exec()
예제 #3
0
    def register_object(self, obj, isdelete = False, listonly = False, postupdate=False, post_update_cols=None, **kwargs):
        """Add an object to this ``UOWTransaction`` to be updated in the database.

        This operation has the combined effect of locating/creating an appropriate
        ``UOWTask`` object, and calling its ``append()`` method which then locates/creates
        an appropriate ``UOWTaskElement`` object.
        """

        #print "REGISTER", repr(obj), repr(getattr(obj, '_instance_key', None)), str(isdelete), str(listonly)

        # if object is not in the overall session, do nothing
        if not self.uow._is_valid(obj):
            if logging.is_debug_enabled(self.logger):
                self.logger.debug("object %s not part of session, not registering for flush" % (mapperutil.instance_str(obj)))
            return

        if logging.is_debug_enabled(self.logger):
            self.logger.debug("register object for flush: %s isdelete=%s listonly=%s postupdate=%s" % (mapperutil.instance_str(obj), isdelete, listonly, postupdate))

        mapper = object_mapper(obj)
        task = self.get_task_by_mapper(mapper)
        if postupdate:
            task.append_postupdate(obj, post_update_cols)
            return

        task.append(obj, listonly, isdelete=isdelete, **kwargs)
예제 #4
0
    def __call__(self):
        if not mapper.has_identity(self.instance):
            return None
            
        localparent = mapper.object_mapper(self.instance, raiseerror=False)
        
        prop = localparent.get_property(self.key)
        strategy = prop._get_strategy(DeferredColumnLoader)

        if self.keys:
            toload = self.keys
        elif strategy.group:
            toload = [p.key for p in localparent.iterate_properties if isinstance(p.strategy, DeferredColumnLoader) and p.group==strategy.group]
        else:
            toload = [self.key]

        # narrow the keys down to just those which have no history
        group = [k for k in toload if k in self.instance._state.unmodified]

        if strategy._should_log_debug:
            strategy.logger.debug("deferred load %s group %s" % (mapperutil.attribute_str(self.instance, self.key), group and ','.join(group) or 'None'))

        session = sessionlib.object_session(self.instance)
        if session is None:
            raise exceptions.UnboundExecutionError("Parent instance %s is not bound to a Session; deferred load operation of attribute '%s' cannot proceed" % (self.instance.__class__, self.key))

        query = session.query(localparent)
        if not self.optimizing_statement:
            ident = self.instance._instance_key[1]
            query._get(None, ident=ident, only_load_props=group, refresh_instance=self.instance._state)
        else:
            statement, params = self.optimizing_statement(self.instance)
            query.from_statement(statement).params(params)._get(None, only_load_props=group, refresh_instance=self.instance._state)
        return attributes.ATTR_WAS_SET
예제 #5
0
    def __call__(self):
        if not mapper.has_identity(self.instance):
            return None
            
        localparent = mapper.object_mapper(self.instance, raiseerror=False)
        
        prop = localparent.get_property(self.key)
        strategy = prop._get_strategy(DeferredColumnLoader)

        if self.keys:
            toload = self.keys
        elif strategy.group:
            toload = [p.key for p in localparent.iterate_properties if isinstance(p.strategy, DeferredColumnLoader) and p.group==strategy.group]
        else:
            toload = [self.key]

        # narrow the keys down to just those which have no history
        group = [k for k in toload if k in self.instance._state.unmodified]

        if strategy._should_log_debug:
            strategy.logger.debug("deferred load %s group %s" % (mapperutil.attribute_str(self.instance, self.key), group and ','.join(group) or 'None'))

        session = sessionlib.object_session(self.instance)
        if session is None:
            raise exceptions.UnboundExecutionError("Parent instance %s is not bound to a Session; deferred load operation of attribute '%s' cannot proceed" % (self.instance.__class__, self.key))

        query = session.query(localparent)
        if not self.optimizing_statement:
            ident = self.instance._instance_key[1]
            query._get(None, ident=ident, only_load_props=group, refresh_instance=self.instance._state)
        else:
            statement, params = self.optimizing_statement(self.instance)
            query.from_statement(statement).params(params)._get(None, only_load_props=group, refresh_instance=self.instance._state)
        return attributes.ATTR_WAS_SET
예제 #6
0
    def register_object(self, obj, isdelete = False, listonly = False, postupdate=False, post_update_cols=None, **kwargs):
        """Add an object to this UOWTransaction to be updated in the database.

        `isdelete` indicates whether the object is to be deleted or
        saved (update/inserted).

        `listonly` indicates that only this object's dependency
        relationships should be refreshed/updated to reflect a recent
        save/upcoming delete operation, but not a full save/delete
        operation on the object itself, unless an additional
        save/delete registration is entered for the object.
        """

        #print "REGISTER", repr(obj), repr(getattr(obj, '_instance_key', None)), str(isdelete), str(listonly)

        # if object is not in the overall session, do nothing
        if not self.uow._is_valid(obj):
            return

        mapper = object_mapper(obj)
        self.mappers.add(mapper)
        task = self.get_task_by_mapper(mapper)
        if postupdate:
            task.append_postupdate(obj, post_update_cols)
            return

        # for a cyclical task, things need to be sorted out already,
        # so this object should have already been added to the appropriate sub-task
        # can put an assertion here to make sure....
        if task.circular:
            return

        task.append(obj, listonly, isdelete=isdelete, **kwargs)
예제 #7
0
    def setup_loader(self, instance, options=None):
        if not mapper.has_mapper(instance):
            return None
        else:
            prop = mapper.object_mapper(instance).props[self.key]
            if prop is not self.parent_property:
                return prop._get_strategy(LazyLoader).setup_loader(instance)
        def lazyload():
            self.logger.debug("lazy load attribute %s on instance %s" % (self.key, mapperutil.instance_str(instance)))
            params = {}
            allparams = True
            # if the instance wasnt loaded from the database, then it cannot lazy load
            # child items.  one reason for this is that a bi-directional relationship
            # will not update properly, since bi-directional uses lazy loading functions
            # in both directions, and this instance will not be present in the lazily-loaded
            # results of the other objects since its not in the database
            if not mapper.has_identity(instance):
                return None
            #print "setting up loader, lazywhere", str(self.lazywhere), "binds", self.lazybinds
            for col, bind in self.lazybinds.iteritems():
                params[bind.key] = self.parent.get_attr_by_column(instance, col)
                if params[bind.key] is None:
                    allparams = False
                    break

            if not allparams:
                return None

            session = sessionlib.object_session(instance)
            if session is None:
                try:
                    session = mapper.object_mapper(instance).get_session()
                except exceptions.InvalidRequestError:
                    raise exceptions.InvalidRequestError("Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key))

            # if we have a simple straight-primary key load, use mapper.get()
            # to possibly save a DB round trip
            if self.use_get:
                ident = []
                for primary_key in self.select_mapper.pks_by_table[self.select_mapper.mapped_table]:
                    bind = self.lazyreverse[primary_key]
                    ident.append(params[bind.key])
                return session.query(self.mapper).get(ident)
            elif self.order_by is not False:
                order_by = self.order_by
            elif self.secondary is not None and self.secondary.default_order_by() is not None:
                order_by = self.secondary.default_order_by()
            else:
                order_by = False
            result = session.query(self.mapper, with_options=options).select_whereclause(self.lazywhere, order_by=order_by, params=params)

            if self.uselist:
                return result
            else:
                if len(result):
                    return result[0]
                else:
                    return None
        return lazyload
예제 #8
0
 def append(self, event, obj, item):
     # process "save_update" cascade rules for when an instance is appended to the list of another instance
     sess = object_session(obj)
     if sess is not None:
         if self.cascade is not None and self.cascade.save_update and item not in sess:
             mapper = object_mapper(obj)
             prop = mapper.props[self.key]
             ename = prop.mapper.entity_name
             sess.save_or_update(item, entity_name=ename)
예제 #9
0
 def unregister_object(self, obj):
     """remove an object from its parent UOWTask.
     
     called by mapper.save_obj() when an 'identity switch' is detected, so that
     no further operations occur upon the instance."""
     mapper = object_mapper(obj)
     task = self.get_task_by_mapper(mapper)
     if obj in task._objects:
         task.delete(obj)
예제 #10
0
 def set(self, event, obj, newvalue, oldvalue):
     # process "save_update" cascade rules for when an instance is attached to another instance
     sess = object_session(obj)
     if sess is not None:
         if newvalue is not None and self.cascade is not None and self.cascade.save_update and newvalue not in sess:
             mapper = object_mapper(obj)
             prop = mapper.props[self.key]
             ename = prop.mapper.entity_name
             sess.save_or_update(newvalue, entity_name=ename)
예제 #11
0
 def set(self, obj, newvalue, oldvalue, initiator):
     # process "save_update" cascade rules for when an instance is attached to another instance
     sess = object_session(obj)
     if sess is not None:
         if newvalue is not None and self.cascade is not None and self.cascade.save_update and newvalue not in sess:
             mapper = object_mapper(obj)
             prop = mapper.get_property(self.key)
             ename = prop.mapper.entity_name
             sess.save_or_update(newvalue, entity_name=ename)
예제 #12
0
        def lazyload():
            if self._should_log_debug:
                self.logger.debug(
                    "lazy load attribute %s on instance %s" %
                    (self.key, mapperutil.instance_str(instance)))

            if not mapper.has_identity(instance):
                return None

            session = sessionlib.object_session(instance)
            if session is None:
                try:
                    session = mapper.object_mapper(instance).get_session()
                except exceptions.InvalidRequestError:
                    raise exceptions.InvalidRequestError(
                        "Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed"
                        % (instance.__class__, self.key))

            # if we have a simple straight-primary key load, use mapper.get()
            # to possibly save a DB round trip
            q = session.query(self.mapper).autoflush(False)
            if self.use_get:
                params = {}
                for col, bind in self.lazybinds.iteritems():
                    params[bind.key] = self.parent.get_attr_by_column(
                        instance, col)
                ident = []
                nonnulls = False
                for primary_key in self.select_mapper.primary_key:
                    bind = self.lazyreverse[primary_key]
                    v = params[bind.key]
                    if v is not None:
                        nonnulls = True
                    ident.append(v)
                if not nonnulls:
                    return None
                if options:
                    q = q.options(*options)
                return q.get(ident)
            elif self.order_by is not False:
                q = q.order_by(self.order_by)
            elif self.secondary is not None and self.secondary.default_order_by(
            ) is not None:
                q = q.order_by(self.secondary.default_order_by())

            if options:
                q = q.options(*options)
            q = q.filter(self.lazy_clause(instance))

            result = q.all()
            if self.uselist:
                return result
            else:
                if result:
                    return result[0]
                else:
                    return None
예제 #13
0
 def unregister_object(self, obj):
     """remove an object from its parent UOWTask.
     
     called by mapper._save_obj() when an 'identity switch' is detected, so that
     no further operations occur upon the instance."""
     mapper = object_mapper(obj)
     task = self.get_task_by_mapper(mapper)
     if obj._state in task._objects:
         task.delete(obj._state)
예제 #14
0
        def lazyload():
            if self._should_log_debug:
                self.logger.debug("deferred load %s group %s" %
                                  (mapperutil.attribute_str(
                                      instance, self.key), str(self.group)))

            if not mapper.has_identity(instance):
                return None

            try:
                pk = self.parent.pks_by_table[self.columns[0].table]
            except KeyError:
                pk = self.columns[0].table.primary_key

            clause = sql.and_()
            for primary_key in pk:
                attr = self.parent.get_attr_by_column(instance, primary_key)
                if not attr:
                    return None
                clause.clauses.append(primary_key == attr)

            session = sessionlib.object_session(instance)
            if session is None:
                raise exceptions.InvalidRequestError(
                    "Parent instance %s is not bound to a Session; deferred load operation of attribute '%s' cannot proceed"
                    % (instance.__class__, self.key))

            localparent = mapper.object_mapper(instance)
            if self.group is not None:
                groupcols = [
                    p for p in localparent.props.values()
                    if isinstance(p.strategy, DeferredColumnLoader)
                    and p.group == self.group
                ]
                result = session.execute(
                    localparent,
                    sql.select([g.columns[0] for g in groupcols],
                               clause,
                               use_labels=True), None)
                try:
                    row = result.fetchone()
                    for prop in groupcols:
                        if prop is self:
                            continue
                        # set a scalar object instance directly on the object,
                        # bypassing SmartProperty event handlers.
                        sessionlib.attribute_manager.init_instance_attribute(
                            instance, prop.key, uselist=False)
                        instance.__dict__[prop.key] = row[prop.columns[0]]
                    return row[self.columns[0]]
                finally:
                    result.close()
            else:
                return session.scalar(
                    localparent,
                    sql.select([self.columns[0]], clause, use_labels=True),
                    None)
예제 #15
0
 def append(self, obj, item, initiator):
     # process "save_update" cascade rules for when an instance is appended to the list of another instance
     sess = object_session(obj)
     if sess is not None:
         if self.cascade is not None and self.cascade.save_update and item not in sess:
             mapper = object_mapper(obj)
             prop = mapper.get_property(self.key)
             ename = prop.mapper.entity_name
             sess.save_or_update(item, entity_name=ename)
예제 #16
0
    def __call__(self):
        instance = self.instance
        
        if not mapper.has_identity(instance):
            return None

        instance_mapper = mapper.object_mapper(instance)
        prop = instance_mapper.get_property(self.key)
        strategy = prop._get_strategy(LazyLoader)
        
        if strategy._should_log_debug:
            strategy.logger.debug("lazy load attribute %s on instance %s" % (self.key, mapperutil.instance_str(instance)))

        session = sessionlib.object_session(instance)
        if session is None:
            try:
                session = instance_mapper.get_session()
            except exceptions.InvalidRequestError:
                raise exceptions.UnboundExecutionError("Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key))

        q = session.query(prop.mapper).autoflush(False)
        if self.path:
            q = q._with_current_path(self.path)
            
        # if we have a simple primary key load, use mapper.get()
        # to possibly save a DB round trip
        if strategy.use_get:
            ident = []
            allnulls = True
            for primary_key in prop.mapper.primary_key: 
                val = instance_mapper._get_committed_attr_by_column(instance, strategy._equated_columns[primary_key])
                allnulls = allnulls and val is None
                ident.append(val)
            if allnulls:
                return None
            if self.options:
                q = q._conditional_options(*self.options)
            return q.get(ident)
            
        if strategy.order_by is not False:
            q = q.order_by(strategy.order_by)
        elif strategy.secondary is not None and strategy.secondary.default_order_by() is not None:
            q = q.order_by(strategy.secondary.default_order_by())

        if self.options:
            q = q._conditional_options(*self.options)
        q = q.filter(strategy.lazy_clause(instance))

        result = q.all()
        if strategy.uselist:
            return result
        else:
            if result:
                return result[0]
            else:
                return None
예제 #17
0
    def __call__(self):
        instance = self.instance
        
        if not mapper.has_identity(instance):
            return None

        instance_mapper = mapper.object_mapper(instance)
        prop = instance_mapper.get_property(self.key)
        strategy = prop._get_strategy(LazyLoader)
        
        if strategy._should_log_debug:
            strategy.logger.debug("lazy load attribute %s on instance %s" % (self.key, mapperutil.instance_str(instance)))

        session = sessionlib.object_session(instance)
        if session is None:
            try:
                session = instance_mapper.get_session()
            except exceptions.InvalidRequestError:
                raise exceptions.UnboundExecutionError("Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key))

        q = session.query(prop.mapper).autoflush(False)
        if self.path:
            q = q._with_current_path(self.path)
            
        # if we have a simple primary key load, use mapper.get()
        # to possibly save a DB round trip
        if strategy.use_get:
            ident = []
            allnulls = True
            for primary_key in prop.mapper.primary_key: 
                val = instance_mapper._get_committed_attr_by_column(instance, strategy._equated_columns[primary_key])
                allnulls = allnulls and val is None
                ident.append(val)
            if allnulls:
                return None
            if self.options:
                q = q._conditional_options(*self.options)
            return q.get(ident)
            
        if strategy.order_by is not False:
            q = q.order_by(strategy.order_by)
        elif strategy.secondary is not None and strategy.secondary.default_order_by() is not None:
            q = q.order_by(strategy.secondary.default_order_by())

        if self.options:
            q = q._conditional_options(*self.options)
        q = q.filter(strategy.lazy_clause(instance))

        result = q.all()
        if strategy.uselist:
            return result
        else:
            if result:
                return result[0]
            else:
                return None
예제 #18
0
 def register_clean(self, obj):
     if obj in self.new:
         self.new.remove(obj)
     if not hasattr(obj, '_instance_key'):
         mapper = object_mapper(obj)
         obj._instance_key = mapper.instance_key(obj)
     if hasattr(obj, '_sa_insert_order'):
         delattr(obj, '_sa_insert_order')
     self.identity_map[obj._instance_key] = obj
     attribute_manager.commit(obj)
예제 #19
0
 def register_clean(self, obj):
     if obj in self.new:
         self.new.remove(obj)
     if not hasattr(obj, '_instance_key'):
         mapper = object_mapper(obj)
         obj._instance_key = mapper.instance_key(obj)
     if hasattr(obj, '_sa_insert_order'):
         delattr(obj, '_sa_insert_order')
     self.identity_map[obj._instance_key] = obj
     attribute_manager.commit(obj)
예제 #20
0
 def register_clean(self, obj):
     """register the given object as 'clean' (i.e. persistent) within this unit of work."""
     
     if obj in self.new:
         self.new.remove(obj)
     if not hasattr(obj, '_instance_key'):
         mapper = object_mapper(obj)
         obj._instance_key = mapper.instance_key(obj)
     if hasattr(obj, '_sa_insert_order'):
         delattr(obj, '_sa_insert_order')
     self.identity_map[obj._instance_key] = obj
     attribute_manager.commit(obj)
예제 #21
0
    def _register_clean(self, obj):
        """register the given object as 'clean' (i.e. persistent) within this unit of work, after
        a save operation has taken place."""

        if obj in self.new:
            self.new.remove(obj)
        if not hasattr(obj, '_instance_key'):
            mapper = object_mapper(obj)
            obj._instance_key = mapper.identity_key_from_instance(obj)
        if hasattr(obj, '_sa_insert_order'):
            delattr(obj, '_sa_insert_order')
        self.identity_map[obj._instance_key] = obj
        attribute_manager.commit(obj)
예제 #22
0
def object_was_deleted(session, obj):
    # hopefully there is a more future proof way to do this...
    from sqlalchemy.orm.mapper import object_mapper
    for c in [obj] + list(
            object_mapper(obj).cascade_iterator('delete', obj._state)):
        if c in session.deleted:
            return True


#         elif not session.uow._is_valid(c._state):
#             # it must have been deleted elsewhere.  is there any other
#             # reason for this scenario?
#             return True
    return False
예제 #23
0
    def _clone(self, sess=None):
        # note we're returning an entirely new Query class instance here
        # without any assignment capabilities;
        # the class of this query is determined by the session.
        instance = self.state.obj()
        if sess is None:
            sess = object_session(instance)
            if sess is None:
                try:
                    sess = object_mapper(instance).get_session()
                except exceptions.InvalidRequestError:
                    raise exceptions.InvalidRequestError("Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (self.instance.__class__, self.key))

        return sess.query(self.attr.target_mapper).with_parent(instance)
예제 #24
0
    def setup_loader(self, instance, options=None):
        if not mapper.has_mapper(instance):
            return None
        else:
            prop = mapper.object_mapper(instance).props[self.key]
            if prop is not self.parent_property:
                return prop._get_strategy(DeferredColumnLoader).setup_loader(instance)
        def lazyload():
            if self._should_log_debug:
                self.logger.debug("deferred load %s group %s" % (mapperutil.attribute_str(instance, self.key), str(self.group)))

            if not mapper.has_identity(instance):
                return None

            try:
                pk = self.parent.pks_by_table[self.columns[0].table]
            except KeyError:
                pk = self.columns[0].table.primary_key

            clause = sql.and_()
            for primary_key in pk:
                attr = self.parent.get_attr_by_column(instance, primary_key)
                if not attr:
                    return None
                clause.clauses.append(primary_key == attr)

            session = sessionlib.object_session(instance)
            if session is None:
                raise exceptions.InvalidRequestError("Parent instance %s is not bound to a Session; deferred load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key))

            localparent = mapper.object_mapper(instance)
            if self.group is not None:
                groupcols = [p for p in localparent.props.values() if isinstance(p.strategy, DeferredColumnLoader) and p.group==self.group]
                result = session.execute(localparent, sql.select([g.columns[0] for g in groupcols], clause, use_labels=True), None)
                try:
                    row = result.fetchone()
                    for prop in groupcols:
                        if prop is self:
                            continue
                        # set a scalar object instance directly on the object, 
                        # bypassing SmartProperty event handlers.
                        sessionlib.attribute_manager.init_instance_attribute(instance, prop.key, uselist=False)
                        instance.__dict__[prop.key] = row[prop.columns[0]]
                    return row[self.columns[0]]    
                finally:
                    result.close()
            else:
                return session.scalar(localparent, sql.select([self.columns[0]], clause, use_labels=True),None)

        return lazyload
예제 #25
0
    def class_level_loader(self, instance, props=None):
        if not mapper.has_mapper(instance):
            return None
            
        localparent = mapper.object_mapper(instance)

        # adjust for the ColumnProperty associated with the instance
        # not being our own ColumnProperty.  This can occur when entity_name
        # mappers are used to map different versions of the same ColumnProperty
        # to the class.
        prop = localparent.get_property(self.key)
        if prop is not self.parent_property:
            return prop._get_strategy(DeferredColumnLoader).setup_loader(instance)

        return LoadDeferredColumns(instance, self.key, props)
예제 #26
0
    def class_level_loader(self, instance, options=None, path=None):
        if not mapper.has_mapper(instance):
            return None

        localparent = mapper.object_mapper(instance)

        # adjust for the PropertyLoader associated with the instance
        # not being our own PropertyLoader.  This can occur when entity_name
        # mappers are used to map different versions of the same PropertyLoader
        # to the class.
        prop = localparent.get_property(self.key)
        if prop is not self.parent_property:
            return prop._get_strategy(LazyLoader).setup_loader(instance)
        
        return LoadLazyAttribute(instance, self.key, options, path)
예제 #27
0
    def class_level_loader(self, instance, options=None, path=None):
        if not mapper.has_mapper(instance):
            return None

        localparent = mapper.object_mapper(instance)

        # adjust for the PropertyLoader associated with the instance
        # not being our own PropertyLoader.  This can occur when entity_name
        # mappers are used to map different versions of the same PropertyLoader
        # to the class.
        prop = localparent.get_property(self.key)
        if prop is not self.parent_property:
            return prop._get_strategy(LazyLoader).setup_loader(instance)

        return LoadLazyAttribute(instance, self.key, options, path)
예제 #28
0
        def __init__(self, obj):
            self.columns = obj.c
            self.id_attr = obj.id.key

            from sqlalchemy.orm.mapper import object_mapper
            # is this safe?
            self.mapper = object_mapper(obj())

            if self.mapper.local_table:
                self.table = self.mapper.local_table
            elif self.mapper.select_table:
                self.table = self.mapper.select_table
            else:
                raise LookupError(
                    "not sure how to get a table from mapper %s" % self.mapper)
예제 #29
0
    def class_level_loader(self, instance, props=None):
        if not mapper.has_mapper(instance):
            return None
            
        localparent = mapper.object_mapper(instance)

        # adjust for the ColumnProperty associated with the instance
        # not being our own ColumnProperty.  This can occur when entity_name
        # mappers are used to map different versions of the same ColumnProperty
        # to the class.
        prop = localparent.get_property(self.key)
        if prop is not self.parent_property:
            return prop._get_strategy(DeferredColumnLoader).setup_loader(instance)

        return LoadDeferredColumns(instance, self.key, props)
예제 #30
0
        def __init__(self, obj):
            self.columns = obj.c

            # could grab this from the Handler :
            from sqlalchemy.orm.mapper import object_mapper
            self.mapper = object_mapper(obj())

            if self.mapper.local_table:
                self.table = self.mapper.local_table
            elif self.mapper.select_table:
                self.table = self.mapper.select_table
            else:
                raise LookupError(
                    "not sure how to get a table from mapper %s" % self.mapper)

            self.id_attr = self.table.primary_key.columns.keys()
예제 #31
0
 def __init__(self, obj):
     self.columns = obj.c
     
     # could grab this from the Handler :
     from sqlalchemy.orm.mapper import object_mapper
     self.mapper = object_mapper(obj())
     
     if self.mapper.local_table:
         self.table = self.mapper.local_table
     elif self.mapper.select_table:
         self.table = self.mapper.select_table
     else:
         raise LookupError(
             "not sure how to get a table from mapper %s" % 
                                                 self.mapper)
     
     self.id_attr = self.table.primary_key.columns.keys()
예제 #32
0
    def _clone(self, sess=None):
        # note we're returning an entirely new Query class instance here
        # without any assignment capabilities;
        # the class of this query is determined by the session.
        instance = self.instance
        if sess is None:
            sess = object_session(instance)
            if sess is None:
                try:
                    sess = object_mapper(instance).get_session()
                except exceptions.InvalidRequestError:
                    raise exceptions.UnboundExecutionError("Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (mapperutil.instance_str(instance), self.attr.key))

        q = sess.query(self.attr.target_mapper).with_parent(instance, self.attr.key)
        if self.attr.order_by:
            q = q.order_by(self.attr.order_by)
        return q
예제 #33
0
    def register_object(self,
                        obj,
                        isdelete=False,
                        listonly=False,
                        postupdate=False,
                        post_update_cols=None,
                        **kwargs):
        """Add an object to this UOWTransaction to be updated in the database.

        `isdelete` indicates whether the object is to be deleted or
        saved (update/inserted).

        `listonly` indicates that only this object's dependency
        relationships should be refreshed/updated to reflect a recent
        save/upcoming delete operation, but not a full save/delete
        operation on the object itself, unless an additional
        save/delete registration is entered for the object.
        """

        #print "REGISTER", repr(obj), repr(getattr(obj, '_instance_key', None)), str(isdelete), str(listonly)

        # if object is not in the overall session, do nothing
        if not self.uow._is_valid(obj):
            return

        mapper = object_mapper(obj)
        self.mappers.add(mapper)
        task = self.get_task_by_mapper(mapper)
        if postupdate:
            task.append_postupdate(obj, post_update_cols)
            return

        # for a cyclical task, things need to be sorted out already,
        # so this object should have already been added to the appropriate sub-task
        # can put an assertion here to make sure....
        if task.circular:
            return

        task.append(obj, listonly, isdelete=isdelete, **kwargs)
예제 #34
0
    def register_object(self,
                        obj,
                        isdelete=False,
                        listonly=False,
                        postupdate=False,
                        post_update_cols=None,
                        **kwargs):
        """Add an object to this ``UOWTransaction`` to be updated in the database.

        This operation has the combined effect of locating/creating an appropriate
        ``UOWTask`` object, and calling its ``append()`` method which then locates/creates
        an appropriate ``UOWTaskElement`` object.
        """

        #print "REGISTER", repr(obj), repr(getattr(obj, '_instance_key', None)), str(isdelete), str(listonly)

        # if object is not in the overall session, do nothing
        if not self.uow._is_valid(obj):
            if self._should_log_debug:
                self.logger.debug(
                    "object %s not part of session, not registering for flush"
                    % (mapperutil.instance_str(obj)))
            return

        if self._should_log_debug:
            self.logger.debug(
                "register object for flush: %s isdelete=%s listonly=%s postupdate=%s"
                %
                (mapperutil.instance_str(obj), isdelete, listonly, postupdate))

        mapper = object_mapper(obj)
        task = self.get_task_by_mapper(mapper)
        if postupdate:
            task.append_postupdate(obj, post_update_cols)
            return

        task.append(obj, listonly, isdelete=isdelete, **kwargs)
예제 #35
0
 def keyfunc(value):
     m = mapper.object_mapper(value)
     return tuple(
         [m.get_attr_by_column(value, c) for c in mapping_spec])
예제 #36
0
 def keyfunc(value):
     m = mapper.object_mapper(value)
     return m.get_attr_by_column(value, mapping_spec)
예제 #37
0
 def unregister_object(self, obj):
     #print "UNREGISTER", obj
     mapper = object_mapper(obj)
     task = self.get_task_by_mapper(mapper)
     if obj in task.objects:
         task.delete(obj)
예제 #38
0
    def flush(self, session, objects=None):
        """create a dependency tree of all pending SQL operations within this unit of work and execute."""

        # this context will track all the objects we want to save/update/delete,
        # and organize a hierarchical dependency structure.  it also handles
        # communication with the mappers and relationships to fire off SQL
        # and synchronize attributes between related objects.

        # detect persistent objects that have changes
        dirty = self.locate_dirty()

        if len(dirty) == 0 and len(self.deleted) == 0 and len(self.new) == 0:
            return

        flush_context = UOWTransaction(self, session)

        if session.extension is not None:
            session.extension.before_flush(session, flush_context, objects)

        # create the set of all objects we want to operate upon
        if objects is not None:
            # specific list passed in
            objset = util.Set(objects)
        else:
            # or just everything
            objset = util.Set(self.identity_map.values()).union(self.new)

        # store objects whose fate has been decided
        processed = util.Set()

        # put all saves/updates into the flush context.  detect top-level orphans and throw them into deleted.
        for obj in self.new.union(dirty).intersection(objset).difference(
                self.deleted):
            if obj in processed:
                continue

            flush_context.register_object(
                obj, isdelete=object_mapper(obj)._is_orphan(obj))
            processed.add(obj)

        # put all remaining deletes into the flush context.
        for obj in self.deleted.intersection(objset).difference(processed):
            flush_context.register_object(obj, isdelete=True)

        if len(flush_context.tasks) == 0:
            return

        session.create_transaction(autoflush=False)
        flush_context.transaction = session.transaction
        try:
            flush_context.execute()

            if session.extension is not None:
                session.extension.after_flush(session, flush_context)
        except:
            session.rollback()
            raise
        session.commit()

        flush_context.post_exec()

        if session.extension is not None:
            session.extension.after_flush_postexec(session, flush_context)
예제 #39
0
 def unregister_object(self, obj):
     #print "UNREGISTER", obj
     mapper = object_mapper(obj)
     task = self.get_task_by_mapper(mapper)
     if obj in task.objects:
         task.delete(obj)
예제 #40
0
 def is_deleted(self, obj):
     mapper = object_mapper(obj)
     task = self.get_task_by_mapper(mapper)
     return task.is_deleted(obj)
예제 #41
0
    def is_deleted(self, obj):
        """return true if the given object is marked as deleted within this UOWTransaction."""

        mapper = object_mapper(obj)
        task = self.get_task_by_mapper(mapper)
        return task.is_deleted(obj)
예제 #42
0
 def is_deleted(self, obj):
     """return true if the given object is marked as deleted within this UOWTransaction."""
     
     mapper = object_mapper(obj)
     task = self.get_task_by_mapper(mapper)
     return task.is_deleted(obj)
예제 #43
0
 def _target_mapper(self, obj):
     prop = object_mapper(obj).get_property(self.key)
     return prop.mapper
예제 #44
0
        def lazyload():
            self.logger.debug("lazy load attribute %s on instance %s" %
                              (self.key, mapperutil.instance_str(instance)))
            params = {}
            allparams = True
            # if the instance wasnt loaded from the database, then it cannot lazy load
            # child items.  one reason for this is that a bi-directional relationship
            # will not update properly, since bi-directional uses lazy loading functions
            # in both directions, and this instance will not be present in the lazily-loaded
            # results of the other objects since its not in the database
            if not mapper.has_identity(instance):
                return None
            #print "setting up loader, lazywhere", str(self.lazywhere), "binds", self.lazybinds
            for col, bind in self.lazybinds.iteritems():
                params[bind.key] = self.parent.get_attr_by_column(
                    instance, col)
                if params[bind.key] is None:
                    allparams = False
                    break

            if not allparams:
                return None

            session = sessionlib.object_session(instance)
            if session is None:
                try:
                    session = mapper.object_mapper(instance).get_session()
                except exceptions.InvalidRequestError:
                    raise exceptions.InvalidRequestError(
                        "Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed"
                        % (instance.__class__, self.key))

            # if we have a simple straight-primary key load, use mapper.get()
            # to possibly save a DB round trip
            if self.use_get:
                ident = []
                for primary_key in self.select_mapper.pks_by_table[
                        self.select_mapper.mapped_table]:
                    bind = self.lazyreverse[primary_key]
                    ident.append(params[bind.key])
                return session.query(self.mapper).get(ident)
            elif self.order_by is not False:
                order_by = self.order_by
            elif self.secondary is not None and self.secondary.default_order_by(
            ) is not None:
                order_by = self.secondary.default_order_by()
            else:
                order_by = False
            result = session.query(self.mapper,
                                   with_options=options).select_whereclause(
                                       self.lazywhere,
                                       order_by=order_by,
                                       params=params)

            if self.uselist:
                return result
            else:
                if len(result):
                    return result[0]
                else:
                    return None
예제 #45
0
    def setup_loader(self, instance, props=None, create_statement=None):
        localparent = mapper.object_mapper(instance, raiseerror=False)
        if localparent is None:
            return None

        # adjust for the ColumnProperty associated with the instance
        # not being our own ColumnProperty.  This can occur when entity_name
        # mappers are used to map different versions of the same ColumnProperty
        # to the class.
        prop = localparent.get_property(self.key)
        if prop is not self.parent_property:
            return prop._get_strategy(DeferredColumnLoader).setup_loader(
                instance)

        def lazyload():
            if not mapper.has_identity(instance):
                return None

            if props is not None:
                group = props
            elif self.group is not None:
                group = [
                    p for p in localparent.iterate_properties
                    if isinstance(p.strategy, DeferredColumnLoader)
                    and p.group == self.group
                ]
            else:
                group = [self.parent_property]

            if self._should_log_debug:
                self.logger.debug(
                    "deferred load %s group %s" %
                    (mapperutil.attribute_str(instance, self.key),
                     group and ','.join([p.key for p in group]) or 'None'))

            session = sessionlib.object_session(instance)
            if session is None:
                raise exceptions.InvalidRequestError(
                    "Parent instance %s is not bound to a Session; deferred load operation of attribute '%s' cannot proceed"
                    % (instance.__class__, self.key))

            if create_statement is None:
                (clause, param_map) = localparent._get_clause
                ident = instance._instance_key[1]
                params = {}
                for i, primary_key in enumerate(localparent.primary_key):
                    params[param_map[primary_key].key] = ident[i]
                statement = sql.select([p.columns[0] for p in group],
                                       clause,
                                       from_obj=[localparent.mapped_table],
                                       use_labels=True)
            else:
                statement, params = create_statement()

            # TODO: have the "fetch of one row" operation go through the same channels as a query._get()
            # deferred load of several attributes should be a specialized case of a query refresh operation
            conn = session.connection(mapper=localparent, instance=instance)
            result = conn.execute(statement, params)
            try:
                row = result.fetchone()
                for prop in group:
                    sessionlib.attribute_manager.set_committed_value(
                        instance, prop.key, row[prop.columns[0]])
                return attributes.ATTR_WAS_SET
            finally:
                result.close()

        return lazyload
예제 #46
0
 def is_deleted(self, obj):
     mapper = object_mapper(obj)
     task = self.get_task_by_mapper(mapper)
     return task.is_deleted(obj)
예제 #47
0
 def _target_mapper(self, obj):
     prop = object_mapper(obj).get_property(self.key)
     return prop.mapper