Line data Source code
1 : // Copyright (C) 2014 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.index.query; 16 : 17 : import com.google.common.primitives.Ints; 18 : import com.google.gerrit.common.Nullable; 19 : import java.util.regex.Matcher; 20 : import java.util.regex.Pattern; 21 : 22 : public final class RangeUtil { 23 14 : private static final Pattern RANGE_PATTERN = Pattern.compile("(>|>=|=|<|<=|)([+-]?\\d+)$"); 24 : 25 : private RangeUtil() {} 26 : 27 : public static class Range { 28 : /** The prefix of the query, before the range component. */ 29 : public final String prefix; 30 : 31 : /** The minimum value specified in the query, inclusive. */ 32 : public final int min; 33 : 34 : /** The maximum value specified in the query, inclusive. */ 35 : public final int max; 36 : 37 14 : public Range(String prefix, int min, int max) { 38 14 : this.prefix = prefix; 39 14 : this.min = min; 40 14 : this.max = max; 41 14 : } 42 : } 43 : 44 : /** 45 : * Determine the range of values being requested in the given query. 46 : * 47 : * @param rangeQuery the raw query, e.g. "{@code added:>12345}" 48 : * @param minValue the minimum possible value for the field, inclusive 49 : * @param maxValue the maximum possible value for the field, inclusive 50 : * @return the calculated {@link Range}, or null if the query is invalid 51 : */ 52 : @Nullable 53 : public static Range getRange(String rangeQuery, int minValue, int maxValue) { 54 6 : Matcher m = RANGE_PATTERN.matcher(rangeQuery); 55 : String prefix; 56 : String test; 57 : Integer queryInt; 58 6 : if (m.find()) { 59 6 : prefix = rangeQuery.substring(0, m.start()); 60 6 : test = m.group(1); 61 6 : queryInt = value(m.group(2)); 62 6 : if (queryInt == null) { 63 0 : return null; 64 : } 65 : } else { 66 5 : return null; 67 : } 68 : 69 6 : return getRange(prefix, test, queryInt, minValue, maxValue); 70 : } 71 : 72 : /** 73 : * Determine the range of values being requested in the given query. 74 : * 75 : * @param prefix a prefix string which is copied into the range 76 : * @param test the test operator, one of >, >=, =, <, or <= 77 : * @param queryInt the integer being queried 78 : * @param minValue the minimum possible value for the field, inclusive 79 : * @param maxValue the maximum possible value for the field, inclusive 80 : * @return the calculated {@link Range} 81 : */ 82 : public static Range getRange( 83 : String prefix, String test, int queryInt, int minValue, int maxValue) { 84 : int min; 85 : int max; 86 14 : switch (test) { 87 : case "=": 88 : default: 89 14 : min = max = queryInt; 90 14 : break; 91 : case ">": 92 7 : min = Ints.saturatedCast(queryInt + 1L); 93 7 : max = maxValue; 94 7 : break; 95 : case ">=": 96 6 : min = queryInt; 97 6 : max = maxValue; 98 6 : break; 99 : case "<": 100 6 : min = minValue; 101 6 : max = Ints.saturatedCast(queryInt - 1L); 102 6 : break; 103 : case "<=": 104 6 : min = minValue; 105 6 : max = queryInt; 106 : break; 107 : } 108 : 109 : // Ensure that minValue <= min/max <= maxValue. 110 14 : min = Ints.constrainToRange(min, minValue, maxValue); 111 14 : max = Ints.constrainToRange(max, minValue, maxValue); 112 : 113 14 : return new Range(prefix, min, max); 114 : } 115 : 116 : private static Integer value(String value) { 117 6 : if (value.startsWith("+")) { 118 4 : value = value.substring(1); 119 : } 120 6 : return Ints.tryParse(value); 121 : } 122 : }