1 // Copyright (C) 2023 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 #ifndef ICING_QUERY_ADVANCED_QUERY_PARSER_PENDING_VALUE_H_ 15 #define ICING_QUERY_ADVANCED_QUERY_PARSER_PENDING_VALUE_H_ 16 17 #include <cstdint> 18 #include <memory> 19 #include <string> 20 #include <string_view> 21 #include <utility> 22 #include <vector> 23 24 #include "icing/text_classifier/lib3/utils/base/status.h" 25 #include "icing/text_classifier/lib3/utils/base/statusor.h" 26 #include "icing/absl_ports/canonical_errors.h" 27 #include "icing/absl_ports/str_cat.h" 28 #include "icing/index/iterator/doc-hit-info-iterator.h" 29 #include "icing/util/status-macros.h" 30 31 namespace icing { 32 namespace lib { 33 34 enum class DataType { 35 kNone, 36 kLong, 37 kDouble, 38 kText, 39 kString, 40 kStringList, 41 kDocumentIterator, 42 // TODO(b/326656531): Instead of creating a vector index type, consider 43 // changing it to vector type so that the data is the vector directly. 44 kVectorIndex, 45 }; 46 47 struct QueryTerm { 48 std::string term; 49 std::string_view raw_term; 50 bool is_prefix_val; 51 }; 52 53 // A holder for intermediate results when processing child nodes. 54 struct PendingValue { CreateStringPendingValuePendingValue55 static PendingValue CreateStringPendingValue(QueryTerm str) { 56 return PendingValue(std::move(str), DataType::kString); 57 } 58 CreateTextPendingValuePendingValue59 static PendingValue CreateTextPendingValue(QueryTerm text) { 60 return PendingValue(std::move(text), DataType::kText); 61 } 62 CreateVectorIndexPendingValuePendingValue63 static PendingValue CreateVectorIndexPendingValue(int64_t vector_index) { 64 return PendingValue(vector_index, DataType::kVectorIndex); 65 } 66 PendingValuePendingValue67 PendingValue() : data_type_(DataType::kNone) {} 68 PendingValuePendingValue69 explicit PendingValue(std::unique_ptr<DocHitInfoIterator> iterator) 70 : iterator_(std::move(iterator)), 71 data_type_(DataType::kDocumentIterator) {} 72 PendingValuePendingValue73 explicit PendingValue(std::vector<std::string> string_lists) 74 : string_vals_(std::move(string_lists)), 75 data_type_(DataType::kStringList) {} 76 77 PendingValue(const PendingValue&) = delete; 78 PendingValue(PendingValue&&) = default; 79 80 PendingValue& operator=(const PendingValue&) = delete; 81 PendingValue& operator=(PendingValue&&) = default; 82 83 // Placeholder is used to indicate where the children of a particular node 84 // begin. is_placeholderPendingValue85 bool is_placeholder() const { return data_type_ == DataType::kNone; } 86 87 libtextclassifier3::StatusOr<std::unique_ptr<DocHitInfoIterator>> iteratorPendingValue88 iterator() && { 89 ICING_RETURN_IF_ERROR(CheckDataType(DataType::kDocumentIterator)); 90 return std::move(iterator_); 91 } 92 string_valsPendingValue93 libtextclassifier3::StatusOr<const std::vector<std::string>*> string_vals() 94 const& { 95 ICING_RETURN_IF_ERROR(CheckDataType(DataType::kStringList)); 96 return &string_vals_; 97 } string_valsPendingValue98 libtextclassifier3::StatusOr<std::vector<std::string>> string_vals() && { 99 ICING_RETURN_IF_ERROR(CheckDataType(DataType::kStringList)); 100 return std::move(string_vals_); 101 } 102 string_valPendingValue103 libtextclassifier3::StatusOr<const QueryTerm*> string_val() const& { 104 ICING_RETURN_IF_ERROR(CheckDataType(DataType::kString)); 105 return &query_term_; 106 } string_valPendingValue107 libtextclassifier3::StatusOr<QueryTerm> string_val() && { 108 ICING_RETURN_IF_ERROR(CheckDataType(DataType::kString)); 109 return std::move(query_term_); 110 } 111 text_valPendingValue112 libtextclassifier3::StatusOr<const QueryTerm*> text_val() const& { 113 ICING_RETURN_IF_ERROR(CheckDataType(DataType::kText)); 114 return &query_term_; 115 } text_valPendingValue116 libtextclassifier3::StatusOr<QueryTerm> text_val() && { 117 ICING_RETURN_IF_ERROR(CheckDataType(DataType::kText)); 118 return std::move(query_term_); 119 } 120 long_valPendingValue121 libtextclassifier3::StatusOr<int64_t> long_val() { 122 ICING_RETURN_IF_ERROR(ParseInt()); 123 return long_val_; 124 } 125 double_valPendingValue126 libtextclassifier3::StatusOr<double> double_val() { 127 ICING_RETURN_IF_ERROR(ParseDouble()); 128 return double_val_; 129 } 130 vector_index_valPendingValue131 libtextclassifier3::StatusOr<int64_t> vector_index_val() const { 132 ICING_RETURN_IF_ERROR(CheckDataType(DataType::kVectorIndex)); 133 return long_val_; 134 } 135 136 // Attempts to interpret the value as an int. A pending value can be parsed as 137 // an int under two circumstances: 138 // 1. It holds a kText value which can be parsed to an int 139 // 2. It holds a kLong value 140 // If #1 is true, then the parsed value will be stored in long_value and 141 // data_type will be updated to kLong. 142 // RETURNS: 143 // - OK, if able to successfully parse the value into a long 144 // - INVALID_ARGUMENT if the value could not be parsed as a long 145 libtextclassifier3::Status ParseInt(); 146 147 // Attempts to interpret the value as a double. A pending value can be parsed 148 // as a double under two circumstances: 149 // 1. It holds a kText value which can be parsed to a double 150 // 2. It holds a kDouble value 151 // If #1 is true, then the parsed value will be stored in double_val_ and 152 // data_type will be updated to kDouble. 153 // RETURNS: 154 // - OK, if able to successfully parse the value into a double 155 // - INVALID_ARGUMENT if the value could not be parsed as a double 156 libtextclassifier3::Status ParseDouble(); 157 data_typePendingValue158 DataType data_type() const { return data_type_; } 159 160 private: PendingValuePendingValue161 explicit PendingValue(QueryTerm query_term, DataType data_type) 162 : query_term_(std::move(query_term)), data_type_(data_type) {} 163 PendingValuePendingValue164 explicit PendingValue(int64_t long_val, DataType data_type) 165 : long_val_(long_val), data_type_(data_type) {} 166 CheckDataTypePendingValue167 libtextclassifier3::Status CheckDataType(DataType required_data_type) const { 168 if (data_type_ == required_data_type) { 169 return libtextclassifier3::Status::OK; 170 } 171 return absl_ports::InvalidArgumentError( 172 absl_ports::StrCat("Unable to retrieve value of type '", 173 std::to_string(static_cast<int>(required_data_type)), 174 "' from pending value of type '", 175 std::to_string(static_cast<int>(data_type_)), "'")); 176 } 177 178 // iterator_ will be populated when data_type_ is kDocumentIterator. 179 std::unique_ptr<DocHitInfoIterator> iterator_; 180 181 // string_vals_ will be populated when data_type_ kStringList. 182 std::vector<std::string> string_vals_; 183 184 // query_term_ will be populated when data_type_ is kString or kText 185 QueryTerm query_term_; 186 187 // long_val_ will be populated when data_type_ is kLong - after a successful 188 // call to ParseInt. 189 int64_t long_val_; 190 // double_val_ will be populated when data_type_ is kDouble - after a 191 // successful call to ParseDouble. 192 double double_val_; 193 DataType data_type_; 194 }; 195 196 } // namespace lib 197 } // namespace icing 198 199 #endif // ICING_QUERY_ADVANCED_QUERY_PARSER_PENDING_VALUE_H_ 200