00001 #ifndef DVMYSQL_ROW_H 00002 #define DVMYSQL_ROW_H 00003 // $Id: row.h,v 1.28 2008/02/25 17:45:28 dvermeir Exp $ 00004 #include <dvmysql/table.h> 00005 #include <dvmysql/object.h> 00006 #include <dvmysql/set.h> 00007 #include <dvmysql/reference.h> 00008 #include <dvmysql/column.h> 00009 00010 namespace Dv { 00011 namespace Sql { 00012 00013 /** A class template of which each instantiation class represents 00014 * the rows of a relational table. 00015 * The template parameter is a (reference to) a Dv::Sql::Table 00016 * object, for which the class instances represent rows. 00017 * A Row object is essentially a Dv::Sql::Object with a fixed 00018 * associated database table (note that the association between 00019 * an object and a database table cannot be changed: see 00020 * Dv::Sql::Object::set_table). 00021 * @see Dv::Sql::Table 00022 * @see Dv::Sql::Object 00023 */ 00024 template<Dv::Sql::Table::Ref& database_table> 00025 class Row: public Object { 00026 public: 00027 00028 static Dv::Sql::Table::Ref table() { return database_table; } 00029 static Dv::Sql::Db& db() { return database_table->db(); } 00030 00031 /** An empty row. 00032 * @see Dv::Sql::Object::Object(Dv::Sql::Table::Ref) 00033 */ 00034 Row(): Object(database_table) {} 00035 00036 /** Initialize a row object with data matching the first 00037 * result in an SQL select statement defined by @a select_exp 00038 * followed by @a rest. 00039 * 00040 * @par Example: 00041 * @code 00042 * std::string n("Jones"0; 00043 * Row<customer> customer(name == n, "order by age"); 00044 * @endcode 00045 * will retrieve the youngest customer called "Jones". 00046 * @param select_exp boolean condition that is translated 00047 * to the "where" clause in the SQL select statement. 00048 * @param rest optional part of the SQL select statement 00049 * follwing the "where" clause. 00050 * @exception std::runtime_error if the query returns no 00051 * anwers 00052 * @exception std::logic_error if the query caused an SQL 00053 * error 00054 */ 00055 Row(SelectExp select_exp, const std::string& rest="") 00056 throw (std::logic_error, std::runtime_error): 00057 Object(database_table, select_exp, rest) {} 00058 00059 /** Initialize a row object with data from the r'th row in 00060 * the answer of a query @a q. 00061 * @par Example 00062 * @code 00063 * Db::Sql::Command q(db, "select * from customer where", 00064 * age < 21 && name ^ "A%", "order by age"); 00065 * Row<customer> customer(q, 2); 00066 * @endcode 00067 * @param q the query for which the answer will supply the 00068 * data to initialize the row object 00069 * @param r the number of the row in the query answer from which the data will 00070 * be used to initialize this row object. 00071 * @exception std::runtime_error if the query returns less 00072 * than @a r answers 00073 * @exception std::logic_error if the query caused an SQL 00074 * error or if the number of columns in the query answer 00075 * is not equal to the number of columns in @a table_ref 00076 * (the template parameter). 00077 */ 00078 Row(Dv::Sql::Command& q, unsigned int r) throw (std::logic_error, std::runtime_error): 00079 Object(q, r, database_table) {} 00080 00081 /** Initialize a row using data from a row that is obtained 00082 * by "following a reference". 00083 * The data are obtained from the first row of the result 00084 * of a query that selects the rows of the target table 00085 * that match data from the source object in the colums 00086 * indicated by the reference object. 00087 * @par Example 00088 * @code 00089 * // Define reference from account(customer_id) to customer(id) 00090 * const Dv::Sql::Reference acct_cust( 00091 * Database::account, (cols = &Account::customer_id), 00092 * Database::customer, (cols = &Customer::id) 00093 * ); 00094 * Row<account> acct; 00095 * // Cust will be initialized using data from the first 00096 * // (only) customer with id acct.cust_id 00097 * Row<customer> cust(acct, acct_cust); 00098 * @endcode 00099 * @param source object from which the reference will be 00100 * followed. It should be a row from reference.from_table. 00101 * @param reference that will be followed. Its to_table 00102 * should match database_table (the template parameter) of 00103 * this object. 00104 * @exception std::runtime_error if the resulting query returns no 00105 * answers 00106 * @exception std::logic_error if the query caused an SQL 00107 * error or if the number of columns in the query answer 00108 * is not equal to the number of columns in @a table_ref 00109 * (the template parameter) or if the number of columns 00110 * in the source object does not equal the number of columns 00111 * in @a reference.from_table. 00112 */ 00113 Row(const Dv::Sql::Object& source, const Dv::Sql::Reference& reference) 00114 throw (std::runtime_error, std::logic_error): Object(source, reference) { 00115 } 00116 00117 static void erase_all(SelectExp select_exp) { 00118 static const std::string prefix("delete from "); 00119 Dv::Sql::Command q(db(), prefix + table()->name().c_str() + " where", select_exp); 00120 } 00121 00122 /** A Row<T>::Column object should be considered as a 00123 * reference to a Table::Column object. This class is 00124 * useful because a Row<T>::Column object can be 00125 * meaningfully initialized (i.e. with static storage) 00126 * before the associated database is actually opened 00127 * while Table::Column objects need an open database. 00128 * @see Dv::Sql::Table::Column. 00129 */ 00130 struct Column: Dv::Sql::Column { 00131 Column(size_t i): Dv::Sql::Column(i) {} 00132 /** Convert this object to a (reference to a) Table::Column object. 00133 * @pre the database_table template parameter has been initialized 00134 * (which can only be done after opening the database). 00135 */ 00136 const Dv::Sql::Table::Column& convert() const { 00137 if (! database_table) 00138 throw std::logic_error("Cannot convert null Row<database_table>::Column"); 00139 return database_table->column(index()); 00140 } 00141 /** Convert this object to a (reference to a) Table::Column object. 00142 * @pre the database_table template parameter has been initialized 00143 * (which can only be done after opening the database). 00144 * 00145 * Note that this conversion function is necessary in 00146 * order to support select expressions such as in 00147 * @code 00148 * Dv::Sql::Row<Database::customer>::Column Customer::id(0); 00149 * Customer::Row cust(Customer::id == cust_id) 00150 * @endcode 00151 * @return a reference to the Table::Column object that 00152 * represents this column. 00153 * @exception std::logic_error if the database_table (template 00154 * parameter) is 0. 00155 * @see Dv::Sql::Table::Column. 00156 * @see Dv::Sql::SelectExp 00157 */ 00158 operator const Dv::Sql::Table::Column&() const { return convert(); } 00159 00160 }; 00161 00162 /** Is the column value null? 00163 * @param column as generated by db2cpp 00164 * @return true iff the column value is null 00165 */ 00166 bool is_null(const Column& column) const { 00167 return ((*const_cast<Row*>(this))[column.index()].null()); 00168 } 00169 00170 /** Obtain column value for a row. 00171 * @param column as generated by db2cpp 00172 * @param default_value returned if the 'real' value of the 00173 * column is null, should enable automatic deduction of T 00174 * @return the value of the column for this row 00175 */ 00176 template<typename T> 00177 T operator()(const Column& column, const T& default_value) const { 00178 if (is_null(column)) 00179 return default_value; 00180 return get<T>(column.index()); 00181 } 00182 00183 00184 /** A set of rows of this table. */ 00185 class Set: public Dv::Sql::Set<Row<database_table> > { 00186 public: 00187 /** Initialize a set using the result of a query. 00188 * The query has the following form. 00189 * @code 00190 * select * from database_table where select_exp rest 00191 * @endcode 00192 * @par Example 00193 * @code 00194 * Dv::Sql::Table::Ref customer; 00195 * typedef Dv::Sql::Row<customer> Customer; 00196 * std::string zip; 00197 * // list of customers in area ordered by age 00198 * Customer::Set customers(Customer::zip = zip and age > 10, "order by age"); 00199 * @endcode 00200 * @param select_exp condition to be used in the query text 00201 * @param rest suffix of the query text, may be 0 00202 * @exception std::logic_error if executing the query fails 00203 */ 00204 Set(SelectExp select_exp, const std::string& rest = "") throw (std::logic_error): 00205 Dv::Sql::Set<Row<database_table> >(database_table, select_exp, rest) { 00206 } 00207 00208 /** Initialize the set with all objects that match 00209 * the dirty column values in @p r 00210 * @param r object to match 00211 * @param rest optional suffix for the constructed query 00212 * @exception std::logic_error iff executing the query fails 00213 * @see Object::match 00214 */ 00215 Set(Row<database_table>& r, const std::string& rest="") throw (std::logic_error): 00216 Dv::Sql::Set<Row<database_table> >(r, rest) { 00217 } 00218 00219 /** Initialize a set with all source objects that are 00220 * linked to a target object via a reference. 00221 * @param target object 00222 * @param reference to follow (in the inverse direction: 00223 * from taregt to source) 00224 */ 00225 template<typename Target> 00226 Set(const Target& target, const Dv::Sql::Reference& reference) throw (std::logic_error): 00227 Dv::Sql::Set<Row<database_table> >(target, reference) { 00228 } 00229 }; 00230 }; 00231 00232 } 00233 } 00234 #endif 00235
dvmysql-1.0.3 | [17 November, 2010] |