diff options
Diffstat (limited to 'src/database/index.cpp')
| -rw-r--r-- | src/database/index.cpp | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/src/database/index.cpp b/src/database/index.cpp new file mode 100644 index 00000000..a828578d --- /dev/null +++ b/src/database/index.cpp @@ -0,0 +1,88 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "index.hpp" +#include <stdint.h> +#include <variant> +#include "komihash.h" +#include "leveldb/write_batch.h" +#include "records.hpp" + +namespace database { + +const IndexInfo kAlbumsByArtist{ + .id = 1, + .name = "Albums by Artist", + .components = {Tag::kArtist, Tag::kAlbum, Tag::kAlbumTrack}, +}; + +const IndexInfo kTracksByGenre{ + .id = 2, + .name = "Tracks by Genre", + .components = {Tag::kGenre, Tag::kTitle}, +}; + +const IndexInfo kAllTracks{ + .id = 3, + .name = "All Tracks", + .components = {Tag::kTitle}, +}; + +auto Index(const IndexInfo& info, const Track& t, leveldb::WriteBatch* batch) + -> bool { + IndexKey key{ + .header{ + .id = info.id, + .depth = 0, + .components_hash = 0, + }, + .item = {}, + .track = {}, + }; + + for (std::uint8_t i = 0; i < info.components.size(); i++) { + // Fill in the text for this depth. + auto text = t.tags().at(info.components.at(i)); + if (text) { + key.item = *text; + } else { + key.item = {}; + } + + // If this is the last component, then we should also fill in the track id. + if (i == info.components.size() - 1) { + key.track = t.data().id(); + } else { + key.track = {}; + } + + auto encoded = EncodeIndexKey(key); + batch->Put(encoded.slice, leveldb::Slice{}); + + // If there are more components after this, then we need to finish by + // narrowing the header with the current title. + if (i < info.components.size() - 1) { + key.header = ExpandHeader(key.header, key.item); + } + } + return true; +} + +auto ExpandHeader(const IndexKey::Header& header, + const std::optional<std::string>& component) + -> IndexKey::Header { + IndexKey::Header ret{header}; + ret.depth++; + if (component) { + ret.components_hash = + komihash(component->data(), component->size(), ret.components_hash); + } else { + ret.components_hash = komihash(NULL, 0, ret.components_hash); + } + return ret; +} + +} // namespace database |
