Make queries a little less copy-paste

custom
jacqueline 2 years ago
parent 5d7cbec34c
commit cd520b9360
  1. 41
      src/database/database.cpp
  2. 80
      src/database/include/database.hpp
  3. 14
      src/main/app_console.cpp

@ -1,4 +1,5 @@
#include "database.hpp" #include "database.hpp"
#include <functional>
#include "esp_log.h" #include "esp_log.h"
#include "ff.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>> { auto parse_song(const leveldb::Slice& key, const leveldb::Slice& val)
return RunOnDbTask<DbResult<Song>>([&]() -> DbResult<Song> { -> std::optional<Song> {
std::unique_ptr<leveldb::Iterator> it( Song s;
db_->NewIterator(leveldb::ReadOptions())); s.title = key.ToString();
it->Seek("title:"); return s;
std::vector<Song> results; }
IterateAndParse(it.get(), page_size,
[&](const leveldb::Slice& key, const leveldb::Slice& val) { auto Database::GetSongs(std::size_t page_size) -> std::future<Result<Song>> {
Song s; return RunOnDbTask<Result<Song>>([=, this]() -> Result<Song> {
s.title = key.ToString(); return Query<Song>("title:", page_size, &parse_song);
results.push_back(s);
});
return DbResult<Song>(results, std::move(it));
}); });
} }
auto Database::GetMoreSongs(std::size_t page_size, DbResult<Song> continuation) auto Database::GetMoreSongs(std::size_t page_size, Continuation c)
-> std::future<DbResult<Song>> { -> std::future<Result<Song>> {
return RunOnDbTask<DbResult<Song>>([&]() -> DbResult<Song> { leveldb::Iterator* it = c.release();
std::unique_ptr<leveldb::Iterator> it(continuation.it()); return RunOnDbTask<Result<Song>>([=, this]() -> Result<Song> {
std::vector<Song> results; return Query<Song>(it, page_size, &parse_song);
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));
}); });
} }

@ -11,6 +11,7 @@
#include "leveldb/cache.h" #include "leveldb/cache.h"
#include "leveldb/db.h" #include "leveldb/db.h"
#include "leveldb/iterator.h" #include "leveldb/iterator.h"
#include "leveldb/options.h"
#include "leveldb/slice.h" #include "leveldb/slice.h"
#include "result.hpp" #include "result.hpp"
@ -33,17 +34,33 @@ struct Song {
struct SongMetadata {}; struct SongMetadata {};
typedef std::unique_ptr<leveldb::Iterator> Continuation;
template <typename T> template <typename T>
class DbResult { class Result {
public: public:
DbResult(const std::vector<T>& values, std::unique_ptr<leveldb::Iterator> it) auto values() -> std::unique_ptr<std::vector<T>> {
: values_(values), it_(std::move(it)) {} return std::move(values_);
auto values() -> std::vector<T> { return values_; } }
auto it() -> leveldb::Iterator* { return it_.release(); }; 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: private:
std::vector<T> values_; std::unique_ptr<std::vector<T>> values_;
std::unique_ptr<leveldb::Iterator> it_; Continuation c_;
}; };
class Database { class Database {
@ -58,23 +75,23 @@ class Database {
auto Populate() -> std::future<void>; auto Populate() -> std::future<void>;
auto GetArtists(std::size_t page_size) -> std::future<DbResult<Artist>>; auto GetArtists(std::size_t page_size) -> std::future<Result<Artist>>;
auto GetMoreArtists(std::size_t page_size, DbResult<Artist> continuation) auto GetMoreArtists(std::size_t page_size, Continuation c)
-> std::future<DbResult<Artist>>; -> std::future<Result<Artist>>;
auto GetAlbums(std::size_t page_size, std::optional<Artist> artist) auto GetAlbums(std::size_t page_size, std::optional<Artist> artist)
-> std::future<DbResult<Album>>; -> std::future<Result<Album>>;
auto GetMoreAlbums(std::size_t page_size, DbResult<Album> continuation) auto GetMoreAlbums(std::size_t page_size, Continuation c)
-> std::future<DbResult<Album>>; -> 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) 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, auto GetSongs(std::size_t page_size,
std::optional<Artist> artist, std::optional<Artist> artist,
std::optional<Album> album) -> std::future<DbResult<Song>>; std::optional<Album> album) -> std::future<Result<Song>>;
auto GetMoreSongs(std::size_t page_size, DbResult<Song> continuation) auto GetMoreSongs(std::size_t page_size, Continuation c)
-> std::future<DbResult<Song>>; -> std::future<Result<Song>>;
auto GetSongIds(std::optional<Artist> artist, std::optional<Album> album) auto GetSongIds(std::optional<Artist> artist, std::optional<Album> album)
-> std::future<std::vector<SongId_t>>; -> std::future<std::vector<SongId_t>>;
@ -89,6 +106,33 @@ class Database {
std::unique_ptr<leveldb::Cache> cache_; std::unique_ptr<leveldb::Cache> cache_;
Database(leveldb::DB* db, 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 } // namespace database

@ -176,10 +176,18 @@ int CmdDbSongs(int argc, char** argv) {
return 1; return 1;
} }
database::DbResult<database::Song> res = database::Result<database::Song> res =
sInstance->database_->GetSongs(10).get(); sInstance->database_->GetSongs(10).get();
for (database::Song s : res.values()) { while (true) {
std::cout << s.title << std::endl; std::unique_ptr<std::vector<database::Song>> r = res.values();
for (database::Song s : *r) {
std::cout << s.title << std::endl;
}
if (res.HasMore()) {
res = sInstance->database_->GetMoreSongs(10, res.continuation()).get();
} else {
break;
}
} }
return 0; return 0;

Loading…
Cancel
Save