aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlouiz’2019-09-27 18:55:15 (GMT)
committerlouiz’2019-09-27 18:57:30 (GMT)
commit4b8d3430c7fff8b869ec895dbffac748db72a237 (patch)
treecc472dec9485f7cb4886900f313d5231229507c8
parent05ba076a0ec451a5a67410731f5ea23ec1faaa74 (diff)
downloadbiboumi-async_sql.tar.gz
biboumi-async_sql.tar.xz
-rw-r--r--src/database/async_result.hpp77
-rw-r--r--src/database/select_query.hpp10
-rw-r--r--tests/database.cpp23
3 files changed, 110 insertions, 0 deletions
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 <database/row.hpp>
+
+template <typename... T>
+class AsyncResult
+{
+ std::unique_ptr<Statement> statement{};
+ std::string table_name;
+
+public:
+ AsyncResult(std::unique_ptr<Statement> 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<T...>;
+ using difference_type = std::ptrdiff_t;
+ using pointer = Row<T...>*;
+ using reference = Row<T...>&;
+
+ Row<T...> 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 <database/query.hpp>
#include <logger/logger.hpp>
#include <database/row.hpp>
+#include <database/async_result.hpp>
#include <utils/optional_bool.hpp>
@@ -131,6 +132,15 @@ struct SelectQuery: public Query
return rows;
}
+ AsyncResult<T...> 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 <database/database.hpp>
#include <database/save.hpp>
+#include <database/select_query.hpp>
#include <config/config.hpp>
@@ -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