Savarese Software Research Corporation
RowOperations.h
Go to the documentation of this file.
00001 /*
00002  * Copyright 2006-2009 Savarese Software Research Corporation
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     https://www.savarese.com/software/ApacheLicense-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00022 #ifndef __SSRC_WSPR_DATABASE_ROW_OPERATIONS_H
00023 #define __SSRC_WSPR_DATABASE_ROW_OPERATIONS_H
00024 
00025 #include <ssrc/wispers/database/Database.h>
00026 #include <ssrc/wisp/utility/wisp_import.h>
00027 
00028 #include <boost/integer_traits.hpp>
00029 
00030 __BEGIN_NS_SSRC_WSPR_DATABASE
00031 
00032 namespace detail {
00033   template<typename T, bool is_basic> struct FindRow;
00034 
00035   template<typename T>
00036   struct FindRow<T, true> {
00037     template<typename... P>
00038     static std::pair<bool, T> exec(PreparedStatement & query, P && ...p) {
00039       QueryResult && result = query.execute(std::forward<P>(p)...);
00040 
00041       if(result.result_set) {
00042         std::pair<bool, T> value(true, result.result_set->value<T>());
00043         query.reset();
00044         return value;
00045       }
00046 
00047       return std::pair<bool, T>(false, T());
00048     }
00049   };
00050 
00051   template<typename T>
00052   struct FindRow<T, false> {
00053     template<typename... P>
00054     static std::pair<bool, T> exec(PreparedStatement & query, P && ...p) {
00055       QueryResult && result = query.execute(std::forward<P>(p)...);
00056 
00057       if(result.result_set) {
00058         std::pair<bool, T> value(true, *result.result_set);
00059         query.reset();
00060         return value;
00061       }
00062 
00063       return std::pair<bool, T>(false, T());
00064     }
00065   };
00066 }
00067 
00068 // Convenience function for implementing single object lookups.
00069 template<typename T, typename... P>
00070 inline std::pair<bool, T> find_row(PreparedStatement & query, P && ...p)
00071   SSRC_DECL_THROW(DatabaseException)
00072 {
00073   return detail::FindRow<T, detail::is_basic_type<T>::value>::exec(query, std::forward<P>(p)...);
00074 }
00075 
00076 struct DefaultValueBinder {
00077   typedef PreparedStatement binder_type;
00078 
00079   static binder_type & binder(PreparedStatement & statement) {
00080     return statement;
00081   }
00082 };
00083 
00084 struct DefaultValueLoader {
00085   template<typename T>
00086   const DefaultValueLoader &
00087   load(const ResultSet & result, const unsigned int index, T & value) const {
00088     value = std::move(result.value<typename detail::ResultSetValueTraits<T, detail::is_basic_type<T>::value>::db_value_type>(index));
00089     return *this;
00090   }
00091 
00092 private:
00093   template<const unsigned int index, typename T, typename... P>
00094   const DefaultValueLoader & _loadp(const ResultSet & result,  T & value) const
00095     SSRC_DECL_THROW(DatabaseException)
00096   {
00097     return load(result, index, value);
00098   }
00099 
00100   template<const unsigned int index, typename T, typename... P>
00101   const DefaultValueLoader & _loadp(const ResultSet & result,  T & value, P & ...p) const
00102     SSRC_DECL_THROW(DatabaseException)
00103   {
00104     return load(result, index, value)._loadp<index + 1>(result, p...);
00105   }
00106 
00107 public:
00108   template<typename... P>
00109   const DefaultValueLoader & loadp(const ResultSet & result,  P & ...p) const
00110     SSRC_DECL_THROW(DatabaseException)
00111   {
00112     return _loadp<0>(result, p...);
00113   }
00114 
00115   template<const unsigned int index, typename... P>
00116   const DefaultValueLoader & loadp(const ResultSet & result,  P & ...p) const
00117     SSRC_DECL_THROW(DatabaseException)
00118   {
00119     return _loadp<index>(result, p...);
00120   }
00121 };
00122 
00123 namespace detail {
00124   template<typename row_type, unsigned int i>
00125   struct PrimaryKeyCond {
00126     static inline std::ostream & apply(std::ostream & query) {
00127       return (PrimaryKeyCond<row_type, i-1>::apply(query) << " AND `" << row_type::template column_name<row_type::template Key<i>::column>() << "` = ?");
00128     }
00129   };
00130 
00131   template<typename row_type>
00132   struct PrimaryKeyCond<row_type, 0> {
00133     static inline std::ostream & apply(std::ostream & query) {
00134       return
00135         (query << "`" << row_type::template column_name<row_type::template Key<0>::column>() << "` = ?");
00136     }
00137   };
00138 }
00139 
00140 template<typename Row, typename ValueBinder = DefaultValueBinder,
00141          typename ValueLoader = DefaultValueLoader>
00142 struct RowOperationsReadOnly {
00143   typedef Row row_type;
00144   typedef std::pair<bool, row_type> find_result_type;
00145   typedef ValueBinder binder_type;
00146   typedef ValueLoader loader_type;
00147 
00148   static const bool ImplicitColumns = false;
00149   static const bool ExplicitColumns = true;
00150 
00151   prepared_statement_ptr find_statement, exists_statement;
00152   binder_type binder;
00153   loader_type loader;
00154 
00155 protected:
00156 
00157   static string select_columns_expression(bool explicit_columns) {
00158     std::ostringstream query;
00159 
00160     if(explicit_columns) {
00161       query << '`' << row_type::column_name(0) << '`';
00162       for(unsigned int i = 1; i < row_type::ElementCount; ++i)
00163         query << ",`" << row_type::column_name(i) << '`';
00164       return query.str();
00165     } else {
00166       return string("*");
00167     }
00168   }
00169 
00170 public:
00171   RowOperationsReadOnly(Database & db,
00172                         const binder_type & binder = DefaultValueBinder(),
00173                         const loader_type & loader = DefaultValueLoader(),
00174                         const bool explicit_columns = ImplicitColumns,
00175                         const string & table_name = row_type::table_name()) :
00176     binder(binder), loader(loader)
00177   {
00178     using detail::PrimaryKeyCond;
00179 
00180     std::ostringstream query;
00181     string && select_columns = select_columns_expression(explicit_columns);
00182 
00183     query << "SELECT " << select_columns << " FROM `"
00184           << table_name << "` WHERE ";
00185     PrimaryKeyCond<row_type, row_type::PrimaryKeyCount - 1>::apply(query);
00186 
00187     find_statement = db.prepare(query.str());
00188 
00189     query.str("");
00190     query << "SELECT count(1) FROM `" << table_name << "` WHERE ";
00191     PrimaryKeyCond<row_type, row_type::PrimaryKeyCount - 1>::apply(query);
00192     exists_statement = db.prepare(query.str());
00193   }
00194 
00195   bool exists(const typename row_type::primary_key_type & key)
00196     SSRC_DECL_THROW(DatabaseException)
00197   {
00198     row_type::bind_primary_key(binder.binder(*exists_statement), key);
00199     unsigned int result = exists_statement->execute().result_set->value<unsigned int>();
00200     exists_statement->reset();
00201     return (result != 0);
00202   }
00203 
00204   bool exists(const row_type & row) SSRC_DECL_THROW(DatabaseException) {
00205     row.bind_primary_key(binder.binder(*exists_statement));
00206     unsigned int result = exists_statement->execute().result_set->value<unsigned int>();
00207     exists_statement->reset();
00208     return (result != 0);
00209   }
00210 
00211   template<typename... P> 
00212   bool exists(const P & ...p) SSRC_DECL_THROW(DatabaseException) {
00213     unsigned int result =
00214       exists_statement->execute(p...).result_set->value<unsigned int>();
00215     exists_statement->reset();
00216     return (result != 0);
00217   }
00218 
00219   find_result_type find(const typename row_type::primary_key_type & key)
00220     SSRC_DECL_THROW(DatabaseException)
00221   {
00222     row_type::bind_primary_key(binder.binder(*find_statement), key);
00223     QueryResult && result = find_statement->execute();
00224 
00225     if(result.result_set) {
00226       find_result_type value(true, *result.result_set);
00227       find_statement->reset();
00228       return value;
00229     }
00230 
00231     return find_result_type(false, row_type());
00232   }
00233 
00234   find_result_type find(const row_type & row) SSRC_DECL_THROW(DatabaseException) {
00235     row.bind_primary_key(binder.binder(*find_statement));
00236     QueryResult && result = find_statement->execute();
00237 
00238     if(result.result_set) {
00239       find_result_type value(true, *result.result_set);
00240       find_statement->reset();
00241       return value;
00242     }
00243 
00244     return find_result_type(false, row_type());
00245   }
00246 
00247   bool find(const typename row_type::primary_key_type & key,
00248             row_type & result_row)
00249     SSRC_DECL_THROW(DatabaseException)
00250   {
00251     row_type::bind_primary_key(binder.binder(*find_statement), key);
00252     QueryResult && result = find_statement->execute();
00253 
00254     if(result.result_set) {
00255       result_row.load_row(*result.result_set, loader);
00256       find_statement->reset();
00257       return true;
00258     }
00259 
00260     return false;
00261   }
00262 
00263   bool find(const row_type & row, row_type & result_row)
00264     SSRC_DECL_THROW(DatabaseException)
00265   {
00266     row.bind_primary_key(binder.binder(*find_statement));
00267     QueryResult && result = find_statement->execute();
00268 
00269     if(result.result_set) {
00270       result_row.load_row(*result.result_set, loader);
00271       find_statement->reset();
00272       return true;
00273     }
00274 
00275     return false;
00276   }
00277 
00278   template<typename... P> 
00279   find_result_type find(const P & ...p) SSRC_DECL_THROW(DatabaseException) {
00280     QueryResult && result = find_statement->execute(p...);
00281 
00282     if(result.result_set) {
00283       find_result_type value(true, *result.result_set);
00284       find_statement->reset();
00285       return value;
00286     }
00287 
00288     return find_result_type(false, row_type());
00289   }
00290 
00291 };
00292 
00293 template<typename Row, typename ValueBinder = DefaultValueBinder,
00294          typename ValueLoader = DefaultValueLoader>
00295 struct RowOperations :
00296   public RowOperationsReadOnly<Row, ValueBinder, ValueLoader>
00297 {
00298   typedef RowOperationsReadOnly<Row, ValueBinder, ValueLoader> super;
00299 
00300   WISP_IMPORT_T(super, row_type);
00301   WISP_IMPORT_T(super, find_result_type);
00302   WISP_IMPORT_T(super, binder_type);
00303   WISP_IMPORT_T(super, loader_type);
00304 
00305   prepared_statement_ptr insert_statement, save_statement, erase_statement;
00306 
00307 public:
00308   RowOperations(Database & db,
00309                 const binder_type & binder = DefaultValueBinder(),
00310                 const loader_type & loader = DefaultValueLoader(),
00311                 const bool explicit_columns = super::ImplicitColumns,
00312                 const string & table_name = row_type::table_name()) :
00313     super(db, binder, loader, explicit_columns, table_name)
00314   {
00315     using detail::PrimaryKeyCond;
00316 
00317     std::ostringstream query;
00318     string insert_columns(" ");
00319     string && select_columns =
00320       super::select_columns_expression(explicit_columns);
00321 
00322     if(explicit_columns) {
00323       insert_columns.append("(").append(select_columns).append(")");
00324     }
00325 
00326     query << "INSERT OR IGNORE INTO `" << table_name << "`"
00327           << insert_columns << "VALUES(?";
00328 
00329     for(unsigned int i = 1; i < row_type::ElementCount; ++i)
00330       query << ",?";
00331     query << ")";
00332 
00333     insert_statement = db.prepare(query.str());
00334 
00335     query.str("");
00336     query << "INSERT OR REPLACE INTO `" << table_name
00337           << "`" << insert_columns << "VALUES(?";
00338 
00339     for(unsigned int i = 1; i < row_type::ElementCount; ++i)
00340       query << ",?";
00341     query << ")";
00342 
00343     save_statement = db.prepare(query.str());
00344 
00345     query.str("");
00346     query << "DELETE FROM `" << table_name << "` WHERE ";
00347     PrimaryKeyCond<row_type, row_type::PrimaryKeyCount - 1>::apply(query);
00348 
00349     erase_statement = db.prepare(query.str());
00350   }
00351 
00352   bool insert(const row_type & row) SSRC_DECL_THROW(DatabaseException) {
00353     row.bind_row(super::binder.binder(*insert_statement));
00354     return (insert_statement->execute().changes > 0);
00355   }
00356 
00357   template<typename iterator_type>
00358   unsigned int insert(const iterator_type & begin, const iterator_type & end)
00359     SSRC_DECL_THROW(DatabaseException)
00360   {
00361     unsigned int total = 0;
00362     for(iterator_type it = begin; it !=end; ++it) {
00363       if(insert(*it))
00364         ++total;
00365     }
00366     return total;
00367   }
00368 
00369   bool save(const row_type & row) SSRC_DECL_THROW(DatabaseException) {
00370     row.bind_row(super::binder.binder(*save_statement));
00371     return (save_statement->execute().changes > 0);
00372   }
00373 
00374   template<typename iterator_type>
00375   unsigned int save(const iterator_type & begin, const iterator_type & end)
00376     SSRC_DECL_THROW(DatabaseException)
00377   {
00378     unsigned int total = 0;
00379     for(iterator_type it = begin; it !=end; ++it) {
00380       if(save(*it))
00381         ++total;
00382     }
00383     return total;
00384   }
00385 
00386   unsigned int erase(const typename row_type::primary_key_type & key)
00387     SSRC_DECL_THROW(DatabaseException)
00388   {
00389     row_type::bind_primary_key(super::binder.binder(*erase_statement), key);
00390     return erase_statement->execute().changes;
00391   }
00392 
00393   unsigned int erase(const row_type & row) SSRC_DECL_THROW(DatabaseException) {
00394     row.bind_primary_key(super::binder.binder(*erase_statement));
00395     return erase_statement->execute().changes;
00396   }
00397 
00398   template<typename iterator_type>
00399   unsigned int
00400   erase_range(const iterator_type & begin, const iterator_type & end)
00401     SSRC_DECL_THROW(DatabaseException)
00402   {
00403     unsigned int total = 0;
00404     for(iterator_type it = begin; it !=end; ++it) {
00405       total+=erase(*it);
00406     }
00407     return total;
00408   }
00409 
00410   template<typename... P> 
00411   unsigned int erase(const P & ...p) SSRC_DECL_THROW(DatabaseException) {
00412     return erase_statement->execute(p...).changes;
00413   }
00414 };
00415 
00416 // Utility functions for commonly recurring cases.
00417 template<typename value_type, typename... P>
00418 inline value_type find_value(const prepared_statement_ptr & query,
00419                              const value_type & default_value,
00420                              P && ...p)
00421 {
00422   std::pair<bool, value_type> && result =
00423     find_row<value_type>(*query, std::forward<P>(p)...);
00424   return (result.first ? result.second : default_value);
00425 }
00426 
00427 template<typename value_type, typename... P>
00428 inline value_type max_id(const prepared_statement_ptr & max_query, P && ...p) {
00429   return find_value<value_type>(max_query,
00430                                 boost::integer_traits<value_type>::const_min,
00431                                 std::forward<P>(p)...);
00432 }
00433 
00434 __END_NS_SSRC_WSPR_DATABASE
00435 
00436 #endif

Savarese Software Research Corporation
Copyright © 2006-2011 Savarese Software Research Corporation. All rights reserved.