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
|