summaryrefslogtreecommitdiff
path: root/src/database/include
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-05-16 14:11:38 +1000
committerjacqueline <me@jacqueline.id.au>2023-05-16 14:11:38 +1000
commitd71f726c42963d55809605b4dc4144970ca0f230 (patch)
tree5dc8e6355f5e870e767c3d23ec4009bc39155821 /src/database/include
parent785349eb5b3255d0a51ca7459531f75cb47c90ac (diff)
downloadtangara-fw-d71f726c42963d55809605b4dc4144970ca0f230.tar.gz
Add pagination to database queries
Diffstat (limited to 'src/database/include')
-rw-r--r--src/database/include/database.hpp81
-rw-r--r--src/database/include/song.hpp11
2 files changed, 43 insertions, 49 deletions
diff --git a/src/database/include/database.hpp b/src/database/include/database.hpp
index 29872e8d..da0ed083 100644
--- a/src/database/include/database.hpp
+++ b/src/database/include/database.hpp
@@ -22,7 +22,15 @@
namespace database {
-typedef std::unique_ptr<leveldb::Iterator> Continuation;
+template <typename T>
+struct Continuation {
+ std::shared_ptr<std::unique_ptr<leveldb::Iterator>> iterator;
+ std::string prefix;
+ std::string start_key;
+ bool forward;
+ bool was_prev_forward;
+ size_t page_size;
+};
/*
* Wrapper for a set of results from the database. Owns the list of results, as
@@ -32,29 +40,23 @@ typedef std::unique_ptr<leveldb::Iterator> Continuation;
template <typename T>
class Result {
public:
- auto values() -> std::vector<T>* { return values_.release(); }
- auto continuation() -> Continuation { return std::move(c_); }
- auto HasMore() -> bool { return c_->Valid(); }
-
- Result(std::vector<T>* values, Continuation c)
- : values_(values), c_(std::move(c)) {}
-
- Result(std::unique_ptr<std::vector<T>> values, Continuation c)
- : values_(std::move(values)), c_(std::move(c)) {}
+ auto values() const -> const std::vector<T>& { return values_; }
- Result(Result&& other)
- : values_(move(other.values_)), c_(std::move(other.c_)) {}
+ auto next_page() -> std::optional<Continuation<T>>& { return next_page_; }
+ auto prev_page() -> std::optional<Continuation<T>>& { return prev_page_; }
- Result operator=(Result&& other) {
- return Result(other.values(), std::move(other.continuation()));
- }
+ Result(const std::vector<T>&& values,
+ std::optional<Continuation<T>> next,
+ std::optional<Continuation<T>> prev)
+ : values_(values), next_page_(next), prev_page_(prev) {}
Result(const Result&) = delete;
Result& operator=(const Result&) = delete;
private:
- std::unique_ptr<std::vector<T>> values_;
- Continuation c_;
+ std::vector<T> values_;
+ std::optional<Continuation<T>> next_page_;
+ std::optional<Continuation<T>> prev_page_;
};
class Database {
@@ -73,13 +75,11 @@ class Database {
auto Update() -> std::future<void>;
- auto GetSongs(std::size_t page_size) -> std::future<Result<Song>>;
- auto GetMoreSongs(std::size_t page_size, Continuation c)
- -> std::future<Result<Song>>;
+ auto GetSongs(std::size_t page_size) -> std::future<Result<Song>*>;
+ auto GetDump(std::size_t page_size) -> std::future<Result<std::string>*>;
- auto GetDump(std::size_t page_size) -> std::future<Result<std::string>>;
- auto GetMoreDump(std::size_t page_size, Continuation c)
- -> std::future<Result<std::string>>;
+ template <typename T>
+ auto GetPage(Continuation<T>* c) -> std::future<Result<T>*>;
Database(const Database&) = delete;
Database& operator=(const Database&) = delete;
@@ -110,31 +110,20 @@ class Database {
-> void;
template <typename T>
- using Parser = std::function<std::optional<T>(const leveldb::Slice& key,
- const leveldb::Slice& value)>;
-
- template <typename T>
- auto Query(const leveldb::Slice& prefix,
- std::size_t max_results,
- Parser<T> parser) -> Result<T> {
- leveldb::Iterator* it = db_->NewIterator(leveldb::ReadOptions());
- it->Seek(prefix);
- return Query(it, max_results, parser);
- }
+ auto dbGetPage(const Continuation<T>& c) -> Result<T>*;
template <typename T>
- auto Query(leveldb::Iterator* it, std::size_t max_results, Parser<T> parser)
- -> Result<T> {
- auto results = std::make_unique<std::vector<T>>();
- for (std::size_t i = 0; i < max_results && it->Valid(); i++) {
- std::optional<T> r = std::invoke(parser, it->key(), it->value());
- if (r) {
- results->push_back(*r);
- }
- it->Next();
- }
- return {std::move(results), std::unique_ptr<leveldb::Iterator>(it)};
- }
+ auto ParseRecord(const leveldb::Slice& key, const leveldb::Slice& val)
+ -> std::optional<T>;
};
+template <>
+auto Database::ParseRecord<Song>(const leveldb::Slice& key,
+ const leveldb::Slice& val)
+ -> std::optional<Song>;
+template <>
+auto Database::ParseRecord<std::string>(const leveldb::Slice& key,
+ const leveldb::Slice& val)
+ -> std::optional<std::string>;
+
} // namespace database
diff --git a/src/database/include/song.hpp b/src/database/include/song.hpp
index e51e5587..9a84e124 100644
--- a/src/database/include/song.hpp
+++ b/src/database/include/song.hpp
@@ -4,6 +4,7 @@
#include <optional>
#include <string>
+#include <utility>
#include "leveldb/db.h"
#include "span.hpp"
@@ -133,16 +134,20 @@ class SongData {
*/
class Song {
public:
- Song(SongData data, SongTags tags) : data_(data), tags_(tags) {}
+ Song(const SongData& data, const SongTags& tags) : data_(data), tags_(tags) {}
+ Song(const Song& other) = default;
- auto data() -> const SongData& { return data_; }
- auto tags() -> const SongTags& { return tags_; }
+ auto data() const -> const SongData& { return data_; }
+ auto tags() const -> const SongTags& { return tags_; }
bool operator==(const Song&) const = default;
+ Song operator=(const Song& other) const { return Song(other); }
private:
const SongData data_;
const SongTags tags_;
};
+void swap(Song& first, Song& second);
+
} // namespace database