diff options
Diffstat (limited to 'lib/query.h')
-rw-r--r-- | lib/query.h | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/lib/query.h b/lib/query.h new file mode 100644 index 0000000..e31be3d --- /dev/null +++ b/lib/query.h | |||
@@ -0,0 +1,123 @@ | |||
1 | #ifndef QUERY_H_7CC5284C | ||
2 | #define QUERY_H_7CC5284C | ||
3 | |||
4 | #include <vector> | ||
5 | #include <stdexcept> | ||
6 | #include <string> | ||
7 | #include <list> | ||
8 | #include <sqlite3.h> | ||
9 | #include <iostream> | ||
10 | #include "statement.h" | ||
11 | #include "binding.h" | ||
12 | |||
13 | namespace verbly { | ||
14 | |||
15 | class database_error : public std::logic_error { | ||
16 | public: | ||
17 | |||
18 | database_error(std::string msg, std::string sqlMsg) : std::logic_error(msg + " (" + sqlMsg + ")") | ||
19 | { | ||
20 | } | ||
21 | }; | ||
22 | |||
23 | template <typename Object> | ||
24 | class query { | ||
25 | public: | ||
26 | |||
27 | query(const database& db, sqlite3* ppdb, filter queryFilter, bool random, int limit) : db_(&db) | ||
28 | { | ||
29 | statement stmt(Object::objectType, std::move(queryFilter)); | ||
30 | |||
31 | std::string queryString = stmt.getQueryString(Object::select, random, limit); | ||
32 | std::list<binding> bindings = stmt.getBindings(); | ||
33 | |||
34 | std::cout << queryString << std::endl; | ||
35 | |||
36 | if (sqlite3_prepare_v2(ppdb, queryString.c_str(), queryString.length(), &ppstmt_, NULL) != SQLITE_OK) | ||
37 | { | ||
38 | std::string errorMsg = sqlite3_errmsg(ppdb); | ||
39 | sqlite3_finalize(ppstmt_); | ||
40 | |||
41 | throw database_error("Error preparing query", errorMsg); | ||
42 | } | ||
43 | |||
44 | int i = 1; | ||
45 | for (const binding& value : bindings) | ||
46 | { | ||
47 | switch (value.getType()) | ||
48 | { | ||
49 | case binding::type::integer: | ||
50 | { | ||
51 | if (sqlite3_bind_int(ppstmt_, i, value.getInteger()) != SQLITE_OK) | ||
52 | { | ||
53 | std::string errorMsg = sqlite3_errmsg(ppdb); | ||
54 | sqlite3_finalize(ppstmt_); | ||
55 | |||
56 | throw database_error("Error binding value to query", errorMsg); | ||
57 | } | ||
58 | |||
59 | break; | ||
60 | } | ||
61 | |||
62 | case binding::type::string: | ||
63 | { | ||
64 | if (sqlite3_bind_text(ppstmt_, i, value.getString().c_str(), value.getString().length(), SQLITE_TRANSIENT) != SQLITE_OK) | ||
65 | { | ||
66 | std::string errorMsg = sqlite3_errmsg(ppdb); | ||
67 | sqlite3_finalize(ppstmt_); | ||
68 | |||
69 | throw database_error("Error binding value to query", errorMsg); | ||
70 | } | ||
71 | |||
72 | break; | ||
73 | } | ||
74 | |||
75 | case binding::type::invalid: | ||
76 | { | ||
77 | throw std::logic_error("Cannot use invalid bindings"); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | i++; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | ~query() | ||
86 | { | ||
87 | sqlite3_finalize(ppstmt_); | ||
88 | } | ||
89 | |||
90 | std::vector<Object> all() const | ||
91 | { | ||
92 | std::vector<Object> result; | ||
93 | |||
94 | while (sqlite3_step(ppstmt_) == SQLITE_ROW) | ||
95 | { | ||
96 | result.emplace_back(*db_, ppstmt_); | ||
97 | } | ||
98 | |||
99 | sqlite3_reset(ppstmt_); | ||
100 | |||
101 | return result; | ||
102 | } | ||
103 | |||
104 | Object first() const | ||
105 | { | ||
106 | std::vector<Object> results = all(); | ||
107 | if (!results.empty()) | ||
108 | { | ||
109 | return results.front(); | ||
110 | } else { | ||
111 | throw std::logic_error("query returned empty dataset"); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | private: | ||
116 | const database* db_; | ||
117 | sqlite3_stmt* ppstmt_; | ||
118 | |||
119 | }; | ||
120 | |||
121 | }; | ||
122 | |||
123 | #endif /* end of include guard: QUERY_H_7CC5284C */ | ||