#pragma once #include "Query.h" #include "QueryResult.h" #include #include #include #include namespace Database { template class QueryExecuter { public: /* Creates a prepared statement and initializes the query. */ explicit QueryExecuter(sqlite3* db) : database(db) {} /* Sets the query this executer will execute. */ QueryExecuter& setQuery(Query query) { this->query = std::make_unique>(query); this->query->prepare(database); return *this; } /* Binds the given name-value pairs to the statement. Recursive case. */ template QueryExecuter& bindParams(BindType locationValuePair, int depth = 1) { query->template bind(locationValuePair, depth); return *this; } /* Binds the given name-value pairs to the statement. Recursive case. */ template QueryExecuter& bindParams(BindType locationValuePair, BindTypes... locationValuePairs, int depth = 1) { query->template bind(locationValuePair, depth); bindParams(locationValuePairs..., depth + 1); return *this; } /* Executes the query and returns a tuple with an entry for each type. Use this to recieve only the first result. Multiple calls, or calls when there are no rows in the db, can lead to exceptions. This is functionally equivalent to stepping and then calling getResult */ QueryResult executeOnce() { query->step(); return QueryResult(getResult()); } /* Steps the query. */ bool step() { return query->step(); } /* Returns the result. */ QueryResult result() { return QueryResult(getResult()); } /* Executes the query and returns a vector of tuples for each result. */ std::vector> execute(int limit = 0) { std::vector> result; // Return code bool more; int limiter = 0; do { // Execution of the statement more = query->step(); if (!more || (limiter >= limit && limit > 0)) break; limiter++; std::tuple row = getResult(); result.emplace_back(row); } while (more); return result; } /* Resets the sqlite3 query object. */ QueryExecuter& reset() { query->reset(); return *this; } private: /* Returns the results after executing the query. Base case. */ template std::tuple getResult(int depth = 0) { return std::tuple(query->template getResult(depth)); } /* Returns the results after executing the query. Recursive Case. */ template std::tuple getResult(int depth = 0) { std::tuple first = std::tuple(query->template getResult(depth)); std::tuple rest = getResult(depth + 1); return std::tuple_cat(first, rest); } /* Returns an empty tuple for when there are no return values. */ template std::tuple<> getResult(int depth = 0) const { return std::tuple<>(); } std::unique_ptr> query; sqlite3* database; }; }