summaryrefslogtreecommitdiff
path: root/src/database
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-04-27 16:03:55 +1000
committerjacqueline <me@jacqueline.id.au>2023-04-27 16:03:55 +1000
commitcd520b9360f0d0d4ab7582d2cbf2aa96060a0500 (patch)
treeb55e9c4376395e79e3d85fe02e26ec730803d284 /src/database
parent5d7cbec34cd5e473d5768b39054d99bc72ddad62 (diff)
downloadtangara-fw-cd520b9360f0d0d4ab7582d2cbf2aa96060a0500.tar.gz
Make queries a little less copy-paste
Diffstat (limited to 'src/database')
-rw-r--r--src/database/database.cpp41
-rw-r--r--src/database/include/database.hpp80
2 files changed, 78 insertions, 43 deletions
diff --git a/src/database/database.cpp b/src/database/database.cpp
index 8ca72771..2cff51ce 100644
--- a/src/database/database.cpp
+++ b/src/database/database.cpp
@@ -1,4 +1,5 @@
#include "database.hpp"
+#include <functional>
#include "esp_log.h"
#include "ff.h"
@@ -92,34 +93,24 @@ auto Database::Populate() -> std::future<void> {
});
}
-auto Database::GetSongs(std::size_t page_size) -> std::future<DbResult<Song>> {
- return RunOnDbTask<DbResult<Song>>([&]() -> DbResult<Song> {
- std::unique_ptr<leveldb::Iterator> it(
- db_->NewIterator(leveldb::ReadOptions()));
- it->Seek("title:");
- std::vector<Song> results;
- IterateAndParse(it.get(), page_size,
- [&](const leveldb::Slice& key, const leveldb::Slice& val) {
- Song s;
- s.title = key.ToString();
- results.push_back(s);
- });
- return DbResult<Song>(results, std::move(it));
+auto parse_song(const leveldb::Slice& key, const leveldb::Slice& val)
+ -> std::optional<Song> {
+ Song s;
+ s.title = key.ToString();
+ return s;
+}
+
+auto Database::GetSongs(std::size_t page_size) -> std::future<Result<Song>> {
+ return RunOnDbTask<Result<Song>>([=, this]() -> Result<Song> {
+ return Query<Song>("title:", page_size, &parse_song);
});
}
-auto Database::GetMoreSongs(std::size_t page_size, DbResult<Song> continuation)
- -> std::future<DbResult<Song>> {
- return RunOnDbTask<DbResult<Song>>([&]() -> DbResult<Song> {
- std::unique_ptr<leveldb::Iterator> it(continuation.it());
- std::vector<Song> results;
- IterateAndParse(it.get(), page_size,
- [&](const leveldb::Slice& key, const leveldb::Slice& val) {
- Song s;
- s.title = key.ToString();
- results.push_back(s);
- });
- return DbResult<Song>(results, std::move(it));
+auto Database::GetMoreSongs(std::size_t page_size, Continuation c)
+ -> std::future<Result<Song>> {
+ leveldb::Iterator* it = c.release();
+ return RunOnDbTask<Result<Song>>([=, this]() -> Result<Song> {
+ return Query<Song>(it, page_size, &parse_song);
});
}
diff --git a/src/database/include/database.hpp b/src/database/include/database.hpp
index bc102ca8..61918d96 100644
--- a/src/database/include/database.hpp
+++ b/src/database/include/database.hpp
@@ -11,6 +11,7 @@
#include "leveldb/cache.h"
#include "leveldb/db.h"
#include "leveldb/iterator.h"
+#include "leveldb/options.h"
#include "leveldb/slice.h"
#include "result.hpp"
@@ -33,17 +34,33 @@ struct Song {
struct SongMetadata {};
+typedef std::unique_ptr<leveldb::Iterator> Continuation;
+
template <typename T>
-class DbResult {
+class Result {
public:
- DbResult(const std::vector<T>& values, std::unique_ptr<leveldb::Iterator> it)
- : values_(values), it_(std::move(it)) {}
- auto values() -> std::vector<T> { return values_; }
- auto it() -> leveldb::Iterator* { return it_.release(); };
+ auto values() -> std::unique_ptr<std::vector<T>> {
+ return std::move(values_);
+ }
+ auto continuation() -> Continuation { return std::move(c_); }
+ auto HasMore() -> bool { return c_->Valid(); }
+
+ Result(std::unique_ptr<std::vector<T>> values, Continuation c)
+ : values_(std::move(values)), c_(std::move(c)) {}
+
+ Result(Result&& other)
+ : values_(std::move(other.values_)), c_(std::move(other.c_)) {}
+
+ Result operator=(Result&& other) {
+ return Result(other.values(), other.continuation());
+ }
+
+ Result(const Result&) = delete;
+ Result& operator=(const Result&) = delete;
private:
- std::vector<T> values_;
- std::unique_ptr<leveldb::Iterator> it_;
+ std::unique_ptr<std::vector<T>> values_;
+ Continuation c_;
};
class Database {
@@ -58,23 +75,23 @@ class Database {
auto Populate() -> std::future<void>;
- auto GetArtists(std::size_t page_size) -> std::future<DbResult<Artist>>;
- auto GetMoreArtists(std::size_t page_size, DbResult<Artist> continuation)
- -> std::future<DbResult<Artist>>;
+ auto GetArtists(std::size_t page_size) -> std::future<Result<Artist>>;
+ auto GetMoreArtists(std::size_t page_size, Continuation c)
+ -> std::future<Result<Artist>>;
auto GetAlbums(std::size_t page_size, std::optional<Artist> artist)
- -> std::future<DbResult<Album>>;
- auto GetMoreAlbums(std::size_t page_size, DbResult<Album> continuation)
- -> std::future<DbResult<Album>>;
+ -> std::future<Result<Album>>;
+ auto GetMoreAlbums(std::size_t page_size, Continuation c)
+ -> std::future<Result<Album>>;
- auto GetSongs(std::size_t page_size) -> std::future<DbResult<Song>>;
+ auto GetSongs(std::size_t page_size) -> std::future<Result<Song>>;
auto GetSongs(std::size_t page_size, std::optional<Artist> artist)
- -> std::future<DbResult<Song>>;
+ -> std::future<Result<Song>>;
auto GetSongs(std::size_t page_size,
std::optional<Artist> artist,
- std::optional<Album> album) -> std::future<DbResult<Song>>;
- auto GetMoreSongs(std::size_t page_size, DbResult<Song> continuation)
- -> std::future<DbResult<Song>>;
+ std::optional<Album> album) -> std::future<Result<Song>>;
+ auto GetMoreSongs(std::size_t page_size, Continuation c)
+ -> std::future<Result<Song>>;
auto GetSongIds(std::optional<Artist> artist, std::optional<Album> album)
-> std::future<std::vector<SongId_t>>;
@@ -89,6 +106,33 @@ class Database {
std::unique_ptr<leveldb::Cache> cache_;
Database(leveldb::DB* db, leveldb::Cache* cache);
+
+ 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);
+ }
+
+ 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)};
+ }
};
} // namespace database