#pragma once #include #include #include #include #include #include using namespace std::string_literals; template typename std::enable_if::value, sqlite3_int64>::type extract_row_value(sqlite3_stmt* statement, const int i) { return sqlite3_column_int64(statement, i); } template typename std::enable_if::value, std::string>::type extract_row_value(sqlite3_stmt* statement, const int i) { const auto size = sqlite3_column_bytes(statement, i); const unsigned char* str = sqlite3_column_text(statement, i); std::string result(reinterpret_cast(str), size); return result; } template typename std::enable_if::type extract_row_values(Row& row, sqlite3_stmt* statement) { using ColumnType = typename std::remove_reference(row.columns))>::type; auto&& column = std::get(row.columns); column.value = static_cast(extract_row_value(statement, N)); extract_row_values(row, statement); } template typename std::enable_if::type extract_row_values(Row&, sqlite3_stmt*) {} template struct SelectQuery: public Query { SelectQuery(std::string table_name): Query("SELECT"), table_name(table_name) { this->insert_col_name<0>(); this->body += " from " + this->table_name; } template typename std::enable_if::type insert_col_name() { using ColumnsType = std::tuple; ColumnsType tuple{}; auto value = std::get(tuple); this->body += " "s + value.name; if (N < (sizeof...(T) - 1)) this->body += ", "; this->insert_col_name(); } template typename std::enable_if::type insert_col_name() {} SelectQuery& where() { this->body += " WHERE "; return *this; }; SelectQuery& order_by() { this->body += " ORDER BY "; return *this; } SelectQuery& limit() { this->body += " LIMIT "; return *this; } auto execute(sqlite3* db) { auto statement = this->prepare(db); int i = 1; for (const std::string& param: this->params) { if (sqlite3_bind_text(statement, i, param.data(), static_cast(param.size()), SQLITE_TRANSIENT) != SQLITE_OK) log_debug("Failed to bind ", param, " to param ", i); else log_debug("Bound ", param, " to ", i); i++; } std::vector> rows; while (sqlite3_step(statement) == SQLITE_ROW) { Row row(this->table_name); extract_row_values(row, statement); rows.push_back(row); } return rows; } const std::string table_name; }; template typename std::enable_if::value, SelectQuery&>::type operator<<(SelectQuery& query, const T&) { query.body += T::name; return query; } template SelectQuery& operator<<(SelectQuery& query, const char* str) { query.body += str; return query; } template SelectQuery& operator<<(SelectQuery& query, const std::string& str) { query.body += "?"; actual_add_param(query, str); return query; } template typename std::enable_if::value, SelectQuery&>::type operator<<(SelectQuery& query, const Integer& i) { query.body += "?"; actual_add_param(query, i); return query; }