xref: /aosp_15_r20/external/icing/icing/schema/joinable-property-manager.h (revision 8b6cd535a057e39b3b86660c4aa06c99747c2136)
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