query_result.h
Go to the documentation of this file.
1 #ifndef cetlib_sqlite_query_result_h
2 #define cetlib_sqlite_query_result_h
3 
4 // ================================================================
5 // query_result<T...>
6 //
7 // The query_result template contains the result of an SQLite table
8 // query. The supplied template arguments specify the C++ types that
9 // should be used to represent the entries of each row returned by the
10 // query.
11 //
12 // The query_result is not automatically populated upon construction,
13 // but it is populated to a call to operator<< (e.g.):
14 //
15 // query_result<int, string> nums;
16 // nums << select("id", "name").from(db, "workers");
17 //
18 // where 'nums' now contains the set of values from column "id" and
19 // column "name" of table "workers" in the database db. After the
20 // query result has been filled, it can be interacted through a simple
21 // loop:
22 //
23 // for (auto const& [id, name] : nums) {
24 // // 'id' (type int) and 'name' (type string) now filled with the
25 // // results of each row from the query.
26 // }
27 //
28 // For cases where only one row and one column are expected for the
29 // query, an automatic conversion can be achieved by using
30 // 'unique_value' (e.g.):
31 //
32 // query_result<unsigned> r;
33 // r << select("age").from(db, "workers");
34 // unsigned const highest_age {unique_value(r)};
35 //
36 // If 'r' contains more than one row and/or more than one column, an
37 // exception would be thrown upon a call to unique_value.
38 //
39 // ----------------------------------------------------------------
40 // Technical considerations:
41 //
42 // Instead of filling a query_result via a call like:
43 //
44 // query_result<T...> r;
45 // r << select(...).from(...);
46 //
47 // a query_result should probably take a SelectStmt as its c'tor
48 // argument, whereupon construction, the query takes place and the
49 // query_result can then be used without any operator<< equals
50 // calls:
51 //
52 // query_result<T...> const r {select(...).from(...)};
53 //
54 // This was not implemented since the c'tor calls could get
55 // very long--but that is arguably a poor reason for retaining the
56 // above interface.
57 //
58 // =======================================================
59 
60 #include <sstream>
61 #include <tuple>
62 #include <vector>
63 
66 
67 namespace cet::sqlite {
68 
69  template <typename... Args>
70  struct query_result {
71  bool
72  empty() const
73  {
74  return data.empty();
75  }
76  auto
77  begin() const
78  {
79  return data.begin();
80  }
81  auto
82  end() const
83  {
84  return data.end();
85  }
86  explicit operator bool() const { return !empty(); }
87 
88  std::vector<std::string> columns;
89  std::vector<std::tuple<Args...>> data;
90  };
91 
92  template <typename T>
93  inline T
95  {
96  if (r.data.size() != 1ull) {
98  << "unique_value expected of non-unique query.";
99  }
100  return std::get<T>(r.data[0]);
101  }
102 
103  template <typename... Args>
104  std::ostream&
105  operator<<(std::ostream& os, query_result<Args...> const& res)
106  {
107  using size_t = decltype(res.columns.size());
108  auto const ncolumns = res.columns.size();
109  for (size_t i{}; i != ncolumns; ++i) {
110  os << res.columns[i] << ' ';
111  }
112  os << "\n--------------------------------\n";
113  for (auto const& row : res.data) {
114  os << row.str() << '\n';
115  }
116  return os;
117  }
118 
119 } // cet::sqlite
120 
121 #endif /* cetlib_sqlite_query_result_h */
122 
123 // Local Variables:
124 // mode: c++
125 // End:
T unique_value(query_result< T > const &r)
Definition: query_result.h:94
std::vector< std::string > columns
Definition: query_result.h:88
struct vector vector
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:27
std::ostream & operator<<(std::ostream &os, query_result< Args... > const &res)
Definition: query_result.h:105
std::vector< std::tuple< Args... > > data
Definition: query_result.h:89
int bool
Definition: qglobal.h:345