|
#include <cassert>
|
|
#include <string>
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
#include <sqlite3.h>
|
|
|
|
// Helper function prototypes
|
|
void get_value(int64_t& val, int idx, sqlite3_stmt* stmt);
|
|
void get_value(double& val, int idx, sqlite3_stmt* stmt);
|
|
void get_value(std::string& val, int idx, sqlite3_stmt* stmt);
|
|
void get_value(bool& val, int idx, sqlite3_stmt* stmt);
|
|
|
|
template<size_t I>
|
|
struct builder_impl
|
|
{
|
|
template<typename T>
|
|
static void set_values_helper(T& tup, sqlite3_stmt* stmt)
|
|
{
|
|
// Assign the "current" value
|
|
get_value(std::get<I - 1>(tup), I - 1, stmt);
|
|
|
|
// Recurse to the next value in the tuple
|
|
builder_impl<I - 1>::set_values_helper(tup, stmt);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct builder_impl<0>
|
|
{
|
|
template<typename T>
|
|
static void set_values_helper(T& tup, sqlite3_stmt* stmt)
|
|
{
|
|
// Stop recursing
|
|
return;
|
|
}
|
|
};
|
|
|
|
template <typename... Ts>
|
|
void set_values(std::tuple<Ts...>& tup, sqlite3_stmt* stmt)
|
|
{
|
|
builder_impl<sizeof...(Ts)>::set_values_helper(tup, stmt);
|
|
}
|
|
|
|
|
|
class DBManager
|
|
{
|
|
public:
|
|
|
|
// Constructor
|
|
DBManager(const std::string& db_path);
|
|
|
|
// Destructor
|
|
~DBManager();
|
|
|
|
// Execute query template function
|
|
template<typename... T>
|
|
std::vector<std::tuple<T...>*>* execute_query(
|
|
const std::string& sql_statement,
|
|
int& return_code)
|
|
{
|
|
sqlite3_stmt* sqlite_statement;
|
|
|
|
// Prepare the sqlite statement
|
|
return_code = sqlite3_prepare_v2(db, sql_statement.c_str(), -1,
|
|
&sqlite_statement, nullptr);
|
|
if (return_code != SQLITE_OK)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
auto output_vector = new std::vector<std::tuple<T...>*>();
|
|
|
|
// Iterate until we've collected all the output
|
|
int step_return = 0;
|
|
while ((step_return = sqlite3_step(sqlite_statement)) != SQLITE_DONE)
|
|
{
|
|
// Create a new result row
|
|
auto result_row = new std::tuple<T...>();
|
|
|
|
// Now populate the result row using some neato variadic
|
|
// template function magic NOTE: a small amount of black magic
|
|
// is in use here; animal sacrifices not necessary
|
|
set_values(*result_row, sqlite_statement);
|
|
|
|
// Add the result row to our vector of output rows
|
|
output_vector->push_back(result_row);
|
|
}
|
|
|
|
return output_vector;
|
|
}
|
|
|
|
private:
|
|
|
|
sqlite3 *db;
|
|
};
|