Web Wispers 1.2.2 C++ Unit Test Coverage
Current view: top level - ssrc/wispers/database - RowOperations.h (source / functions) Hit Total Coverage
Test: Web Wispers 1.2.2 C++ Unit Tests Lines: 128 130 98.5 %
Date: 2012-04-09 Functions: 80 80 100.0 %
Branches: 378 766 49.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright 2006-2009 Savarese Software Research Corporation
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at
       7                 :            :  *
       8                 :            :  *     https://www.savarese.com/software/ApacheLicense-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : /**
      18                 :            :  * @file
      19                 :            :  * This header defines the RowOperations class.
      20                 :            :  */
      21                 :            : 
      22                 :            : #ifndef __SSRC_WSPR_DATABASE_ROW_OPERATIONS_H
      23                 :            : #define __SSRC_WSPR_DATABASE_ROW_OPERATIONS_H
      24                 :            : 
      25                 :            : #include <ssrc/wispers/database/Database.h>
      26                 :            : #include <ssrc/wisp/utility/wisp_import.h>
      27                 :            : 
      28                 :            : #include <boost/integer_traits.hpp>
      29                 :            : 
      30                 :            : __BEGIN_NS_SSRC_WSPR_DATABASE
      31                 :            : 
      32                 :            : namespace detail {
      33                 :            :   template<typename T, bool is_basic> struct FindRow;
      34                 :            : 
      35                 :            :   template<typename T>
      36                 :            :   struct FindRow<T, true> {
      37                 :            :     template<typename... P>
      38                 :            :     static std::pair<bool, T> exec(PreparedStatement & query, P && ...p) {
      39                 :            :       QueryResult && result = query.execute(std::forward<P>(p)...);
      40                 :            : 
      41                 :            :       if(result.result_set) {
      42                 :            :         std::pair<bool, T> value(true, result.result_set->value<T>());
      43                 :            :         query.reset();
      44                 :            :         return value;
      45                 :            :       }
      46                 :            : 
      47                 :            :       return std::pair<bool, T>(false, T());
      48                 :            :     }
      49                 :            :   };
      50                 :            : 
      51                 :            :   template<typename T>
      52                 :            :   struct FindRow<T, false> {
      53                 :            :     template<typename... P>
      54                 :            :     static std::pair<bool, T> exec(PreparedStatement & query, P && ...p) {
      55                 :            :       QueryResult && result = query.execute(std::forward<P>(p)...);
      56                 :            : 
      57                 :            :       if(result.result_set) {
      58                 :            :         std::pair<bool, T> value(true, *result.result_set);
      59                 :            :         query.reset();
      60                 :            :         return value;
      61                 :            :       }
      62                 :            : 
      63                 :            :       return std::pair<bool, T>(false, T());
      64                 :            :     }
      65                 :            :   };
      66                 :            : }
      67                 :            : 
      68                 :            : // Convenience function for implementing single object lookups.
      69                 :            : template<typename T, typename... P>
      70                 :            : inline std::pair<bool, T> find_row(PreparedStatement & query, P && ...p)
      71                 :            :   SSRC_DECL_THROW(DatabaseException)
      72                 :            : {
      73                 :            :   return detail::FindRow<T, detail::is_basic_type<T>::value>::exec(query, std::forward<P>(p)...);
      74                 :            : }
      75                 :            : 
      76                 :            : struct DefaultValueBinder {
      77                 :            :   typedef PreparedStatement binder_type;
      78                 :            : 
      79                 :        180 :   static binder_type & binder(PreparedStatement & statement) {
      80                 :        180 :     return statement;
      81                 :            :   }
      82                 :            : };
      83                 :            : 
      84                 :            : struct DefaultValueLoader {
      85                 :            :   template<typename T>
      86                 :            :   const DefaultValueLoader &
      87                 :          8 :   load(const ResultSet & result, const unsigned int index, T & value) const {
      88   [ +  -  +  - ]:          8 :     value = std::move(result.value<typename detail::ResultSetValueTraits<T, detail::is_basic_type<T>::value>::db_value_type>(index));
      89                 :          8 :     return *this;
      90                 :            :   }
      91                 :            : 
      92                 :            : private:
      93                 :            :   template<const unsigned int index, typename T, typename... P>
      94                 :          4 :   const DefaultValueLoader & _loadp(const ResultSet & result,  T & value) const
      95                 :            :     SSRC_DECL_THROW(DatabaseException)
      96                 :            :   {
      97                 :          4 :     return load(result, index, value);
      98                 :            :   }
      99                 :            : 
     100                 :            :   template<const unsigned int index, typename T, typename... P>
     101                 :          4 :   const DefaultValueLoader & _loadp(const ResultSet & result,  T & value, P & ...p) const
     102                 :            :     SSRC_DECL_THROW(DatabaseException)
     103                 :            :   {
     104                 :          4 :     return load(result, index, value)._loadp<index + 1>(result, p...);
     105                 :            :   }
     106                 :            : 
     107                 :            : public:
     108                 :            :   template<typename... P>
     109                 :            :   const DefaultValueLoader & loadp(const ResultSet & result,  P & ...p) const
     110                 :            :     SSRC_DECL_THROW(DatabaseException)
     111                 :            :   {
     112                 :            :     return _loadp<0>(result, p...);
     113                 :            :   }
     114                 :            : 
     115                 :            :   template<const unsigned int index, typename... P>
     116                 :          4 :   const DefaultValueLoader & loadp(const ResultSet & result,  P & ...p) const
     117                 :            :     SSRC_DECL_THROW(DatabaseException)
     118                 :            :   {
     119                 :          4 :     return _loadp<index>(result, p...);
     120                 :            :   }
     121                 :            : };
     122                 :            : 
     123                 :            : namespace detail {
     124                 :            :   template<typename row_type, unsigned int i>
     125                 :            :   struct PrimaryKeyCond {
     126                 :        158 :     static inline std::ostream & apply(std::ostream & query) {
     127   [ +  -  +  -  :        158 :       return (PrimaryKeyCond<row_type, i-1>::apply(query) << " AND `" << row_type::template column_name<row_type::template Key<i>::column>() << "` = ?");
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     128                 :            :     }
     129                 :            :   };
     130                 :            : 
     131                 :            :   template<typename row_type>
     132                 :            :   struct PrimaryKeyCond<row_type, 0> {
     133                 :        266 :     static inline std::ostream & apply(std::ostream & query) {
     134                 :            :       return
     135   [ +  -  +  -  :        266 :         (query << "`" << row_type::template column_name<row_type::template Key<0>::column>() << "` = ?");
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
     136                 :            :     }
     137                 :            :   };
     138                 :            : }
     139                 :            : 
     140                 :            : template<typename Row, typename ValueBinder = DefaultValueBinder,
     141                 :            :          typename ValueLoader = DefaultValueLoader>
     142   [ +  -  +  -  :         86 : struct RowOperationsReadOnly {
                   +  - ]
     143                 :            :   typedef Row row_type;
     144                 :            :   typedef std::pair<bool, row_type> find_result_type;
     145                 :            :   typedef ValueBinder binder_type;
     146                 :            :   typedef ValueLoader loader_type;
     147                 :            : 
     148                 :            :   static const bool ImplicitColumns = false;
     149                 :            :   static const bool ExplicitColumns = true;
     150                 :            : 
     151                 :            :   prepared_statement_ptr find_statement, exists_statement;
     152                 :            :   binder_type binder;
     153                 :            :   loader_type loader;
     154                 :            : 
     155                 :            : protected:
     156                 :            : 
     157                 :        176 :   static string select_columns_expression(bool explicit_columns) {
     158                 :        352 :     std::ostringstream query;
     159                 :            : 
     160   [ +  +  +  +  :        176 :     if(explicit_columns) {
                   -  + ]
     161   [ +  -  +  -  :         38 :       query << '`' << row_type::column_name(0) << '`';
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  #  #  #  #  
          #  #  #  #  #  
                      # ]
     162   [ +  +  +  +  :        300 :       for(unsigned int i = 1; i < row_type::ElementCount; ++i)
                   #  # ]
     163   [ +  -  +  -  :        262 :         query << ",`" << row_type::column_name(i) << '`';
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  #  #  #  #  
          #  #  #  #  #  
                      # ]
     164   [ +  -  +  -  :         38 :       return query.str();
                   #  # ]
     165                 :            :     } else {
     166   [ +  -  +  -  :        138 :       return string("*");
                   +  - ]
     167                 :            :     }
     168                 :            :   }
     169                 :            : 
     170                 :            : public:
     171                 :         86 :   RowOperationsReadOnly(Database & db,
     172                 :            :                         const binder_type & binder = DefaultValueBinder(),
     173                 :            :                         const loader_type & loader = DefaultValueLoader(),
     174                 :            :                         const bool explicit_columns = ImplicitColumns,
     175                 :            :                         const string & table_name = row_type::table_name()) :
     176                 :         86 :     binder(binder), loader(loader)
     177                 :            :   {
     178                 :            :     using detail::PrimaryKeyCond;
     179                 :            : 
     180   [ +  -  +  -  :        172 :     std::ostringstream query;
          +  -  +  -  +  
                -  +  - ]
     181   [ +  -  +  -  :        172 :     string && select_columns = select_columns_expression(explicit_columns);
          +  -  +  -  +  
                -  +  - ]
     182                 :            : 
     183   [ +  -  +  -  :         86 :     query << "SELECT " << select_columns << " FROM `"
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     184                 :            :           << table_name << "` WHERE ";
     185   [ +  -  +  -  :         86 :     PrimaryKeyCond<row_type, row_type::PrimaryKeyCount - 1>::apply(query);
                   +  - ]
     186                 :            : 
     187   [ +  -  +  -  :         86 :     find_statement = db.prepare(query.str());
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     188                 :            : 
     189   [ +  -  +  -  :         86 :     query.str("");
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
     190   [ +  -  +  -  :         86 :     query << "SELECT count(1) FROM `" << table_name << "` WHERE ";
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
     191   [ +  -  +  -  :         86 :     PrimaryKeyCond<row_type, row_type::PrimaryKeyCount - 1>::apply(query);
                   +  - ]
     192   [ +  -  +  -  :         86 :     exists_statement = db.prepare(query.str());
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     193                 :         86 :   }
     194                 :            : 
     195                 :          2 :   bool exists(const typename row_type::primary_key_type & key)
     196                 :            :     SSRC_DECL_THROW(DatabaseException)
     197                 :            :   {
     198                 :          2 :     row_type::bind_primary_key(binder.binder(*exists_statement), key);
     199         [ +  - ]:          2 :     unsigned int result = exists_statement->execute().result_set->value<unsigned int>();
     200                 :          2 :     exists_statement->reset();
     201                 :          2 :     return (result != 0);
     202                 :            :   }
     203                 :            : 
     204                 :          4 :   bool exists(const row_type & row) SSRC_DECL_THROW(DatabaseException) {
     205                 :          4 :     row.bind_primary_key(binder.binder(*exists_statement));
     206   [ +  -  +  - ]:          4 :     unsigned int result = exists_statement->execute().result_set->value<unsigned int>();
     207                 :          4 :     exists_statement->reset();
     208                 :          4 :     return (result != 0);
     209                 :            :   }
     210                 :            : 
     211                 :            :   template<typename... P> 
     212                 :          2 :   bool exists(const P & ...p) SSRC_DECL_THROW(DatabaseException) {
     213                 :            :     unsigned int result =
     214         [ +  - ]:          2 :       exists_statement->execute(p...).result_set->value<unsigned int>();
     215                 :          2 :     exists_statement->reset();
     216                 :          2 :     return (result != 0);
     217                 :            :   }
     218                 :            : 
     219                 :         44 :   find_result_type find(const typename row_type::primary_key_type & key)
     220                 :            :     SSRC_DECL_THROW(DatabaseException)
     221                 :            :   {
     222                 :         44 :     row_type::bind_primary_key(binder.binder(*find_statement), key);
     223                 :         88 :     QueryResult && result = find_statement->execute();
     224                 :            : 
     225   [ +  -  +  +  :         44 :     if(result.result_set) {
                   +  - ]
     226   [ +  -  +  -  :         49 :       find_result_type value(true, *result.result_set);
             +  -  +  -  
                      + ]
     227   [ +  -  +  -  :         42 :       find_statement->reset();
          +  -  +  -  +  
                -  +  - ]
     228   [ +  -  +  -  :         42 :       return value;
                   +  - ]
     229                 :            :     }
     230                 :            : 
     231   [ #  #  #  #  :          2 :     return find_result_type(false, row_type());
          +  -  +  -  +  
          -  +  -  +  -  
          #  #  #  #  #  
             #  #  #  # ]
     232                 :            :   }
     233                 :            : 
     234                 :          4 :   find_result_type find(const row_type & row) SSRC_DECL_THROW(DatabaseException) {
     235                 :          4 :     row.bind_primary_key(binder.binder(*find_statement));
     236                 :          8 :     QueryResult && result = find_statement->execute();
     237                 :            : 
     238         [ +  + ]:          4 :     if(result.result_set) {
     239         [ +  - ]:          2 :       find_result_type value(true, *result.result_set);
     240   [ +  -  +  - ]:          2 :       find_statement->reset();
     241         [ +  - ]:          2 :       return value;
     242                 :            :     }
     243                 :            : 
     244   [ +  -  +  - ]:          2 :     return find_result_type(false, row_type());
     245                 :            :   }
     246                 :            : 
     247                 :          2 :   bool find(const typename row_type::primary_key_type & key,
     248                 :            :             row_type & result_row)
     249                 :            :     SSRC_DECL_THROW(DatabaseException)
     250                 :            :   {
     251                 :          2 :     row_type::bind_primary_key(binder.binder(*find_statement), key);
     252                 :          4 :     QueryResult && result = find_statement->execute();
     253                 :            : 
     254         [ +  - ]:          2 :     if(result.result_set) {
     255         [ +  - ]:          2 :       result_row.load_row(*result.result_set, loader);
     256   [ +  -  +  - ]:          2 :       find_statement->reset();
     257                 :          2 :       return true;
     258                 :            :     }
     259                 :            : 
     260                 :          0 :     return false;
     261                 :            :   }
     262                 :            : 
     263                 :          2 :   bool find(const row_type & row, row_type & result_row)
     264                 :            :     SSRC_DECL_THROW(DatabaseException)
     265                 :            :   {
     266                 :          2 :     row.bind_primary_key(binder.binder(*find_statement));
     267                 :          4 :     QueryResult && result = find_statement->execute();
     268                 :            : 
     269         [ +  - ]:          2 :     if(result.result_set) {
     270         [ +  - ]:          2 :       result_row.load_row(*result.result_set, loader);
     271   [ +  -  +  - ]:          2 :       find_statement->reset();
     272                 :          2 :       return true;
     273                 :            :     }
     274                 :            : 
     275                 :          0 :     return false;
     276                 :            :   }
     277                 :            : 
     278                 :            :   template<typename... P> 
     279                 :         19 :   find_result_type find(const P & ...p) SSRC_DECL_THROW(DatabaseException) {
     280                 :         38 :     QueryResult && result = find_statement->execute(p...);
     281                 :            : 
     282   [ +  +  +  + ]:         19 :     if(result.result_set) {
     283   [ +  -  +  -  :         14 :       find_result_type value(true, *result.result_set);
             +  -  +  - ]
     284   [ +  -  +  -  :          8 :       find_statement->reset();
             +  -  +  - ]
     285   [ +  -  +  - ]:          8 :       return value;
     286                 :            :     }
     287                 :            : 
     288   [ -  #  -  #  :         11 :     return find_result_type(false, row_type());
          +  +  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  +  - ]
     289                 :            :   }
     290                 :            : 
     291                 :            : };
     292                 :            : 
     293                 :            : template<typename Row, typename ValueBinder = DefaultValueBinder,
     294                 :            :          typename ValueLoader = DefaultValueLoader>
     295   [ +  -  +  -  :         86 : struct RowOperations :
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
     296                 :            :   public RowOperationsReadOnly<Row, ValueBinder, ValueLoader>
     297                 :            : {
     298                 :            :   typedef RowOperationsReadOnly<Row, ValueBinder, ValueLoader> super;
     299                 :            : 
     300                 :            :   WISP_IMPORT_T(super, row_type);
     301                 :            :   WISP_IMPORT_T(super, find_result_type);
     302                 :            :   WISP_IMPORT_T(super, binder_type);
     303                 :            :   WISP_IMPORT_T(super, loader_type);
     304                 :            : 
     305                 :            :   prepared_statement_ptr insert_statement, save_statement, erase_statement;
     306                 :            : 
     307                 :            : public:
     308                 :         86 :   RowOperations(Database & db,
     309                 :            :                 const binder_type & binder = DefaultValueBinder(),
     310                 :            :                 const loader_type & loader = DefaultValueLoader(),
     311                 :            :                 const bool explicit_columns = super::ImplicitColumns,
     312                 :            :                 const string & table_name = row_type::table_name()) :
     313                 :         86 :     super(db, binder, loader, explicit_columns, table_name)
     314                 :            :   {
     315                 :            :     using detail::PrimaryKeyCond;
     316                 :            : 
     317   [ +  -  +  -  :        172 :     std::ostringstream query;
          +  -  +  -  +  
                -  +  - ]
     318   [ +  -  +  -  :        172 :     string insert_columns(" ");
          +  -  +  -  +  
                -  +  - ]
     319                 :            :     string && select_columns =
     320   [ +  -  +  -  :        172 :       super::select_columns_expression(explicit_columns);
          +  -  +  -  +  
                -  +  - ]
     321                 :            : 
     322   [ +  +  +  +  :         86 :     if(explicit_columns) {
                   -  + ]
     323   [ +  -  +  -  :         18 :       insert_columns.append("(").append(select_columns).append(")");
          +  -  +  -  +  
          -  +  -  #  #  
             #  #  #  # ]
     324                 :            :     }
     325                 :            : 
     326   [ +  -  +  -  :         86 :     query << "INSERT OR IGNORE INTO `" << table_name << "`"
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     327                 :            :           << insert_columns << "VALUES(?";
     328                 :            : 
     329   [ +  +  +  +  :        365 :     for(unsigned int i = 1; i < row_type::ElementCount; ++i)
                   +  + ]
     330   [ +  -  +  -  :        279 :       query << ",?";
                   +  - ]
     331   [ +  -  +  -  :         86 :     query << ")";
                   +  - ]
     332                 :            : 
     333   [ +  -  +  -  :         86 :     insert_statement = db.prepare(query.str());
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     334                 :            : 
     335   [ +  -  +  -  :         86 :     query.str("");
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
     336   [ +  -  +  -  :         86 :     query << "INSERT OR REPLACE INTO `" << table_name
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     337                 :            :           << "`" << insert_columns << "VALUES(?";
     338                 :            : 
     339   [ +  +  +  +  :        365 :     for(unsigned int i = 1; i < row_type::ElementCount; ++i)
                   +  + ]
     340   [ +  -  +  -  :        279 :       query << ",?";
                   +  - ]
     341   [ +  -  +  -  :         86 :     query << ")";
                   +  - ]
     342                 :            : 
     343   [ +  -  +  -  :         86 :     save_statement = db.prepare(query.str());
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     344                 :            : 
     345   [ +  -  +  -  :         86 :     query.str("");
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
     346   [ +  -  +  -  :         86 :     query << "DELETE FROM `" << table_name << "` WHERE ";
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
     347   [ +  -  +  -  :         86 :     PrimaryKeyCond<row_type, row_type::PrimaryKeyCount - 1>::apply(query);
                   +  - ]
     348                 :            : 
     349   [ +  -  +  -  :         86 :     erase_statement = db.prepare(query.str());
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     350                 :         86 :   }
     351                 :            : 
     352                 :         48 :   bool insert(const row_type & row) SSRC_DECL_THROW(DatabaseException) {
     353                 :         48 :     row.bind_row(super::binder.binder(*insert_statement));
     354                 :         48 :     return (insert_statement->execute().changes > 0);
     355                 :            :   }
     356                 :            : 
     357                 :            :   template<typename iterator_type>
     358                 :          2 :   unsigned int insert(const iterator_type & begin, const iterator_type & end)
     359                 :            :     SSRC_DECL_THROW(DatabaseException)
     360                 :            :   {
     361                 :          2 :     unsigned int total = 0;
     362         [ +  + ]:          8 :     for(iterator_type it = begin; it !=end; ++it) {
     363         [ +  - ]:          6 :       if(insert(*it))
     364                 :          6 :         ++total;
     365                 :            :     }
     366                 :          2 :     return total;
     367                 :            :   }
     368                 :            : 
     369                 :         66 :   bool save(const row_type & row) SSRC_DECL_THROW(DatabaseException) {
     370                 :         66 :     row.bind_row(super::binder.binder(*save_statement));
     371                 :         66 :     return (save_statement->execute().changes > 0);
     372                 :            :   }
     373                 :            : 
     374                 :            :   template<typename iterator_type>
     375                 :            :   unsigned int save(const iterator_type & begin, const iterator_type & end)
     376                 :            :     SSRC_DECL_THROW(DatabaseException)
     377                 :            :   {
     378                 :            :     unsigned int total = 0;
     379                 :            :     for(iterator_type it = begin; it !=end; ++it) {
     380                 :            :       if(save(*it))
     381                 :            :         ++total;
     382                 :            :     }
     383                 :            :     return total;
     384                 :            :   }
     385                 :            : 
     386                 :            :   unsigned int erase(const typename row_type::primary_key_type & key)
     387                 :            :     SSRC_DECL_THROW(DatabaseException)
     388                 :            :   {
     389                 :            :     row_type::bind_primary_key(super::binder.binder(*erase_statement), key);
     390                 :            :     return erase_statement->execute().changes;
     391                 :            :   }
     392                 :            : 
     393                 :          4 :   unsigned int erase(const row_type & row) SSRC_DECL_THROW(DatabaseException) {
     394                 :          4 :     row.bind_primary_key(super::binder.binder(*erase_statement));
     395                 :          4 :     return erase_statement->execute().changes;
     396                 :            :   }
     397                 :            : 
     398                 :            :   template<typename iterator_type>
     399                 :            :   unsigned int
     400                 :            :   erase_range(const iterator_type & begin, const iterator_type & end)
     401                 :            :     SSRC_DECL_THROW(DatabaseException)
     402                 :            :   {
     403                 :            :     unsigned int total = 0;
     404                 :            :     for(iterator_type it = begin; it !=end; ++it) {
     405                 :            :       total+=erase(*it);
     406                 :            :     }
     407                 :            :     return total;
     408                 :            :   }
     409                 :            : 
     410                 :            :   template<typename... P> 
     411                 :          5 :   unsigned int erase(const P & ...p) SSRC_DECL_THROW(DatabaseException) {
     412                 :          5 :     return erase_statement->execute(p...).changes;
     413                 :            :   }
     414                 :            : };
     415                 :            : 
     416                 :            : // Utility functions for commonly recurring cases.
     417                 :            : template<typename value_type, typename... P>
     418                 :            : inline value_type find_value(const prepared_statement_ptr & query,
     419                 :            :                              const value_type & default_value,
     420                 :            :                              P && ...p)
     421                 :            : {
     422                 :            :   std::pair<bool, value_type> && result =
     423                 :            :     find_row<value_type>(*query, std::forward<P>(p)...);
     424                 :            :   return (result.first ? result.second : default_value);
     425                 :            : }
     426                 :            : 
     427                 :            : template<typename value_type, typename... P>
     428                 :            : inline value_type max_id(const prepared_statement_ptr & max_query, P && ...p) {
     429                 :            :   return find_value<value_type>(max_query,
     430                 :            :                                 boost::integer_traits<value_type>::const_min,
     431                 :            :                                 std::forward<P>(p)...);
     432                 :            : }
     433                 :            : 
     434                 :            : __END_NS_SSRC_WSPR_DATABASE
     435                 :            : 
     436                 :            : #endif