Loading apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java +94 −1 Original line number Original line Diff line number Diff line /* /* * Copyright (C) 2019 The Android Open Source Project * Copyright (C) 2020 The Android Open Source Project * * * Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License. Loading @@ -25,9 +25,12 @@ import android.os.RemoteException; import com.android.internal.infra.AndroidFuture; import com.android.internal.infra.AndroidFuture; import com.google.android.icing.proto.SchemaProto; import com.google.android.icing.proto.SchemaProto; import com.google.android.icing.proto.SearchResultProto; import com.google.android.icing.protobuf.InvalidProtocolBufferException; import java.util.List; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executor; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Consumer; /** /** Loading Loading @@ -127,4 +130,94 @@ public class AppSearchManager { // TODO(b/147614371) Fix error report for multiple documents. // TODO(b/147614371) Fix error report for multiple documents. future.whenCompleteAsync((noop, err) -> callback.accept(err), executor); future.whenCompleteAsync((noop, err) -> callback.accept(err), executor); } } /** * This method searches for documents based on a given query string. It also accepts * specifications regarding how to search and format the results. * *<p>Currently we support following features in the raw query format: * <ul> * <li>AND * AND joins (e.g. “match documents that have both the terms ‘dog’ and * ‘cat’”). * Example: hello world matches documents that have both ‘hello’ and ‘world’ * <li>OR * OR joins (e.g. “match documents that have either the term ‘dog’ or * ‘cat’”). * Example: dog OR puppy * <li>Exclusion * Exclude a term (e.g. “match documents that do * not have the term ‘dog’”). * Example: -dog excludes the term ‘dog’ * <li>Grouping terms * Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g. * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”). * Example: (dog puppy) (cat kitten) two one group containing two terms. * <li>Property restricts * which properties of a document to specifically match terms in (e.g. * “match documents where the ‘subject’ property contains ‘important’”). * Example: subject:important matches documents with the term ‘important’ in the * ‘subject’ property * <li>Schema type restricts * This is similar to property restricts, but allows for restricts on top-level document * fields, such as schema_type. Clients should be able to limit their query to documents of * a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”). * Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents * that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the * ‘Video’ schema type. * </ul> * * <p> It is strongly recommended to use Jetpack APIs. * * @param queryExpression Query String to search. * @param searchSpec Spec for setting filters, raw query etc. * @param executor Executor on which to invoke the callback. * @param callback Callback to receive errors resulting from the query operation. If the * operation succeeds, the callback will be invoked with {@code null}. * @hide */ @NonNull public void query( @NonNull String queryExpression, @NonNull SearchSpec searchSpec, @NonNull @CallbackExecutor Executor executor, @NonNull BiConsumer<? super SearchResults, ? super Throwable> callback) { AndroidFuture<byte[]> future = new AndroidFuture<>(); future.whenCompleteAsync((searchResultBytes, err) -> { if (err != null) { callback.accept(null, err); return; } if (searchResultBytes != null) { SearchResultProto searchResultProto; try { searchResultProto = SearchResultProto.parseFrom(searchResultBytes); } catch (InvalidProtocolBufferException e) { callback.accept(null, e); return; } if (searchResultProto.hasError()) { // TODO(sidchhabra): Add better exception handling. callback.accept( null, new RuntimeException(searchResultProto.getError().getErrorMessage())); return; } SearchResults searchResults = new SearchResults(searchResultProto); callback.accept(searchResults, null); return; } // Nothing was supplied in the future at all callback.accept( null, new IllegalStateException("Unknown failure occurred while querying")); }, executor); try { mService.query(queryExpression, searchSpec.getProto().toByteArray(), future); } catch (RemoteException e) { future.completeExceptionally(e); } } } } apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl +10 −1 Original line number Original line Diff line number Diff line /** /** * Copyright 2019, The Android Open Source Project * Copyright 2020, The Android Open Source Project * * * Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License. Loading Loading @@ -29,4 +29,13 @@ interface IAppSearchManager { */ */ void setSchema(in byte[] schemaProto, in AndroidFuture callback); void setSchema(in byte[] schemaProto, in AndroidFuture callback); void put(in byte[] documentBytes, in AndroidFuture callback); void put(in byte[] documentBytes, in AndroidFuture callback); /** * Searches a document based on a given query string. * * @param queryExpression Query String to search. * @param searchSpec Serialized SearchSpecProto. * @param callback {@link AndroidFuture}. Will be completed with a serialized * {@link SearchResultsProto}, or completed exceptionally if query fails. */ void query(in String queryExpression, in byte[] searchSpecBytes, in AndroidFuture callback); } } apex/appsearch/framework/java/android/app/appsearch/IllegalSearchSpecException.java 0 → 100644 +36 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * 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. */ package android.app.appsearch; import android.annotation.NonNull; /** * Indicates that a {@link android.app.appsearch.SearchResults} has logical inconsistencies such * as unpopulated mandatory fields or illegal combinations of parameters. * * @hide */ public class IllegalSearchSpecException extends IllegalArgumentException { /** * Constructs a new {@link IllegalSearchSpecException}. * * @param message A developer-readable description of the issue with the bundle. */ public IllegalSearchSpecException(@NonNull String message) { super(message); } } apex/appsearch/framework/java/android/app/appsearch/SearchResults.java 0 → 100644 +89 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * 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. */ package android.app.appsearch; import android.annotation.NonNull; import com.google.android.icing.proto.SearchResultProto; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * SearchResults are a list of results that are returned from a query. Each result from this * list contains a document and may contain other fields like snippets based on request. * @hide */ public final class SearchResults { private final SearchResultProto mSearchResultProto; /** @hide */ public SearchResults(SearchResultProto searchResultProto) { mSearchResultProto = searchResultProto; } /** * This class represents the result obtained from the query. It will contain the document which * which matched the specified query string and specifications. * @hide */ public static final class Result { private final SearchResultProto.ResultProto mResultProto; private Result(SearchResultProto.ResultProto resultProto) { mResultProto = resultProto; } /** * Contains the matching {@link AppSearch.Document}. * @return Document object which matched the query. * @hide */ // TODO(sidchhabra): Switch to Document constructor that takes proto. @NonNull public AppSearch.Document getDocument() { return AppSearch.Document.newBuilder(mResultProto.getDocument().getUri(), mResultProto.getDocument().getSchema()) .setCreationTimestampSecs(mResultProto.getDocument().getCreationTimestampSecs()) .setScore(mResultProto.getDocument().getScore()) .build(); } // TODO(sidchhabra): Add Getter for ResultReader for Snippet. } @Override public String toString() { return mSearchResultProto.toString(); } /** * Returns a {@link Result} iterator. Returns Empty Iterator if there are no matching results. * @hide */ @NonNull public Iterator<Result> getResults() { List<Result> results = new ArrayList<>(); // TODO(sidchhabra): Pass results using a RemoteStream. for (SearchResultProto.ResultProto resultProto : mSearchResultProto.getResultsList()) { results.add(new Result(resultProto)); } return results.iterator(); } } apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java 0 → 100644 +127 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * 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. */ package android.app.appsearch; import android.annotation.IntDef; import android.annotation.NonNull; import com.google.android.icing.proto.SearchSpecProto; import com.google.android.icing.proto.TermMatchType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * This class represents the specification logic for AppSearch. It can be used to set the type of * search, like prefix or exact only or apply filters to search for a specific schema type only etc. * @hide * */ // TODO(sidchhabra) : AddResultSpec fields for Snippets etc. public final class SearchSpec { private final SearchSpecProto mSearchSpecProto; private SearchSpec(SearchSpecProto searchSpecProto) { mSearchSpecProto = searchSpecProto; } /** Creates a new {@link SearchSpec.Builder}. */ @NonNull public static SearchSpec.Builder newBuilder() { return new SearchSpec.Builder(); } /** @hide */ @NonNull SearchSpecProto getProto() { return mSearchSpecProto; } /** Term Match Type for the query. */ // NOTE: The integer values of these constants must match the proto enum constants in // {@link com.google.android.icing.proto.SearchSpecProto.termMatchType} @IntDef(prefix = {"TERM_MATCH_TYPE_"}, value = { TERM_MATCH_TYPE_EXACT_ONLY, TERM_MATCH_TYPE_PREFIX }) @Retention(RetentionPolicy.SOURCE) public @interface TermMatchTypeCode {} public static final int TERM_MATCH_TYPE_EXACT_ONLY = 1; public static final int TERM_MATCH_TYPE_PREFIX = 2; /** Builder for {@link SearchSpec objects}. */ public static final class Builder { private final SearchSpecProto.Builder mBuilder = SearchSpecProto.newBuilder(); private Builder(){} /** * Indicates how the query terms should match {@link TermMatchTypeCode} in the index. * * TermMatchType.Code=EXACT_ONLY * Query terms will only match exact tokens in the index. * Ex. A query term "foo" will only match indexed token "foo", and not "foot" * or "football" * * TermMatchType.Code=PREFIX * Query terms will match indexed tokens when the query term is a prefix of * the token. * Ex. A query term "foo" will match indexed tokens like "foo", "foot", and * "football". */ @NonNull public Builder setTermMatchType(@TermMatchTypeCode int termMatchTypeCode) { TermMatchType.Code termMatchTypeCodeProto = TermMatchType.Code.forNumber(termMatchTypeCode); if (termMatchTypeCodeProto == null) { throw new IllegalArgumentException("Invalid term match type: " + termMatchTypeCode); } mBuilder.setTermMatchType(termMatchTypeCodeProto); return this; } /** * Adds a Schema type filter to {@link SearchSpec} Entry. * Only search for documents that have the specified schema types. * If unset, the query will search over all schema types. */ @NonNull public Builder setSchemaTypes(@NonNull String... schemaTypes) { for (String schemaType : schemaTypes) { mBuilder.addSchemaTypeFilters(schemaType); } return this; } /** * Constructs a new {@link SearchSpec} from the contents of this builder. * * <p>After calling this method, the builder must no longer be used. */ @NonNull public SearchSpec build() { if (mBuilder.getTermMatchType() == TermMatchType.Code.UNKNOWN) { throw new IllegalSearchSpecException("Missing termMatchType field."); } return new SearchSpec(mBuilder.build()); } } } Loading
apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java +94 −1 Original line number Original line Diff line number Diff line /* /* * Copyright (C) 2019 The Android Open Source Project * Copyright (C) 2020 The Android Open Source Project * * * Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License. Loading @@ -25,9 +25,12 @@ import android.os.RemoteException; import com.android.internal.infra.AndroidFuture; import com.android.internal.infra.AndroidFuture; import com.google.android.icing.proto.SchemaProto; import com.google.android.icing.proto.SchemaProto; import com.google.android.icing.proto.SearchResultProto; import com.google.android.icing.protobuf.InvalidProtocolBufferException; import java.util.List; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executor; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Consumer; /** /** Loading Loading @@ -127,4 +130,94 @@ public class AppSearchManager { // TODO(b/147614371) Fix error report for multiple documents. // TODO(b/147614371) Fix error report for multiple documents. future.whenCompleteAsync((noop, err) -> callback.accept(err), executor); future.whenCompleteAsync((noop, err) -> callback.accept(err), executor); } } /** * This method searches for documents based on a given query string. It also accepts * specifications regarding how to search and format the results. * *<p>Currently we support following features in the raw query format: * <ul> * <li>AND * AND joins (e.g. “match documents that have both the terms ‘dog’ and * ‘cat’”). * Example: hello world matches documents that have both ‘hello’ and ‘world’ * <li>OR * OR joins (e.g. “match documents that have either the term ‘dog’ or * ‘cat’”). * Example: dog OR puppy * <li>Exclusion * Exclude a term (e.g. “match documents that do * not have the term ‘dog’”). * Example: -dog excludes the term ‘dog’ * <li>Grouping terms * Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g. * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”). * Example: (dog puppy) (cat kitten) two one group containing two terms. * <li>Property restricts * which properties of a document to specifically match terms in (e.g. * “match documents where the ‘subject’ property contains ‘important’”). * Example: subject:important matches documents with the term ‘important’ in the * ‘subject’ property * <li>Schema type restricts * This is similar to property restricts, but allows for restricts on top-level document * fields, such as schema_type. Clients should be able to limit their query to documents of * a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”). * Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents * that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the * ‘Video’ schema type. * </ul> * * <p> It is strongly recommended to use Jetpack APIs. * * @param queryExpression Query String to search. * @param searchSpec Spec for setting filters, raw query etc. * @param executor Executor on which to invoke the callback. * @param callback Callback to receive errors resulting from the query operation. If the * operation succeeds, the callback will be invoked with {@code null}. * @hide */ @NonNull public void query( @NonNull String queryExpression, @NonNull SearchSpec searchSpec, @NonNull @CallbackExecutor Executor executor, @NonNull BiConsumer<? super SearchResults, ? super Throwable> callback) { AndroidFuture<byte[]> future = new AndroidFuture<>(); future.whenCompleteAsync((searchResultBytes, err) -> { if (err != null) { callback.accept(null, err); return; } if (searchResultBytes != null) { SearchResultProto searchResultProto; try { searchResultProto = SearchResultProto.parseFrom(searchResultBytes); } catch (InvalidProtocolBufferException e) { callback.accept(null, e); return; } if (searchResultProto.hasError()) { // TODO(sidchhabra): Add better exception handling. callback.accept( null, new RuntimeException(searchResultProto.getError().getErrorMessage())); return; } SearchResults searchResults = new SearchResults(searchResultProto); callback.accept(searchResults, null); return; } // Nothing was supplied in the future at all callback.accept( null, new IllegalStateException("Unknown failure occurred while querying")); }, executor); try { mService.query(queryExpression, searchSpec.getProto().toByteArray(), future); } catch (RemoteException e) { future.completeExceptionally(e); } } } }
apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl +10 −1 Original line number Original line Diff line number Diff line /** /** * Copyright 2019, The Android Open Source Project * Copyright 2020, The Android Open Source Project * * * Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License. Loading Loading @@ -29,4 +29,13 @@ interface IAppSearchManager { */ */ void setSchema(in byte[] schemaProto, in AndroidFuture callback); void setSchema(in byte[] schemaProto, in AndroidFuture callback); void put(in byte[] documentBytes, in AndroidFuture callback); void put(in byte[] documentBytes, in AndroidFuture callback); /** * Searches a document based on a given query string. * * @param queryExpression Query String to search. * @param searchSpec Serialized SearchSpecProto. * @param callback {@link AndroidFuture}. Will be completed with a serialized * {@link SearchResultsProto}, or completed exceptionally if query fails. */ void query(in String queryExpression, in byte[] searchSpecBytes, in AndroidFuture callback); } }
apex/appsearch/framework/java/android/app/appsearch/IllegalSearchSpecException.java 0 → 100644 +36 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * 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. */ package android.app.appsearch; import android.annotation.NonNull; /** * Indicates that a {@link android.app.appsearch.SearchResults} has logical inconsistencies such * as unpopulated mandatory fields or illegal combinations of parameters. * * @hide */ public class IllegalSearchSpecException extends IllegalArgumentException { /** * Constructs a new {@link IllegalSearchSpecException}. * * @param message A developer-readable description of the issue with the bundle. */ public IllegalSearchSpecException(@NonNull String message) { super(message); } }
apex/appsearch/framework/java/android/app/appsearch/SearchResults.java 0 → 100644 +89 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * 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. */ package android.app.appsearch; import android.annotation.NonNull; import com.google.android.icing.proto.SearchResultProto; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * SearchResults are a list of results that are returned from a query. Each result from this * list contains a document and may contain other fields like snippets based on request. * @hide */ public final class SearchResults { private final SearchResultProto mSearchResultProto; /** @hide */ public SearchResults(SearchResultProto searchResultProto) { mSearchResultProto = searchResultProto; } /** * This class represents the result obtained from the query. It will contain the document which * which matched the specified query string and specifications. * @hide */ public static final class Result { private final SearchResultProto.ResultProto mResultProto; private Result(SearchResultProto.ResultProto resultProto) { mResultProto = resultProto; } /** * Contains the matching {@link AppSearch.Document}. * @return Document object which matched the query. * @hide */ // TODO(sidchhabra): Switch to Document constructor that takes proto. @NonNull public AppSearch.Document getDocument() { return AppSearch.Document.newBuilder(mResultProto.getDocument().getUri(), mResultProto.getDocument().getSchema()) .setCreationTimestampSecs(mResultProto.getDocument().getCreationTimestampSecs()) .setScore(mResultProto.getDocument().getScore()) .build(); } // TODO(sidchhabra): Add Getter for ResultReader for Snippet. } @Override public String toString() { return mSearchResultProto.toString(); } /** * Returns a {@link Result} iterator. Returns Empty Iterator if there are no matching results. * @hide */ @NonNull public Iterator<Result> getResults() { List<Result> results = new ArrayList<>(); // TODO(sidchhabra): Pass results using a RemoteStream. for (SearchResultProto.ResultProto resultProto : mSearchResultProto.getResultsList()) { results.add(new Result(resultProto)); } return results.iterator(); } }
apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java 0 → 100644 +127 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * 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. */ package android.app.appsearch; import android.annotation.IntDef; import android.annotation.NonNull; import com.google.android.icing.proto.SearchSpecProto; import com.google.android.icing.proto.TermMatchType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * This class represents the specification logic for AppSearch. It can be used to set the type of * search, like prefix or exact only or apply filters to search for a specific schema type only etc. * @hide * */ // TODO(sidchhabra) : AddResultSpec fields for Snippets etc. public final class SearchSpec { private final SearchSpecProto mSearchSpecProto; private SearchSpec(SearchSpecProto searchSpecProto) { mSearchSpecProto = searchSpecProto; } /** Creates a new {@link SearchSpec.Builder}. */ @NonNull public static SearchSpec.Builder newBuilder() { return new SearchSpec.Builder(); } /** @hide */ @NonNull SearchSpecProto getProto() { return mSearchSpecProto; } /** Term Match Type for the query. */ // NOTE: The integer values of these constants must match the proto enum constants in // {@link com.google.android.icing.proto.SearchSpecProto.termMatchType} @IntDef(prefix = {"TERM_MATCH_TYPE_"}, value = { TERM_MATCH_TYPE_EXACT_ONLY, TERM_MATCH_TYPE_PREFIX }) @Retention(RetentionPolicy.SOURCE) public @interface TermMatchTypeCode {} public static final int TERM_MATCH_TYPE_EXACT_ONLY = 1; public static final int TERM_MATCH_TYPE_PREFIX = 2; /** Builder for {@link SearchSpec objects}. */ public static final class Builder { private final SearchSpecProto.Builder mBuilder = SearchSpecProto.newBuilder(); private Builder(){} /** * Indicates how the query terms should match {@link TermMatchTypeCode} in the index. * * TermMatchType.Code=EXACT_ONLY * Query terms will only match exact tokens in the index. * Ex. A query term "foo" will only match indexed token "foo", and not "foot" * or "football" * * TermMatchType.Code=PREFIX * Query terms will match indexed tokens when the query term is a prefix of * the token. * Ex. A query term "foo" will match indexed tokens like "foo", "foot", and * "football". */ @NonNull public Builder setTermMatchType(@TermMatchTypeCode int termMatchTypeCode) { TermMatchType.Code termMatchTypeCodeProto = TermMatchType.Code.forNumber(termMatchTypeCode); if (termMatchTypeCodeProto == null) { throw new IllegalArgumentException("Invalid term match type: " + termMatchTypeCode); } mBuilder.setTermMatchType(termMatchTypeCodeProto); return this; } /** * Adds a Schema type filter to {@link SearchSpec} Entry. * Only search for documents that have the specified schema types. * If unset, the query will search over all schema types. */ @NonNull public Builder setSchemaTypes(@NonNull String... schemaTypes) { for (String schemaType : schemaTypes) { mBuilder.addSchemaTypeFilters(schemaType); } return this; } /** * Constructs a new {@link SearchSpec} from the contents of this builder. * * <p>After calling this method, the builder must no longer be used. */ @NonNull public SearchSpec build() { if (mBuilder.getTermMatchType() == TermMatchType.Code.UNKNOWN) { throw new IllegalSearchSpecException("Missing termMatchType field."); } return new SearchSpec(mBuilder.build()); } } }