def insert(self, dbobj, dont_select=False): """ Firebird does not provide a mechanism that let's me query the id of the last row I inserted. This has to be done *before* the INSERT. """ for property in dbobj.__dbproperties__(): if isinstance(property, common_serial): sequence_name = "GEN_PK_%s" % dbobj.__relation__ elif isinstance(property, datatypes.serial): sequence_name = property.sequence else: continue query = sql.select(sql.expression("GEN_ID(", sequence_name, ", 1) AS new_id"), "RDB$DATABASE") cursor = self.execute(query) tpl = cursor.fetchone() new_id = tpl[0] property.__set_from_result__(self, dbobj, new_id) orm2.datasource.datasource_base.insert(self, dbobj, dont_select)
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().__relation__) 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)
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.__relation__, 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 (orm2.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
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().__relation__), *clauses) return self.ds().query_one(query)
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().__relation__, ), *clauses) return self.ds().query_one(query)
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 orm2.sql clauses instances (or equivalent Python object i.e. strings) that are added to the sql.select query. See orm2.sql.select for details """ query = sql.select(dbclass.__select_columns__(), dbclass.__relation__, *clauses) return self.run_select(dbclass, query)
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().__relation__) clauses = self.add_where(clauses) query = sql.select(self.child_class().__select_columns__(), relations, *clauses) return self.ds().run_select(self.child_class(), query)
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) cursor = self.execute(query) tpl = cursor.fetchone() for property, value in zip(properties, tpl): property.__set_from_result__(self, dbobj, value)
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().__relation__, ) 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, )
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. """ where = None for clause in clauses: if isinstance(clause, sql.where): where = clause if where is not None: clauses = [where] else: clauses = [] query = sql.select("COUNT(*)", dbclass.__relation__, *clauses) return self.query_one(query)
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().__relation__, ) clauses = self.add_where(clauses) query = sql.select(self.child_class().__select_columns__(), relations, *clauses) return self.ds().run_select(self.child_class(), query)
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.__relation__, 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 (orm2.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