aboutsummaryrefslogtreecommitdiff
path: root/icing/query/advanced_query_parser/pending-value.h
blob: 34912f3b195e64fc1f074f228b328bb58bdb2ea0 (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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// Copyright (C) 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ICING_QUERY_ADVANCED_QUERY_PARSER_PENDING_VALUE_H_
#define ICING_QUERY_ADVANCED_QUERY_PARSER_PENDING_VALUE_H_

#include <cstdint>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "icing/text_classifier/lib3/utils/base/status.h"
#include "icing/text_classifier/lib3/utils/base/statusor.h"
#include "icing/absl_ports/canonical_errors.h"
#include "icing/absl_ports/str_cat.h"
#include "icing/index/iterator/doc-hit-info-iterator.h"
#include "icing/util/status-macros.h"

namespace icing {
namespace lib {

enum class DataType {
  kNone,
  kLong,
  kDouble,
  kText,
  kString,
  kStringList,
  kDocumentIterator,
  // TODO(b/326656531): Instead of creating a vector index type, consider
  // changing it to vector type so that the data is the vector directly.
  kVectorIndex,
};

struct QueryTerm {
  std::string term;
  std::string_view raw_term;
  bool is_prefix_val;
};

// A holder for intermediate results when processing child nodes.
struct PendingValue {
  static PendingValue CreateStringPendingValue(QueryTerm str) {
    return PendingValue(std::move(str), DataType::kString);
  }

  static PendingValue CreateTextPendingValue(QueryTerm text) {
    return PendingValue(std::move(text), DataType::kText);
  }

  static PendingValue CreateVectorIndexPendingValue(int64_t vector_index) {
    return PendingValue(vector_index, DataType::kVectorIndex);
  }

  PendingValue() : data_type_(DataType::kNone) {}

  explicit PendingValue(std::unique_ptr<DocHitInfoIterator> iterator)
      : iterator_(std::move(iterator)),
        data_type_(DataType::kDocumentIterator) {}

  explicit PendingValue(std::vector<std::string> string_lists)
      : string_vals_(std::move(string_lists)),
        data_type_(DataType::kStringList) {}

  PendingValue(const PendingValue&) = delete;
  PendingValue(PendingValue&&) = default;

  PendingValue& operator=(const PendingValue&) = delete;
  PendingValue& operator=(PendingValue&&) = default;

  // Placeholder is used to indicate where the children of a particular node
  // begin.
  bool is_placeholder() const { return data_type_ == DataType::kNone; }

  libtextclassifier3::StatusOr<std::unique_ptr<DocHitInfoIterator>>
  iterator() && {
    ICING_RETURN_IF_ERROR(CheckDataType(DataType::kDocumentIterator));
    return std::move(iterator_);
  }

  libtextclassifier3::StatusOr<const std::vector<std::string>*> string_vals()
      const& {
    ICING_RETURN_IF_ERROR(CheckDataType(DataType::kStringList));
    return &string_vals_;
  }
  libtextclassifier3::StatusOr<std::vector<std::string>> string_vals() && {
    ICING_RETURN_IF_ERROR(CheckDataType(DataType::kStringList));
    return std::move(string_vals_);
  }

  libtextclassifier3::StatusOr<const QueryTerm*> string_val() const& {
    ICING_RETURN_IF_ERROR(CheckDataType(DataType::kString));
    return &query_term_;
  }
  libtextclassifier3::StatusOr<QueryTerm> string_val() && {
    ICING_RETURN_IF_ERROR(CheckDataType(DataType::kString));
    return std::move(query_term_);
  }

  libtextclassifier3::StatusOr<const QueryTerm*> text_val() const& {
    ICING_RETURN_IF_ERROR(CheckDataType(DataType::kText));
    return &query_term_;
  }
  libtextclassifier3::StatusOr<QueryTerm> text_val() && {
    ICING_RETURN_IF_ERROR(CheckDataType(DataType::kText));
    return std::move(query_term_);
  }

  libtextclassifier3::StatusOr<int64_t> long_val() {
    ICING_RETURN_IF_ERROR(ParseInt());
    return long_val_;
  }

  libtextclassifier3::StatusOr<double> double_val() {
    ICING_RETURN_IF_ERROR(ParseDouble());
    return double_val_;
  }

  libtextclassifier3::StatusOr<int64_t> vector_index_val() const {
    ICING_RETURN_IF_ERROR(CheckDataType(DataType::kVectorIndex));
    return long_val_;
  }

  // Attempts to interpret the value as an int. A pending value can be parsed as
  // an int under two circumstances:
  //   1. It holds a kText value which can be parsed to an int
  //   2. It holds a kLong value
  // If #1 is true, then the parsed value will be stored in long_value and
  // data_type will be updated to kLong.
  // RETURNS:
  //   - OK, if able to successfully parse the value into a long
  //   - INVALID_ARGUMENT if the value could not be parsed as a long
  libtextclassifier3::Status ParseInt();

  // Attempts to interpret the value as a double. A pending value can be parsed
  // as a double under two circumstances:
  //   1. It holds a kText value which can be parsed to a double
  //   2. It holds a kDouble value
  // If #1 is true, then the parsed value will be stored in double_val_ and
  // data_type will be updated to kDouble.
  // RETURNS:
  //   - OK, if able to successfully parse the value into a double
  //   - INVALID_ARGUMENT if the value could not be parsed as a double
  libtextclassifier3::Status ParseDouble();

  DataType data_type() const { return data_type_; }

 private:
  explicit PendingValue(QueryTerm query_term, DataType data_type)
      : query_term_(std::move(query_term)), data_type_(data_type) {}

  explicit PendingValue(int64_t long_val, DataType data_type)
      : long_val_(long_val), data_type_(data_type) {}

  libtextclassifier3::Status CheckDataType(DataType required_data_type) const {
    if (data_type_ == required_data_type) {
      return libtextclassifier3::Status::OK;
    }
    return absl_ports::InvalidArgumentError(
        absl_ports::StrCat("Unable to retrieve value of type '",
                           std::to_string(static_cast<int>(required_data_type)),
                           "' from pending value of type '",
                           std::to_string(static_cast<int>(data_type_)), "'"));
  }

  // iterator_ will be populated when data_type_ is kDocumentIterator.
  std::unique_ptr<DocHitInfoIterator> iterator_;

  // string_vals_ will be populated when data_type_ kStringList.
  std::vector<std::string> string_vals_;

  // query_term_ will be populated when data_type_ is kString or kText
  QueryTerm query_term_;

  // long_val_ will be populated when data_type_ is kLong - after a successful
  // call to ParseInt.
  int64_t long_val_;
  // double_val_ will be populated when data_type_ is kDouble - after a
  // successful call to ParseDouble.
  double double_val_;
  DataType data_type_;
};

}  // namespace lib
}  // namespace icing

#endif  // ICING_QUERY_ADVANCED_QUERY_PARSER_PENDING_VALUE_H_