Orbit Framework
An ultra-modern, asynchronous, cross-platform C++ Web Framework.
Loading...
Searching...
No Matches
QueryBuilder.hpp
Go to the documentation of this file.
1#pragma once
2#include <string>
3#include <vector>
4#include <memory>
5#include <coroutine>
6#include <orbit/http/json.hpp>
8
9namespace orm {
10
14struct Expr {
15 std::string sql;
16
17 Expr operator&&(const Expr& other) const {
18 return Expr{"(" + sql + " AND " + other.sql + ")"};
19 }
20
21 Expr operator||(const Expr& other) const {
22 return Expr{"(" + sql + " OR " + other.sql + ")"};
23 }
24};
25
29class Col {
30public:
31 explicit Col(std::string name) : name_(std::move(name)) {}
32
33 template <typename T>
34 Expr operator==(const T& val) const { return Expr{name_ + " = '" + format_val(val) + "'"}; }
35
36 template <typename T>
37 Expr operator!=(const T& val) const { return Expr{name_ + " != '" + format_val(val) + "'"}; }
38
39 template <typename T>
40 Expr operator>(const T& val) const { return Expr{name_ + " > '" + format_val(val) + "'"}; }
41
42 template <typename T>
43 Expr operator<(const T& val) const { return Expr{name_ + " < '" + format_val(val) + "'"}; }
44
45 template <typename T>
46 Expr operator>=(const T& val) const { return Expr{name_ + " >= '" + format_val(val) + "'"}; }
47
48 template <typename T>
49 Expr operator<=(const T& val) const { return Expr{name_ + " <= '" + format_val(val) + "'"}; }
50
51private:
52 std::string name_;
53
54 template <typename T>
55 std::string format_val(const T& val) const {
56 if constexpr (std::is_same_v<T, bool>) {
57 return val ? "true" : "false";
58 } else if constexpr (std::is_arithmetic_v<T>) {
59 return std::to_string(val);
60 } else {
61 return std::string(val); // Strings
62 }
63 }
64};
65
69template <typename DBClient>
70auto do_query_async(std::shared_ptr<DBClient> client, const std::string& sql) {
71 // We use if constexpr to detect if DBClient has a query_async member.
72 // If it does (e.g. MysqlClient), we use it. If not, we assume a free function exists (PostgresClient).
73 if constexpr (requires { client->query_async(sql); }) {
74 return client->query_async(sql);
75 } else {
76 return database::query_async(client, sql);
77 }
78}
79
80template <typename DBClient, typename ModelType>
82 using NativeAwaiter = decltype(do_query_async(std::declval<std::shared_ptr<DBClient>>(), std::declval<std::string>()));
84
85 bool await_ready() const { return native_awaiter.await_ready(); }
86 void await_suspend(std::coroutine_handle<> h) { native_awaiter.await_suspend(h); }
87
88 std::vector<ModelType> await_resume() {
89 database::ResultSet rs = native_awaiter.await_resume();
90 return rs.to_json().get<std::vector<ModelType>>();
91 }
92};
93
94template <typename DBClient, typename ModelType>
96 using NativeAwaiter = decltype(do_query_async(std::declval<std::shared_ptr<DBClient>>(), std::declval<std::string>()));
98
99 bool await_ready() const { return native_awaiter.await_ready(); }
100 void await_suspend(std::coroutine_handle<> h) { native_awaiter.await_suspend(h); }
101
102 uint64_t await_resume() {
103 database::ResultSet rs = native_awaiter.await_resume();
104 return rs.affected_rows();
105 }
106};
107
111template <typename DBClient, typename ModelType>
113public:
114 QueryBuilder(std::shared_ptr<DBClient> db, const std::string& table)
115 : db_(std::move(db)), table_(table) {}
116
120 QueryBuilder& where(const std::string& field, const std::string& op, const std::string& val) {
121 wheres_.push_back(field + " " + op + " '" + val + "'");
122 return *this;
123 }
124
130 QueryBuilder& where(const Expr& expr) {
131 wheres_.push_back(expr.sql);
132 return *this;
133 }
134
139 std::string sql = "SELECT * FROM " + table_;
140 if (!wheres_.empty()) {
141 sql += " WHERE ";
142 for (size_t i = 0; i < wheres_.size(); ++i) {
143 if (i > 0) sql += " AND ";
144 sql += wheres_[i];
145 }
146 }
148 }
149
154 nlohmann::json j = model;
155 std::string cols = "";
156 std::string vals = "";
157
158 bool first = true;
159 for (auto& el : j.items()) {
160 if (!first) { cols += ", "; vals += ", "; }
161 cols += el.key();
162
163 if (el.value().is_string()) {
164 vals += "'" + el.value().get<std::string>() + "'";
165 } else if (el.value().is_null()) {
166 vals += "NULL";
167 } else {
168 vals += el.value().dump(); // dump converts numbers/booleans to string representations
169 }
170 first = false;
171 }
172
173 std::string sql = "INSERT INTO " + table_ + " (" + cols + ") VALUES (" + vals + ");";
175 }
176
177private:
178 std::shared_ptr<DBClient> db_;
179 std::string table_;
180 std::vector<std::string> wheres_;
181};
182
183} // namespace orm
Represents a generic, unified result set from a database query.
Definition ResultSet.hpp:111
nlohmann::json to_json() const
Serializes the entire result set to a JSON array of objects.
Definition ResultSet.hpp:132
uint64_t affected_rows() const
Definition ResultSet.hpp:120
a class to store JSON values
Definition json.hpp:19401
iteration_proxy< iterator > items() noexcept
helper to access iterator member functions in range-based for
Definition json.hpp:22185
ValueType value(const typename object_t::key_type &key, const ValueType &default_value) const
access specified object element with default value
Definition json.hpp:21528
auto get() const noexcept(noexcept(std::declval< const basic_json_t & >().template get_impl< ValueType >(detail::priority_tag< 4 > {}))) -> decltype(std::declval< const basic_json_t & >().template get_impl< ValueType >(detail::priority_tag< 4 > {}))
get a (pointer) value (explicit)
Definition json.hpp:21046
Represents a database column, allowing C++ operator overloading to build SQL expressions seamlessly.
Definition QueryBuilder.hpp:29
Expr operator>(const T &val) const
Definition QueryBuilder.hpp:40
Expr operator!=(const T &val) const
Definition QueryBuilder.hpp:37
Col(std::string name)
Definition QueryBuilder.hpp:31
Expr operator>=(const T &val) const
Definition QueryBuilder.hpp:46
Expr operator==(const T &val) const
Definition QueryBuilder.hpp:34
Expr operator<(const T &val) const
Definition QueryBuilder.hpp:43
Expr operator<=(const T &val) const
Definition QueryBuilder.hpp:49
A lightweight, JSON-backed ORM Query Builder.
Definition QueryBuilder.hpp:112
QueryGetAwaiter< DBClient, ModelType > get_async()
Executes a SELECT query asynchronously and maps results to a vector of ModelType.
Definition QueryBuilder.hpp:138
QueryInsertAwaiter< DBClient, ModelType > insert_async(const ModelType &model)
Executes an INSERT query for a model.
Definition QueryBuilder.hpp:153
QueryBuilder & where(const std::string &field, const std::string &op, const std::string &val)
Adds a WHERE clause using an explicit field, operator, and value.
Definition QueryBuilder.hpp:120
QueryBuilder & where(const Expr &expr)
Definition QueryBuilder.hpp:130
QueryBuilder(std::shared_ptr< DBClient > db, const std::string &table)
Definition QueryBuilder.hpp:114
QueryAwaiter query_async(std::shared_ptr< PostgresClient > client, const std::string &sql)
Creates an awaiter for executing a query on a PostgresClient.
Definition PostgresCoro.hpp:65
Definition MigrationRunner.hpp:13
auto do_query_async(std::shared_ptr< DBClient > client, const std::string &sql)
Helper to unify query_async calls for both MysqlClient and PostgresClient.
Definition QueryBuilder.hpp:70
Definition json.hpp:5363
Represents a logical SQL expression (e.g., "age > 18 AND is_active = 'true'").
Definition QueryBuilder.hpp:14
Expr operator&&(const Expr &other) const
Definition QueryBuilder.hpp:17
Expr operator||(const Expr &other) const
Definition QueryBuilder.hpp:21
std::string sql
Definition QueryBuilder.hpp:15
Definition QueryBuilder.hpp:81
std::vector< ModelType > await_resume()
Definition QueryBuilder.hpp:88
bool await_ready() const
Definition QueryBuilder.hpp:85
void await_suspend(std::coroutine_handle<> h)
Definition QueryBuilder.hpp:86
decltype(do_query_async(std::declval< std::shared_ptr< DBClient > >(), std::declval< std::string >())) NativeAwaiter
Definition QueryBuilder.hpp:82
NativeAwaiter native_awaiter
Definition QueryBuilder.hpp:83
Definition QueryBuilder.hpp:95
uint64_t await_resume()
Definition QueryBuilder.hpp:102
decltype(do_query_async(std::declval< std::shared_ptr< DBClient > >(), std::declval< std::string >())) NativeAwaiter
Definition QueryBuilder.hpp:96
void await_suspend(std::coroutine_handle<> h)
Definition QueryBuilder.hpp:100
NativeAwaiter native_awaiter
Definition QueryBuilder.hpp:97
bool await_ready() const
Definition QueryBuilder.hpp:99