summaryrefslogtreecommitdiff
path: root/src/database/database.cpp
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-12-05 17:00:28 +1100
committerjacqueline <me@jacqueline.id.au>2023-12-05 17:00:28 +1100
commit009f69c929eb1d1b65d75b0937fbf3b8de5d9148 (patch)
treead7f9994226eb8c57ac7c060d4c4476f5c7d0c46 /src/database/database.cpp
parent4f5422e906b1d17720592d97bc0d5e82a71b1e5f (diff)
downloadtangara-fw-009f69c929eb1d1b65d75b0937fbf3b8de5d9148.tar.gz
Add basic track queue save/load support
Not wired up yet; I need to do a bunch of cleanup before i wire it in
Diffstat (limited to 'src/database/database.cpp')
-rw-r--r--src/database/database.cpp117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/database/database.cpp b/src/database/database.cpp
index 03451c05..e646154e 100644
--- a/src/database/database.cpp
+++ b/src/database/database.cpp
@@ -18,6 +18,7 @@
#include <sstream>
#include "collation.hpp"
+#include "cppbor.h"
#include "esp_log.h"
#include "ff.h"
#include "freertos/projdefs.h"
@@ -52,6 +53,8 @@ static const char kDbPath[] = "/.tangara-db";
static const char kKeyDbVersion[] = "schema_version";
static const uint8_t kCurrentDbVersion = 3;
+
+static const char kKeyCustom[] = "U\0";
static const char kKeyCollator[] = "collator";
static const char kKeyTrackId[] = "next_track_id";
@@ -197,6 +200,19 @@ Database::~Database() {
sIsDbOpen.store(false);
}
+auto Database::Put(const std::string& key, const std::string& val) -> void {
+ db_->Put(leveldb::WriteOptions{}, kKeyCustom + key, val);
+}
+
+auto Database::Get(const std::string& key) -> std::optional<std::string> {
+ std::string val;
+ auto res = db_->Get(leveldb::ReadOptions{}, kKeyCustom + key, &val);
+ if (!res.ok()) {
+ return {};
+ }
+ return val;
+}
+
auto Database::Update() -> std::future<void> {
events::Ui().Dispatch(event::UpdateStarted{});
return worker_task_->Dispatch<void>([&]() -> void {
@@ -883,6 +899,45 @@ Iterator::Iterator(std::weak_ptr<Database> db, const IndexInfo& idx)
.page_size = 1};
}
+auto Iterator::Parse(std::weak_ptr<Database> db, const cppbor::Array& encoded)
+ -> std::optional<Iterator> {
+ // Ensure the input looks reasonable.
+ if (encoded.size() != 3) {
+ return {};
+ }
+
+ if (encoded[0]->type() != cppbor::TSTR) {
+ return {};
+ }
+ const std::string& prefix = encoded[0]->asTstr()->value();
+
+ std::optional<Continuation> current_pos{};
+ if (encoded[1]->type() == cppbor::TSTR) {
+ const std::string& key = encoded[1]->asTstr()->value();
+ current_pos = Continuation{
+ .prefix = {prefix.data(), prefix.size()},
+ .start_key = {key.data(), key.size()},
+ .forward = true,
+ .was_prev_forward = true,
+ .page_size = 1,
+ };
+ }
+
+ std::optional<Continuation> prev_pos{};
+ if (encoded[2]->type() == cppbor::TSTR) {
+ const std::string& key = encoded[2]->asTstr()->value();
+ current_pos = Continuation{
+ .prefix = {prefix.data(), prefix.size()},
+ .start_key = {key.data(), key.size()},
+ .forward = false,
+ .was_prev_forward = false,
+ .page_size = 1,
+ };
+ }
+
+ return Iterator{db, std::move(current_pos), std::move(prev_pos)};
+}
+
Iterator::Iterator(std::weak_ptr<Database> db, const Continuation& c)
: db_(db), pos_mutex_(), current_pos_(c), prev_pos_() {}
@@ -892,6 +947,11 @@ Iterator::Iterator(const Iterator& other)
current_pos_(other.current_pos_),
prev_pos_(other.prev_pos_) {}
+Iterator::Iterator(std::weak_ptr<Database> db,
+ std::optional<Continuation>&& cur,
+ std::optional<Continuation>&& prev)
+ : db_(db), current_pos_(cur), prev_pos_(prev) {}
+
Iterator& Iterator::operator=(const Iterator& other) {
current_pos_ = other.current_pos_;
prev_pos_ = other.prev_pos_;
@@ -995,6 +1055,53 @@ auto Iterator::InvokeNull(Callback cb) -> void {
std::invoke(cb, std::optional<IndexRecord>{});
}
+auto Iterator::cbor() const -> cppbor::Array&& {
+ cppbor::Array res;
+
+ std::pmr::string prefix;
+ if (current_pos_) {
+ prefix = current_pos_->prefix;
+ } else if (prev_pos_) {
+ prefix = prev_pos_->prefix;
+ } else {
+ ESP_LOGW(kTag, "iterator has no prefix");
+ return std::move(res);
+ }
+
+ if (current_pos_) {
+ res.add(cppbor::Tstr(current_pos_->start_key));
+ } else {
+ res.add(cppbor::Null());
+ }
+
+ if (prev_pos_) {
+ res.add(cppbor::Tstr(prev_pos_->start_key));
+ } else {
+ res.add(cppbor::Null());
+ }
+
+ return std::move(res);
+}
+
+auto TrackIterator::Parse(std::weak_ptr<Database> db,
+ const cppbor::Array& encoded)
+ -> std::optional<TrackIterator> {
+ TrackIterator ret{db};
+
+ for (const auto& item : encoded) {
+ if (item->type() == cppbor::ARRAY) {
+ auto it = Iterator::Parse(db, *item->asArray());
+ if (it) {
+ ret.levels_.push_back(std::move(*it));
+ } else {
+ return {};
+ }
+ }
+ }
+
+ return ret;
+}
+
TrackIterator::TrackIterator(const Iterator& it) : db_(it.db_), levels_() {
if (it.current_pos_) {
levels_.push_back(it);
@@ -1005,6 +1112,8 @@ TrackIterator::TrackIterator(const Iterator& it) : db_(it.db_), levels_() {
TrackIterator::TrackIterator(const TrackIterator& other)
: db_(other.db_), levels_(other.levels_) {}
+TrackIterator::TrackIterator(std::weak_ptr<Database> db) : db_(db), levels_() {}
+
TrackIterator& TrackIterator::operator=(TrackIterator&& other) {
levels_ = std::move(other.levels_);
return *this;
@@ -1057,4 +1166,12 @@ auto TrackIterator::NextLeaf() -> void {
}
}
+auto TrackIterator::cbor() const -> cppbor::Array&& {
+ cppbor::Array res;
+ for (const auto& i : levels_) {
+ res.add(i.cbor());
+ }
+ return std::move(res);
+}
+
} // namespace database