Cppinecone
A C++ client for the Pinecone vector database
vector_metadata.hpp
Go to the documentation of this file.
1 #pragma once
7 #include <cstdint>
8 #include <sstream>
9 #include <string>
10 #include <string_view>
11 #include <tuple>
12 #include <unordered_map>
13 #include <variant>
14 
15 #include <nlohmann/json.hpp>
16 
17 #include "pinecone/util/result.hpp"
18 
19 using json = nlohmann::json;
20 
21 namespace pinecone::types
22 {
26 enum class binary_operator {
27  unknown,
28  eq,
29  ne,
30  gt,
31  gte,
32  lt,
33  lte,
34 };
35 
36 // NOLINTNEXTLINE
37 NLOHMANN_JSON_SERIALIZE_ENUM(binary_operator, {{binary_operator::unknown, nullptr},
38  {binary_operator::eq, "$eq"},
39  {binary_operator::ne, "$ne"},
40  {binary_operator::gt, "$gt"},
41  {binary_operator::gte, "$gte"},
42  {binary_operator::lt, "$lt"},
43  {binary_operator::lte, "$lte"}})
44 
48 enum class array_operator {
49  unknown,
50  in,
51  nin,
52 };
53 
54 // NOLINTNEXTLINE
55 NLOHMANN_JSON_SERIALIZE_ENUM(array_operator, {{array_operator::unknown, nullptr},
56  {array_operator::in, "$in"},
57  {array_operator::nin, "$nin"}})
58 
62 enum class combination_operator {
63  unknown,
64  and_,
65  or_,
66 };
67 
68 // NOLINTNEXTLINE
69 NLOHMANN_JSON_SERIALIZE_ENUM(combination_operator, {{combination_operator::unknown, nullptr},
70  {combination_operator::and_, "$and"},
71  {combination_operator::or_, "$or"}})
72 
76 struct metadata_value {
77  using value_type = std::variant<bool, int64_t, double, std::string>;
78  // NOLINTNEXTLINE
79  constexpr metadata_value(char const* value) noexcept : _var(value) {}
80  // NOLINTNEXTLINE
81  metadata_value(std::string value) noexcept : _var(value) {}
82  // NOLINTNEXTLINE
83  constexpr metadata_value(bool value) noexcept : _var(value) {}
84  // NOLINTNEXTLINE
85  constexpr metadata_value(int64_t value) noexcept : _var(value) {}
86  // NOLINTNEXTLINE
87  constexpr metadata_value(double value) noexcept : _var(value) {}
88 
89  [[nodiscard]] auto var() const noexcept -> value_type const& { return _var; }
90 
91  friend void to_json(nlohmann ::json& nlohmann_json_j, const metadata_value& nlohmann_json_t)
92  {
93  std::visit([&nlohmann_json_j](auto const& v) { nlohmann_json_j = v; }, nlohmann_json_t._var);
94  }
95 
96  private:
97  value_type _var;
98 };
99 
109 struct metadata {
110  metadata() = default;
112  : _values(std::move(values))
113  {
114  }
115 
119  [[nodiscard]] auto values() const noexcept
120  -> std::unordered_map<std::string, metadata_value> const&
121  {
122  return _values;
123  }
124 
125  friend void to_json(nlohmann ::json& nlohmann_json_j, const metadata& nlohmann_json_t)
126  {
127  for (auto const& [key, value] : nlohmann_json_t._values) {
128  std::visit([&, k = key](auto const& v) { nlohmann_json_j[k] = v; }, value.var());
129  }
130  }
131 
132  friend void from_json(const nlohmann ::json& nlohmann_json_j, metadata& nlohmann_json_t)
133  {
135  for (auto const& [key, value] : nlohmann_json_j.items()) {
136  if (value.is_boolean()) {
137  values.emplace(key, value.get<bool>());
138  } else if (value.is_number_integer()) {
139  values.emplace(key, value.get<int64_t>());
140  } else if (value.is_number_float()) {
141  values.emplace(key, value.get<double>());
142  } else if (value.is_string()) {
143  values.emplace(key, value.get<std::string>());
144  } else {
145  // TODO: handle failure
146  // return {"Metadata value was not a boolean, integer, float, or string"};
147  }
148  }
149 
150  nlohmann_json_t._values = std::move(values);
151  }
152 
153  private:
155 };
156 
162 template <typename Derived>
163 struct filter_base {
164  friend void to_json(nlohmann ::json& nlohmann_json_j, const filter_base& nlohmann_json_t)
165  {
166  nlohmann_json_j["filter"] = json::object();
167  to_json(nlohmann_json_j["filter"], static_cast<Derived const&>(nlohmann_json_t));
168  }
169 };
170 
175 struct binary_filter : public filter_base<binary_filter> {
176  friend void to_json(nlohmann ::json& nlohmann_json_j, const binary_filter& nlohmann_json_t)
177  {
178  json j = nlohmann_json_t._op;
179  nlohmann_json_j[nlohmann_json_t._key][j] = nlohmann_json_t._value;
180  }
181 
182  binary_filter(std::string key, binary_operator op, metadata_value value) noexcept
183  : _key(std::move(key)), _op(op), _value(std::move(value))
184  {
185  }
186 
187  private:
188  std::string _key;
189  binary_operator _op;
190  metadata_value _value;
191 };
192 
199 template <typename iter>
200 struct array_filter : public filter_base<array_filter<iter>> {
201  friend void to_json(nlohmann ::json& nlohmann_json_j, const array_filter& nlohmann_json_t)
202  {
203  json j = nlohmann_json_t._op;
204  nlohmann_json_j[nlohmann_json_t._key][j] = json::array();
205  auto& arr = nlohmann_json_j[nlohmann_json_t._key][j];
206  for (auto const& v : nlohmann_json_t._values) {
207  arr.emplace_back(v);
208  }
209  }
210 
211  array_filter(std::string key, array_operator op, iter values) noexcept
212  : _key(std::move(key)), _op(op), _values(std::move(values))
213  {
214  }
215 
216  private:
217  std::string _key;
218  array_operator _op;
219  iter _values;
220 };
221 
222 template <typename filter>
223 auto serialize_expand(json& arr, filter const& f) -> void
224 {
225  to_json(arr.emplace_back(), f);
226 }
227 
228 template <typename filter, typename... filters>
229 auto serialize_expand(json& arr, filter const& f, filters const&... fs) -> void
230 {
231  serialize_expand(arr, f);
232  serialize_expand(arr, fs...);
233 }
234 
241 template <typename... ts>
242 struct combination_filter : public filter_base<combination_filter<ts...>> {
243  friend void to_json(nlohmann ::json& nlohmann_json_j, const combination_filter& nlohmann_json_t)
244  {
245  json j = nlohmann_json_t._op;
246  nlohmann_json_j[j] = json::array();
247  auto& arr = nlohmann_json_j[j];
248  std::apply([&arr](auto const&... filter) -> void { serialize_expand(arr, filter...); },
249  nlohmann_json_t._filters);
250  }
251 
252  // NOLINTNEXTLINE
253  constexpr combination_filter(combination_operator op, ts... filters) noexcept
254  : _op(op), _filters(std::move(filters)...)
255  {
256  }
257 
258  private:
259  combination_operator _op;
260  std::tuple<ts...> _filters;
261 };
262 
266 struct no_filter : public filter_base<no_filter> {
267  friend void to_json(nlohmann ::json& nlohmann_json_j, const no_filter& /*nlohmann_json_t*/)
268  {
269  nlohmann_json_j = json::object({});
270  }
271 };
272 } // namespace pinecone::types
T move(T... args)
STL namespace.
Models the possibility of failure for Pinecone operations.
Array filters test a single metadata value against multiple operands.
Binary filters are simple predicates; they compare a single metadata value to a provided operand.
Combination filters apply boolean logic to the other filter types.
Common operations shared for all filter types.
Metadata for a single Pinecone vector.
auto values() const noexcept -> std::unordered_map< std::string, metadata_value > const &
No filter applied; always returns true.
binary_operator
The binary operators supported by the metadata filtering API.