29 using mapped_type = std::optional<TValue>;
30 using valuetype = std::pair<const keytype, mapped_type>;
31 using size_type = uint64_t;
32 using result_type = std::vector<valuetype>;
50 const TagColumns& tag_columns
53 , tag_columns_{tag_columns}
54 , query_type_{QueryType::NONE}
55 , filters_{TRUE_TIME_SERIES_KEY_FILTER} {}
98 validate_tags(key.tags());
99 set_query_type(QueryType::POINT);
100 query_params_ = QueryParams{PointParams{key}};
117 validate_tags(start.
tags());
118 validate_tags(end.
tags());
119 set_query_type(QueryType::RANGE);
120 query_params_ = QueryParams{RangeParams{start, end}};
137 const TagValue& value
139 validate_tags(Tag{key, value});
140 add_filter([key, value](
const auto& k) {
141 return k.tags().contains(key) && k.tags().at(key) == value;
157 template <
typename... Tags>
160 validate_tags(tags...);
161 add_filter([tags...](
const auto& k) {
162 return ((k.tags().contains(tags.first) &&
163 k.tags().at(tags.first) == tags.second) || ...);
179 template <
typename... Tags>
182 validate_tags(tags...);
183 add_filter([tags...](
const auto& k) {
184 return ((k.tags().contains(tags.first) &&
185 k.tags().at(tags.first) == tags.second) && ...);
201 add_filter([metric](
const auto& k) {
202 return k.metric() == metric;
218 template <
typename... Metrics>
221 add_filter([metrics...](
const auto& k) {
222 return ((k.metric() == metrics) || ...);
238 add_filter([timestamp](
const auto& k) {
239 return k.timestamp() == timestamp;
255 template <
typename... Timestamps>
258 const Timestamps&... timestamps
260 add_filter([timestamps...](
const auto& k) {
261 return ((k.timestamp() == timestamps) || ...);
277 validate_tags(key.
tags());
278 set_query_type(QueryType::PUT);
279 query_params_ = QueryParams{PutParams{key, value}};
293 validate_tags(key.
tags());
294 set_query_type(QueryType::REMOVE);
295 query_params_ = QueryParams{RemoveParams{key}};
310 return std::ranges::distance(get_filtered_range());
323 [[nodiscard]] TValue
sum() {
325 auto range{get_nonempty_filtered_range()};
326 return std::accumulate(
range.begin(),
range.end(), TValue{},
327 [](
const TValue& acc,
const valuetype& entry) {
328 return acc + entry.second.value();
342 [[nodiscard]]
double avg() {
344 auto range{get_nonempty_filtered_range()};
345 auto sum{std::accumulate(
range.begin(),
range.end(), TValue{},
346 [](
const auto& acc,
const auto& entry) {
347 return acc + entry.second.value();
349 return static_cast<double>(
sum) / std::ranges::distance(
range);
362 [[nodiscard]] TValue
min() {
364 auto range{get_nonempty_filtered_range()};
365 return std::ranges::min_element(
range, {}, [](
const auto& entry) {
366 return entry.second.value();
380 [[nodiscard]] TValue
max() {
382 auto range{get_nonempty_filtered_range()};
383 return std::ranges::max_element(
range, {}, [](
const auto& entry) {
384 return entry.second.value();
399 switch (query_type_) {
400 case QueryType::NONE:
401 if (filters_.size() == 1) {
402 throw std::runtime_error{
403 "QueryBuilder::execute(): No query type specified."
406 set_default_range_if_none();
407 return get_filtered_range();
408 case QueryType::POINT:
409 return execute_point_query();
410 case QueryType::RANGE:
411 return execute_range_query();
413 return execute_put_query();
414 case QueryType::REMOVE:
415 return execute_remove_query();
417 throw std::runtime_error{
418 "QueryBuilder::execute(): Invalid query type."
427 enum class QueryType { NONE, POINT, RANGE, PUT, REMOVE };
481 struct RemoveParams {
494 using QueryParams = std::variant<
509 void set_query_type(QueryType query_type) {
510 if (query_type_ != QueryType::NONE) {
511 throw std::runtime_error{
512 "QueryBuilder::set_query_type(): Query type already set."
515 query_type_ = query_type;
524 void set_default_range_if_none() noexcept {
525 if (query_type_ == QueryType::NONE) {
526 query_params_ = QueryParams{RangeParams{
530 query_type_ = QueryType::RANGE;
541 void check_if_aggregable()
const {
542 if (query_type_ != QueryType::RANGE && query_type_ != QueryType::POINT) {
543 throw std::runtime_error{
544 "QueryBuilder::check_if_aggregable(): Query type must be aggregable."
556 void setup_aggregate() {
557 set_default_range_if_none();
558 check_if_aggregable();
566 void add_filter(TimeSeriesKeyFilter&& filter) {
567 filters_.push_back(std::move(filter));
576 [[nodiscard]] result_type get_filtered_range()
const {
577 if (query_type_ == QueryType::POINT) {
578 return execute_point_query();
580 const auto& params{std::get<RangeParams>(query_params_)};
581 return lsm_tree_.getRange(params.start, params.end,
582 [
this](
const auto& k) {
583 return std::ranges::all_of(filters_, [&k](const auto& filter) {
597 [[nodiscard]] result_type get_nonempty_filtered_range()
const {
598 auto filtered_range{get_filtered_range()};
599 if (filtered_range.empty()) {
600 throw std::runtime_error{
601 "QueryBuilder::get_nonempty_filtered_range(): "
602 "Cannot aggregate on empty range."
605 return filtered_range;
615 [[nodiscard]] result_type execute_point_query()
const {
616 const auto& params{std::get<PointParams>(query_params_)};
617 auto value{lsm_tree_.get(params.key)};
618 if (!value.has_value()) {
621 return {{params.key, value}};
631 [[nodiscard]] result_type execute_range_query()
const {
632 auto range{get_filtered_range()};
633 return {range.begin(), range.end()};
643 [[nodiscard]] result_type execute_put_query() {
644 const auto& params{std::get<PutParams>(query_params_)};
645 lsm_tree_.put(params.key, params.value);
656 [[nodiscard]] result_type execute_remove_query() {
657 const auto& params{std::get<RemoveParams>(query_params_)};
658 lsm_tree_.remove(params.key);
670 void validate_tags(
const TagTable& tag_table)
const {
671 for (
const auto& [key, value] : tag_table) {
672 if (!tag_columns_.contains(key)) {
673 throw std::runtime_error{
674 "QueryBuilder::validate_tags(): Tag '"
675 + key +
"' not in tag columns."
690 template <
typename... Tags>
692 void validate_tags(
const Tags&... tags)
const {
693 for (
const auto& [key, value] : std::initializer_list<Tag>{tags...}) {
694 if (!tag_columns_.contains(key)) {
695 throw std::runtime_error{
696 "QueryBuilder::validate_tags(): Tag '"
697 + key +
"' not in tag columns."
707 LSMTree<TValue>& lsm_tree_;
713 const TagColumns& tag_columns_;
719 QueryType query_type_;
725 QueryParams query_params_;
731 std::vector<TimeSeriesKeyFilter> filters_;