예제 #1
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
예제 #2
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
예제 #3
0
 def __session(self):
     sess = object_session(self.instance)
     if sess is not None and self.autoflush and sess.autoflush and self.instance in sess:
         sess.flush()
     if not has_identity(self.instance):
         return None
     else:
         return sess
예제 #4
0
 def assign(self, collection):
     instance = self.state.obj()
     if has_identity(instance):
         oldlist = list(self)
     else:
         oldlist = []
     self.attr.get_history(self.state).replace(oldlist, collection)
     return oldlist
예제 #5
0
 def assign(self, collection):
     instance = self.instance
     if has_identity(instance):
         oldlist = list(self)
     else:
         oldlist = []
     self.attr._get_collection_history(self.instance._state, passive=True).replace(oldlist, collection)
     return oldlist
예제 #6
0
 def __session(self):
     sess = object_session(self.instance)
     if sess is not None and self.autoflush and sess.autoflush and self.instance in sess:
         sess.flush()
     if not has_identity(self.instance):
         return None
     else:
         return sess
예제 #7
0
 def assign(self, collection):
     instance = self.instance
     if has_identity(instance):
         oldlist = list(self)
     else:
         oldlist = []
     self.attr._get_collection(self.instance._state,
                               passive=True).replace(oldlist, collection)
     return oldlist
예제 #8
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
예제 #9
0
 def __session(self):
     instance = self.state.obj()
     sess = object_session(instance)
     if sess is not None and instance in sess and sess.autoflush:
         sess.flush()
     if not has_identity(instance):
         return None
     else:
         return sess
예제 #10
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)
예제 #11
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
예제 #12
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
예제 #13
0
        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()
예제 #14
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
예제 #15
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)
예제 #16
0
    def flush(self, session, objects=None):
        """create a dependency tree of all pending SQL operations within this unit of work and execute."""

        dirty = [x for x in self.identity_map.all_states()
            if x.modified
            or (x.class_._class_state.has_mutable_scalars and x.is_modified())
        ]
        
        if not dirty and not self.deleted and not self.new:
            return
        
        deleted = util.Set(self.deleted)
        new = util.Set(self.new)
        
        dirty = util.Set(dirty).difference(deleted)
        
        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:
            # specific list passed in
            objset = util.Set([o._state for o in objects])
        else:
            # or just everything
            objset = util.Set(self.identity_map.all_states()).union(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 state in new.union(dirty).intersection(objset).difference(deleted):
            if state in processed:
                continue

            obj = state.obj()
            is_orphan = _state_mapper(state)._is_orphan(obj)
            if is_orphan and not has_identity(obj):
                raise exceptions.FlushError("instance %s is an unsaved, pending instance and is an orphan (is not attached to %s)" %
                    (
                        obj,
                        ", nor ".join(["any parent '%s' instance via that classes' '%s' attribute" % (klass.__name__, key) for (key,klass) in _state_mapper(state).delete_orphans])
                    ))
            flush_context.register_object(state, isdelete=is_orphan)
            processed.add(state)

        # put all remaining deletes into the flush context.
        for state in deleted.intersection(objset).difference(processed):
            flush_context.register_object(state, 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)
            session.commit()
        except:
            session.rollback()
            raise

        for state in deleted.intersection(objset):
            state.is_deleted = True

        flush_context.post_exec()

        if session.extension is not None:
            session.extension.after_flush_postexec(session, flush_context)
예제 #17
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
예제 #18
0
    def flush(self, session, objects=None):
        """create a dependency tree of all pending SQL operations within this unit of work and execute."""

        dirty = [x for x in self.identity_map.all_states()
            if x.modified
            or (x.class_._class_state.has_mutable_scalars and x.is_modified())
        ]
        
        if not dirty and not self.deleted and not self.new:
            return
        
        deleted = util.Set(self.deleted)
        new = util.Set(self.new)
        
        dirty = util.Set(dirty).difference(deleted)
        
        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:
            # specific list passed in
            objset = util.Set([o._state for o in objects])
        else:
            # or just everything
            objset = util.Set(self.identity_map.all_states()).union(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 state in new.union(dirty).intersection(objset).difference(deleted):
            if state in processed:
                continue

            obj = state.obj()
            is_orphan = _state_mapper(state)._is_orphan(obj)
            if is_orphan and not has_identity(obj):
                raise exceptions.FlushError("instance %s is an unsaved, pending instance and is an orphan (is not attached to %s)" %
                    (
                        obj,
                        ", nor ".join(["any parent '%s' instance via that classes' '%s' attribute" % (klass.__name__, key) for (key,klass) in _state_mapper(state).delete_orphans])
                    ))
            flush_context.register_object(state, isdelete=is_orphan)
            processed.add(state)

        # put all remaining deletes into the flush context.
        for state in deleted.intersection(objset).difference(processed):
            flush_context.register_object(state, 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)
            session.commit()
        except:
            session.rollback()
            raise

        flush_context.post_exec()

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