#pragma once #include #include #include #include #include #include #include #include #include #include using namespace std::string_literals; template typename std::enable_if::value, std::int64_t>::type extract_row_value(Statement& statement, const int i) { return statement.get_column_int64(i); } template typename std::enable_if::value, T>::type extract_row_value(Statement& statement, const int i) { return statement.get_column_text(i); } template typename std::enable_if::value, T>::type extract_row_value(Statement& statement, const int i) { const auto integer = statement.get_column_int(i); OptionalBool result; if (integer > 0) result.set_value(true); else if (integer < 0) result.set_value(false); return result; } template typename std::enable_if::value, T>::type extract_row_value(Statement& statement, const int i) { const std::string timestamp = statement.get_column_text(i); return {timestamp}; } template typename std::enable_if::type extract_row_values(Row& row, Statement& 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&, Statement&) {} template std::string before_column() { return {}; } template std::string after_column() { return {}; } template <> std::string before_column(); template <> std::string after_column(); 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 typename std::enable_if::type insert_col_name() { using ColumnsType = std::tuple; using ColumnType = typename std::remove_reference(std::declval()))>::type; this->body += " "; this->body += before_column() + ColumnType::name + after_column(); 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(DatabaseEngine& db) { std::vector> rows; #ifdef DEBUG_SQL_QUERIES const auto timer = this->log_and_time(); #endif auto statement = db.prepare(this->body); if (!statement) return rows; 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; }; template auto select(const Table table) { SelectQuery query(table.name); return query; }