Beispiel #1
0
    def __perform_updates__(self, update_cursor, select_after_update=False):
        if len(self.__changed_columns__) == 0:
            return
        else:
            info = {}
            for column, datatypes in self.__changed_columns__.items():
                for dt in datatypes:
                    if not info.has_key(column):
                        update_expression = dt.update_expression(self)
                        if update_expression is not None:
                            info[column] = update_expression

            statement = sql.update(self.__relation__, self.__primary_key__.where(), info)

            update_cursor.execute(statement)

            if select_after_update:
                need_select = []
                for column, dbprops in self.__changed_columns__.items():
                    dbprops = filter(lambda d: d.__select_after_insert__(self), dbprops)
                    if len(dbprops) > 0:
                        need_select.append((column, dbprops))

                if len(need_select) > 0:
                    columns = map(lambda (c, d): c, need_select)
                    query = sql.select(columns, self.__relation__, self.__primary_key__.where())
                    update_cursor.execute(query)
                    tpl = update_cursor.fetchone()

                    for (column, dbprops), value in zip(need_select, tpl):
                        for dbprop in dbprops:
                            dbprop.__set_from_result__(self.__ds__(), self, value)

            # Clear the list of changed columns
            self.__changed_columns__.clear()
Beispiel #2
0
        def all(self, *clauses):
            """
            This method will return all entries in the child relation (or a
            subset specified by clauses) and a list of those primary keys
            which are present in the link table. You can check if a dbobj is
            linked by doing:

                >>> result, active_keys = dbobj.relation.all()
                >>> for a in result:
                ...     if a.__primary_key__.values() in active_keys:
                ...         do_something(a)
                ...     else:
                ...         do_somethin_else(a)

            
            """
            if self.dbobj.__is_stored__():
                relations = ( self.relationship.link_relation,
                              self.child_class().__view__, ) 
                join_clauses = self.add_where(clauses)
                
                child_pkey = keys.primary_key(self.child_class())
                query = sql.select( tuple(child_pkey.columns()),
                                    relations, *join_clauses)
                
                cursor = self.ds().execute(query)
                active_keys = list(cursor.fetchall())
            else:
                active_keys = []

            result = self.ds().select(self.child_class(), *clauses)

            return ( result, active_keys, )
Beispiel #3
0
        def select(self, *clauses):
            """
            Use like this:

               >>> result = dbobj.children.select(sql.where(...))

            This will yield those child objects that fit the condition
            in the where statements. Note that your WHERE will be
            integrated into a more complex WHERE clause. The many2many
            relationship uses a LEFT JOIN to connect the link_relation
            and the child relation.  You must do that by hand. Also,
            doing so might mess up your db, so you might want to use
            FOREIGN KEY constraints on the link relation.
            """
            relations = ( self.relationship.link_relation,
                          self.child_class().__view__, )

            clauses = self.add_where(clauses)

            query = sql.select(
                self.child_class().__select_expressions__(
                    full_column_names=True),
                relations, *clauses)
            
            return self.ds().run_select(
                self.child_class(), query)
Beispiel #4
0
    def select(self, dbclass, *clauses):
        """
        SELECT dbobjs from the database, according to clauses.

        @param dbclass: The dbclass of the objects to be selected.

        @param clauses: A list of t4.orm.sql clauses instances (or
                        equivalent Python object i.e. strings) that
                        are added to the sql.select query.  See
                        t4.orm.sql.select for details        
        """
        from dbobject import dbobject

        clauses = filter(lambda clause: clause is not None, clauses)
        
        full_column_names = False
        for clause in clauses:
            if isinstance(clause, (sql.left_join, sql.right_join,)):
                full_column_names = True

            # GROUP BY clauses receive special treatment (in a good
            # way): If their first and only column (i.e. parameter
            # passed on creation) is a dbclass, it is replaced by the
            # dbclass' columns. This is a shorthand to formulate
            # joins. (And t4.sql can't know about dbclasses).
            if isinstance(clause, sql.group_by) and \
                    len(clause._columns) == 1 and \
                    hasattr(clause._columns[0], "__select_expressions__"):
                clause._columns = clause._columns[0].__select_expressions__(
                    True)
                
        query = sql.select(dbclass.__select_expressions__(full_column_names),
                           dbclass.__view__, *clauses)
        
        return self.run_select(dbclass, query)
Beispiel #5
0
    def select_after_insert(self, dbobj):
        """
        This method will be run after each INSERT statement automaticaly
        generated by a ds to pick up default values and primary keys set
        by the backend. See insert().
        """
        properties = []
        columns = []
        for property in dbobj.__dbproperties__():
            if property.__select_after_insert__(dbobj):
                properties.append(property)
                columns.append(property.column)

        if len(properties) > 0:
            where = self.select_after_insert_where(dbobj)
            query = sql.select(columns, dbobj.__relation__, where)

            self._modify_cursor.execute(query)
            tpl = self._modify_cursor.fetchone()

            if tpl is None:
                raise ObjectWasNotInserted()
            
            for property, value in zip(properties, tpl):
                property.__set_from_result__(self, dbobj, value)
