From 4b8d3430c7fff8b869ec895dbffac748db72a237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 27 Sep 2019 20:55:15 +0200 Subject: Add an AsyncResult type to iterate over the Select results --- src/database/async_result.hpp | 77 +++++++++++++++++++++++++++++++++++++++++++ src/database/select_query.hpp | 10 ++++++ tests/database.cpp | 23 +++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 src/database/async_result.hpp diff --git a/src/database/async_result.hpp b/src/database/async_result.hpp new file mode 100644 index 0000000..f4109c0 --- /dev/null +++ b/src/database/async_result.hpp @@ -0,0 +1,77 @@ +#include + +template +class AsyncResult +{ + std::unique_ptr statement{}; + std::string table_name; + +public: + AsyncResult(std::unique_ptr s, const std::string& table_name): + statement{std::move(s)}, + table_name{table_name} + {} + + class iterator + { + using iterator_category = std::input_iterator_tag; + using value_type = Row; + using difference_type = std::ptrdiff_t; + using pointer = Row*; + using reference = Row&; + + Row row{}; + Statement* statement; + bool is_end; + + public: + iterator(Statement* s, const std::string& table_name, bool end=false): + row{table_name}, + statement{s}, + is_end{end} + {} + + reference operator*() + { + extract_row_values(this->row, *statement); + return this->row; + } + + bool operator==(const iterator& o) const + { + if (this->is_end && o.is_end) + return true; + return false; + } + bool operator!=(const iterator& o) const + { + return !(*this == o); + } + + iterator& operator++() + { + if (statement->step() != StepResult::Row) + this->is_end = true; + return *this; + } + + iterator& operator++(int) + { + iterator old = *this; + if (statement->step() != StepResult::Row) + this->is_end = true; + return old; + } + }; + + iterator begin() const + { + iterator it{this->statement.get(), this->table_name}; + ++it; + return it; + } + iterator end() const + { + return {this->statement.get(), this->table_name, true}; + } +}; diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp index e372f2e..1399417 100644 --- a/src/database/select_query.hpp +++ b/src/database/select_query.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -131,6 +132,15 @@ struct SelectQuery: public Query return rows; } + AsyncResult execute_async(DatabaseEngine& db) + { + auto statement = db.prepare(this->body); + if (!statement) + return {{}, {}}; + statement->bind(std::move(this->params)); + return {std::move(statement), this->table_name}; + } + const std::string table_name; }; diff --git a/tests/database.cpp b/tests/database.cpp index 070a460..aab10f4 100644 --- a/tests/database.cpp +++ b/tests/database.cpp @@ -8,6 +8,7 @@ #include #include +#include #include @@ -165,6 +166,28 @@ TEST_CASE("Database") CHECK(after_connection_commands.size() == 2); } + SECTION("async_select") + { + constexpr auto db_size = 8; + CHECK(Database::count(Database::muc_log_lines) == 0); + auto uuid = Database::store_muc_message("owner", "#chan", "irc.example.com", std::chrono::system_clock::now(), "hello!", "louiz'"); + CHECK(Database::count(Database::muc_log_lines) == 1); + CHECK(uuid.size() == 36); + + for (int i = 1; i < db_size; ++i) + Database::store_muc_message("owner", "#chan", "irc.example.com", std::chrono::system_clock::now(), "hello "s + std::to_string(i) + "!"s, "louiz'"); + CHECK(Database::count(Database::muc_log_lines) == db_size); + + auto query = select(Database::muc_log_lines); + query.where() << Database::Owner{} << "=" << "owner"s; + auto async_result = query.execute_async(*Database::db); + + int i = 0; + for (auto rows: async_result) + ++i; + CHECK(i == db_size); + } + Database::close(); } #endif -- cgit v1.2.3