1524 lines
66 KiB
Java
1524 lines
66 KiB
Java
![]() |
/*
|
||
|
* Copyright 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.FlaggedApi;
|
||
|
import android.annotation.IntDef;
|
||
|
import android.annotation.NonNull;
|
||
|
import android.annotation.Nullable;
|
||
|
import android.annotation.SuppressLint;
|
||
|
import android.app.appsearch.annotation.CanIgnoreReturnValue;
|
||
|
import android.app.appsearch.exceptions.AppSearchException;
|
||
|
import android.app.appsearch.exceptions.IllegalSchemaException;
|
||
|
import android.app.appsearch.flags.Flags;
|
||
|
import android.app.appsearch.safeparcel.AbstractSafeParcelable;
|
||
|
import android.app.appsearch.safeparcel.PropertyConfigParcel;
|
||
|
import android.app.appsearch.safeparcel.PropertyConfigParcel.DocumentIndexingConfigParcel;
|
||
|
import android.app.appsearch.safeparcel.PropertyConfigParcel.JoinableConfigParcel;
|
||
|
import android.app.appsearch.safeparcel.PropertyConfigParcel.StringIndexingConfigParcel;
|
||
|
import android.app.appsearch.safeparcel.SafeParcelable;
|
||
|
import android.app.appsearch.util.IndentingStringBuilder;
|
||
|
import android.os.Bundle;
|
||
|
import android.os.Parcel;
|
||
|
import android.os.Parcelable;
|
||
|
import android.util.ArraySet;
|
||
|
|
||
|
import com.android.internal.util.Preconditions;
|
||
|
|
||
|
import java.lang.annotation.Retention;
|
||
|
import java.lang.annotation.RetentionPolicy;
|
||
|
import java.util.ArrayList;
|
||
|
import java.util.Arrays;
|
||
|
import java.util.Collection;
|
||
|
import java.util.Collections;
|
||
|
import java.util.LinkedHashSet;
|
||
|
import java.util.List;
|
||
|
import java.util.Objects;
|
||
|
import java.util.Set;
|
||
|
|
||
|
/**
|
||
|
* The AppSearch Schema for a particular type of document.
|
||
|
*
|
||
|
* <p>For example, an e-mail message or a music recording could be a schema type.
|
||
|
*
|
||
|
* <p>The schema consists of type information, properties, and config (like tokenization type).
|
||
|
*
|
||
|
* @see AppSearchSession#setSchema
|
||
|
*/
|
||
|
@SafeParcelable.Class(creator = "AppSearchSchemaCreator")
|
||
|
@SuppressWarnings("HiddenSuperclass")
|
||
|
public final class AppSearchSchema extends AbstractSafeParcelable {
|
||
|
|
||
|
@FlaggedApi(Flags.FLAG_ENABLE_SAFE_PARCELABLE_2)
|
||
|
@NonNull
|
||
|
public static final Parcelable.Creator<AppSearchSchema> CREATOR = new AppSearchSchemaCreator();
|
||
|
|
||
|
@Field(id = 1, getter = "getSchemaType")
|
||
|
private final String mSchemaType;
|
||
|
|
||
|
@Field(id = 2)
|
||
|
final List<PropertyConfigParcel> mPropertyConfigParcels;
|
||
|
|
||
|
@Field(id = 3, getter = "getParentTypes")
|
||
|
private final List<String> mParentTypes;
|
||
|
|
||
|
@Field(id = 4, getter = "getDescription")
|
||
|
private final String mDescription;
|
||
|
|
||
|
@Constructor
|
||
|
AppSearchSchema(
|
||
|
@Param(id = 1) @NonNull String schemaType,
|
||
|
@Param(id = 2) @NonNull List<PropertyConfigParcel> propertyConfigParcels,
|
||
|
@Param(id = 3) @NonNull List<String> parentTypes,
|
||
|
@Param(id = 4) @NonNull String description) {
|
||
|
mSchemaType = Objects.requireNonNull(schemaType);
|
||
|
mPropertyConfigParcels = Objects.requireNonNull(propertyConfigParcels);
|
||
|
mParentTypes = Objects.requireNonNull(parentTypes);
|
||
|
mDescription = Objects.requireNonNull(description);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
@NonNull
|
||
|
public String toString() {
|
||
|
IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
|
||
|
appendAppSearchSchemaString(stringBuilder);
|
||
|
return stringBuilder.toString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Appends a debugging string for the {@link AppSearchSchema} instance to the given string
|
||
|
* builder.
|
||
|
*
|
||
|
* @param builder the builder to append to.
|
||
|
*/
|
||
|
private void appendAppSearchSchemaString(@NonNull IndentingStringBuilder builder) {
|
||
|
Objects.requireNonNull(builder);
|
||
|
|
||
|
builder.append("{\n");
|
||
|
builder.increaseIndentLevel();
|
||
|
builder.append("schemaType: \"").append(getSchemaType()).append("\",\n");
|
||
|
builder.append("description: \"").append(getDescription()).append("\",\n");
|
||
|
builder.append("properties: [\n");
|
||
|
|
||
|
AppSearchSchema.PropertyConfig[] sortedProperties =
|
||
|
getProperties().toArray(new AppSearchSchema.PropertyConfig[0]);
|
||
|
Arrays.sort(sortedProperties, (o1, o2) -> o1.getName().compareTo(o2.getName()));
|
||
|
|
||
|
for (int i = 0; i < sortedProperties.length; i++) {
|
||
|
AppSearchSchema.PropertyConfig propertyConfig = sortedProperties[i];
|
||
|
builder.increaseIndentLevel();
|
||
|
propertyConfig.appendPropertyConfigString(builder);
|
||
|
if (i != sortedProperties.length - 1) {
|
||
|
builder.append(",\n");
|
||
|
}
|
||
|
builder.decreaseIndentLevel();
|
||
|
}
|
||
|
|
||
|
builder.append("\n");
|
||
|
builder.append("]\n");
|
||
|
builder.decreaseIndentLevel();
|
||
|
builder.append("}");
|
||
|
}
|
||
|
|
||
|
/** Returns the name of this schema type, such as Email. */
|
||
|
@NonNull
|
||
|
public String getSchemaType() {
|
||
|
return mSchemaType;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a natural language description of this schema type.
|
||
|
*
|
||
|
* <p>Ex. The description for an Email type could be "A type of electronic message".
|
||
|
*
|
||
|
* <p>This information is purely to help apps consuming this type to understand its semantic
|
||
|
* meaning. This field has no effect in AppSearch - it is just stored with the AppSearchSchema.
|
||
|
* If {@link Builder#setDescription} is uncalled, then this method will return an empty string.
|
||
|
*/
|
||
|
@FlaggedApi(Flags.FLAG_ENABLE_APP_FUNCTIONS)
|
||
|
@NonNull
|
||
|
public String getDescription() {
|
||
|
return mDescription;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the list of {@link PropertyConfig}s that are part of this schema.
|
||
|
*
|
||
|
* <p>This method creates a new list when called.
|
||
|
*/
|
||
|
@NonNull
|
||
|
@SuppressWarnings({"MixedMutabilityReturnType"})
|
||
|
public List<PropertyConfig> getProperties() {
|
||
|
if (mPropertyConfigParcels.isEmpty()) {
|
||
|
return Collections.emptyList();
|
||
|
}
|
||
|
List<PropertyConfig> ret = new ArrayList<>(mPropertyConfigParcels.size());
|
||
|
for (int i = 0; i < mPropertyConfigParcels.size(); i++) {
|
||
|
ret.add(PropertyConfig.fromParcel(mPropertyConfigParcels.get(i)));
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/** Returns the list of parent types of this schema for polymorphism. */
|
||
|
@FlaggedApi(Flags.FLAG_ENABLE_GET_PARENT_TYPES_AND_INDEXABLE_NESTED_PROPERTIES)
|
||
|
@NonNull
|
||
|
public List<String> getParentTypes() {
|
||
|
return Collections.unmodifiableList(mParentTypes);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean equals(@Nullable Object other) {
|
||
|
if (this == other) {
|
||
|
return true;
|
||
|
}
|
||
|
if (!(other instanceof AppSearchSchema)) {
|
||
|
return false;
|
||
|
}
|
||
|
AppSearchSchema otherSchema = (AppSearchSchema) other;
|
||
|
if (!getSchemaType().equals(otherSchema.getSchemaType())) {
|
||
|
return false;
|
||
|
}
|
||
|
if (!getDescription().equals(otherSchema.getDescription())) {
|
||
|
return false;
|
||
|
}
|
||
|
if (!getParentTypes().equals(otherSchema.getParentTypes())) {
|
||
|
return false;
|
||
|
}
|
||
|
return getProperties().equals(otherSchema.getProperties());
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int hashCode() {
|
||
|
return Objects.hash(getSchemaType(), getProperties(), getParentTypes(), getDescription());
|
||
|
}
|
||
|
|
||
|
@FlaggedApi(Flags.FLAG_ENABLE_SAFE_PARCELABLE_2)
|
||
|
@Override
|
||
|
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||
|
AppSearchSchemaCreator.writeToParcel(this, dest, flags);
|
||
|
}
|
||
|
|
||
|
/** Builder for {@link AppSearchSchema objects}. */
|
||
|
public static final class Builder {
|
||
|
private final String mSchemaType;
|
||
|
private String mDescription = "";
|
||
|
private ArrayList<PropertyConfigParcel> mPropertyConfigParcels = new ArrayList<>();
|
||
|
private LinkedHashSet<String> mParentTypes = new LinkedHashSet<>();
|
||
|
private final Set<String> mPropertyNames = new ArraySet<>();
|
||
|
private boolean mBuilt = false;
|
||
|
|
||
|
/** Creates a new {@link AppSearchSchema.Builder}. */
|
||
|
public Builder(@NonNull String schemaType) {
|
||
|
mSchemaType = Objects.requireNonNull(schemaType);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets a natural language description of this schema type.
|
||
|
*
|
||
|
* <p>For more details about the description field, see {@link
|
||
|
* AppSearchSchema#getDescription}.
|
||
|
*/
|
||
|
@FlaggedApi(Flags.FLAG_ENABLE_APP_FUNCTIONS)
|
||
|
@CanIgnoreReturnValue
|
||
|
@NonNull
|
||
|
public AppSearchSchema.Builder setDescription(@NonNull String description) {
|
||
|
Objects.requireNonNull(description);
|
||
|
resetIfBuilt();
|
||
|
mDescription = description;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/** Adds a property to the given type. */
|
||
|
@CanIgnoreReturnValue
|
||
|
@NonNull
|
||
|
public AppSearchSchema.Builder addProperty(@NonNull PropertyConfig propertyConfig) {
|
||
|
Objects.requireNonNull(propertyConfig);
|
||
|
resetIfBuilt();
|
||
|
String name = propertyConfig.getName();
|
||
|
if (!mPropertyNames.add(name)) {
|
||
|
throw new IllegalSchemaException("Property defined more than once: " + name);
|
||
|
}
|
||
|
mPropertyConfigParcels.add(propertyConfig.mPropertyConfigParcel);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds a parent type to the given type for polymorphism, so that the given type will be
|
||
|
* considered as a subtype of {@code parentSchemaType}.
|
||
|
*
|
||
|
* <p>Subtype relations are automatically considered transitive, so callers are only
|
||
|
* required to provide direct parents. Specifically, if T1 <: T2 and T2 <: T3 are
|
||
|
* known, then T1 <: T3 will be inferred automatically, where <: is the subtype
|
||
|
* symbol.
|
||
|
*
|
||
|
* <p>Polymorphism is currently supported in the following ways:
|
||
|
*
|
||
|
* <ul>
|
||
|
* <li>Search filters on a parent type will automatically be extended to the child types
|
||
|
* as well. For example, if Artist <: Person, then a search with a filter on type
|
||
|
* Person (by calling {@link SearchSpec.Builder#addFilterSchemas}) will also include
|
||
|
* documents of type Artist in the search result.
|
||
|
* <li>In the projection API, the property paths to project specified for a parent type
|
||
|
* will automatically be extended to the child types as well. If both a parent type
|
||
|
* and one of its child type are specified in the projection API, the parent type's
|
||
|
* paths will be merged into the child's. For more details on projection, see {@link
|
||
|
* SearchSpec.Builder#addProjection}.
|
||
|
* <li>A document property defined as type U is allowed to be set with a document of type
|
||
|
* T, as long as T <: U, but note that index will only be based on the defined
|
||
|
* type, which is U. For example, consider a document of type "Company" with a
|
||
|
* repeated "employees" field of type "Person". We can add employees of either type
|
||
|
* "Person" or type "Artist" or both to this property, as long as "Artist" is a
|
||
|
* subtype of "Person". However, the index of the "employees" property will be based
|
||
|
* on what's defined in "Person", even for an added document of type "Artist".
|
||
|
* </ul>
|
||
|
*
|
||
|
* <p>Subtypes must meet the following requirements. A violation of the requirements will
|
||
|
* cause {@link AppSearchSession#setSchema} to throw an {@link AppSearchException} with the
|
||
|
* result code of {@link AppSearchResult#RESULT_INVALID_ARGUMENT}. Consider a type Artist
|
||
|
* and a type Person, and Artist claims to be a subtype of Person, then:
|
||
|
*
|
||
|
* <ul>
|
||
|
* <li>Every property in Person must have a corresponding property in Artist with the same
|
||
|
* name.
|
||
|
* <li>Every non-document property in Person must have the same type as the type of the
|
||
|
* corresponding property in Artist. For example, if "age" is an integer property in
|
||
|
* Person, then "age" must also be an integer property in Artist, instead of a string.
|
||
|
* <li>The schema type of every document property in Artist must be a subtype of the
|
||
|
* schema type of the corresponding document property in Person, if such a property
|
||
|
* exists in Person. For example, if "awards" is a document property of type Award in
|
||
|
* Person, then the type of the "awards" property in Artist must be a subtype of
|
||
|
* Award, say ArtAward. Note that every type is a subtype of itself.
|
||
|
* <li>Every property in Artist must have a cardinality stricter than or equal to the
|
||
|
* cardinality of the corresponding property in Person, if such a property exists in
|
||
|
* Person. For example, if "awards" is a property in Person of cardinality OPTIONAL,
|
||
|
* then the cardinality of the "awards" property in Artist can only be REQUIRED or
|
||
|
* OPTIONAL. Rule: REQUIRED < OPTIONAL < REPEATED.
|
||
|
* <li>There are no other enforcements on the corresponding properties in Artist, such as
|
||
|
* index type, tokenizer type, etc. These settings can be safely overridden.
|
||
|
* </ul>
|
||
|
*
|
||
|
* <p>A type can be defined to have multiple parents, but it must be compatible with each of
|
||
|
* its parents based on the above rules. For example, if LocalBusiness is defined as a
|
||
|
* subtype of both Place and Organization, then the compatibility of LocalBusiness with
|
||
|
* Place and the compatibility of LocalBusiness with Organization will both be checked.
|
||
|
*/
|
||
|
@CanIgnoreReturnValue
|
||
|
@NonNull
|
||
|
public AppSearchSchema.Builder addParentType(@NonNull String parentSchemaType) {
|
||
|
Objects.requireNonNull(parentSchemaType);
|
||
|
resetIfBuilt();
|
||
|
mParentTypes.add(parentSchemaType);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/** Constructs a new {@link AppSearchSchema} from the contents of this builder. */
|
||
|
@NonNull
|
||
|
public AppSearchSchema build() {
|
||
|
mBuilt = true;
|
||
|
return new AppSearchSchema(
|
||
|
mSchemaType,
|
||
|
mPropertyConfigParcels,
|
||
|
new ArrayList<>(mParentTypes),
|
||
|
mDescription);
|
||
|
}
|
||
|
|
||
|
private void resetIfBuilt() {
|
||
|
if (mBuilt) {
|
||
|
mPropertyConfigParcels = new ArrayList<>(mPropertyConfigParcels);
|
||
|
mParentTypes = new LinkedHashSet<>(mParentTypes);
|
||
|
mBuilt = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Common configuration for a single property (field) in a Document.
|
||
|
*
|
||
|
* <p>For example, an {@code EmailMessage} would be a type and the {@code subject} would be a
|
||
|
* property.
|
||
|
*/
|
||
|
public abstract static class PropertyConfig {
|
||
|
/**
|
||
|
* Physical data-types of the contents of the property.
|
||
|
*
|
||
|
* <p>NOTE: The integer values of these constants must match the proto enum constants in
|
||
|
* com.google.android.icing.proto.PropertyConfigProto.DataType.Code.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@IntDef(
|
||
|
value = {
|
||
|
DATA_TYPE_STRING,
|
||
|
DATA_TYPE_LONG,
|
||
|
DATA_TYPE_DOUBLE,
|
||
|
DATA_TYPE_BOOLEAN,
|
||
|
DATA_TYPE_BYTES,
|
||
|
DATA_TYPE_DOCUMENT,
|
||
|
})
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
public @interface DataType {}
|
||
|
|
||
|
/** @hide */
|
||
|
public static final int DATA_TYPE_STRING = 1;
|
||
|
|
||
|
/** @hide */
|
||
|
public static final int DATA_TYPE_LONG = 2;
|
||
|
|
||
|
/** @hide */
|
||
|
public static final int DATA_TYPE_DOUBLE = 3;
|
||
|
|
||
|
/** @hide */
|
||
|
public static final int DATA_TYPE_BOOLEAN = 4;
|
||
|
|
||
|
/**
|
||
|
* Unstructured BLOB.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
public static final int DATA_TYPE_BYTES = 5;
|
||
|
|
||
|
/**
|
||
|
* Indicates that the property is itself a {@link GenericDocument}, making it part of a
|
||
|
* hierarchical schema. Any property using this DataType MUST have a valid {@link
|
||
|
* PropertyConfig#getSchemaType}.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
public static final int DATA_TYPE_DOCUMENT = 6;
|
||
|
|
||
|
/**
|
||
|
* The cardinality of the property (whether it is required, optional or repeated).
|
||
|
*
|
||
|
* <p>NOTE: The integer values of these constants must match the proto enum constants in
|
||
|
* com.google.android.icing.proto.PropertyConfigProto.Cardinality.Code.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@IntDef(
|
||
|
value = {
|
||
|
CARDINALITY_REPEATED,
|
||
|
CARDINALITY_OPTIONAL,
|
||
|
CARDINALITY_REQUIRED,
|
||
|
})
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
public @interface Cardinality {}
|
||
|
|
||
|
/** Any number of items (including zero) [0...*]. */
|
||
|
public static final int CARDINALITY_REPEATED = 1;
|
||
|
|
||
|
/** Zero or one value [0,1]. */
|
||
|
public static final int CARDINALITY_OPTIONAL = 2;
|
||
|
|
||
|
/** Exactly one value [1]. */
|
||
|
public static final int CARDINALITY_REQUIRED = 3;
|
||
|
|
||
|
final PropertyConfigParcel mPropertyConfigParcel;
|
||
|
|
||
|
PropertyConfig(@NonNull PropertyConfigParcel propertyConfigParcel) {
|
||
|
mPropertyConfigParcel = Objects.requireNonNull(propertyConfigParcel);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
@NonNull
|
||
|
public String toString() {
|
||
|
IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
|
||
|
appendPropertyConfigString(stringBuilder);
|
||
|
return stringBuilder.toString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Appends a debug string for the {@link AppSearchSchema.PropertyConfig} instance to the
|
||
|
* given string builder.
|
||
|
*
|
||
|
* @param builder the builder to append to.
|
||
|
*/
|
||
|
void appendPropertyConfigString(@NonNull IndentingStringBuilder builder) {
|
||
|
Objects.requireNonNull(builder);
|
||
|
|
||
|
builder.append("{\n");
|
||
|
builder.increaseIndentLevel();
|
||
|
builder.append("name: \"").append(getName()).append("\",\n");
|
||
|
builder.append("description: \"").append(getDescription()).append("\",\n");
|
||
|
|
||
|
if (this instanceof AppSearchSchema.StringPropertyConfig) {
|
||
|
((StringPropertyConfig) this).appendStringPropertyConfigFields(builder);
|
||
|
} else if (this instanceof AppSearchSchema.DocumentPropertyConfig) {
|
||
|
((DocumentPropertyConfig) this).appendDocumentPropertyConfigFields(builder);
|
||
|
} else if (this instanceof AppSearchSchema.LongPropertyConfig) {
|
||
|
((LongPropertyConfig) this).appendLongPropertyConfigFields(builder);
|
||
|
}
|
||
|
|
||
|
switch (getCardinality()) {
|
||
|
case AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED:
|
||
|
builder.append("cardinality: CARDINALITY_REPEATED,\n");
|
||
|
break;
|
||
|
case AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL:
|
||
|
builder.append("cardinality: CARDINALITY_OPTIONAL,\n");
|
||
|
break;
|
||
|
case AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED:
|
||
|
builder.append("cardinality: CARDINALITY_REQUIRED,\n");
|
||
|
break;
|
||
|
default:
|
||
|
builder.append("cardinality: CARDINALITY_UNKNOWN,\n");
|
||
|
}
|
||
|
|
||
|
switch (getDataType()) {
|
||
|
case AppSearchSchema.PropertyConfig.DATA_TYPE_STRING:
|
||
|
builder.append("dataType: DATA_TYPE_STRING,\n");
|
||
|
break;
|
||
|
case AppSearchSchema.PropertyConfig.DATA_TYPE_LONG:
|
||
|
builder.append("dataType: DATA_TYPE_LONG,\n");
|
||
|
break;
|
||
|
case AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE:
|
||
|
builder.append("dataType: DATA_TYPE_DOUBLE,\n");
|
||
|
break;
|
||
|
case AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN:
|
||
|
builder.append("dataType: DATA_TYPE_BOOLEAN,\n");
|
||
|
break;
|
||
|
case AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES:
|
||
|
builder.append("dataType: DATA_TYPE_BYTES,\n");
|
||
|
break;
|
||
|
case AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT:
|
||
|
builder.append("dataType: DATA_TYPE_DOCUMENT,\n");
|
||
|
break;
|
||
|
default:
|
||
|
builder.append("dataType: DATA_TYPE_UNKNOWN,\n");
|
||
|
}
|
||
|
builder.decreaseIndentLevel();
|
||
|
builder.append("}");
|
||
|
}
|
||
|
|
||
|
/** Returns the name of this property. */
|
||
|
@NonNull
|
||
|
public String getName() {
|
||
|
return mPropertyConfigParcel.getName();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a natural language description of this property.
|
||
|
*
|
||
|
* <p>Ex. The description for the "homeAddress" property of a "Person" type could be "the
|
||
|
* address at which this person lives".
|
||
|
*
|
||
|
* <p>This information is purely to help apps consuming this type the semantic meaning of
|
||
|
* its properties. This field has no effect in AppSearch - it is just stored with the
|
||
|
* AppSearchSchema. If the description is not set, then this method will return an empty
|
||
|
* string.
|
||
|
*/
|
||
|
@FlaggedApi(Flags.FLAG_ENABLE_APP_FUNCTIONS)
|
||
|
@NonNull
|
||
|
public String getDescription() {
|
||
|
return mPropertyConfigParcel.getDescription();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the type of data the property contains (such as string, int, bytes, etc).
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@DataType
|
||
|
public int getDataType() {
|
||
|
return mPropertyConfigParcel.getDataType();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the cardinality of the property (whether it is optional, required or repeated).
|
||
|
*/
|
||
|
@Cardinality
|
||
|
public int getCardinality() {
|
||
|
return mPropertyConfigParcel.getCardinality();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean equals(@Nullable Object other) {
|
||
|
if (this == other) {
|
||
|
return true;
|
||
|
}
|
||
|
if (!(other instanceof PropertyConfig)) {
|
||
|
return false;
|
||
|
}
|
||
|
PropertyConfig otherProperty = (PropertyConfig) other;
|
||
|
return Objects.equals(mPropertyConfigParcel, otherProperty.mPropertyConfigParcel);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int hashCode() {
|
||
|
return mPropertyConfigParcel.hashCode();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Converts a {@link Bundle} into a {@link PropertyConfig} depending on its internal data
|
||
|
* type.
|
||
|
*
|
||
|
* <p>The bundle is not cloned.
|
||
|
*
|
||
|
* @throws IllegalArgumentException if the bundle does no contain a recognized value in its
|
||
|
* {@code DATA_TYPE_FIELD}.
|
||
|
* @hide
|
||
|
*/
|
||
|
@NonNull
|
||
|
public static PropertyConfig fromParcel(
|
||
|
@NonNull PropertyConfigParcel propertyConfigParcel) {
|
||
|
Objects.requireNonNull(propertyConfigParcel);
|
||
|
switch (propertyConfigParcel.getDataType()) {
|
||
|
case PropertyConfig.DATA_TYPE_STRING:
|
||
|
return new StringPropertyConfig(propertyConfigParcel);
|
||
|
case PropertyConfig.DATA_TYPE_LONG:
|
||
|
return new LongPropertyConfig(propertyConfigParcel);
|
||
|
case PropertyConfig.DATA_TYPE_DOUBLE:
|
||
|
return new DoublePropertyConfig(propertyConfigParcel);
|
||
|
case PropertyConfig.DATA_TYPE_BOOLEAN:
|
||
|
return new BooleanPropertyConfig(propertyConfigParcel);
|
||
|
case PropertyConfig.DATA_TYPE_BYTES:
|
||
|
return new BytesPropertyConfig(propertyConfigParcel);
|
||
|
case PropertyConfig.DATA_TYPE_DOCUMENT:
|
||
|
return new DocumentPropertyConfig(propertyConfigParcel);
|
||
|
default:
|
||
|
throw new IllegalArgumentException(
|
||
|
"Unsupported property bundle of type "
|
||
|
+ propertyConfigParcel.getDataType()
|
||
|
+ "; contents: "
|
||
|
+ propertyConfigParcel);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Configuration for a property of type String in a Document. */
|
||
|
public static final class StringPropertyConfig extends PropertyConfig {
|
||
|
/**
|
||
|
* Encapsulates the configurations on how AppSearch should query/index these terms.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@IntDef(
|
||
|
value = {
|
||
|
INDEXING_TYPE_NONE,
|
||
|
INDEXING_TYPE_EXACT_TERMS,
|
||
|
INDEXING_TYPE_PREFIXES,
|
||
|
})
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
public @interface IndexingType {}
|
||
|
|
||
|
/** Content in this property will not be tokenized or indexed. */
|
||
|
public static final int INDEXING_TYPE_NONE = 0;
|
||
|
|
||
|
/**
|
||
|
* Content in this property should only be returned for queries matching the exact tokens
|
||
|
* appearing in this property.
|
||
|
*
|
||
|
* <p>For example, a property with "fool" should NOT match a query for "foo".
|
||
|
*/
|
||
|
public static final int INDEXING_TYPE_EXACT_TERMS = 1;
|
||
|
|
||
|
/**
|
||
|
* Content in this property should be returned for queries that are either exact matches or
|
||
|
* query matches of the tokens appearing in this property.
|
||
|
*
|
||
|
* <p>For example, a property with "fool" <b>should</b> match a query for "foo".
|
||
|
*/
|
||
|
public static final int INDEXING_TYPE_PREFIXES = 2;
|
||
|
|
||
|
/**
|
||
|
* Configures how tokens should be extracted from this property.
|
||
|
*
|
||
|
* <p>NOTE: The integer values of these constants must match the proto enum constants in
|
||
|
* com.google.android.icing.proto.IndexingConfig.TokenizerType.Code.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@IntDef(
|
||
|
value = {
|
||
|
TOKENIZER_TYPE_NONE,
|
||
|
TOKENIZER_TYPE_PLAIN,
|
||
|
TOKENIZER_TYPE_VERBATIM,
|
||
|
TOKENIZER_TYPE_RFC822
|
||
|
})
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
public @interface TokenizerType {}
|
||
|
|
||
|
/**
|
||
|
* This value indicates that no tokens should be extracted from this property.
|
||
|
*
|
||
|
* <p>It is only valid for tokenizer_type to be 'NONE' if {@link #getIndexingType} is {@link
|
||
|
* #INDEXING_TYPE_NONE}.
|
||
|
*/
|
||
|
public static final int TOKENIZER_TYPE_NONE = 0;
|
||
|
|
||
|
/**
|
||
|
* Tokenization for plain text. This value indicates that tokens should be extracted from
|
||
|
* this property based on word breaks. Segments of whitespace and punctuation are not
|
||
|
* considered tokens.
|
||
|
*
|
||
|
* <p>For example, a property with "foo bar. baz." will produce tokens for "foo", "bar" and
|
||
|
* "baz". The segments " " and "." will not be considered tokens.
|
||
|
*
|
||
|
* <p>It is only valid for tokenizer_type to be 'PLAIN' if {@link #getIndexingType} is
|
||
|
* {@link #INDEXING_TYPE_EXACT_TERMS} or {@link #INDEXING_TYPE_PREFIXES}.
|
||
|
*/
|
||
|
public static final int TOKENIZER_TYPE_PLAIN = 1;
|
||
|
|
||
|
/**
|
||
|
* This value indicates that no normalization or segmentation should be applied to string
|
||
|
* values that are tokenized using this type. Therefore, the output token is equivalent to
|
||
|
* the raw string value.
|
||
|
*
|
||
|
* <p>For example, a property with "Hello, world!" will produce the token "Hello, world!",
|
||
|
* preserving punctuation and capitalization, and not creating separate tokens between the
|
||
|
* space.
|
||
|
*
|
||
|
* <p>It is only valid for tokenizer_type to be 'VERBATIM' if {@link #getIndexingType} is
|
||
|
* {@link #INDEXING_TYPE_EXACT_TERMS} or {@link #INDEXING_TYPE_PREFIXES}.
|
||
|
*/
|
||
|
public static final int TOKENIZER_TYPE_VERBATIM = 2;
|
||
|
|
||
|
/**
|
||
|
* Tokenization for emails. This value indicates that tokens should be extracted from this
|
||
|
* property based on email structure.
|
||
|
*
|
||
|
* <p>For example, a property with "alex.sav@google.com" will produce tokens for "alex",
|
||
|
* "sav", "alex.sav", "google", "com", and "alexsav@google.com"
|
||
|
*
|
||
|
* <p>It is only valid for tokenizer_type to be 'RFC822' if {@link #getIndexingType} is
|
||
|
* {@link #INDEXING_TYPE_EXACT_TERMS} or {@link #INDEXING_TYPE_PREFIXES}.
|
||
|
*/
|
||
|
public static final int TOKENIZER_TYPE_RFC822 = 3;
|
||
|
|
||
|
/**
|
||
|
* The joinable value type of the property. By setting the appropriate joinable value type
|
||
|
* for a property, the client can use the property for joining documents from other schema
|
||
|
* types using Search API (see {@link JoinSpec}).
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
// NOTE: The integer values of these constants must match the proto enum constants in
|
||
|
// com.google.android.icing.proto.JoinableConfig.ValueType.Code.
|
||
|
@IntDef(
|
||
|
value = {
|
||
|
JOINABLE_VALUE_TYPE_NONE,
|
||
|
JOINABLE_VALUE_TYPE_QUALIFIED_ID,
|
||
|
})
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
public @interface JoinableValueType {}
|
||
|
|
||
|
/** Content in this property is not joinable. */
|
||
|
public static final int JOINABLE_VALUE_TYPE_NONE = 0;
|
||
|
|
||
|
/**
|
||
|
* Content in this string property will be used as a qualified id to join documents.
|
||
|
*
|
||
|
* <ul>
|
||
|
* <li>Qualified id: a unique identifier for a document, and this joinable value type is
|
||
|
* similar to primary and foreign key in relational database. See {@link
|
||
|
* android.app.appsearch.util.DocumentIdUtil} for more details.
|
||
|
* <li>Currently we only support single string joining, so it should only be used with
|
||
|
* {@link PropertyConfig#CARDINALITY_OPTIONAL} and {@link
|
||
|
* PropertyConfig#CARDINALITY_REQUIRED}.
|
||
|
* </ul>
|
||
|
*/
|
||
|
public static final int JOINABLE_VALUE_TYPE_QUALIFIED_ID = 1;
|
||
|
|
||
|
StringPropertyConfig(@NonNull PropertyConfigParcel propertyConfigParcel) {
|
||
|
super(propertyConfigParcel);
|
||
|
}
|
||
|
|
||
|
/** Returns how the property is indexed. */
|
||
|
@IndexingType
|
||
|
public int getIndexingType() {
|
||
|
StringIndexingConfigParcel indexingConfigParcel =
|
||
|
mPropertyConfigParcel.getStringIndexingConfigParcel();
|
||
|
if (indexingConfigParcel == null) {
|
||
|
return INDEXING_TYPE_NONE;
|
||
|
}
|
||
|
|
||
|
return indexingConfigParcel.getIndexingType();
|
||
|
}
|
||
|
|
||
|
/** Returns how this property is tokenized (split into words). */
|
||
|
@TokenizerType
|
||
|
public int getTokenizerType() {
|
||
|
StringIndexingConfigParcel indexingConfigParcel =
|
||
|
mPropertyConfigParcel.getStringIndexingConfigParcel();
|
||
|
if (indexingConfigParcel == null) {
|
||
|
return TOKENIZER_TYPE_NONE;
|
||
|
}
|
||
|
|
||
|
return indexingConfigParcel.getTokenizerType();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns how this property is going to be used to join documents from other schema types.
|
||
|
*/
|
||
|
@JoinableValueType
|
||
|
public int getJoinableValueType() {
|
||
|
JoinableConfigParcel joinableConfigParcel =
|
||
|
mPropertyConfigParcel.getJoinableConfigParcel();
|
||
|
if (joinableConfigParcel == null) {
|
||
|
return JOINABLE_VALUE_TYPE_NONE;
|
||
|
}
|
||
|
|
||
|
return joinableConfigParcel.getJoinableValueType();
|
||
|
}
|
||
|
|
||
|
/** Builder for {@link StringPropertyConfig}. */
|
||
|
public static final class Builder {
|
||
|
private final String mPropertyName;
|
||
|
private String mDescription = "";
|
||
|
@Cardinality private int mCardinality = CARDINALITY_OPTIONAL;
|
||
|
@IndexingType private int mIndexingType = INDEXING_TYPE_NONE;
|
||
|
@TokenizerType private int mTokenizerType = TOKENIZER_TYPE_NONE;
|
||
|
@JoinableValueType private int mJoinableValueType = JOINABLE_VALUE_TYPE_NONE;
|
||
|
private boolean mDeletionPropagation = false;
|
||
|
|
||
|
/** Creates a new {@link StringPropertyConfig.Builder}. */
|
||
|
public Builder(@NonNull String propertyName) {
|
||
|
mPropertyName = Objects.requireNonNull(propertyName);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets a natural language description of this property.
|
||
|
*
|
||
|
* <p>For more details about the description field, see {@link
|
||
|
* AppSearchSchema.PropertyConfig#getDescription}.
|
||
|
*/
|
||
|
@FlaggedApi(Flags.FLAG_ENABLE_APP_FUNCTIONS)
|
||
|
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
|
||
|
@NonNull
|
||
|
public StringPropertyConfig.Builder setDescription(@NonNull String description) {
|
||
|
mDescription = Objects.requireNonNull(description);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the cardinality of the property (whether it is optional, required or repeated).
|
||
|
*
|
||
|
* <p>If this method is not called, the default cardinality is {@link
|
||
|
* PropertyConfig#CARDINALITY_OPTIONAL}.
|
||
|
*/
|
||
|
@CanIgnoreReturnValue
|
||
|
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
|
||
|
@NonNull
|
||
|
public StringPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
|
||
|
Preconditions.checkArgumentInRange(
|
||
|
cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
|
||
|
mCardinality = cardinality;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Configures how a property should be indexed so that it can be retrieved by queries.
|
||
|
*
|
||
|
* <p>If this method is not called, the default indexing type is {@link
|
||
|
* StringPropertyConfig#INDEXING_TYPE_NONE}, so that it cannot be matched by queries.
|
||
|
*/
|
||
|
@CanIgnoreReturnValue
|
||
|
@NonNull
|
||
|
public StringPropertyConfig.Builder setIndexingType(@IndexingType int indexingType) {
|
||
|
Preconditions.checkArgumentInRange(
|
||
|
indexingType, INDEXING_TYPE_NONE, INDEXING_TYPE_PREFIXES, "indexingType");
|
||
|
mIndexingType = indexingType;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Configures how this property should be tokenized (split into words).
|
||
|
*
|
||
|
* <p>If this method is not called, the default indexing type is {@link
|
||
|
* StringPropertyConfig#TOKENIZER_TYPE_NONE}, so that it is not tokenized.
|
||
|
*
|
||
|
* <p>This method must be called with a value other than {@link
|
||
|
* StringPropertyConfig#TOKENIZER_TYPE_NONE} if the property is indexed (that is, if
|
||
|
* {@link #setIndexingType} has been called with a value other than {@link
|
||
|
* StringPropertyConfig#INDEXING_TYPE_NONE}).
|
||
|
*/
|
||
|
@CanIgnoreReturnValue
|
||
|
@NonNull
|
||
|
public StringPropertyConfig.Builder setTokenizerType(@TokenizerType int tokenizerType) {
|
||
|
Preconditions.checkArgumentInRange(
|
||
|
tokenizerType, TOKENIZER_TYPE_NONE, TOKENIZER_TYPE_RFC822, "tokenizerType");
|
||
|
mTokenizerType = tokenizerType;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Configures how this property should be used as a joining matcher.
|
||
|
*
|
||
|
* <p>If this method is not called, the default joinable value type is {@link
|
||
|
* StringPropertyConfig#JOINABLE_VALUE_TYPE_NONE}, so that it is not joinable.
|
||
|
*
|
||
|
* <p>At most, 64 properties can be set as joinable per schema.
|
||
|
*/
|
||
|
@CanIgnoreReturnValue
|
||
|
@NonNull
|
||
|
public StringPropertyConfig.Builder setJoinableValueType(
|
||
|
@JoinableValueType int joinableValueType) {
|
||
|
Preconditions.checkArgumentInRange(
|
||
|
joinableValueType,
|
||
|
JOINABLE_VALUE_TYPE_NONE,
|
||
|
JOINABLE_VALUE_TYPE_QUALIFIED_ID,
|
||
|
"joinableValueType");
|
||
|
mJoinableValueType = joinableValueType;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/** Constructs a new {@link StringPropertyConfig} from the contents of this builder. */
|
||
|
@NonNull
|
||
|
public StringPropertyConfig build() {
|
||
|
if (mTokenizerType == TOKENIZER_TYPE_NONE) {
|
||
|
Preconditions.checkState(
|
||
|
mIndexingType == INDEXING_TYPE_NONE,
|
||
|
"Cannot set "
|
||
|
+ "TOKENIZER_TYPE_NONE with an indexing type other than "
|
||
|
+ "INDEXING_TYPE_NONE.");
|
||
|
} else {
|
||
|
Preconditions.checkState(
|
||
|
mIndexingType != INDEXING_TYPE_NONE,
|
||
|
"Cannot set " + "TOKENIZER_TYPE_PLAIN with INDEXING_TYPE_NONE.");
|
||
|
}
|
||
|
if (mJoinableValueType == JOINABLE_VALUE_TYPE_QUALIFIED_ID) {
|
||
|
Preconditions.checkState(
|
||
|
mCardinality != CARDINALITY_REPEATED,
|
||
|
"Cannot set JOINABLE_VALUE_TYPE_QUALIFIED_ID with"
|
||
|
+ " CARDINALITY_REPEATED.");
|
||
|
} else {
|
||
|
Preconditions.checkState(
|
||
|
!mDeletionPropagation,
|
||
|
"Cannot set deletion "
|
||
|
+ "propagation without setting a joinable value type");
|
||
|
}
|
||
|
PropertyConfigParcel.StringIndexingConfigParcel stringConfigParcel =
|
||
|
new StringIndexingConfigParcel(mIndexingType, mTokenizerType);
|
||
|
JoinableConfigParcel joinableConfigParcel =
|
||
|
new JoinableConfigParcel(mJoinableValueType, mDeletionPropagation);
|
||
|
return new StringPropertyConfig(
|
||
|
PropertyConfigParcel.createForString(
|
||
|
mPropertyName,
|
||
|
mDescription,
|
||
|
mCardinality,
|
||
|
stringConfigParcel,
|
||
|
joinableConfigParcel));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Appends a debug string for the {@link StringPropertyConfig} instance to the given string
|
||
|
* builder.
|
||
|
*
|
||
|
* <p>This appends fields specific to a {@link StringPropertyConfig} instance.
|
||
|
*
|
||
|
* @param builder the builder to append to.
|
||
|
*/
|
||
|
void appendStringPropertyConfigFields(@NonNull IndentingStringBuilder builder) {
|
||
|
switch (getIndexingType()) {
|
||
|
case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE:
|
||
|
builder.append("indexingType: INDEXING_TYPE_NONE,\n");
|
||
|
break;
|
||
|
case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS:
|
||
|
builder.append("indexingType: INDEXING_TYPE_EXACT_TERMS,\n");
|
||
|
break;
|
||
|
case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES:
|
||
|
builder.append("indexingType: INDEXING_TYPE_PREFIXES,\n");
|
||
|
break;
|
||
|
default:
|
||
|
builder.append("indexingType: INDEXING_TYPE_UNKNOWN,\n");
|
||
|
}
|
||
|
|
||
|
switch (getTokenizerType()) {
|
||
|
case AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE:
|
||
|
builder.append("tokenizerType: TOKENIZER_TYPE_NONE,\n");
|
||
|
break;
|
||
|
case AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN:
|
||
|
builder.append("tokenizerType: TOKENIZER_TYPE_PLAIN,\n");
|
||
|
break;
|
||
|
case AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_VERBATIM:
|
||
|
builder.append("tokenizerType: TOKENIZER_TYPE_VERBATIM,\n");
|
||
|
break;
|
||
|
case AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_RFC822:
|
||
|
builder.append("tokenizerType: TOKENIZER_TYPE_RFC822,\n");
|
||
|
break;
|
||
|
default:
|
||
|
builder.append("tokenizerType: TOKENIZER_TYPE_UNKNOWN,\n");
|
||
|
}
|
||
|
|
||
|
switch (getJoinableValueType()) {
|
||
|
case AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE:
|
||
|
builder.append("joinableValueType: JOINABLE_VALUE_TYPE_NONE,\n");
|
||
|
break;
|
||
|
case AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_QUALIFIED_ID:
|
||
|
builder.append("joinableValueType: JOINABLE_VALUE_TYPE_QUALIFIED_ID,\n");
|
||
|
break;
|
||
|
default:
|
||
|
builder.append("joinableValueType: JOINABLE_VALUE_TYPE_UNKNOWN,\n");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Configuration for a property containing a 64-bit integer. */
|
||
|
public static final class LongPropertyConfig extends PropertyConfig {
|
||
|
/**
|
||
|
* Encapsulates the configurations on how AppSearch should query/index these 64-bit
|
||
|
* integers.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@IntDef(value = {INDEXING_TYPE_NONE, INDEXING_TYPE_RANGE})
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
public @interface IndexingType {}
|
||
|
|
||
|
/** Content in this property will not be indexed. */
|
||
|
public static final int INDEXING_TYPE_NONE = 0;
|
||
|
|
||
|
/**
|
||
|
* Content in this property will be indexed and can be fetched via numeric search range
|
||
|
* query.
|
||
|
*
|
||
|
* <p>For example, a property with 1024 should match numeric search range query [0, 2000].
|
||
|
*/
|
||
|
public static final int INDEXING_TYPE_RANGE = 1;
|
||
|
|
||
|
LongPropertyConfig(@NonNull PropertyConfigParcel propertyConfigParcel) {
|
||
|
super(propertyConfigParcel);
|
||
|
}
|
||
|
|
||
|
/** Returns how the property is indexed. */
|
||
|
@IndexingType
|
||
|
public int getIndexingType() {
|
||
|
PropertyConfigParcel.IntegerIndexingConfigParcel indexingConfigParcel =
|
||
|
mPropertyConfigParcel.getIntegerIndexingConfigParcel();
|
||
|
if (indexingConfigParcel == null) {
|
||
|
return INDEXING_TYPE_NONE;
|
||
|
}
|
||
|
return indexingConfigParcel.getIndexingType();
|
||
|
}
|
||
|
|
||
|
/** Builder for {@link LongPropertyConfig}. */
|
||
|
public static final class Builder {
|
||
|
private final String mPropertyName;
|
||
|
private String mDescription = "";
|
||
|
@Cardinality private int mCardinality = CARDINALITY_OPTIONAL;
|
||
|
@IndexingType private int mIndexingType = INDEXING_TYPE_NONE;
|
||
|
|
||
|
/** Creates a new {@link LongPropertyConfig.Builder}. */
|
||
|
public Builder(@NonNull String propertyName) {
|
||
|
mPropertyName = Objects.requireNonNull(propertyName);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets a natural language description of this property.
|
||
|
*
|
||
|
* <p>For more details about the description field, see {@link
|
||
|
* AppSearchSchema.PropertyConfig#getDescription}.
|
||
|
*/
|
||
|
@FlaggedApi(Flags.FLAG_ENABLE_APP_FUNCTIONS)
|
||
|
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
|
||
|
@NonNull
|
||
|
public LongPropertyConfig.Builder setDescription(@NonNull String description) {
|
||
|
mDescription = Objects.requireNonNull(description);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the cardinality of the property (whether it is optional, required or repeated).
|
||
|
*
|
||
|
* <p>If this method is not called, the default cardinality is {@link
|
||
|
* PropertyConfig#CARDINALITY_OPTIONAL}.
|
||
|
*/
|
||
|
@CanIgnoreReturnValue
|
||
|
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
|
||
|
@NonNull
|
||
|
public LongPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
|
||
|
Preconditions.checkArgumentInRange(
|
||
|
cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
|
||
|
mCardinality = cardinality;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Configures how a property should be indexed so that it can be retrieved by queries.
|
||
|
*
|
||
|
* <p>If this method is not called, the default indexing type is {@link
|
||
|
* LongPropertyConfig#INDEXING_TYPE_NONE}, so that it will not be indexed and cannot be
|
||
|
* matched by queries.
|
||
|
*/
|
||
|
@CanIgnoreReturnValue
|
||
|
@NonNull
|
||
|
public LongPropertyConfig.Builder setIndexingType(@IndexingType int indexingType) {
|
||
|
Preconditions.checkArgumentInRange(
|
||
|
indexingType, INDEXING_TYPE_NONE, INDEXING_TYPE_RANGE, "indexingType");
|
||
|
mIndexingType = indexingType;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/** Constructs a new {@link LongPropertyConfig} from the contents of this builder. */
|
||
|
@NonNull
|
||
|
public LongPropertyConfig build() {
|
||
|
return new LongPropertyConfig(
|
||
|
PropertyConfigParcel.createForLong(
|
||
|
mPropertyName, mDescription, mCardinality, mIndexingType));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Appends a debug string for the {@link LongPropertyConfig} instance to the given string
|
||
|
* builder.
|
||
|
*
|
||
|
* <p>This appends fields specific to a {@link LongPropertyConfig} instance.
|
||
|
*
|
||
|
* @param builder the builder to append to.
|
||
|
*/
|
||
|
void appendLongPropertyConfigFields(@NonNull IndentingStringBuilder builder) {
|
||
|
switch (getIndexingType()) {
|
||
|
case AppSearchSchema.LongPropertyConfig.INDEXING_TYPE_NONE:
|
||
|
builder.append("indexingType: INDEXING_TYPE_NONE,\n");
|
||
|
break;
|
||
|
case AppSearchSchema.LongPropertyConfig.INDEXING_TYPE_RANGE:
|
||
|
builder.append("indexingType: INDEXING_TYPE_RANGE,\n");
|
||
|
break;
|
||
|
default:
|
||
|
builder.append("indexingType: INDEXING_TYPE_UNKNOWN,\n");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Configuration for a property containing a double-precision decimal number. */
|
||
|
public static final class DoublePropertyConfig extends PropertyConfig {
|
||
|
DoublePropertyConfig(@NonNull PropertyConfigParcel propertyConfigParcel) {
|
||
|
super(propertyConfigParcel);
|
||
|
}
|
||
|
|
||
|
/** Builder for {@link DoublePropertyConfig}. */
|
||
|
public static final class Builder {
|
||
|
private final String mPropertyName;
|
||
|
private String mDescription = "";
|
||
|
@Cardinality private int mCardinality = CARDINALITY_OPTIONAL;
|
||
|
|
||
|
/** Creates a new {@link DoublePropertyConfig.Builder}. */
|
||
|
public Builder(@NonNull String propertyName) {
|
||
|
mPropertyName = Objects.requireNonNull(propertyName);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets a natural language description of this property.
|
||
|
*
|
||
|
* <p>For more details about the description field, see {@link
|
||
|
* AppSearchSchema.PropertyConfig#getDescription}.
|
||
|
*/
|
||
|
@FlaggedApi(Flags.FLAG_ENABLE_APP_FUNCTIONS)
|
||
|
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
|
||
|
@NonNull
|
||
|
public DoublePropertyConfig.Builder setDescription(@NonNull String description) {
|
||
|
mDescription = Objects.requireNonNull(description);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the cardinality of the property (whether it is optional, required or repeated).
|
||
|
*
|
||
|
* <p>If this method is not called, the default cardinality is {@link
|
||
|
* PropertyConfig#CARDINALITY_OPTIONAL}.
|
||
|
*/
|
||
|
@CanIgnoreReturnValue
|
||
|
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
|
||
|
@NonNull
|
||
|
public DoublePropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
|
||
|
Preconditions.checkArgumentInRange(
|
||
|
cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
|
||
|
mCardinality = cardinality;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/** Constructs a new {@link DoublePropertyConfig} from the contents of this builder. */
|
||
|
@NonNull
|
||
|
public DoublePropertyConfig build() {
|
||
|
return new DoublePropertyConfig(
|
||
|
PropertyConfigParcel.createForDouble(
|
||
|
mPropertyName, mDescription, mCardinality));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Configuration for a property containing a boolean. */
|
||
|
public static final class BooleanPropertyConfig extends PropertyConfig {
|
||
|
BooleanPropertyConfig(@NonNull PropertyConfigParcel propertyConfigParcel) {
|
||
|
super(propertyConfigParcel);
|
||
|
}
|
||
|
|
||
|
/** Builder for {@link BooleanPropertyConfig}. */
|
||
|
public static final class Builder {
|
||
|
private final String mPropertyName;
|
||
|
private String mDescription = "";
|
||
|
@Cardinality private int mCardinality = CARDINALITY_OPTIONAL;
|
||
|
|
||
|
/** Creates a new {@link BooleanPropertyConfig.Builder}. */
|
||
|
public Builder(@NonNull String propertyName) {
|
||
|
mPropertyName = Objects.requireNonNull(propertyName);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets a natural language description of this property.
|
||
|
*
|
||
|
* <p>For more details about the description field, see {@link
|
||
|
* AppSearchSchema.PropertyConfig#getDescription}.
|
||
|
*/
|
||
|
@FlaggedApi(Flags.FLAG_ENABLE_APP_FUNCTIONS)
|
||
|
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
|
||
|
@NonNull
|
||
|
public BooleanPropertyConfig.Builder setDescription(@NonNull String description) {
|
||
|
mDescription = Objects.requireNonNull(description);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the cardinality of the property (whether it is optional, required or repeated).
|
||
|
*
|
||
|
* <p>If this method is not called, the default cardinality is {@link
|
||
|
* PropertyConfig#CARDINALITY_OPTIONAL}.
|
||
|
*/
|
||
|
@CanIgnoreReturnValue
|
||
|
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
|
||
|
@NonNull
|
||
|
public BooleanPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
|
||
|
Preconditions.checkArgumentInRange(
|
||
|
cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
|
||
|
mCardinality = cardinality;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/** Constructs a new {@link BooleanPropertyConfig} from the contents of this builder. */
|
||
|
@NonNull
|
||
|
public BooleanPropertyConfig build() {
|
||
|
return new BooleanPropertyConfig(
|
||
|
PropertyConfigParcel.createForBoolean(
|
||
|
mPropertyName, mDescription, mCardinality));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Configuration for a property containing a byte array. */
|
||
|
public static final class BytesPropertyConfig extends PropertyConfig {
|
||
|
BytesPropertyConfig(@NonNull PropertyConfigParcel propertyConfigParcel) {
|
||
|
super(propertyConfigParcel);
|
||
|
}
|
||
|
|
||
|
/** Builder for {@link BytesPropertyConfig}. */
|
||
|
public static final class Builder {
|
||
|
private final String mPropertyName;
|
||
|
private String mDescription = "";
|
||
|
@Cardinality private int mCardinality = CARDINALITY_OPTIONAL;
|
||
|
|
||
|
/** Creates a new {@link BytesPropertyConfig.Builder}. */
|
||
|
public Builder(@NonNull String propertyName) {
|
||
|
mPropertyName = Objects.requireNonNull(propertyName);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets a natural language description of this property.
|
||
|
*
|
||
|
* <p>For more details about the description field, see {@link
|
||
|
* AppSearchSchema.PropertyConfig#getDescription}.
|
||
|
*/
|
||
|
@FlaggedApi(Flags.FLAG_ENABLE_APP_FUNCTIONS)
|
||
|
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
|
||
|
@NonNull
|
||
|
public BytesPropertyConfig.Builder setDescription(@NonNull String description) {
|
||
|
mDescription = Objects.requireNonNull(description);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the cardinality of the property (whether it is optional, required or repeated).
|
||
|
*
|
||
|
* <p>If this method is not called, the default cardinality is {@link
|
||
|
* PropertyConfig#CARDINALITY_OPTIONAL}.
|
||
|
*/
|
||
|
@CanIgnoreReturnValue
|
||
|
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
|
||
|
@NonNull
|
||
|
public BytesPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
|
||
|
Preconditions.checkArgumentInRange(
|
||
|
cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
|
||
|
mCardinality = cardinality;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/** Constructs a new {@link BytesPropertyConfig} from the contents of this builder. */
|
||
|
@NonNull
|
||
|
public BytesPropertyConfig build() {
|
||
|
return new BytesPropertyConfig(
|
||
|
PropertyConfigParcel.createForBytes(
|
||
|
mPropertyName, mDescription, mCardinality));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Configuration for a property containing another Document. */
|
||
|
public static final class DocumentPropertyConfig extends PropertyConfig {
|
||
|
DocumentPropertyConfig(@NonNull PropertyConfigParcel propertyConfigParcel) {
|
||
|
super(propertyConfigParcel);
|
||
|
}
|
||
|
|
||
|
/** Returns the logical schema-type of the contents of this document property. */
|
||
|
@NonNull
|
||
|
public String getSchemaType() {
|
||
|
return Objects.requireNonNull(mPropertyConfigParcel.getSchemaType());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether properties in the nested document should be indexed according to that
|
||
|
* document's schema.
|
||
|
*
|
||
|
* <p>If false, the nested document's properties are not indexed regardless of its own
|
||
|
* schema.
|
||
|
*
|
||
|
* @see DocumentPropertyConfig.Builder#addIndexableNestedProperties(Collection) for indexing
|
||
|
* a subset of properties from the nested document.
|
||
|
*/
|
||
|
public boolean shouldIndexNestedProperties() {
|
||
|
DocumentIndexingConfigParcel indexingConfigParcel =
|
||
|
mPropertyConfigParcel.getDocumentIndexingConfigParcel();
|
||
|
if (indexingConfigParcel == null) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return indexingConfigParcel.shouldIndexNestedProperties();
|
||
|
}
|
||
|
|
||
|
/** Returns the list of indexable nested properties for the nested document. */
|
||
|
@FlaggedApi(Flags.FLAG_ENABLE_GET_PARENT_TYPES_AND_INDEXABLE_NESTED_PROPERTIES)
|
||
|
@NonNull
|
||
|
public List<String> getIndexableNestedProperties() {
|
||
|
DocumentIndexingConfigParcel indexingConfigParcel =
|
||
|
mPropertyConfigParcel.getDocumentIndexingConfigParcel();
|
||
|
if (indexingConfigParcel == null) {
|
||
|
return Collections.emptyList();
|
||
|
}
|
||
|
|
||
|
List<String> indexableNestedPropertiesList =
|
||
|
indexingConfigParcel.getIndexableNestedPropertiesList();
|
||
|
if (indexableNestedPropertiesList == null) {
|
||
|
return Collections.emptyList();
|
||
|
}
|
||
|
|
||
|
return Collections.unmodifiableList(indexableNestedPropertiesList);
|
||
|
}
|
||
|
|
||
|
/** Builder for {@link DocumentPropertyConfig}. */
|
||
|
public static final class Builder {
|
||
|
private final String mPropertyName;
|
||
|
private final String mSchemaType;
|
||
|
private String mDescription = "";
|
||
|
@Cardinality private int mCardinality = CARDINALITY_OPTIONAL;
|
||
|
private boolean mShouldIndexNestedProperties = false;
|
||
|
private final Set<String> mIndexableNestedPropertiesList = new ArraySet<>();
|
||
|
|
||
|
/**
|
||
|
* Creates a new {@link DocumentPropertyConfig.Builder}.
|
||
|
*
|
||
|
* @param propertyName The logical name of the property in the schema, which will be
|
||
|
* used as the key for this property in {@link
|
||
|
* GenericDocument.Builder#setPropertyDocument}.
|
||
|
* @param schemaType The type of documents which will be stored in this property.
|
||
|
* Documents of different types cannot be mixed into a single property.
|
||
|
*/
|
||
|
public Builder(@NonNull String propertyName, @NonNull String schemaType) {
|
||
|
mPropertyName = Objects.requireNonNull(propertyName);
|
||
|
mSchemaType = Objects.requireNonNull(schemaType);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets a natural language description of this property.
|
||
|
*
|
||
|
* <p>For more details about the description field, see {@link
|
||
|
* AppSearchSchema.PropertyConfig#getDescription}.
|
||
|
*/
|
||
|
@FlaggedApi(Flags.FLAG_ENABLE_APP_FUNCTIONS)
|
||
|
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
|
||
|
@NonNull
|
||
|
public DocumentPropertyConfig.Builder setDescription(@NonNull String description) {
|
||
|
mDescription = Objects.requireNonNull(description);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the cardinality of the property (whether it is optional, required or repeated).
|
||
|
*
|
||
|
* <p>If this method is not called, the default cardinality is {@link
|
||
|
* PropertyConfig#CARDINALITY_OPTIONAL}.
|
||
|
*/
|
||
|
@CanIgnoreReturnValue
|
||
|
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
|
||
|
@NonNull
|
||
|
public DocumentPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
|
||
|
Preconditions.checkArgumentInRange(
|
||
|
cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
|
||
|
mCardinality = cardinality;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Configures whether properties in the nested document should be indexed according to
|
||
|
* that document's schema.
|
||
|
*
|
||
|
* <p>If false, the nested document's properties are not indexed regardless of its own
|
||
|
* schema.
|
||
|
*
|
||
|
* <p>To index a subset of properties from the nested document, set this to false and
|
||
|
* use {@link #addIndexableNestedProperties(Collection)}.
|
||
|
*/
|
||
|
@CanIgnoreReturnValue
|
||
|
@NonNull
|
||
|
public DocumentPropertyConfig.Builder setShouldIndexNestedProperties(
|
||
|
boolean indexNestedProperties) {
|
||
|
mShouldIndexNestedProperties = indexNestedProperties;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds one or more properties for indexing from the nested document property.
|
||
|
*
|
||
|
* @see #addIndexableNestedProperties(Collection)
|
||
|
*/
|
||
|
@FlaggedApi(Flags.FLAG_ENABLE_GET_PARENT_TYPES_AND_INDEXABLE_NESTED_PROPERTIES)
|
||
|
@CanIgnoreReturnValue
|
||
|
@NonNull
|
||
|
public DocumentPropertyConfig.Builder addIndexableNestedProperties(
|
||
|
@NonNull String... indexableNestedProperties) {
|
||
|
Objects.requireNonNull(indexableNestedProperties);
|
||
|
return addIndexableNestedProperties(Arrays.asList(indexableNestedProperties));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds one or more property paths for indexing from the nested document property.
|
||
|
*
|
||
|
* @see #addIndexableNestedProperties(Collection)
|
||
|
*/
|
||
|
@FlaggedApi(Flags.FLAG_ENABLE_GET_PARENT_TYPES_AND_INDEXABLE_NESTED_PROPERTIES)
|
||
|
@CanIgnoreReturnValue
|
||
|
@SuppressLint("MissingGetterMatchingBuilder")
|
||
|
@NonNull
|
||
|
public DocumentPropertyConfig.Builder addIndexableNestedPropertyPaths(
|
||
|
@NonNull PropertyPath... indexableNestedPropertyPaths) {
|
||
|
Objects.requireNonNull(indexableNestedPropertyPaths);
|
||
|
return addIndexableNestedPropertyPaths(Arrays.asList(indexableNestedPropertyPaths));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds one or more properties for indexing from the nested document. The added property
|
||
|
* will be indexed according to that property's indexing configurations in the
|
||
|
* document's schema definition. All properties in this list will consume a sectionId
|
||
|
* regardless of its actual indexing config -- this includes properties added that do
|
||
|
* not actually exist, as well as properties that are not set as indexable in the nested
|
||
|
* schema type.
|
||
|
*
|
||
|
* <p>Input strings should follow the format of the property path for the nested
|
||
|
* property, with '.' as the path separator. This nested document's property name should
|
||
|
* not be included in the property path.
|
||
|
*
|
||
|
* <p>Ex. Consider an 'Organization' schema type which defines a nested document
|
||
|
* property 'address' (Address schema type), where Address has a nested document
|
||
|
* property 'country' (Country schema type with string 'name' property), and a string
|
||
|
* 'street' property. The 'street' and 'country's name' properties from the 'address'
|
||
|
* document property can be indexed for the 'Organization' schema type by calling:
|
||
|
*
|
||
|
* <pre>{@code
|
||
|
* OrganizationSchema.addProperty(
|
||
|
* new DocumentPropertyConfig.Builder("address", "Address")
|
||
|
* .addIndexableNestedProperties("street", "country.name")
|
||
|
* .build()).
|
||
|
* }</pre>
|
||
|
*
|
||
|
* <p>{@link DocumentPropertyConfig.Builder#setShouldIndexNestedProperties} is required
|
||
|
* to be false if any indexable nested property is added this way for the document
|
||
|
* property. Attempting to build a DocumentPropertyConfig when this is not true throws
|
||
|
* {@link IllegalArgumentException}.
|
||
|
*/
|
||
|
@CanIgnoreReturnValue
|
||
|
@NonNull
|
||
|
public DocumentPropertyConfig.Builder addIndexableNestedProperties(
|
||
|
@NonNull Collection<String> indexableNestedProperties) {
|
||
|
Objects.requireNonNull(indexableNestedProperties);
|
||
|
mIndexableNestedPropertiesList.addAll(indexableNestedProperties);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds one or more property paths for indexing from the nested document property.
|
||
|
*
|
||
|
* @see #addIndexableNestedProperties(Collection)
|
||
|
*/
|
||
|
@FlaggedApi(Flags.FLAG_ENABLE_GET_PARENT_TYPES_AND_INDEXABLE_NESTED_PROPERTIES)
|
||
|
@CanIgnoreReturnValue
|
||
|
@SuppressLint("MissingGetterMatchingBuilder")
|
||
|
@NonNull
|
||
|
public DocumentPropertyConfig.Builder addIndexableNestedPropertyPaths(
|
||
|
@NonNull Collection<PropertyPath> indexableNestedPropertyPaths) {
|
||
|
Objects.requireNonNull(indexableNestedPropertyPaths);
|
||
|
List<PropertyPath> propertyPathList = new ArrayList<>(indexableNestedPropertyPaths);
|
||
|
for (int i = 0; i < indexableNestedPropertyPaths.size(); i++) {
|
||
|
mIndexableNestedPropertiesList.add(propertyPathList.get(i).toString());
|
||
|
}
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Constructs a new {@link PropertyConfig} from the contents of this builder.
|
||
|
*
|
||
|
* @throws IllegalArgumentException if the provided PropertyConfig sets {@link
|
||
|
* #shouldIndexNestedProperties()} to true and has one or more properties defined
|
||
|
* using {@link #addIndexableNestedProperties(Collection)}.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public DocumentPropertyConfig build() {
|
||
|
if (mShouldIndexNestedProperties && !mIndexableNestedPropertiesList.isEmpty()) {
|
||
|
throw new IllegalArgumentException(
|
||
|
"DocumentIndexingConfig#shouldIndexNestedProperties is required "
|
||
|
+ "to be false when one or more indexableNestedProperties are "
|
||
|
+ "provided.");
|
||
|
}
|
||
|
return new DocumentPropertyConfig(
|
||
|
PropertyConfigParcel.createForDocument(
|
||
|
mPropertyName,
|
||
|
mDescription,
|
||
|
mCardinality,
|
||
|
mSchemaType,
|
||
|
new DocumentIndexingConfigParcel(
|
||
|
mShouldIndexNestedProperties,
|
||
|
new ArrayList<>(mIndexableNestedPropertiesList))));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Appends a debug string for the {@link DocumentPropertyConfig} instance to the given
|
||
|
* string builder.
|
||
|
*
|
||
|
* <p>This appends fields specific to a {@link DocumentPropertyConfig} instance.
|
||
|
*
|
||
|
* @param builder the builder to append to.
|
||
|
*/
|
||
|
void appendDocumentPropertyConfigFields(@NonNull IndentingStringBuilder builder) {
|
||
|
builder.append("shouldIndexNestedProperties: ")
|
||
|
.append(shouldIndexNestedProperties())
|
||
|
.append(",\n");
|
||
|
|
||
|
builder.append("indexableNestedProperties: ")
|
||
|
.append(getIndexableNestedProperties())
|
||
|
.append(",\n");
|
||
|
|
||
|
builder.append("schemaType: \"").append(getSchemaType()).append("\",\n");
|
||
|
}
|
||
|
}
|
||
|
}
|