Beispiel #6
0
 def len(self, *clauses):
     """
     Return the number of child objects associated with a parent.
     You may supply a where clause. The same things apply as for the
     where clause for select(), see above.
     """
     clauses = self.add_where(clauses)
     
     query = sql.select("COUNT(*)",
                        ( self.relationship.link_relation,
                          self.child_class().__view__, ),
                        *clauses)
     
     len, = self.ds().query_one(query)
     return len
Beispiel #7
0
 def count(self, dbclass, *clauses):
     """
     All clauses except the WHERE clause will be ignored
     (including OFFSET and LIMIT!)
     
     @param dbclass: See select() above.
     @param clauses: See select() above.
     
     @return: An integer value indicating the number of objects
              of dbclass select() would return if run with these clauses.
     """
     clauses = filter(lambda clause: (isinstance(clause, sql.where) or
                                      isinstance(clause, sql.left_join)),
                      clauses)
         
     query = sql.select("COUNT(*)", dbclass.__view__, *clauses)
     return self.query_one(query)[0]
Beispiel #8
0
    def __get__(self, dbobj, owner="What??"):
        if dbobj is None: return self
        self.check_dbobj(dbobj)

        if self.isset(dbobj):
            return getattr(dbobj, self.data_attribute_name())
        else:
            # Consturct the SQL query
            query = sql.select( self.child_column.column,
                                self.child_relation,
                                self.child_where(dbobj),
                                self.orderby )
            cursor = dbobj.__ds__().execute(query)
            ret = map(lambda tpl: self.child_column.__convert__(tpl[0]),
                      cursor.fetchall())
            ret = tuple(ret)
            setattr(dbobj, self.data_attribute_name(), ret)
            return ret
Beispiel #9
0
    def count(self):
        """
        This is a helper function that will perform a query as

           SELECT COUNT(*) ...

        appropriate to determine the number of rows in this result.
        This will remove all clauses of the original select except the
        WHERE clause.

        This can't be called __len__(), because then it is used by
        list() and yields a superflous SELECT query.
        """
        if not isinstance(self.select, sql.select):
            raise TypeError("result.count() can only work if the select was a" "sql.select instance!")

        where = filter(lambda clause: isinstance(clause, (sql.where, sql.left_join)), self.select.clauses)
        count_select = sql.select(sql.expression("COUNT(*)"), self.select.relations, *where)
        count, = self.ds.query_one(count_select)
        return count
Beispiel #10
0
   def __get__(self, dbobj, owner="Who??"):
        if dbobj is None: return self
        self.check_dbobj(dbobj)

        if self.isset(dbobj):
            return getattr(dbobj, self.data_attribute_name())
        else:
            # Consturct the SQL query
            query = sql.select( ( self.child_key_column.column,
                                  self.child_value_column.column, ), 
                                self.child_relation,
                                self.child_where(dbobj) )
            cursor = dbobj.__ds__().execute(query)
            ret = map(lambda tpl:
                         ( self.child_key_column.__convert__(tpl[0]),
                           self.child_value_column.__convert__(tpl[1]), ),
                      cursor.fetchall())
            ret = self.sqldict_dict(self, dbobj, dict(ret))
            setattr(dbobj, self.data_attribute_name(), ret)
            return ret
Beispiel #11
0
    def __get__(self, dbobj, owner="I don't know what this is for"):
        if dbobj is None: return self
        
        self.check_dbobj(dbobj)
            
        if self.isset(dbobj):
            return getattr(dbobj, self.data_attribute_name())
        else:
            query = sql.select(( self.column, ),
                               dbobj.__view__,
                               dbobj.__primary_key__.where())
            cursor = dbobj.__ds__().execute(query)
            row = cursor.fetchone()

            if row is None: raise IllegelPrimaryKey() # This shouldn't happen

            value = row[0]

            # The way this is handled is a little strange. Let me explain!
            # The point is, __set_from_result__() may convert the 
            # data retreived from the RDBMS into some other Python
            # representation (t4.orm.util.pickle works that way for instance).
            # So we use the function to do its job and, if we're not supposed
            # to cache the value, *undo* the changes it made on the dbobj.
            # This presumes that the data_attribute_name() mechanism is used
            # by __set_from_result__(), which is relatively save, I guess.
            
            self.inside_datatype.__set_from_result__(dbobj.__ds__(),
                                                     dbobj, value)

            ret = getattr(dbobj, self.data_attribute_name())

            if not self.cache and hasattr(dbobj, self.data_attribute_name()):
                delattr(dbobj, self.data_attribute_name())

            return ret