├── LICENSE ├── pg_ormlite.hpp ├── pg_query_object.hpp ├── readme.md ├── reflection.hpp ├── test.cpp └── traits_utils.hpp /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 hanson.young 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pg_ormlite.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PG_ORMLITE_HPP 2 | #define PG_ORMLITE_HPP 3 | #include 4 | #include 5 | #include 6 | #include "reflection.hpp" 7 | #include "traits_utils.hpp" 8 | #include "pg_query_object.hpp" 9 | 10 | namespace pg_ormlite 11 | { 12 | 13 | struct key_map 14 | { 15 | std::string fields; 16 | }; 17 | 18 | struct auto_key_map 19 | { 20 | std::string fields; 21 | }; 22 | 23 | struct not_null_map 24 | { 25 | std::set fields; 26 | }; 27 | 28 | template 29 | constexpr auto sort_tuple(const std::tuple& t) 30 | { 31 | if constexpr (sizeof...(Args) == 2) 32 | { 33 | auto [a, b] = t; 34 | if constexpr (!std::is_same_v && !std::is_same_v) 35 | { 36 | return std::make_tuple(b, a); 37 | } 38 | } 39 | return t; 40 | } 41 | 42 | 43 | class pg_connection 44 | { 45 | private: 46 | template 47 | std::string generate_connect_sql(const Tuple1& t1, const Tuple2& t2,std::index_sequence) 48 | { 49 | std::stringstream os; 50 | auto serialize = [&os](const std::string& key, const auto& val) 51 | { 52 | os << key << "="<< val<< " "; 53 | }; 54 | 55 | int unused[] = {0, (serialize(std::get(t1), std::get(t2)), 0)...}; 56 | (void) unused; 57 | return os.str(); 58 | } 59 | 60 | public: 61 | template 62 | pg_connection(Args&&... args) 63 | { 64 | auto args_tp = std::make_tuple(std::forward(args)...); 65 | auto index = std::make_index_sequence(); 66 | constexpr size_t size = std::tuple_size::value; 67 | std::string sql; 68 | if constexpr(size == 5) 69 | { 70 | auto fields = std::make_tuple("host", "port", "user", "password", "dbname"); 71 | sql = generate_connect_sql(fields, args_tp, index); 72 | } 73 | if constexpr(size == 6) 74 | { 75 | auto fields = std::make_tuple("host", "port", "user", "password", "dbname", "connect_timeout"); 76 | sql = generate_connect_sql(fields, args_tp, index); 77 | } 78 | 79 | std::cout<<"connect:"< 88 | bool prepare(const std::string& sql) 89 | { 90 | res_ = PQprepare(conn_, "", sql.data(), (int)reflection::get_value(), nullptr); 91 | if (PQresultStatus(res_) != PGRES_COMMAND_OK) 92 | { 93 | std::cout<< PQerrorMessage(conn_) < 101 | bool create_table(Args&&... args) 102 | { 103 | std::string sql = generate_create_table_sql(std::forward(args)...); 104 | std::cout<<"create:"< 116 | constexpr auto generate_insert_sql(bool replace) 117 | { 118 | std::string sql = replace ? "replace into " : "insert into "; 119 | std::string table_name = reflection::get_name().data(); 120 | std::string field_name_pack = reflection::get_field().data(); 121 | sql += table_name + "(" + field_name_pack + ") values("; 122 | constexpr auto field_size = reflection::get_value(); 123 | for (size_t i = 0; i < field_size; i++) 124 | { 125 | sql += "$"; 126 | sql += std::to_string(i + 1); 127 | if (i != field_size - 1) 128 | { 129 | sql += ", "; 130 | } 131 | } 132 | sql += ");"; 133 | return sql; 134 | } 135 | 136 | template 137 | constexpr void set_param_values(std::vector>& param_values, T&& value) 138 | { 139 | using U = std::remove_const_t>; 140 | if constexpr(std::is_same_v || std::is_same_v) 141 | { 142 | std::vector temp(65, 0); 143 | auto v_str = std::to_string(value); 144 | memcpy(temp.data(), v_str.data(), v_str.size()); 145 | param_values.push_back(temp); 146 | } 147 | else if constexpr(std::is_integral_v || std::is_floating_point_v) 148 | { 149 | std::vector temp(20, 0); 150 | auto v_str = std::to_string(value); 151 | memcpy(temp.data(), v_str.data(), v_str.size()); 152 | param_values.push_back(std::move(temp)); 153 | } 154 | else if constexpr(std::is_enum_v) 155 | { 156 | std::vector temp(20, 0); 157 | auto v_str = std::to_string(static_cast>(value)); 158 | memcpy(temp.data(), v_str.data(), v_str.size()); 159 | param_values.push_back(std::move(temp)); 160 | } 161 | else if constexpr(std::is_same_v) 162 | { 163 | std::vector temp = {}; 164 | std::copy(value.data(), value.data() + value.size() + 1, std::back_inserter(temp)); 165 | param_values.push_back(std::move(temp)); 166 | } 167 | else if constexpr(std::is_array::value) 168 | { 169 | std::vector temp = {}; 170 | std::copy(value, value + traits_utils::array_size::value, std::back_inserter(temp)); 171 | param_values.push_back(std::move(temp)); 172 | } 173 | } 174 | 175 | template 176 | bool insert_impl(std::string& sql, T&& t) 177 | { 178 | std::vector> param_values; 179 | reflection::for_each(t, [&](auto& item, auto field, auto j){ 180 | set_param_values(param_values, t.*item); 181 | }); 182 | if (param_values.empty()) 183 | { 184 | return false; 185 | } 186 | std::vector param_values_buf; 187 | for (auto &item : param_values) 188 | { 189 | param_values_buf.push_back(item.data()); 190 | } 191 | 192 | std::cout<<"params:"; 193 | for (size_t i = 0; i < param_values_buf.size(); i++) 194 | { 195 | std::cout << i << "="<<*(param_values_buf.data() + i)<<", "; 196 | } 197 | std::cout< 213 | int insert(T&& t) 214 | { 215 | std::string sql = generate_insert_sql(false); 216 | std::cout<<"insert prepare:"<(sql)) 218 | return false; 219 | return insert_impl(sql, std::forward(t)); 220 | } 221 | 222 | template 223 | int insert(std::vector& t) 224 | { 225 | std::string sql = generate_insert_sql(false); 226 | std::cout<<"insert prepare:"<(sql)) 228 | return 0; 229 | 230 | for (auto& item : t) 231 | { 232 | if(!insert_impl(sql, item)) 233 | { 234 | execute("rollback;"); 235 | return 0; 236 | } 237 | } 238 | if (!execute("commit;")) 239 | return 0; 240 | return t.size(); 241 | } 242 | 243 | template 244 | constexpr auto get_type_names() 245 | { 246 | constexpr auto field_size = reflection::get_value(); 247 | std::array field_types; 248 | reflection::for_each(T{}, [&](auto& item, auto field, auto j){ 249 | constexpr auto Idx = decltype(j)::value; 250 | using U = std::remove_reference_t(std::declval()))>; 251 | if constexpr(std::is_same_v || 252 | std::is_same_v || 253 | std::is_same_v || 254 | std::is_same_v || 255 | std::is_enum_v) 256 | { field_types[Idx] = "integer"; return; } 257 | if constexpr(std::is_same_v || std::is_same_v || 258 | std::is_same_v || std::is_same_v) 259 | { field_types[Idx] = "smallint"; return; } 260 | if constexpr(std::is_same_v || std::is_same_v) 261 | { field_types[Idx] = "bigint"; return; } 262 | if constexpr(std::is_same_v) 263 | { field_types[Idx] = "real"; return; } 264 | if constexpr(std::is_same_v) 265 | { field_types[Idx] = "double precision"; return; } 266 | if constexpr(std::is_same_v) 267 | { field_types[Idx] = "text"; return; } 268 | if constexpr(std::is_array::value) 269 | { field_types[Idx] = "varchar(" + std::to_string(traits_utils::array_size::value) + ")"; return; } 270 | }); 271 | return field_types; 272 | } 273 | template 274 | std::string generate_create_table_sql(Args&&... args) 275 | { 276 | auto table_name = reflection::get_name(); 277 | std::string sql = std::string("create table if not exists ") + table_name.data() + "("; 278 | auto field_names = reflection::get_array(); 279 | auto field_types = get_type_names(); 280 | using TT = std::tuple...>; 281 | if constexpr (sizeof...(Args) > 0) 282 | { 283 | 284 | static_assert(!(traits_utils::has_type::value && traits_utils::has_type::value), 285 | "key_map and auto_key_map cannot be used together"); 286 | 287 | } 288 | 289 | auto tp = sort_tuple(std::make_tuple(std::forward(args)...)); 290 | constexpr auto field_size = reflection::get_value(); 291 | static_assert(field_size == field_names.size(), "field_size != field_names.size"); 292 | for (size_t i = 0; i < field_size; i++) 293 | { 294 | std::string field_name = field_names[i].data(); 295 | std::string field_type = field_types[i].data(); 296 | bool has_add = false; 297 | reflection::for_each( 298 | tp, 299 | [&](auto item, auto j){ 300 | if constexpr (std::is_same_v) 301 | { 302 | // 如果字段不存在在not_null_map里面,则直接返回,进行普通填充 303 | if(item.fields.find(field_name) == item.fields.end()) 304 | return; 305 | } 306 | else 307 | { 308 | // 如果字段不是主键,则直接返回,进行普通填充 309 | if(item.fields != field_name) 310 | return; 311 | } 312 | 313 | if constexpr (std::is_same_v) 314 | { 315 | if(!has_add) 316 | { 317 | sql += field_name + " " + field_type + " serial primary key"; 318 | has_add = true; 319 | } 320 | } 321 | else if constexpr (std::is_same_v) 322 | { 323 | if(!has_add) 324 | { 325 | sql += field_name + " " + field_type + " primary key"; 326 | has_add = true; 327 | } 328 | } 329 | else if constexpr (std::is_same_v) 330 | { 331 | if(!has_add) 332 | { 333 | if(item.fields.find(field_name) == item.fields.end()) 334 | return; 335 | sql += field_name + " " + field_type + " not null"; 336 | has_add = true; 337 | } 338 | } 339 | } 340 | ); 341 | 342 | if(!has_add) 343 | { 344 | sql += field_name + " " + field_type; 345 | has_add = true; 346 | } 347 | 348 | if( i < field_size-1) 349 | sql += ", "; 350 | } 351 | sql += ");"; 352 | return sql; 353 | } 354 | 355 | template 356 | constexpr typename std::enable_if::value, pg_query_object::query_object>::type query() 357 | { 358 | return pg_query_object::query_object(conn_, reflection::get_name()); 359 | } 360 | 361 | template 362 | constexpr typename std::enable_if::value, pg_query_object::query_object>::type del() 363 | { 364 | return pg_query_object::query_object(conn_, reflection::get_name(), "delete", ""); 365 | } 366 | 367 | template 368 | constexpr typename std::enable_if::value, pg_query_object::query_object>::type update() 369 | { 370 | return pg_query_object::query_object(conn_, reflection::get_name(), "", "update"); 371 | } 372 | 373 | ~pg_connection() 374 | { 375 | if(conn_ != nullptr) 376 | { 377 | std::cout<<"release pg conn"< 4 | #include 5 | #include 6 | #include 7 | #include "reflection.hpp" 8 | 9 | namespace pg_query_object 10 | { 11 | 12 | template 13 | struct selectable 14 | { 15 | selectable(std::string_view&& field, std::string_view&& tbl_name, std::string_view&& op) 16 | : expr_(std::string(op) + "(" + std::string(field) + ")"), tbl_name_(tbl_name){}; 17 | 18 | inline std::string to_string() const 19 | { 20 | return expr_; 21 | } 22 | 23 | inline std::string table_name() const 24 | { 25 | return tbl_name_; 26 | } 27 | 28 | RNT_TYPE return_type; 29 | 30 | private: 31 | std::string expr_; 32 | std::string tbl_name_; 33 | 34 | }; 35 | 36 | class expr 37 | { 38 | public: 39 | expr(std::string_view&& field, std::string_view&& tbl_name) : expr_(field), tbl_name_(tbl_name) {}; 40 | 41 | template 42 | expr make_expr(std::string&& op, T value) 43 | { 44 | using U = std::decay_t; 45 | if constexpr (std::is_array::value || std::is_same_v || std::is_same_v) 46 | return expr (expr_ + " " + op + " " + "'" + value + "'", tbl_name_); 47 | else if constexpr (std::is_same_v) 48 | return expr (expr_ + " " + op + " " + value.expr_, tbl_name_); 49 | else 50 | return expr (expr_ + " " + op + " " + std::to_string(value), tbl_name_); 51 | } 52 | 53 | template 54 | inline expr operator == (T value) 55 | { 56 | return expr(make_expr("=", value)); 57 | } 58 | 59 | template 60 | inline expr operator = (T value) 61 | { 62 | return expr(make_expr("=", value)); 63 | } 64 | 65 | template 66 | inline expr operator | (T value) 67 | { 68 | return expr(make_expr(",", value)); 69 | } 70 | 71 | template 72 | inline expr operator != (T value) 73 | { 74 | return expr(make_expr("!=", value)); 75 | } 76 | 77 | template 78 | inline expr operator < (T value) 79 | { 80 | return expr(make_expr("<", value)); 81 | } 82 | 83 | template 84 | inline expr operator > (T value) 85 | { 86 | return expr(make_expr(">", value)); 87 | } 88 | 89 | template 90 | inline expr operator <= (T value) 91 | { 92 | return expr(make_expr("<=", value)); 93 | } 94 | 95 | template 96 | inline expr operator >= (T value) 97 | { 98 | 99 | return expr(make_expr(">=", value)); 100 | } 101 | 102 | inline expr operator % (std::string&& value) 103 | { 104 | return expr(make_expr("like", value)); 105 | } 106 | 107 | inline expr operator ^ (std::string&& value) 108 | { 109 | return expr(make_expr("not like", value)); 110 | } 111 | 112 | inline expr operator && (expr&& value) 113 | { 114 | return expr(make_expr("and", value)); 115 | } 116 | 117 | inline expr operator || (expr&& value) 118 | { 119 | return expr(make_expr("or", value)); 120 | } 121 | 122 | inline std::string to_string() const 123 | { 124 | return expr_; 125 | } 126 | 127 | inline std::string table_name() const 128 | { 129 | return tbl_name_; 130 | } 131 | 132 | inline std::string print() const 133 | { 134 | return tbl_name_ + ", "+ expr_; 135 | } 136 | 137 | private: 138 | std::string expr_; 139 | std::string tbl_name_; 140 | }; 141 | 142 | template 143 | class query_object 144 | { 145 | private: 146 | std::string select_sql_; 147 | std::string where_sql_; 148 | std::string group_by_sql_; 149 | std::string having_sql_; 150 | std::string order_by_sql_; 151 | std::string limit_sql_; 152 | std::string offset_sql_; 153 | std::string delete_sql_; 154 | std::string update_sql_; 155 | std::string set_sql_; 156 | 157 | std::string table_name_; 158 | QueryResult query_result_; 159 | PGconn* conn_; 160 | PGresult* res_; 161 | 162 | public: 163 | 164 | query_object(PGconn* conn, std::string_view table_name) : conn_(conn), table_name_(table_name) 165 | { 166 | 167 | } 168 | 169 | query_object(PGconn* conn, std::string_view table_name, const std::string& delete_sql, const std::string& update_sql) 170 | : conn_(conn), 171 | table_name_(table_name), 172 | delete_sql_(update_sql.empty() ? delete_sql + " from " + std::string(table_name): ""), 173 | update_sql_(delete_sql.empty() ? update_sql + " " + std::string(table_name): "") 174 | { 175 | 176 | } 177 | 178 | query_object(PGconn* conn, std::string_view table_name, QueryResult& query_result, 179 | const std::string& select_sql, const std::string& where_sql, const std::string& group_by_sql, 180 | const std::string& having_sql, const std::string& order_by_sql, const std::string& limit_sql, 181 | const std::string& offset_sql, const std::string& delete_sql, const std::string& update_sql, const std::string& set_sql) 182 | : conn_(conn), 183 | table_name_(table_name), 184 | query_result_(query_result), 185 | select_sql_(select_sql), 186 | where_sql_(where_sql), 187 | group_by_sql_(group_by_sql), 188 | having_sql_(having_sql), 189 | order_by_sql_(order_by_sql), 190 | limit_sql_(limit_sql), 191 | offset_sql_(offset_sql), 192 | delete_sql_(delete_sql), 193 | update_sql_(update_sql), 194 | set_sql_(set_sql) 195 | { 196 | 197 | } 198 | 199 | template 200 | inline void select_impl(std::string& sql, Args&&... args) 201 | { 202 | constexpr auto size = sizeof...(Args); 203 | auto tp = std::make_tuple(std::forward(args)...); 204 | reflection::for_each(tp, [&](auto arg, auto i) { 205 | if constexpr (std::is_same_v>) 206 | { 207 | bool same_table = arg.table_name() == table_name_; 208 | assert(same_table); 209 | table_name_ = arg.table_name(); 210 | sql += arg.to_string(); 211 | if(i != size - 1) 212 | sql += ", "; 213 | } 214 | }); 215 | } 216 | 217 | template 218 | inline query_object> new_query(std::tuple&& query_result) 219 | { 220 | return query_object>(conn_, table_name_, query_result, 221 | select_sql_, where_sql_, group_by_sql_, 222 | having_sql_, order_by_sql_, limit_sql_, 223 | offset_sql_, delete_sql_, update_sql_, set_sql_); 224 | } 225 | 226 | 227 | template 228 | inline auto select(Args&&... args) 229 | { 230 | std::string sql = "select "; 231 | if constexpr (sizeof...(Args) > 0) 232 | select_impl(sql, std::forward(args)...); 233 | else 234 | sql += " * "; 235 | sql += " from " + table_name_; 236 | (*this).select_sql_ = sql; 237 | return new_query(std::tuple{}); 238 | } 239 | 240 | inline query_object&& set(const expr& expression) 241 | { 242 | table_name_ = expression.table_name(); 243 | (*this).set_sql_ = " set " + expression.to_string(); 244 | return std::move(*this); 245 | } 246 | 247 | inline query_object&& where(const expr& expression) 248 | { 249 | table_name_ = expression.table_name(); 250 | (*this).where_sql_ = " where (" + expression.to_string() + ")"; 251 | return std::move(*this); 252 | } 253 | 254 | inline query_object&& group_by(const expr& expression) 255 | { 256 | (*this).group_by_sql_ = " group by (" + expression.to_string() + ")"; 257 | return std::move(*this); 258 | } 259 | 260 | inline query_object&& having(const expr& expression) 261 | { 262 | (*this).having_sql_ = " having (" + expression.to_string() + ")"; 263 | return std::move(*this); 264 | } 265 | 266 | inline query_object&& order_by(const expr& expression) 267 | { 268 | (*this).order_by_sql_ = " order by " + expression.to_string() + " asc"; 269 | return std::move(*this); 270 | } 271 | 272 | inline query_object&& order_by_desc(const expr& expression) 273 | { 274 | (*this).order_by_sql_ = " order by " + expression.to_string() + " desc"; 275 | return std::move(*this); 276 | } 277 | 278 | inline query_object&& limit(std::size_t n) 279 | { 280 | (*this).limit_sql_ = " limit " + std::to_string(n); 281 | return std::move(*this); 282 | } 283 | 284 | inline query_object&& offset(std::size_t n) 285 | { 286 | (*this).offset_sql_ = " offset " + std::to_string(n); 287 | return std::move(*this); 288 | } 289 | 290 | std::string to_string() 291 | { 292 | if (select_sql_.empty() && delete_sql_.empty() && update_sql_.empty()) 293 | { 294 | select_sql_ = "select * from " + table_name_; 295 | } 296 | return update_sql_ + delete_sql_ + select_sql_ + set_sql_ + where_sql_ + group_by_sql_ + 297 | having_sql_ + order_by_sql_ + limit_sql_ + offset_sql_ + ";"; 298 | } 299 | 300 | template 301 | constexpr void assign_value(T&& value, int row, int col) 302 | { 303 | using U = std::remove_const_t>; 304 | if constexpr(std::is_integral::value && !(std::is_same::value || std::is_same::value)) 305 | { 306 | // std::cout<<"smallint:"<) 310 | { 311 | value = static_cast(atoi(PQgetvalue(res_, row, col))); 312 | } 313 | else if constexpr(std::is_floating_point::value) 314 | { 315 | // std::cout<<"float:"<::value || std::is_same::value) 319 | { 320 | // std::cout<<"bigint:"<::value) 324 | { 325 | // std::cout<<"string:"<::value && std::is_same>>::value) 329 | { 330 | // std::cout<<"array:"<::value< 341 | constexpr std::enable_if_t::value, std::vector> query(const std::string& sql) 342 | { 343 | std::vector ret_vector; 344 | std::cout<<"query:"< 367 | constexpr std::enable_if_t::value, std::vector> query(const std::string& sql) 368 | { 369 | std::vector ret_vector; 370 | std::cout<<"query:"<>) 386 | { 387 | std::decay_t t = {}; 388 | reflection::for_each(t, [this, &index, &t](auto ele, auto field, auto j){ 389 | assign_value(t.*ele, j, index++); 390 | }); 391 | item = std::move(t); 392 | } 393 | else 394 | { 395 | assign_value(item, (int)i, index++); 396 | } 397 | }); 398 | ret_vector.push_back(tp); 399 | } 400 | PQclear(res_); 401 | return ret_vector; 402 | } 403 | 404 | std::vector to_vector() 405 | { 406 | return query(to_string()); 407 | } 408 | 409 | bool execute() 410 | { 411 | auto sql = to_string(); 412 | std::cout<<"exec:"< 424 | struct field_attribute; 425 | 426 | template 427 | struct field_attribute { 428 | using type = T; 429 | using return_type = U; 430 | }; 431 | 432 | template 433 | constexpr std::string_view get_field_name(std::string_view full_name) 434 | { 435 | using T = typename field_attribute::type; 436 | return full_name.substr(reflection::get_name().length() + 2, 437 | full_name.length()); 438 | } 439 | 440 | template 441 | constexpr std::string_view get_table_name(std::string_view full_name) 442 | { 443 | using T = typename field_attribute::type; 444 | return reflection::get_name(); 445 | } 446 | 447 | } 448 | 449 | #define FD(field) \ 450 | pg_query_object::expr( \ 451 | pg_query_object::get_field_name(std::string_view(#field)), \ 452 | pg_query_object::get_table_name(std::string_view(#field))) \ 453 | 454 | #define ORM_AGG(field, op, type) \ 455 | pg_query_object::selectable( \ 456 | pg_query_object::get_field_name(std::string_view(#field)), \ 457 | pg_query_object::get_table_name(std::string_view(#field)), \ 458 | op) \ 459 | 460 | #define RNT(field) ORM_AGG(field, "", pg_query_object::field_attribute::return_type) 461 | #define ORM_COUNT(field) ORM_AGG(field, "count", std::size_t) 462 | #define ORM_SUM(field) ORM_AGG(field, "sum", pg_query_object::field_attribute::return_type) 463 | #define ORM_AVG(field) ORM_AGG(field, "avg", pg_query_object::field_attribute::return_type) 464 | #define ORM_MAX(field) ORM_AGG(field, "max", pg_query_object::field_attribute::return_type) 465 | #define ORM_MIN(field) ORM_AGG(field, "min", pg_query_object::field_attribute::return_type) 466 | 467 | 468 | #endif -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | # 🌟 ORM-CPP: A Header-only Library for Modern C++17 3 | 4 | ORM-CPP is a header-only library for modern C++17 that supports PostgreSQL CURD operations. It allows you to use LINQ syntax without the need to write any SQL queries. 5 | 6 | ## Features 7 | - Header-only library 8 | - Supports PostgreSQL database, will support TDengine/CK/sqlite. 9 | - LINQ syntax for SQL queries 10 | - No need to write raw SQL code 11 | - Compile-time reflection can reduce runtime overhead. 12 | 13 | ## 🚀 Getting Started 14 | 15 | ### Installing 16 | 17 | To use ORM-CPP, simply add the `*.hpp` header file to your project.Make sure you have installed the PostgreSQL client and server. 18 | Ubuntu/Debian: `sudo apt install libpq-dev` 19 | You can use the command `g++ -o test test.cpp --std=c++17 -lpq -I /usr/include/postgresql` to compile the example program. 20 | 21 | ### Usage 22 | 23 | Include the header file `pg_ormlite.hpp` and Create a struct and decorate the struct name and members with the REFLECTION_TEMPLATE macro. 24 | ```cpp 25 | #include "pg_ormlite.hpp" 26 | enum Gender: int 27 | { 28 | Mail, 29 | Femail, 30 | }; 31 | 32 | struct person { 33 | short id; 34 | char name[10]; 35 | Gender gender; 36 | int age; 37 | float score; 38 | }__attribute__((packed)); 39 | REFLECTION_TEMPLATE(person, id, name, gender, age, score) 40 | ``` 41 | #### Connect 42 | To use ORM-CPP, you need to first create a connection object to your PostgreSQL database, like so: 43 | 44 | ```cpp 45 | pg_ormlite::pg_connection conn("xx.xx.xx.xx", "1234", "user", "password", "dbname"); 46 | ``` 47 | #### Create 48 | Once you have a connection object, you can create a table using the following statement 49 | ```cpp 50 | pg_ormlite::key_map key_map_{"id"}; 51 | pg_ormlite::not_null_map not_null_map_; 52 | not_null_map_.fields = {"id", "age"}; 53 | conn.create_table(key_map_, not_null_map_); 54 | // create:create table if not exists person(id smallint primary key, name varchar(10), gender integer, age integer not null, score real); 55 | ``` 56 | #### Insert 57 | You can use the insert method to insert a single person object or insert multiple objects in batches into the database table. 58 | ``` cpp 59 | // insert single object one by one 60 | person p1{1, "hxf1", Gender::Femail, 30, 101.1f}; 61 | person p2{2, "hxf2", Gender::Femail, 28, 102.2f}; 62 | person p3{3, "hxf3", Gender::Mail, 27, 103.3f}; 63 | person p4{4, "hxf4", Gender::Femail, 26, 104.4f}; 64 | person p5{5, "hxf1", Gender::Mail, 30, 108.1f}; 65 | person p6{6, "hxf3", Gender::Femail, 30, 109.1f}; 66 | 67 | conn.insert(p1); 68 | // insert prepare:insert into person(id, name, gender, age, score) values($1, $2, $3, $4, $5); 69 | conn.insert(p2); 70 | conn.insert(p3); 71 | conn.insert(p4); 72 | conn.insert(p5); 73 | conn.insert(p6); 74 | 75 | // insert multiple objects in batches 76 | std::vector persons; 77 | for (size_t i = 6; i < 10; i++) 78 | { 79 | person p; 80 | p.id = i + 1; 81 | std::string name = "hxf" + std::to_string(i + 1); 82 | strcpy(p.name, name.c_str()); 83 | p.gender = Gender::Mail; 84 | p.age = 30 + i; 85 | p.score = 101.1f + i; 86 | persons.push_back(p); 87 | } 88 | conn.insert(persons); 89 | ``` 90 | #### Query 91 | Use ORM-CPP's LINQ syntax to query database. Directly return an array of structs. 92 | ``` cpp 93 | auto pn1 = 94 | conn.query() 95 | .where(FD(person::age) > 27 && FD(person::id) < 3) 96 | .limit(2) 97 | .to_vector(); 98 | 99 | for(auto it: pn1) 100 | { 101 | std::cout< 27 and id < 3) limit 2; 104 | // 1 hxf1 1 30 101.1 105 | // 2 hxf2 1 28 102.2 106 | ``` 107 | If you only want to query certain fields, you can use the select method to filter them. In the end, it will return an array of `tuple` objects. 108 | 109 | ```cpp 110 | auto pn2 = 111 | conn.query() 112 | .select(RNT(person::id), RNT(person::name), RNT(person::gender), RNT(person::age)) 113 | .where(FD(person::age) >= 28 && FD(person::id) < 5) 114 | .to_vector(); 115 | 116 | for(auto it: pn2) 117 | { 118 | std::apply([](auto&&... args) { 119 | ((std::cout << args << ' '), ...); 120 | }, it); 121 | std::cout<= 28 and id < 5); 124 | // 1 hxf1 1 30 125 | // 2 hxf2 1 28 126 | ``` 127 | To use the calculation engine of the database itself, you can use more complex operations such as group_by, order_by, etc. You can also add some aggregate functions to perform data statistics. The aggregate functions currently provided include count, sum, avg, max, and min. 128 | ```cpp 129 | auto pn3 = 130 | conn.query() 131 | .select(RNT(person::age), ORM_SUM(person::score), ORM_COUNT(person::name)) 132 | .where(FD(person::age) > 24 && FD(person::id) < 7) 133 | .limit(3) 134 | .group_by(FD(person::age)) 135 | .order_by_desc(FD(person::age)) 136 | .to_vector(); 137 | 138 | for(auto it: pn3) 139 | { 140 | std::apply([](auto&&... args) { 141 | ((std::cout << args << ' '), ...); 142 | }, it); 143 | std::cout< 24 and id < 7) group by (age) order by age desc limit 3; 146 | // 30 318.3 3 147 | // 28 102.2 1 148 | // 27 103.3 1 149 | ``` 150 | #### Update 151 | The syntax for updating data is similar to that of querying data, you can do: 152 | 153 | ```cpp 154 | auto res2 = 155 | conn.update() 156 | .set((FD(person::age) = 50) | (FD(person::name) = "hxf100")) 157 | .where(FD(person::age) > 29) 158 | .execute(); 159 | // update person set age = 50 , name = 'hxf100' where (age > 29); 160 | ``` 161 | 162 | #### Delete 163 | To delete data, you can use the del method. 164 | ```cpp 165 | auto res = 166 | conn.del() 167 | .where(FD(person::age) > 29) 168 | .execute(); 169 | // delete from person where (age > 29); 170 | ``` 171 | 172 | ## 📖 Documentation 173 | 174 | For more information on how to implement ORM-CPP, check out the [post](https://zhuanlan.zhihu.com/p/629445959). 175 | 176 | ## 🤝 Contributing 177 | 178 | Contributions are welcome! If you find a bug or have a feature request, please open an issue on the [issue tracker](https://github.com/hanson-young/orm-cpp/issues). If you want to contribute code, please fork the repository and submit a pull request. 179 | 180 | ## 📃 License 181 | 182 | ORM-CPP is licensed under the [MIT License](https://github.com/hanson-young/orm-cpp/blob/main/LICENSE). 183 | -------------------------------------------------------------------------------- /reflection.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Author: YangJian 3 | Date: 2023-05-11 4 | */ 5 | #ifndef REFLECTION_HPP 6 | #define REFLECTION_HPP 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace reflection { 17 | 18 | #define MARCO_EXPAND(...) __VA_ARGS__ 19 | #define ADD_VIEW(str) std::string_view(#str, sizeof(#str) - 1) 20 | #define SEPERATOR , 21 | #define CON_STR_1(element, ...) ADD_VIEW(element) 22 | #define CON_STR_2(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_1(__VA_ARGS__)) 23 | #define CON_STR_3(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_2(__VA_ARGS__)) 24 | #define CON_STR_4(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_3(__VA_ARGS__)) 25 | #define CON_STR_5(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_4(__VA_ARGS__)) 26 | #define CON_STR_6(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_5(__VA_ARGS__)) 27 | #define CON_STR_7(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_6(__VA_ARGS__)) 28 | #define CON_STR_8(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_7(__VA_ARGS__)) 29 | #define CON_STR_9(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_8(__VA_ARGS__)) 30 | #define CON_STR_10(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_9(__VA_ARGS__)) 31 | #define CON_STR_11(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_10(__VA_ARGS__)) 32 | #define CON_STR_12(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_11(__VA_ARGS__)) 33 | #define CON_STR_13(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_12(__VA_ARGS__)) 34 | #define CON_STR_14(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_13(__VA_ARGS__)) 35 | #define CON_STR_15(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_14(__VA_ARGS__)) 36 | #define CON_STR_16(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_15(__VA_ARGS__)) 37 | #define CON_STR_17(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_16(__VA_ARGS__)) 38 | #define CON_STR_18(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_17(__VA_ARGS__)) 39 | #define CON_STR_19(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_18(__VA_ARGS__)) 40 | #define CON_STR_20(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_19(__VA_ARGS__)) 41 | #define CON_STR_21(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_20(__VA_ARGS__)) 42 | #define CON_STR_22(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_21(__VA_ARGS__)) 43 | #define CON_STR_23(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_22(__VA_ARGS__)) 44 | #define CON_STR_24(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_23(__VA_ARGS__)) 45 | #define CON_STR_25(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_24(__VA_ARGS__)) 46 | #define CON_STR_26(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_25(__VA_ARGS__)) 47 | #define CON_STR_27(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_26(__VA_ARGS__)) 48 | #define CON_STR_28(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_27(__VA_ARGS__)) 49 | #define CON_STR_29(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_28(__VA_ARGS__)) 50 | #define CON_STR_30(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_29(__VA_ARGS__)) 51 | #define CON_STR_31(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_30(__VA_ARGS__)) 52 | #define CON_STR_32(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_31(__VA_ARGS__)) 53 | #define CON_STR_33(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_32(__VA_ARGS__)) 54 | #define CON_STR_34(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_33(__VA_ARGS__)) 55 | #define CON_STR_35(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_34(__VA_ARGS__)) 56 | #define CON_STR_36(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_35(__VA_ARGS__)) 57 | #define CON_STR_37(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_36(__VA_ARGS__)) 58 | #define CON_STR_38(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_37(__VA_ARGS__)) 59 | #define CON_STR_39(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_38(__VA_ARGS__)) 60 | #define CON_STR_40(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_39(__VA_ARGS__)) 61 | #define CON_STR_41(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_40(__VA_ARGS__)) 62 | #define CON_STR_42(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_41(__VA_ARGS__)) 63 | #define CON_STR_43(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_42(__VA_ARGS__)) 64 | #define CON_STR_44(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_43(__VA_ARGS__)) 65 | #define CON_STR_45(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_44(__VA_ARGS__)) 66 | #define CON_STR_46(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_45(__VA_ARGS__)) 67 | #define CON_STR_47(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_46(__VA_ARGS__)) 68 | #define CON_STR_48(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_47(__VA_ARGS__)) 69 | #define CON_STR_49(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_48(__VA_ARGS__)) 70 | #define CON_STR_50(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_49(__VA_ARGS__)) 71 | #define CON_STR_51(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_50(__VA_ARGS__)) 72 | #define CON_STR_52(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_51(__VA_ARGS__)) 73 | #define CON_STR_53(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_52(__VA_ARGS__)) 74 | #define CON_STR_54(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_53(__VA_ARGS__)) 75 | #define CON_STR_55(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_54(__VA_ARGS__)) 76 | #define CON_STR_56(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_55(__VA_ARGS__)) 77 | #define CON_STR_57(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_56(__VA_ARGS__)) 78 | #define CON_STR_58(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_57(__VA_ARGS__)) 79 | #define CON_STR_59(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_58(__VA_ARGS__)) 80 | #define CON_STR_60(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_59(__VA_ARGS__)) 81 | #define CON_STR_61(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_60(__VA_ARGS__)) 82 | #define CON_STR_62(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_61(__VA_ARGS__)) 83 | #define CON_STR_63(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_62(__VA_ARGS__)) 84 | #define CON_STR_64(element, ...) ADD_VIEW(element) SEPERATOR MARCO_EXPAND(CON_STR_63(__VA_ARGS__)) 85 | 86 | #define MACRO_ARGS_(exp) exp 87 | #define MACRO_FILTER(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _N, ...) _N 88 | #define RNG_N() 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 89 | #define MACRO_ARGS_INNER(...) MACRO_FILTER(__VA_ARGS__) 90 | #define MACRO_ARGS_SIZE(...) MACRO_ARGS_(MACRO_ARGS_INNER(0, ##__VA_ARGS__, RNG_N())) 91 | 92 | #define MACRO_CONCAT(a, b) a##_##b 93 | #define FIELD(f) f 94 | 95 | #define MAKE_ARG_LIST_1(op, arg, ...) op(arg) 96 | #define MAKE_ARG_LIST_2(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_1(op, __VA_ARGS__)) 97 | #define MAKE_ARG_LIST_3(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_2(op, __VA_ARGS__)) 98 | #define MAKE_ARG_LIST_4(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_3(op, __VA_ARGS__)) 99 | #define MAKE_ARG_LIST_5(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_4(op, __VA_ARGS__)) 100 | #define MAKE_ARG_LIST_6(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_5(op, __VA_ARGS__)) 101 | #define MAKE_ARG_LIST_7(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_6(op, __VA_ARGS__)) 102 | #define MAKE_ARG_LIST_8(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_7(op, __VA_ARGS__)) 103 | #define MAKE_ARG_LIST_9(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_8(op, __VA_ARGS__)) 104 | #define MAKE_ARG_LIST_10(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_9(op, __VA_ARGS__)) 105 | #define MAKE_ARG_LIST_11(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_10(op, __VA_ARGS__)) 106 | #define MAKE_ARG_LIST_12(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_11(op, __VA_ARGS__)) 107 | #define MAKE_ARG_LIST_13(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_12(op, __VA_ARGS__)) 108 | #define MAKE_ARG_LIST_14(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_13(op, __VA_ARGS__)) 109 | #define MAKE_ARG_LIST_15(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_14(op, __VA_ARGS__)) 110 | #define MAKE_ARG_LIST_16(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_15(op, __VA_ARGS__)) 111 | #define MAKE_ARG_LIST_17(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_16(op, __VA_ARGS__)) 112 | #define MAKE_ARG_LIST_18(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_17(op, __VA_ARGS__)) 113 | #define MAKE_ARG_LIST_19(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_18(op, __VA_ARGS__)) 114 | #define MAKE_ARG_LIST_20(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_19(op, __VA_ARGS__)) 115 | #define MAKE_ARG_LIST_21(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_20(op, __VA_ARGS__)) 116 | #define MAKE_ARG_LIST_22(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_21(op, __VA_ARGS__)) 117 | #define MAKE_ARG_LIST_23(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_22(op, __VA_ARGS__)) 118 | #define MAKE_ARG_LIST_24(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_23(op, __VA_ARGS__)) 119 | #define MAKE_ARG_LIST_25(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_24(op, __VA_ARGS__)) 120 | #define MAKE_ARG_LIST_26(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_25(op, __VA_ARGS__)) 121 | #define MAKE_ARG_LIST_27(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_26(op, __VA_ARGS__)) 122 | #define MAKE_ARG_LIST_28(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_27(op, __VA_ARGS__)) 123 | #define MAKE_ARG_LIST_29(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_28(op, __VA_ARGS__)) 124 | #define MAKE_ARG_LIST_30(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_29(op, __VA_ARGS__)) 125 | #define MAKE_ARG_LIST_31(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_30(op, __VA_ARGS__)) 126 | #define MAKE_ARG_LIST_32(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_31(op, __VA_ARGS__)) 127 | #define MAKE_ARG_LIST_33(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_32(op, __VA_ARGS__)) 128 | #define MAKE_ARG_LIST_34(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_33(op, __VA_ARGS__)) 129 | #define MAKE_ARG_LIST_35(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_34(op, __VA_ARGS__)) 130 | #define MAKE_ARG_LIST_36(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_35(op, __VA_ARGS__)) 131 | #define MAKE_ARG_LIST_37(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_36(op, __VA_ARGS__)) 132 | #define MAKE_ARG_LIST_38(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_37(op, __VA_ARGS__)) 133 | #define MAKE_ARG_LIST_39(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_38(op, __VA_ARGS__)) 134 | #define MAKE_ARG_LIST_40(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_39(op, __VA_ARGS__)) 135 | #define MAKE_ARG_LIST_41(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_40(op, __VA_ARGS__)) 136 | #define MAKE_ARG_LIST_42(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_41(op, __VA_ARGS__)) 137 | #define MAKE_ARG_LIST_43(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_42(op, __VA_ARGS__)) 138 | #define MAKE_ARG_LIST_44(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_43(op, __VA_ARGS__)) 139 | #define MAKE_ARG_LIST_45(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_44(op, __VA_ARGS__)) 140 | #define MAKE_ARG_LIST_46(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_45(op, __VA_ARGS__)) 141 | #define MAKE_ARG_LIST_47(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_46(op, __VA_ARGS__)) 142 | #define MAKE_ARG_LIST_48(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_47(op, __VA_ARGS__)) 143 | #define MAKE_ARG_LIST_49(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_48(op, __VA_ARGS__)) 144 | #define MAKE_ARG_LIST_50(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_49(op, __VA_ARGS__)) 145 | #define MAKE_ARG_LIST_51(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_50(op, __VA_ARGS__)) 146 | #define MAKE_ARG_LIST_52(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_51(op, __VA_ARGS__)) 147 | #define MAKE_ARG_LIST_53(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_52(op, __VA_ARGS__)) 148 | #define MAKE_ARG_LIST_54(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_53(op, __VA_ARGS__)) 149 | #define MAKE_ARG_LIST_55(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_54(op, __VA_ARGS__)) 150 | #define MAKE_ARG_LIST_56(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_55(op, __VA_ARGS__)) 151 | #define MAKE_ARG_LIST_57(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_56(op, __VA_ARGS__)) 152 | #define MAKE_ARG_LIST_58(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_57(op, __VA_ARGS__)) 153 | #define MAKE_ARG_LIST_59(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_58(op, __VA_ARGS__)) 154 | #define MAKE_ARG_LIST_60(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_59(op, __VA_ARGS__)) 155 | #define MAKE_ARG_LIST_61(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_60(op, __VA_ARGS__)) 156 | #define MAKE_ARG_LIST_62(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_61(op, __VA_ARGS__)) 157 | #define MAKE_ARG_LIST_63(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_62(op, __VA_ARGS__)) 158 | #define MAKE_ARG_LIST_64(op, arg, ...) op(arg), MARCO_EXPAND(MAKE_ARG_LIST_63(op, __VA_ARGS__)) 159 | 160 | #define MAKE_ARG_LIST(N, op, arg, ...) MACRO_CONCAT(MAKE_ARG_LIST, N)(op, arg, __VA_ARGS__) 161 | 162 | #define MAKE_REFLECT_MEMBERS(class_name, ...) \ 163 | inline auto reflect_members_func(class_name const &){ \ 164 | struct reflect_members \ 165 | { \ 166 | constexpr decltype(auto) static apply_impl() \ 167 | { \ 168 | return std::make_tuple(__VA_ARGS__); \ 169 | } \ 170 | using size_type = std::integral_constant; \ 171 | constexpr static std::string_view name() { return name_##class_name; } \ 172 | constexpr static std::string_view fields() { return fields_##class_name; } \ 173 | constexpr static size_t value() { return size_type::value; } \ 174 | constexpr static std::array arr() \ 175 | { return arr_##class_name; } \ 176 | }; \ 177 | return reflect_members{}; \ 178 | } 179 | 180 | #define MAKE_META_DATA(class_name, table_name, N, ...) \ 181 | constexpr std::array arr_##class_name = { \ 182 | MARCO_EXPAND(MACRO_CONCAT(CON_STR, N)(__VA_ARGS__)) }; \ 183 | constexpr std::string_view fields_##class_name = { #__VA_ARGS__ }; \ 184 | constexpr std::string_view name_##class_name = table_name; \ 185 | MAKE_REFLECT_MEMBERS(class_name, MAKE_ARG_LIST(N, &class_name::FIELD, __VA_ARGS__))\ 186 | 187 | 188 | #define REFLECTION_TEMPLATE(class_name, ...) \ 189 | MAKE_META_DATA(class_name, #class_name, MACRO_ARGS_SIZE(__VA_ARGS__), __VA_ARGS__) \ 190 | 191 | #define REFLECTION_TEMPLATE_WITH_NAME(class_name, table_name, ...) \ 192 | MAKE_META_DATA(class_name, table_name, MACRO_ARGS_SIZE(__VA_ARGS__), __VA_ARGS__) \ 193 | 194 | 195 | template 196 | using Reflect_members = decltype(reflect_members_func(std::declval())); 197 | 198 | template 199 | struct is_reflection : std::false_type {}; 200 | 201 | template 202 | struct is_reflection::arr())>> 203 | : std::true_type {}; 204 | 205 | 206 | template