1 /* 2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.app.appsearch.ast.operators; 18 19 import android.annotation.FlaggedApi; 20 import android.annotation.IntDef; 21 import android.app.appsearch.PropertyPath; 22 import android.app.appsearch.ast.Node; 23 24 import com.android.appsearch.flags.Flags; 25 import com.android.internal.util.Preconditions; 26 27 import org.jspecify.annotations.NonNull; 28 29 import java.lang.annotation.Retention; 30 import java.lang.annotation.RetentionPolicy; 31 import java.util.Objects; 32 33 /** 34 * {@link Node} that represents a numeric search expression between a property and a numeric value. 35 * 36 * <p>All numeric search expressions are represented by this {@link Node} by passing in a {@link 37 * Comparator} that represent one of the comparator operators available in the query language, a 38 * {@link PropertyPath} representing the property, and a numeric value to compare the property 39 * against. 40 * 41 * <p>This node represents comparators as defined in the <a 42 * href="https://google.aip.dev/assets/misc/ebnf-filtering.txt">Google AIP EBNF Filtering 43 * Definition</a>. 44 */ 45 @FlaggedApi(Flags.FLAG_ENABLE_ABSTRACT_SYNTAX_TREES) 46 public final class ComparatorNode implements Node { 47 /** 48 * Enums representing different comparators for numeric search expressions in the query 49 * language. 50 * 51 * @hide 52 */ 53 @Retention(RetentionPolicy.SOURCE) 54 @IntDef( 55 value = { 56 EQUALS, 57 LESS_THAN, 58 LESS_EQUALS, 59 GREATER_THAN, 60 GREATER_EQUALS, 61 }) 62 public @interface Comparator {} 63 64 public static final int EQUALS = 0; 65 public static final int LESS_THAN = 1; 66 public static final int LESS_EQUALS = 2; 67 public static final int GREATER_THAN = 3; 68 public static final int GREATER_EQUALS = 4; 69 70 private static final int MAX_COMPARATOR_VALUE = GREATER_EQUALS; 71 72 private @Comparator int mComparator; 73 private PropertyPath mPropertyPath; 74 private long mValue; 75 76 /** 77 * Construct a {@link Node} representing a numeric search expression between a property and a 78 * numeric value. 79 * 80 * @param comparator An {@code IntDef} representing what comparison is being made. 81 * @param propertyPath A {@link PropertyPath} that is property being compared i.e. the left hand 82 * side of the comparison. 83 * @param value The numeric value being compared i.e. the right hand side of the comparison. 84 */ ComparatorNode( @omparator int comparator, @NonNull PropertyPath propertyPath, long value)85 public ComparatorNode( 86 @Comparator int comparator, @NonNull PropertyPath propertyPath, long value) { 87 Preconditions.checkArgumentInRange( 88 comparator, EQUALS, MAX_COMPARATOR_VALUE, "Comparator intDef"); 89 mComparator = comparator; 90 mPropertyPath = Objects.requireNonNull(propertyPath); 91 mValue = value; 92 } 93 94 /** Get the {@code @Comparator} used in the comparison. */ 95 @Comparator getComparator()96 public int getComparator() { 97 return mComparator; 98 } 99 100 /** 101 * Get the {@code PropertyPath} being compared. 102 * 103 * <p>I.e. left hand side of the comparison represented by this node. 104 */ getPropertyPath()105 public @NonNull PropertyPath getPropertyPath() { 106 return mPropertyPath; 107 } 108 109 /** 110 * Get the numeric value being compared. 111 * 112 * <p>I.e. the right hand side of the comparison represented by this node. 113 */ getValue()114 public long getValue() { 115 return mValue; 116 } 117 118 /** Set the {@code @Comparator} being used to compare the {@code PropertyPath} and value. */ setComparator(@omparator int comparator)119 public void setComparator(@Comparator int comparator) { 120 Preconditions.checkArgumentInRange( 121 comparator, EQUALS, MAX_COMPARATOR_VALUE, "Comparator intDef"); 122 mComparator = comparator; 123 } 124 125 /** Set the {@code PropertyPath} being compared, i.e. the left side of the comparison. */ setPropertyPath(@onNull PropertyPath propertyPath)126 public void setPropertyPath(@NonNull PropertyPath propertyPath) { 127 mPropertyPath = Objects.requireNonNull(propertyPath); 128 } 129 130 /** Set the numeric value being compared, i.e. the right side of the comparison. */ setValue(long value)131 public void setValue(long value) { 132 mValue = value; 133 } 134 135 /** 136 * Get the query string representation of {@link ComparatorNode}. 137 * 138 * <p>The string representation is the string representation of the property path joined from 139 * the left to the value being compared with the string representation of the {@link 140 * Comparator}. 141 */ 142 @Override toString()143 public @NonNull String toString() { 144 String comparatorString = ""; 145 switch (mComparator) { 146 case ComparatorNode.EQUALS: 147 comparatorString = "=="; 148 break; 149 case ComparatorNode.LESS_THAN: 150 comparatorString = "<"; 151 break; 152 case ComparatorNode.LESS_EQUALS: 153 comparatorString = "<="; 154 break; 155 case ComparatorNode.GREATER_THAN: 156 comparatorString = ">"; 157 break; 158 case ComparatorNode.GREATER_EQUALS: 159 comparatorString = ">="; 160 } 161 // Equivalent in behavior but more efficient than 162 // String.format("(%s %s %s)", mPropertyPath, comparatorString, mValue); 163 return "(" + mPropertyPath + " " + comparatorString + " " + mValue + ")"; 164 } 165 166 @Override equals(Object o)167 public boolean equals(Object o) { 168 if (this == o) return true; 169 if (!(o instanceof ComparatorNode)) return false; 170 ComparatorNode that = (ComparatorNode) o; 171 return mComparator == that.mComparator 172 && mValue == that.mValue 173 && Objects.equals(mPropertyPath, that.mPropertyPath); 174 } 175 176 @Override hashCode()177 public int hashCode() { 178 return Objects.hash(mComparator, mPropertyPath, mValue); 179 } 180 } 181