00001 #ifndef DVMYSQL_OBJECT_H 00002 #define DVMYSQL_OBJECT_H 00003 // $Id: object.h,v 1.75 2008/03/18 19:55:40 dvermeir Exp $ 00004 #include <vector> 00005 00006 #include <dvutil/convert.h> 00007 #include <dvutil/shared_ptr.h> 00008 00009 #include <dvmysql/sqldb.h> 00010 #include <dvmysql/table.h> 00011 #include <dvmysql/select_exp.h> 00012 #include <dvmysql/set.h> 00013 00014 namespace Dv { 00015 namespace Sql { 00016 00017 extern const std::string select_all; 00018 00019 /** A class that represents a row in a database table or in a 00020 * query result. Objects represent an intermediate abstraction 00021 * level between the low level interface provided by 00022 * Dv::Sql::Command and the slightly higher level interface 00023 * provided by Dv::Sql::Row. Nevertheless, objects may 00024 * be useful for ad-hoc queries that e.g. apply sql aggregate functions. 00025 * @par 00026 * An instance of Object can be thought of as 00027 * a vector of named columns, each column representing a value. 00028 * In addition, a column my be null and/or dirty. 00029 * A null column corresponds to a database NULL value. 00030 * A dirty column 00031 * value represents the assumption that the value was not 00032 * retrieved from the database, but was set explicitly by the 00033 * user. 00034 * @par 00035 * An object is also associated with a @p table, either 00036 * a database table or a query table. 00037 * The former have a name and correspond to the actual 00038 * relations in the database. The latter have the empty string 00039 * as name and correspond to the layout of a query result. 00040 * An object's table is used to translate column names to indexes 00041 * in the data array of the Object. If the table is a database 00042 * table, it can also be used to e.g. insert, erase, etc. the object. 00043 * @see Dv::Sql::Row 00044 */ 00045 class Object { 00046 public: 00047 /** Type representing a set of rows. */ 00048 typedef Dv::Sql::Set<Dv::Sql::Object> Set; 00049 00050 /** A class that represents a reference to a column value in 00051 * an Object. ColumnRef objects result from calling operator[] on an object. 00052 * Such objects can convert to actual data values or be 00053 * assigned to to change the value of a column in an object. 00054 * @see Object::operator[]. 00055 */ 00056 class ColumnRef { 00057 friend class Object; 00058 public: 00059 /** Obtain the associated column value as a value of type T. 00060 * @par Example 00061 * @code 00062 * Dv::Sql::Table::Ref customer; 00063 * Dv::Sql::Object cust(customer); 00064 * Dv::Util::Date birth_date = cust["birth_date"]; // will convert 00065 * @endcode 00066 * @exception std::logic_error if the conversion failed. 00067 */ 00068 template<typename T> 00069 T convert() const throw (std::logic_error) { 00070 try { // Dv::Util::fromstring may throw 00071 return Dv::fromstring<T>(object_.data_[index_]); 00072 } 00073 catch (std::exception& e) { 00074 throw std::logic_error(e.what()); 00075 } 00076 } 00077 00078 /** Obtain the associated column value as a value of type T. 00079 * @par Example 00080 * @code 00081 * Dv::Sql::Table::Ref customer; 00082 * Dv::Sql::Object cust(customer); 00083 * Dv::Util::Date birth_date = cust["birth_date"]; // will convert 00084 * @endcode 00085 * @exception std::logic_error if the conversion failed. 00086 */ 00087 template<typename T> 00088 operator T() const throw (std::logic_error) { 00089 return convert<T>(); 00090 } 00091 00092 /** Assign a new value to the referenced object column. 00093 * @par Example 00094 * @code 00095 * Dv::Sql::Table::Ref customer; 00096 * Dv::Sql::Object cust(customer); 00097 * cust["id"] = 123; 00098 * @endcode 00099 * @param t value to be assigned 00100 * @return a reference to the underlying object 00101 * @exception std::logic_error if the ColumnRef object 00102 * refers to a nonexisting colum in the associated Object 00103 */ 00104 template<typename T> 00105 Object& operator=(const T& t) throw (std::logic_error) { 00106 return object_.set_data(index_, Dv::tostring<T>(t), true); 00107 } 00108 00109 /** Copy one column value to another. 00110 * @par Example 00111 * @code 00112 * Dv::Sql::Table::Ref customer; 00113 * Dv::Sql::Object cust(customer); 00114 * Dv::Sql::Table::Ref account; 00115 * Dv::Sql::Object acct(account); 00116 * cust["id"] = acct["customer_id"] 00117 * @endcode 00118 * @param r the ColumnRef for which the associated column 00119 * value is to be assigned to the column value associated 00120 * with this ColumnRef 00121 * @return a reference to the underlying Object of this 00122 * ColumnRef 00123 * @exception std::logic_error if this or ColumnRef object 00124 * refers to a nonexisting colum in the associated Object 00125 */ 00126 Object& operator=(const ColumnRef& r) throw (std::logic_error) { 00127 return object_.set_data(index_, r.object_.data_[r.index_], true); 00128 } 00129 00130 /** Check whether the column value referred to equals the 00131 * parameter. 00132 * @par Example 00133 * @code 00134 * Dv::Sql::Table::Ref customer; 00135 * Dv::Sql::Object cust(customer); 00136 * if ( cust["id"] == 123) { 00137 * .. 00138 * } 00139 * @endcode 00140 * @param t the value to compare with 00141 * @return true iff the values are equal 00142 * @return false iff the values are not equal 00143 * @exception std::logic_error if the conversion fails 00144 */ 00145 template<typename T> 00146 bool operator==(const T& t) const throw (std::logic_error) { 00147 return (convert<T>() == t); 00148 } 00149 00150 /** Special case of check whether the column value referred to equals the 00151 * parameter. 00152 * @par Example 00153 * @code 00154 * Dv::Sql::Table::Ref customer; 00155 * Dv::Sql::Object cust(customer); 00156 * if ( cust["name"] == "Jones") { 00157 * .. 00158 * } 00159 * @endcode 00160 * @param t the value to compare with 00161 * @return true iff the values are equal 00162 * @return false iff the values are not equal 00163 * @exception std::logic_error if the conversion fails 00164 */ 00165 00166 bool operator==(const char* t) const throw (std::logic_error) { 00167 return (convert<std::string>() == std::string(t)); 00168 } 00169 00170 /** Check whether the column value referred to equals the 00171 * column value referred to by the parameter. 00172 * @par Example 00173 * @code 00174 * Dv::Sql::Table::Ref customer; 00175 * Dv::Sql::Object cust(customer); 00176 * Dv::Sql::Table::Ref account; 00177 * Dv::Sql::Object acct(account); 00178 * if (cust["id"] == acct["customer_id"]) { 00179 * .. 00180 * } 00181 * @endcode 00182 * @param r the ColumnRef to compare with 00183 * @return true iff the values are both null or are equal and (both) not null 00184 * @return false otherwise 00185 * @exception std::logic_error if the conversion fails 00186 */ 00187 bool operator==(const ColumnRef& r) throw (std::logic_error) { 00188 if (object_.null_[index_]) 00189 return r.object_.null_[r.index_]; 00190 else 00191 return object_.data_[index_] == r.object_.data_[r.index_]; 00192 } 00193 00194 /** Check whether the column value referred to is 00195 * different from the parameter. 00196 * @par Example 00197 * @code 00198 * Dv::Sql::Table::Ref customer; 00199 * Dv::Sql::Object cust(customer); 00200 * if ( cust["id"] != 123) { 00201 * .. 00202 * } 00203 * @endcode 00204 * @param t the value to compare with 00205 * @return true iff the values are different 00206 * @return false iff the values are equal 00207 * @exception std::logic_error if the conversion fails 00208 */ 00209 template<typename T> 00210 bool operator!=(const T& t) const throw (std::logic_error) { 00211 return (convert<T>() != t); 00212 } 00213 00214 /** Special case of check whether the column value referred to is 00215 * different from the parameter. 00216 * @par Example 00217 * @code 00218 * Dv::Sql::Table::Ref customer; 00219 * Dv::Sql::Object cust(customer); 00220 * if ( cust["name"] != "Jones") { 00221 * .. 00222 * } 00223 * @endcode 00224 * @param t the value to compare with 00225 * @return true iff the values are different 00226 * @return false iff the values are equal 00227 * @exception std::logic_error if the conversion fails 00228 */ 00229 bool operator!=(const char* t) const throw (std::logic_error) { 00230 return (convert<std::string>() != std::string(t)); 00231 } 00232 00233 /** Check whether the column value referred to is 00234 * different from the column value referred to by the parameter. 00235 * @par Example 00236 * @code 00237 * Dv::Sql::Table::Ref customer; 00238 * Dv::Sql::Object cust(customer); 00239 * Dv::Sql::Table::Ref account; 00240 * Dv::Sql::Object acct(account); 00241 * if (cust["id"] != acct["customer_id"]) { 00242 * .. 00243 * } 00244 * @endcode 00245 * @param r the ColumnRef to compare with 00246 * @return false iff the values are both null or are equal and (both) not null 00247 * @return true otherwise 00248 * @exception std::logic_error if the conversion fails 00249 */ 00250 bool operator!=(const ColumnRef& r) throw (std::logic_error) { 00251 return ! (*this == r); 00252 } 00253 00254 /** Check whether the column value referred to by the 00255 * second parameter is 00256 * different from the first parameter. 00257 * @par Example 00258 * @code 00259 * Dv::Sql::Table::Ref customer; 00260 * Dv::Sql::Object cust(customer); 00261 * if ( 123 != cust["id"] ) { 00262 * .. 00263 * } 00264 * @endcode 00265 * @param t the value to compare with 00266 * @param c the ColumnRef referring to the column value to 00267 * compare @p t with 00268 * @return true iff the values are different 00269 * @return false iff the values are equal 00270 * @exception std::logic_error if the conversion fails 00271 */ 00272 template<typename T> 00273 friend bool operator!=(const T& t, const ColumnRef& c) throw (std::logic_error) { 00274 return c != t; 00275 } 00276 00277 /** Check whether the column value referred to by the second parameter equals the 00278 * first parameter. This is an ordinary function. 00279 * @par Example 00280 * @code 00281 * Dv::Sql::Table::Ref customer; 00282 * Dv::Sql::Object cust(customer); 00283 * if ( 123 == cust["id"] ) { 00284 * .. 00285 * } 00286 * @endcode 00287 * @param t the value to compare with 00288 * @param c the ColumnRef referring to the column value to 00289 * compare @p t with 00290 * @return true iff the values are equal 00291 * @return false iff the values are not equal 00292 * @exception std::logic_error if the conversion fails 00293 */ 00294 template<typename T> 00295 friend bool operator==(const T& t, const ColumnRef& c) throw (std::logic_error) { 00296 return c == t; 00297 } 00298 00299 /** Set the corresponding value to null (or not). 00300 * A null column corresponds to a database NULL value. 00301 * @par Example 00302 * @code 00303 * Dv::Sql::Table::Ref customer; 00304 * Dv::Sql::Object cust(customer); 00305 * cust["id"].set_null(true); 00306 * @endcode 00307 * @param new_value if true, the column value will be set 00308 * to null, if false, it will be set to non-null. 00309 * @return a reference to the referenced Object 00310 */ 00311 Object& set_null(bool new_value); 00312 00313 /** Check null status of the underlying column value. 00314 * A null column corresponds to a database NULL value. 00315 * @return true iff the underlying column value is null 00316 */ 00317 bool null() const; 00318 00319 /** Set the dirty status of the underlying column value. 00320 * A dirty column 00321 * value represents the assumption that the value was not 00322 * retrieved from the database, but was set explicitly by the 00323 * user. 00324 * @par Example 00325 * @code 00326 * Dv::Sql::Table::Ref customer; 00327 * Dv::Sql::Object cust(customer); 00328 * cust["id"] = 123; 00329 * std::cout << cust.dirty("id"); // prints 1 00330 * cust["id"].set_dirty(false); 00331 * std::cout << cust.dirty("id"); // prints 0 00332 * @endcode 00333 * @param new_value if true, the dirty status will be set 00334 * to true 00335 * @return a reference to the referenced Object 00336 */ 00337 Object& set_dirty(bool new_value); 00338 00339 /** Set the dirty status of the underlying column value to 00340 * true. A dirty column 00341 * value represents the assumption that the value was not 00342 * retrieved from the database, but was set explicitly by the 00343 * user. 00344 * @par Example 00345 * @code 00346 * Dv::Sql::Table::Ref customer; 00347 * Dv::Sql::Object cust(customer); 00348 * cust["id"].touch(); 00349 * std::cout << cust.dirty("id"); // prints 1 00350 * @endcode 00351 * @return a reference to the referenced Object 00352 */ 00353 Object& touch() { return set_dirty(true); } 00354 00355 /** Check dirty status of the underlying column value. 00356 * A dirty column 00357 * value represents the assumption that the value was not 00358 * retrieved from the database, but was set explicitly by the 00359 * user. 00360 * @par Example 00361 * @code 00362 * Dv::Sql::Table::Ref customer; 00363 * Dv::Sql::Object cust(customer); 00364 * cust["id"] = 123; 00365 * std::cout << cust.dirty("id"); // prints 1 00366 * cust["id"].set_dirty(false); 00367 * std::cout << cust.dirty("id"); // prints 0 00368 * @endcode 00369 * @return true iff the underlying column value is null 00370 */ 00371 bool dirty() const; 00372 00373 private: 00374 /** Construcor. 00375 * @param o referenced object 00376 * @param i number of referenced column 00377 * @exception std::logic_error if @p i exceeds the arity 00378 * of the object 00379 * @see Object::arity 00380 */ 00381 ColumnRef(Object& o, size_t i) throw (std::logic_error); 00382 /** This ColumnRef refers to a column value in this object */ 00383 Object& object_; 00384 /** Index of column to which this ColumnRef refers (in @p object_ ) */ 00385 size_t index_; 00386 }; 00387 00388 /** Type of (reference counted) pointer to Object */ 00389 typedef Dv::shared_ptr<Object> Ref; 00390 00391 /** Create an empty object with a given arity. 00392 * @param db database connection to be used in further SQL 00393 * statements with this object 00394 * @param arity number of column values that may be stored in this object 00395 */ 00396 Object(Dv::Sql::Db& db, size_t arity); 00397 00398 /** Create an empty object associated with a given table. 00399 * The object will be copy the database connection 00400 * from the table. 00401 * @param table reference 00402 * @exception std::logic_error if table is a null reference 00403 * @see Dv::Sql::Object::table 00404 */ 00405 Object(Table::Ref table) throw (std::logic_error); 00406 00407 /** Create an object containing the first row of a "select *" 00408 * statement from a database table. 00409 * The select statement has the form 00410 * @code 00411 * select * from table->name() where select_exp rest 00412 * @endcode 00413 * @param table to associate with this object 00414 * @param select_exp where clause of the query 00415 * @param rest of the query 00416 * @par Example 00417 * @code 00418 * // y is the youngest customer older than 21 (and younger than 100) 00419 * Dv::Sql::Object y(customer, Customer::age > 21 && Customer::age < 100, "order by age"); 00420 * @endcode 00421 * @exception std::logic_error if the query fails or @p table 00422 * is a null reference 00423 * @exception std::runtime_error if the query does not return 00424 * any answers 00425 * @see Dv::Sql::Object::table 00426 */ 00427 Object(Table::Ref table, SelectExp select_exp, const std::string& rest="") 00428 throw (std::logic_error, std::runtime_error); 00429 00430 /** Create an object containing the r'th row of the answer of a 00431 * query. 00432 * @par Example 00433 * @code 00434 * Dv::Sql::Command(db, "select amount from transaction", 00435 * Transaction::acct_code = code, "order by amount"); 00436 * // retrieve the amount of the transaction on the account 00437 * // with the largest amount 00438 * Dv::Sql::Object max_amount(q, q.nrows()-1); 00439 * @endcode 00440 * @param q query from whose answer the r'th row will be retrieved 00441 * @param r number of row in query answer to be retrieved 00442 * @param table optional database table to associate with this object 00443 * If @p table is null, the object will be associated with 00444 * the table of the query result. 00445 * @exception std::logic_error if execution of the query failed 00446 * @exception std::logic_error if the table is non-null and 00447 * does not have the same arity as the query answer 00448 * @exception std::runtime_error if the query answer contains 00449 * less than @p r rows 00450 * @see Dv::Sql::Command::table 00451 * @see Dv::Sql::Object::table 00452 */ 00453 Object(Dv::Sql::Command& q, unsigned int r = 0, const Table::Ref& table=Table::Ref(0)) 00454 throw (std::logic_error, std::runtime_error); 00455 00456 /** Create an object containing the first row of the answer of a 00457 * query. The query is composed by prefix followed by the select 00458 * expression, followed by the optional rest. 00459 * Example 00460 * @code 00461 * Object p(db, "select * from person where", Person::age > 3, "order by age"); 00462 * @endcode 00463 * @param db database connection to be used in further queries 00464 * @param prefix of query string 00465 * @param select_exp condition to follow "where" 00466 * @param rest of query string 00467 * @exception std::logic_error if mysql rejects the query 00468 * @exception std::runtime_error if the query returns 0 rows 00469 * @see Dv::Sql::SelectExp 00470 * @see Dv::Sql::Command 00471 */ 00472 Object(Dv::Sql::Db& db, const std::string& prefix, SelectExp select_exp, 00473 const std::string& rest = "") throw (std::logic_error, std::runtime_error); 00474 00475 /** Create an object containing the first row of the answer of a 00476 * query for which the complete text is provided. 00477 * Example 00478 * @code 00479 * Object p(db, "select sum(amount)" + select_exp.from_where(db)); 00480 * @endcode 00481 * @param db database connection to be used in further queries 00482 * @param query text of query 00483 * @exception std::logic_error if mysql rejects the query 00484 * @exception std::runtime_error if the query returns 0 rows 00485 * @see Dv::Sql::SelectExp 00486 * @see Dv::Sql::Command 00487 */ 00488 Object(Dv::Sql::Db& db, const std::string& query) 00489 throw (std::logic_error, std::runtime_error); 00490 00491 /** Create an object from the result of following a reference. 00492 * Specifically, a query of the following form will be 00493 * constructed: 00494 * @code 00495 * select * from ref.to_table where (match source_data according to ref) 00496 * @endcode 00497 * @par Example 00498 * @code 00499 * const Dv::Sql::Reference acct_cust( 00500 * Database::account, (cols = &Account::customer_id), 00501 * Database::customer, (cols = &Customer::id) 00502 * ); 00503 * Object acct(..); 00504 * Object cust(acct, acct_cust); // customer owning the account 00505 * // the executed query is 00506 * // select * from customer where customer.id = account.customer_id 00507 * @endcode 00508 * @exception std::logic_error if there is an error executing 00509 * the query 00510 * @exception std::logic_error if the arities of the @p source 00511 * object does not match the arity of @p ref.from_table 00512 * @exception std::runtime_error if the query does not return 00513 * any answers 00514 * @see Dv::Sql::Reference 00515 * @see Dv::Sql::Table 00516 */ 00517 Object(const Dv::Sql::Object& source, const Dv::Sql::Reference& ref) 00518 throw (std::runtime_error, std::logic_error); 00519 00520 /** Destructor. */ 00521 virtual ~Object(); 00522 00523 /** Set the column values of this object to those of the 00524 * r'th row of the result of a query. 00525 * In addition, the object's table will be set to the table 00526 * associated with the query, unless the object already has 00527 * an associated database table. In the latter case, 00528 * the arity of the query result must match the arity of the 00529 * database table. 00530 * The function will set all column values to dirty, and null 00531 * values as appropriate. 00532 * @param q query from which the r'th answer row will be used 00533 * to set the column values of this object 00534 * @param r the number of the row in the query result that 00535 * will be used to set this object's column values. 00536 * @exception std::logic_error if the object is associated 00537 * with a database table and the arity of the query result 00538 * does not match this table's arity. 00539 * @see Dv::Sql::Object::table 00540 */ 00541 bool set(Dv::Sql::Command& q, unsigned int r = 0) throw (std::logic_error); 00542 00543 /** Number of column values in this object. 00544 * @return the number of column values in this object 00545 */ 00546 size_t arity() const { return data_.size(); } 00547 00548 /** Return a reference to the i'th column in this object 00549 * @param i the number (0-based) of the column to refer to 00550 * @exception std::logic_error if @p i exceeds this object's 00551 * arity 00552 */ 00553 ColumnRef operator[](size_t i) throw (std::logic_error); 00554 /** Return a reference to a named column in this object 00555 * @param col_name the name of the column to retrieve 00556 * @exception std::logic_error if the table associated with 00557 * this object does not contain a column with this name 00558 * @see Dv::Sql::Object::table 00559 */ 00560 ColumnRef operator[](const std::string& col_name) throw (std::logic_error); 00561 /** Return a reference to a column in this object 00562 * @param column the column to retrieve. Normally, a column 00563 * from the table associated with this object. 00564 * @exception std::logic_error if @p column.index exceeds the 00565 * arity of this object. 00566 * @see Dv::Sql::Object::table 00567 */ 00568 ColumnRef operator[](const Table::Column& column) throw (std::logic_error); 00569 00570 00571 /** Print a readable representation of this object to a stream. 00572 * @param os stream to print to. 00573 * @return os 00574 */ 00575 virtual std::ostream& print(std::ostream& os) const; 00576 00577 00578 /** The database connection of this object. 00579 * @return the database connection of this object. */ 00580 Dv::Sql::Db& db() const { return const_cast<Object*>(this)->db_; } 00581 00582 /** Assignment operator. Note that both objects must have the 00583 * same associated table. 00584 * @param o object to be assigned 00585 * @return *this 00586 * @exception std::logic_error if the table of @p o does not 00587 * match the table associated with this object. 00588 * @see Dv::Sql::Object::table 00589 */ 00590 Object& operator=(const Object& o) throw (std::logic_error); 00591 00592 /** Test two objects for equality. The objects are equal iff 00593 * they have the same associated table, their null_ arrays are 00594 * equal and the corresponding non-null 00595 * data_ values are also equal. 00596 * @param o1 object to test for equality with @c o2 00597 * @param o2 object to test for equality with @c o1 00598 * @return true iff both objects are equal 00599 * @see Dv::Sql::Object::table 00600 */ 00601 friend bool operator==(const Object& o1, const Object& o2); 00602 00603 /** Test two objects for inequality. The objects are equal iff 00604 * they have the same associated table, their null_ arrays are 00605 * equal and the corresponding non-null 00606 * data_ values are also equal. 00607 * @param o1 object to test for inequality with @c o2 00608 * @param o2 object to test for inequality with @c o1 00609 * @return true iff the objects are not equal 00610 * @see Dv::Sql::Object::table 00611 */ 00612 friend bool operator!=(const Object& o1, const Object& o2); 00613 00614 /** Return a reference to the associated Dv::Sql::Table of this object. 00615 * There are two kinds of table: database tables and query 00616 * tables. The former have a name and correspond to the actual 00617 * relations in the database. The latter have the empty string 00618 * as name and correspond to the layout of a query result. 00619 * An object's table is used to translate column names to indexes 00620 * in the data array of the Object. If the table is a database 00621 * table, it can also be used to e.g. insert, erase, etc. the object. 00622 * @exception std::logic_error if the object has no associated 00623 * table. 00624 * @see Dv::Sql::Table 00625 */ 00626 const Dv::Sql::Table::Ref table() const throw (std::logic_error); 00627 00628 /** Is this object associated with a database table? 00629 * @return true iff this object is associated with a database table 00630 * @see Dv::Sql::Object::table 00631 */ 00632 bool has_db_table() const; 00633 00634 /** Return a reference to the associated database Dv::Sql::Table of this object. 00635 * @exception std::logic_error if the object has no associated 00636 * table or if the associated table is a query table. 00637 * @see Dv::Sql::Object::table 00638 * @see Dv::Sql::Table 00639 */ 00640 Dv::Sql::Table::Ref db_table() const throw (std::logic_error); 00641 00642 /** Retrieve column information for this object. 00643 * @param i the index (0-based) of the column for which info 00644 * is to be retrieved 00645 * @return a pointer to the column information, alwasy nonzero 00646 * @exception std::logic_error if the associated table is null 00647 * @exception std::logic_error if @p i exceeds the object's 00648 * arity. 00649 */ 00650 const Dv::Sql::Table::Column* column(size_t i) const throw (std::logic_error); 00651 00652 /** Retrieve the first row, if any, that matches the dirty 00653 * column values in this object. 00654 * @par Example 00655 * @code 00656 * Dv::Sql::Object cust; 00657 * cust["name"] = "fred"; // will set dirty for "name" 00658 * cust.match_first(); // first customer called "fred" 00659 * @endcode 00660 * @return the number of rows, possibly 0, 00661 * retrieved by the underlying query. 00662 * @exception std::logic_error iff the query execution failed 00663 * @see Object::dirty 00664 */ 00665 size_t match_first() throw (std::logic_error); 00666 00667 /** Retrieve the unique row, if any, that matches the primary 00668 * key column values of this object. The primary key 00669 * information is obtained from the object's table. 00670 * @par Example 00671 * @code 00672 * Dv::Sql::Object cust; 00673 * cust["name"] = "fred"; // will set dirty for "name" 00674 * cust.match_first(); // first customer called "fred" 00675 * cust["name"] = "jane"; 00676 * cust,refresh(); // name will be "fred" again 00677 * @endcode 00678 * @return true iff the object was found in the database 00679 * @exception std::logic_error iff the query execution failed 00680 * @warning upon failure, dirty(c) iff c in primary key 00681 * @see Dv::Sql::Object::table 00682 */ 00683 bool refresh() throw (std::logic_error); 00684 00685 /** Insert the present object into a database, using an Sql 00686 * 'insert' statement. 00687 * All non-null column values will be stored except for @c auto_inc columns. 00688 * After the insert operation, the object will be refreshed thus 00689 * causing @c auto_inc and default values to be available, as 00690 * appropriate. 00691 * @par Example 00692 * @code 00693 * Dv::Sql::Object cust; 00694 * cust.set("last_name", last_nm) 00695 * .set("first_name", first_nm) 00696 * .set("birth_date", Dv::Util::Date(1970, 8, 20)) 00697 * .set("sex", "M") 00698 * .set("email", "dvermeir@vub.ac.be") 00699 * .insert(); 00700 * @endcode 00701 * @exception std::runtime_error iff executing the insert statement 00702 * failed. 00703 * @see Object::null() 00704 * @see Object::refresh() 00705 * @see Dv::Sql::Column::auto_inc 00706 */ 00707 void insert() throw (std::runtime_error); 00708 00709 /** Save dirty column values of an object to the database. 00710 * This function will execute an update statement using all 00711 * dirty columns. The update statement will be executed 00712 * on the row in the database that has the same primary 00713 * key as the current object. 00714 * See the Mysql documentation for the precise semantics. 00715 * @par Example 00716 * @code 00717 * Customer::Row cust(..); 00718 * cust["id"] = cust_id; 00719 * cust["last_name"] = new_name; 00720 * cust.update(); 00721 * @endcode 00722 * @exception std::runtime_error iff the corresponding sql 00723 * statement failed. 00724 * @warning if there are no dirty columns, the operation 00725 * is quietly canceled. 00726 */ 00727 void update() throw (std::runtime_error); 00728 00729 /** Save current state of the object to the database. 00730 * This function will execute a replace statement using all 00731 * dirty columns as well as the columns in all unique keys. 00732 * See the Mysql documentation for the precise semantics. 00733 * @exception std::runtime_error iff the corresponding sql 00734 * statement failed. 00735 */ 00736 void replace() throw (std::runtime_error); 00737 00738 /** Remove the object from the database. 00739 * This function will execute a delete statement using the 00740 * primary key columns. 00741 * See the Mysql documentation for the precise semantics. 00742 * @exception std::runtime_error iff the corresponding sql 00743 * statement failed. 00744 */ 00745 void erase() throw (std::runtime_error); 00746 00747 /** Remove all objects from the table that satisfy some 00748 * select expression. The constructed sql statement 00749 * uses the object's database and associated (database) table 00750 * (only). 00751 */ 00752 void erase(const Dv::Sql::SelectExp& exp) const; 00753 00754 /** Create (and execute) a 'select' query out of the dirty columns of this 00755 * object. 00756 * @param rest optional suffix of the query 00757 * @return a (reference counted) pointer to a newly allocated query 00758 * @exception std::logic_error iff executing the query fails. 00759 * @see Object::match_first 00760 */ 00761 Dv::Sql::Command::Ref match_query(const std::string& rest="") const throw (std::logic_error); 00762 /** Return a boolean expression that expresses a match 00763 * with the dirty columns of this object. 00764 * @return a boolean expression (a conjunction of equalities) 00765 * asserting a match between dirty columns and their current 00766 * values. 00767 * @par Example 00768 * @code 00769 * Dv::Sql::Table::Ref customer; 00770 * Dv::Sql::Object cust(customer); 00771 * cust["first_name"] = "fred"; 00772 * Dv::Sql::SelectExp e = cust.match_exp(); 00773 * // Get all customers called "fred" that are older than 21 00774 * Dv::Sql::Object::Set freds(customer, e && (customer.age > 21)); 00775 * @endcode 00776 */ 00777 Dv::Sql::SelectExp match_exp() const throw (std::logic_error); 00778 00779 /** Create (and execute) a query. 00780 * The query has the form 00781 * @code 00782 * select * from table_name where where_exp rest 00783 * @endcode 00784 * @param where_exp to use in the query 00785 * @param rest of the text of the query 00786 * @exception std::logic_error iff executing the query fails. 00787 */ 00788 Dv::Sql::Command::Ref select(const Dv::Sql::SelectExp& where_exp, 00789 const std::string& rest="") const throw (std::logic_error); 00790 00791 /** Set a column value for this object. 00792 * @param i index (0-based) of the column 00793 * @param t value to store 00794 * @return a reference to this object 00795 * @exception std::logic_error if @p i exceeds the object's 00796 * arity 00797 * @exception std::logic_error if @p t cannot be converted to 00798 * a string using Dv::Util::tostring 00799 */ 00800 template<typename T> 00801 Object& set(size_t i, const T& t) throw (std::logic_error) { 00802 return set_data(i, Dv::tostring<T>(t), true); 00803 } 00804 00805 /** Set a column value for this object. 00806 * @param c the column to set 00807 * @param t value to store 00808 * @return a reference to this object 00809 * @exception std::logic_error if the index of @p c exceeds 00810 * the object's arity 00811 * @exception std::logic_error if @p t cannot be converted to 00812 * a string using Dv::Util::tostring 00813 */ 00814 template<typename T> 00815 Object& set(const Table::Column& c, const T& t) throw (std::logic_error) { 00816 return set<T>(c.index(), t); 00817 } 00818 00819 /** Set a column value for this object. 00820 * @param col_name name of the column to set 00821 * @param t value to store 00822 * @return a reference to this object 00823 * @exception std::logic_error if the object has no column 00824 * with the given name 00825 * @exception std::logic_error if @p t cannot be converted to 00826 * a string using Dv::Util::tostring 00827 * @see Dv::Sql::Object::table 00828 */ 00829 template<typename T> 00830 Object& set(const std::string& col_name, const T& t) throw (std::logic_error) { 00831 return set<T>(table()->find(col_name).index(), t); 00832 } 00833 00834 /** Retrieve a column value for this object. 00835 * @param i index (0-based) of the column value to retrieve 00836 * @return the (converted) column value 00837 * @exception std::logic_error if @p i exceeds the object's 00838 * arity 00839 * @exception std::logic_error if the conversion from a string 00840 * fails 00841 */ 00842 template<typename T> 00843 T get(size_t i) const throw (std::logic_error) { 00844 try { // Dv::Util::fromstring may throw 00845 if (i >= arity() ) 00846 throw std::logic_error("Dv::Sql::Object::get: bad column index"); 00847 return Dv::fromstring<T>(data_[i]); 00848 } 00849 catch (std::exception& e) { 00850 throw std::logic_error(e.what()); 00851 } 00852 } 00853 00854 /** Retrieve a column value for this object. 00855 * @param c the column to set 00856 * @return the (converted) column value 00857 * @exception std::logic_error if the index of @p c exceeds 00858 * the object's arity 00859 * @exception std::logic_error if the conversion from a string 00860 * fails 00861 */ 00862 template<typename T> 00863 T get(const Table::Column& c) const throw (std::logic_error) { 00864 return get<T>(c.index()); 00865 } 00866 00867 /** Retrieve a column value for this object. 00868 * @param col_name name of the column to retrieve 00869 * @return the (converted) column value 00870 * @exception std::logic_error if the object has no column 00871 * with the given name 00872 * @exception std::logic_error if the conversion from a string 00873 * fails 00874 */ 00875 template<typename T> 00876 T get(const std::string& col_name) const throw (std::logic_error) { 00877 return get<T>(table()->find(col_name).index()); 00878 } 00879 00880 /** Return a reference to the set of objects obtained by 00881 * following a given reference in reverse. 00882 * @par Example 00883 * @code 00884 * const Dv::Sql::Reference acct_cust( 00885 * Database::account, (cols = &Account::customer_id), 00886 * Database::customer, (cols = &Customer::id) 00887 * ); 00888 * Object cust(..); 00889 * // all accounts of this customer 00890 * Object::Set::Ref accounts = cust.references(acct_cust); 00891 * @endcode 00892 * @see Dv::Sql::Set(const Source&,const Dv::Sql::Reference&) 00893 */ 00894 Set::Ref references(const Reference& ref) const throw (std::logic_error); 00895 00896 /** Copy a column value from another object to this one. 00897 * If the source column is null, the target column in this 00898 * object will be null. 00899 * @param to_i index of target column in this object 00900 * @param from source object for copy 00901 * @param from_i index of source column in @p source object 00902 * @param dirty the dirty attribute of the target column will 00903 * be set to this value 00904 * @exception std::logic_error if one of the column indexes is 00905 * out of range 00906 * @see Object::set_dirty 00907 */ 00908 Object& copy_data(size_t to_i, const Object& from, size_t from_i, bool dirty) 00909 throw (std::logic_error); 00910 00911 /** Obtain the data value associated with this object. 00912 * This function does not do any checking, it also does not 00913 * take into account the null status of this column. 00914 * @param i index (0-based) of the column to retrieve the value of 00915 * @return the value of the column 00916 */ 00917 const std::string& get_data(const Table::Column& c) const { 00918 static const std::string null_s = "NULL"; 00919 size_t i = c.index(); 00920 if (null(i)) 00921 return null_s; 00922 return data_[i]; 00923 } 00924 00925 00926 protected: 00927 00928 /** Set the value of column @p i in this object to @p value. 00929 * This function checks the validity of @p i. 00930 * @param i index (0-based) of the column to set the value of 00931 * @param value to store in the column 00932 * @param dirty new value of the dirty attribute of the column 00933 * @return a reference to this object 00934 * @exception std::logic_error if @p i exceeds the object's 00935 * arity 00936 */ 00937 Object& set_data(size_t i, const std::string& value, bool dirty) throw (std::logic_error); 00938 00939 /** Obtain the data value associated with this object. 00940 * This function does not do any checking, it also does not 00941 * take into account the null status of this column. 00942 * @param i index (0-based) of the column to retrieve the value of 00943 * @return the value of the column 00944 */ 00945 const std::string& data(size_t i) const { return data_[i]; } 00946 00947 /** Set the null status of a column. This function does not 00948 * verify the validity of its parameters. 00949 * @param i index (0-based) of the column to set the null status for 00950 * @param new_value new null status 00951 * @pre i < arity() 00952 */ 00953 void set_null(size_t i, bool new_value) throw (); 00954 /** Is a column value null? 00955 * @param i index (0-based) of the column to retrieve the null status for 00956 * @return true iff the column value is null 00957 * @pre i < arity() 00958 */ 00959 bool null(size_t i) const throw () { return null_[i]; } 00960 00961 /** Set the dirty status of a column. This function does not 00962 * verify the validity of its parameters. 00963 * @param i index (0-based) of the column to set the dirty status for 00964 * @param new_value new dirty status 00965 * @pre i < arity() 00966 */ 00967 void set_dirty(size_t i, bool new_value) throw (); 00968 /** Is a column value dirty? 00969 * @param i index (0-based) of the column to retrieve the dirty status for 00970 * @return true iff the column value is dirty 00971 * @pre i < arity() 00972 */ 00973 bool dirty(size_t i) const throw () { return dirty_[i]; } 00974 00975 private: 00976 /** Database connection associated with this object */ 00977 Dv::Sql::Db& db_; 00978 /** Dirty flags for each column value in this object */ 00979 std::vector<bool> dirty_; 00980 /** Null flags for each column value in this object */ 00981 std::vector<bool> null_; 00982 /** Actual column data */ 00983 std::vector<std::string> data_; 00984 /** Table of this object */ 00985 const Dv::Sql::Table::Ref table_; 00986 00987 /** Change the associated table of this object. Note that 00988 * if the object currently has a database table, this function 00989 * will throw an exception. 00990 * @param table new table 00991 * @exception std::logic_error if the object is currently 00992 * associated with a database table. 00993 */ 00994 void set_table(Dv::Sql::Table::Ref table) throw (std::logic_error); 00995 }; 00996 00997 /** Print a readable representation of this object to a stream. 00998 * @param os stream to print to 00999 * @param o object to print 01000 * @return os 01001 */ 01002 std::ostream& 01003 operator<<(std::ostream& os, const Object& o); 01004 01005 } 01006 } 01007 01008 #endif
dvmysql-1.0.3 | [17 November, 2010] |