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
Copyright © 2006-2011 Savarese Software Research Corporation. All rights reserved.