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 <memory> 18 #include <string> 19 #include <utility> 20 #include <vector> 21 22 #include "icing/text_classifier/lib3/utils/base/status.h" 23 #include "icing/absl_ports/str_cat.h" 24 #include "icing/index/iterator/doc-hit-info-iterator.h" 25 #include "icing/util/status-macros.h" 26 27 namespace icing { 28 namespace lib { 29 30 enum class DataType { 31 kNone, 32 kLong, 33 kText, 34 kString, 35 kStringList, 36 kDocumentIterator, 37 }; 38 39 struct QueryTerm { 40 std::string term; 41 std::string_view raw_term; 42 bool is_prefix_val; 43 }; 44 45 // A holder for intermediate results when processing child nodes. 46 struct PendingValue { CreateStringPendingValuePendingValue47 static PendingValue CreateStringPendingValue(QueryTerm str) { 48 return PendingValue(std::move(str), DataType::kString); 49 } 50 CreateTextPendingValuePendingValue51 static PendingValue CreateTextPendingValue(QueryTerm text) { 52 return PendingValue(std::move(text), DataType::kText); 53 } 54 PendingValuePendingValue55 PendingValue() : data_type_(DataType::kNone) {} 56 PendingValuePendingValue57 explicit PendingValue(std::unique_ptr<DocHitInfoIterator> iterator) 58 : iterator_(std::move(iterator)), 59 data_type_(DataType::kDocumentIterator) {} 60 PendingValuePendingValue61 explicit PendingValue(std::vector<std::string> string_lists) 62 : string_vals_(std::move(string_lists)), 63 data_type_(DataType::kStringList) {} 64 65 PendingValue(const PendingValue&) = delete; 66 PendingValue(PendingValue&&) = default; 67 68 PendingValue& operator=(const PendingValue&) = delete; 69 PendingValue& operator=(PendingValue&&) = default; 70 71 // Placeholder is used to indicate where the children of a particular node 72 // begin. is_placeholderPendingValue73 bool is_placeholder() const { return data_type_ == DataType::kNone; } 74 75 libtextclassifier3::StatusOr<std::unique_ptr<DocHitInfoIterator>> iteratorPendingValue76 iterator() && { 77 ICING_RETURN_IF_ERROR(CheckDataType(DataType::kDocumentIterator)); 78 return std::move(iterator_); 79 } 80 string_valsPendingValue81 libtextclassifier3::StatusOr<const std::vector<std::string>*> string_vals() 82 const& { 83 ICING_RETURN_IF_ERROR(CheckDataType(DataType::kStringList)); 84 return &string_vals_; 85 } string_valsPendingValue86 libtextclassifier3::StatusOr<std::vector<std::string>> string_vals() && { 87 ICING_RETURN_IF_ERROR(CheckDataType(DataType::kStringList)); 88 return std::move(string_vals_); 89 } 90 string_valPendingValue91 libtextclassifier3::StatusOr<const QueryTerm*> string_val() const& { 92 ICING_RETURN_IF_ERROR(CheckDataType(DataType::kString)); 93 return &query_term_; 94 } string_valPendingValue95 libtextclassifier3::StatusOr<QueryTerm> string_val() && { 96 ICING_RETURN_IF_ERROR(CheckDataType(DataType::kString)); 97 return std::move(query_term_); 98 } 99 text_valPendingValue100 libtextclassifier3::StatusOr<const QueryTerm*> text_val() const& { 101 ICING_RETURN_IF_ERROR(CheckDataType(DataType::kText)); 102 return &query_term_; 103 } text_valPendingValue104 libtextclassifier3::StatusOr<QueryTerm> text_val() && { 105 ICING_RETURN_IF_ERROR(CheckDataType(DataType::kText)); 106 return std::move(query_term_); 107 } 108 long_valPendingValue109 libtextclassifier3::StatusOr<int64_t> long_val() { 110 ICING_RETURN_IF_ERROR(ParseInt()); 111 return long_val_; 112 } 113 114 // Attempts to interpret the value as an int. A pending value can be parsed as 115 // an int under two circumstances: 116 // 1. It holds a kText value which can be parsed to an int 117 // 2. It holds a kLong value 118 // If #1 is true, then the parsed value will be stored in long_value and 119 // data_type will be updated to kLong. 120 // RETURNS: 121 // - OK, if able to successfully parse the value into a long 122 // - INVALID_ARGUMENT if the value could not be parsed as a long 123 libtextclassifier3::Status ParseInt(); 124 data_typePendingValue125 DataType data_type() const { return data_type_; } 126 127 private: PendingValuePendingValue128 explicit PendingValue(QueryTerm query_term, DataType data_type) 129 : query_term_(std::move(query_term)), data_type_(data_type) {} 130 CheckDataTypePendingValue131 libtextclassifier3::Status CheckDataType(DataType required_data_type) const { 132 if (data_type_ == required_data_type) { 133 return libtextclassifier3::Status::OK; 134 } 135 return absl_ports::InvalidArgumentError( 136 absl_ports::StrCat("Unable to retrieve value of type '", 137 std::to_string(static_cast<int>(required_data_type)), 138 "' from pending value of type '", 139 std::to_string(static_cast<int>(data_type_)), "'")); 140 } 141 142 // iterator_ will be populated when data_type_ is kDocumentIterator. 143 std::unique_ptr<DocHitInfoIterator> iterator_; 144 145 // string_vals_ will be populated when data_type_ kStringList. 146 std::vector<std::string> string_vals_; 147 148 // query_term_ will be populated when data_type_ is kString or kText 149 QueryTerm query_term_; 150 151 // long_val_ will be populated when data_type_ is kLong - after a successful 152 // call to ParseInt. 153 int64_t long_val_; 154 DataType data_type_; 155 }; 156 157 } // namespace lib 158 } // namespace icing 159 160 #endif // ICING_QUERY_ADVANCED_QUERY_PARSER_PENDING_VALUE_H_ 161