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 15 #ifndef ICING_SCHEMA_JOINABLE_PROPERTY_MANAGER_H_ 16 #define ICING_SCHEMA_JOINABLE_PROPERTY_MANAGER_H_ 17 18 #include <memory> 19 #include <string> 20 #include <unordered_map> 21 #include <vector> 22 23 #include "icing/text_classifier/lib3/utils/base/status.h" 24 #include "icing/text_classifier/lib3/utils/base/statusor.h" 25 #include "icing/proto/document.pb.h" 26 #include "icing/schema/joinable-property.h" 27 #include "icing/store/document-filter-data.h" 28 #include "icing/store/key-mapper.h" 29 30 namespace icing { 31 namespace lib { 32 33 // This class provides joinable-property-related operations. It assigns joinable 34 // properties according to JoinableConfig and extracts joinable property values 35 // from documents. 36 class JoinablePropertyManager { 37 public: 38 // A wrapper class that contains a vector of metadatas and property path to 39 // JoinablePropertyId reverse lookup map. 40 struct JoinablePropertyMetadataListWrapper { 41 std::vector<JoinablePropertyMetadata> metadata_list; 42 std::unordered_map<std::string, JoinablePropertyId> property_path_to_id_map; 43 }; 44 45 // Builder class to create a JoinablePropertyManager which does not take 46 // ownership of any input components, and all pointers must refer to valid 47 // objects that outlive the created JoinablePropertyManager instance. 48 class Builder { 49 public: Builder(const KeyMapper<SchemaTypeId> & schema_type_mapper)50 explicit Builder(const KeyMapper<SchemaTypeId>& schema_type_mapper) 51 : schema_type_mapper_(schema_type_mapper), 52 joinable_property_metadata_cache_(schema_type_mapper.num_keys()) {} 53 54 // Checks and appends a new JoinablePropertyMetadata for the schema type id 55 // if the given property config is joinable. 56 // 57 // Returns: 58 // - OK on success 59 // - INVALID_ARGUMENT_ERROR if schema type id is invalid (not in range [0, 60 // schema_type_mapper_.num_keys() - 1]) 61 // - OUT_OF_RANGE_ERROR if # of joinable properties in a single Schema 62 // exceeds the threshold (kTotalNumJoinableProperties) 63 libtextclassifier3::Status ProcessSchemaTypePropertyConfig( 64 SchemaTypeId schema_type_id, const PropertyConfigProto& property_config, 65 std::string&& property_path); 66 67 // Builds and returns a JoinablePropertyManager instance. Build()68 std::unique_ptr<JoinablePropertyManager> Build() && { 69 return std::unique_ptr<JoinablePropertyManager>( 70 new JoinablePropertyManager( 71 schema_type_mapper_, 72 std::move(joinable_property_metadata_cache_))); 73 } 74 75 private: 76 const KeyMapper<SchemaTypeId>& schema_type_mapper_; // Does not own. 77 std::vector<JoinablePropertyMetadataListWrapper> 78 joinable_property_metadata_cache_; 79 }; 80 81 JoinablePropertyManager(const JoinablePropertyManager&) = delete; 82 JoinablePropertyManager& operator=(const JoinablePropertyManager&) = delete; 83 84 // Extracts all joinable property contents of different types from the given 85 // document and group them by joinable value type. 86 // - Joinable properties are sorted by joinable property id in ascending 87 // order. 88 // - Joinable property ids start from 0. 89 // - Joinable properties with empty content won't be returned. 90 // 91 // Returns: 92 // - A JoinablePropertyGroup instance on success 93 // - NOT_FOUND_ERROR if the type config name of document is not present in 94 // schema_type_mapper_ 95 libtextclassifier3::StatusOr<JoinablePropertyGroup> ExtractJoinableProperties( 96 const DocumentProto& document) const; 97 98 // Returns the JoinablePropertyMetadata associated with property_path that's 99 // in the SchemaTypeId. 100 // 101 // Returns: 102 // - Valid pointer to JoinablePropertyMetadata on success 103 // - nullptr if property_path doesn't exist (or is not joinable) in the 104 // joinable metadata list of the schema 105 // - INVALID_ARGUMENT_ERROR if schema type id is invalid 106 libtextclassifier3::StatusOr<const JoinablePropertyMetadata*> 107 GetJoinablePropertyMetadata(SchemaTypeId schema_type_id, 108 const std::string& property_path) const; 109 110 // Returns the JoinablePropertyMetadata associated with the JoinablePropertyId 111 // that's in the SchemaTypeId. 112 // 113 // Returns: 114 // - Valid pointer to JoinablePropertyMetadata on success 115 // - INVALID_ARGUMENT_ERROR if schema type id or JoinablePropertyId is 116 // invalid 117 libtextclassifier3::StatusOr<const JoinablePropertyMetadata*> 118 GetJoinablePropertyMetadata(SchemaTypeId schema_type_id, 119 JoinablePropertyId joinable_property_id) const; 120 121 // Returns: 122 // - On success, the joinable property metadatas for the specified type 123 // - NOT_FOUND_ERROR if the type config name is not present in 124 // schema_type_mapper_ 125 libtextclassifier3::StatusOr<const std::vector<JoinablePropertyMetadata>*> 126 GetMetadataList(const std::string& type_config_name) const; 127 128 private: JoinablePropertyManager(const KeyMapper<SchemaTypeId> & schema_type_mapper,std::vector<JoinablePropertyMetadataListWrapper> && joinable_property_metadata_cache)129 explicit JoinablePropertyManager( 130 const KeyMapper<SchemaTypeId>& schema_type_mapper, 131 std::vector<JoinablePropertyMetadataListWrapper>&& 132 joinable_property_metadata_cache) 133 : schema_type_mapper_(schema_type_mapper), 134 joinable_property_metadata_cache_(joinable_property_metadata_cache) {} 135 136 // Maps schema types to a densely-assigned unique id. 137 const KeyMapper<SchemaTypeId>& schema_type_mapper_; // Does not own 138 139 // The index of joinable_property_metadata_cache_ corresponds to a schema 140 // type's SchemaTypeId. At that SchemaTypeId index, we store a 141 // JoinablePropertyMetadataListWrapper instance. The metadata list's index 142 // corresponds to a joinable property's JoinablePropertyId. At the 143 // JoinablePropertyId index, we store the JoinablePropertyMetadata of that 144 // joinable property. 145 // 146 // For example, suppose "email" has a SchemaTypeId of 0 and it has a joinable 147 // property called "senderQualifiedId" with a JoinablePropertyId of 1. Then 148 // the "senderQualifiedId" property's JoinablePropertyMetadata will be at 149 // joinable_property_metadata_cache_[0].metadata_list[1], and 150 // joinable_property_metadata_cache_[0] 151 // .property_path_to_id_map["senderQualifiedId"] 152 // will be 1. 153 const std::vector<JoinablePropertyMetadataListWrapper> 154 joinable_property_metadata_cache_; 155 }; 156 157 } // namespace lib 158 } // namespace icing 159 160 #endif // ICING_SCHEMA_JOINABLE_PROPERTY_MANAGER_H_ 161