summaryrefslogtreecommitdiff
path: root/src/database/index.cpp
blob: a828578df974e0f002bfb7b4c0c73912cb69b189 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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