/* * Copyright 2023 jacqueline * * SPDX-License-Identifier: GPL-3.0-only */ #pragma once #include #include #include #include #include #include #include #include #include "file_gatherer.hpp" #include "index.hpp" #include "leveldb/cache.h" #include "leveldb/db.h" #include "leveldb/iterator.h" #include "leveldb/options.h" #include "leveldb/slice.h" #include "records.hpp" #include "result.hpp" #include "shared_string.h" #include "tag_parser.hpp" #include "tasks.hpp" #include "track.hpp" namespace database { template struct Continuation { std::shared_ptr> 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 * well as a continuation token that can be used to continue fetching more * results if they were paginated. */ template class Result { public: auto values() const -> const std::vector& { return values_; } auto next_page() -> std::optional>& { return next_page_; } auto prev_page() -> std::optional>& { return prev_page_; } Result(const std::vector&& values, std::optional> next, std::optional> prev) : values_(values), next_page_(next), prev_page_(prev) {} Result(const Result&) = delete; Result& operator=(const Result&) = delete; private: std::vector values_; std::optional> next_page_; std::optional> prev_page_; }; class IndexRecord { public: explicit IndexRecord(const IndexKey&, std::optional, std::optional); auto text() const -> std::optional; auto track() const -> std::optional; auto Expand(std::size_t) const -> std::optional>; private: IndexKey key_; std::optional override_text_; std::optional track_; }; class Database { public: enum DatabaseError { ALREADY_OPEN, FAILED_TO_OPEN, }; static auto Open(IFileGatherer& file_gatherer, ITagParser& tag_parser) -> cpp::result; static auto Open() -> cpp::result; static auto Destroy() -> void; ~Database(); auto Update() -> std::future; auto GetTrackPath(TrackId id) -> std::future>; auto GetTrack(TrackId id) -> std::future>; /* * Fetches data for multiple tracks more efficiently than multiple calls to * GetTrack. */ auto GetBulkTracks(std::vector id) -> std::future>>; auto GetIndexes() -> std::vector; auto GetTracksByIndex(const IndexInfo& index, std::size_t page_size) -> std::future*>; auto GetTracks(std::size_t page_size) -> std::future*>; auto GetDump(std::size_t page_size) -> std::future*>; template auto GetPage(Continuation* c) -> std::future*>; Database(const Database&) = delete; Database& operator=(const Database&) = delete; private: // Owned. Dumb pointers because destruction needs to be done in an explicit // order. leveldb::DB* db_; leveldb::Cache* cache_; std::shared_ptr worker_task_; // Not owned. IFileGatherer& file_gatherer_; ITagParser& tag_parser_; Database(leveldb::DB* db, leveldb::Cache* cache, IFileGatherer& file_gatherer, ITagParser& tag_parser, std::shared_ptr worker); auto dbMintNewTrackId() -> TrackId; auto dbEntomb(TrackId track, uint64_t hash) -> void; auto dbPutTrackData(const TrackData& s) -> void; auto dbGetTrackData(TrackId id) -> std::optional; auto dbPutHash(const uint64_t& hash, TrackId i) -> void; auto dbGetHash(const uint64_t& hash) -> std::optional; auto dbCreateIndexesForTrack(Track track) -> void; template auto dbGetPage(const Continuation& c) -> Result*; template auto ParseRecord(const leveldb::Slice& key, const leveldb::Slice& val) -> std::optional; }; template <> auto Database::ParseRecord(const leveldb::Slice& key, const leveldb::Slice& val) -> std::optional; template <> auto Database::ParseRecord(const leveldb::Slice& key, const leveldb::Slice& val) -> std::optional; template <> auto Database::ParseRecord(const leveldb::Slice& key, const leveldb::Slice& val) -> std::optional; } // namespace database