#pragma once #include #include #include #include #include #include #include #include using namespace std::string_literals; template auto extract_row_value(Statement& statement, const int i) { if constexpr(std::is_integral::value) return statement.get_column_int64(i); else if constexpr (std::is_same::value) return statement.get_column_text(i); else if (std::is_same, T>::value) { const auto integer = statement.get_column_int(i); if (integer > 0) return std::optional{true}; else if (integer < 0) return std::optional{false}; return std::optional{}; } } template void extract_row_values(Row& row, Statement& statement) { if constexpr(N < sizeof...(T)) { 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 struct SelectQuery: public Query { SelectQuery(std::string table_name): Query("SELECT"), table_name(table_name) { this->insert_col_name(); this->body += " from " + this->table_name; } template void insert_col_name() { if constexpr(N < sizeof...(T)) { using ColumnsType = std::tuple; using ColumnType = typename std::remove_reference(std::declval()))>::type; this->body += " " + std::string{ColumnType::name}; if (N < (sizeof...(T) - 1)) this->body += ", "; this->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(DatabaseEngine& db) { std::vector> rows; #ifdef DEBUG_SQL_QUERIES const auto timer = this->log_and_time(); #endif auto statement = db.prepare(this->body); statement->bind(std::move(this->params)); while (statement->step() == StepResult::Row) { Row row(this->table_name); extract_row_values(row, *statement); rows.push_back(row); } return rows; } const std::string table_name; };