1 /* 2 * Copyright (C) 2019 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 com.android.car.telephony.common; 18 19 import android.net.Uri; 20 21 import androidx.annotation.NonNull; 22 import androidx.annotation.Nullable; 23 24 import java.util.ArrayList; 25 import java.util.HashSet; 26 import java.util.List; 27 import java.util.Set; 28 import java.util.stream.Collectors; 29 30 /** Represents query parameters. */ 31 public class QueryParam { 32 33 /** Creates a provider always returning the same query param instance. */ of(final QueryParam queryParam)34 public static Provider of(final QueryParam queryParam) { 35 return () -> queryParam; 36 } 37 38 /** 39 * An object capable of providing instances of {@link QueryParam}. It can be used in two 40 * circumstances: 41 * <ul> 42 * <li>Return the same instance every time calling the getter. 43 * <li>Return an updated instance or create a new instance every time calling the getter. 44 * 45 * @deprecated use {@link QueryBuilder}. 46 */ 47 @Deprecated 48 public interface Provider { 49 50 /** Returns an instance of query params. */ 51 @Nullable getQueryParam()52 QueryParam getQueryParam(); 53 } 54 55 /** Used by {@link ObservableAsyncQuery#startQuery()} as query param. */ 56 final Uri mUri; 57 /** Used by {@link ObservableAsyncQuery#startQuery()} as query param. */ 58 final String[] mProjection; 59 /** Used by {@link ObservableAsyncQuery#startQuery()} as query param. */ 60 final String mSelection; 61 /** Used by {@link ObservableAsyncQuery#startQuery()} as query param. */ 62 final String[] mSelectionArgs; 63 /** Used by {@link ObservableAsyncQuery#startQuery()} as query param. */ 64 final String mOrderBy; 65 /** Used by {@link ObservableAsyncQuery#startQuery()} to check query permission. */ 66 final String mPermission; 67 QueryParam( @onNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String orderBy, @NonNull String permission)68 public QueryParam( 69 @NonNull Uri uri, 70 @Nullable String[] projection, 71 @Nullable String selection, 72 @Nullable String[] selectionArgs, 73 @Nullable String orderBy, 74 @NonNull String permission) { 75 mUri = uri; 76 mProjection = projection; 77 mSelection = selection; 78 mSelectionArgs = selectionArgs; 79 mOrderBy = orderBy; 80 mPermission = permission; 81 } 82 83 /** 84 * Builds the {@link QueryParam}. 85 */ 86 public static class QueryBuilder { 87 public static final String AND = "AND"; 88 public static final String OR = "OR"; 89 90 static final String ORDER_ASC = "ASC"; 91 static final String ORDER_DESC = "DESC"; 92 93 private final Uri mUri; 94 95 private String mPermission; 96 97 private Condition mWhere = Condition.emptyCondition(); 98 private final List<String> mOrderBy = new ArrayList<>(); 99 private final Set<String> mProjectionColumns = new HashSet<>(); 100 101 /** 102 * 103 * @param contentUri the content uri for querying. 104 */ QueryBuilder(Uri contentUri)105 public QueryBuilder(Uri contentUri) { 106 mUri = contentUri; 107 } 108 109 /** 110 * Specify the projection column. Calling this function multiple times to add more columns 111 * to the projection. When the same column is added multiple times, only one column will 112 * be remembered. 113 */ project(String columnName)114 public QueryBuilder project(String columnName) { 115 mProjectionColumns.add(columnName); 116 return this; 117 } 118 119 /** 120 * Selects all columns for projection. This function call will override all previous 121 * {@link #project(String)} call. Calling this function is optional. By default, all 122 * columns will be selected. 123 */ projectAll()124 public QueryBuilder projectAll() { 125 mProjectionColumns.clear(); 126 return this; 127 } 128 129 /** 130 * Specify the select condition. 131 * 132 * @see Condition 133 */ where(@onNull Condition condition)134 public QueryBuilder where(@NonNull Condition condition) { 135 mWhere = condition; 136 return this; 137 } 138 orderBy(String column, String order)139 private QueryBuilder orderBy(String column, String order) { 140 mOrderBy.add(column + " " + order); 141 return this; 142 } 143 144 /** 145 * Sorts the query result in an ascending order based on the given column. 146 * Calling this function multiple times will add additional orders. 147 * The order of calling this method matters. 148 * @param column The column to be order by. 149 */ orderAscBy(String column)150 public QueryBuilder orderAscBy(String column) { 151 return orderBy(column, ORDER_ASC); 152 } 153 154 /** 155 * Sorts the query result in an descending order based on the given column. 156 * Calling this function multiple times will add additional orders. 157 * The order of calling this method matters. 158 * @param column The column to be order by. 159 */ orderDescBy(String column)160 public QueryBuilder orderDescBy(String column) { 161 return orderBy(column, ORDER_DESC); 162 } 163 164 /** 165 * Specify the column and order all together. 166 * @param orderBy Should follow "{column} {order}" pattern. 167 */ orderBy(String orderBy)168 public QueryBuilder orderBy(String orderBy) { 169 mOrderBy.add(orderBy); 170 return this; 171 } 172 173 /**Specifies the permission needed for this query.*/ checkPermission(@onNull String permission)174 public QueryBuilder checkPermission(@NonNull String permission) { 175 mPermission = permission; 176 return this; 177 } 178 /** 179 * Builds the selection condition. Use {@link #is(String, String, Object)} to create an 180 * initial condition. 181 */ 182 public static class Condition { 183 private String mSelection = ""; 184 private List<String> mArgs = new ArrayList<>(); 185 Condition()186 private Condition() {} 187 emptyCondition()188 private static Condition emptyCondition() { 189 Condition condition = new Condition(); 190 condition.mSelection = null; 191 return condition; 192 } 193 194 /** 195 * Creates the inital condition. 196 */ is(String columnName, String operator, @NonNull Object value)197 public static Condition is(String columnName, String operator, @NonNull Object value) { 198 Condition condition = new Condition(); 199 condition.mSelection = condition.toSelectionString(columnName, operator); 200 condition.mArgs.add(value.toString()); 201 return condition; 202 } 203 204 /** 205 * Appends an "AND" condition to the existing conditions. 206 */ and(String columnName, String operator, @NonNull Object value)207 public Condition and(String columnName, String operator, @NonNull Object value) { 208 mSelection += wrapWithSpaces(AND) + toSelectionString(columnName, operator); 209 mArgs.add(value.toString()); 210 return this; 211 } 212 213 /** 214 * Appends an "OR" condition to the existing conditions. 215 */ or(String columnName, String operator, @NonNull Object value)216 public Condition or(String columnName, String operator, @NonNull Object value) { 217 mSelection += wrapWithSpaces(OR) + toSelectionString(columnName, operator); 218 mArgs.add(value.toString()); 219 return this; 220 } 221 getSelection()222 public String getSelection() { 223 return mSelection; 224 } 225 getWhereArgs()226 public String[] getWhereArgs() { 227 return mArgs.stream().toArray(String[]::new); 228 } 229 toSelectionString(String columnName, String op)230 static String toSelectionString(String columnName, String op) { 231 return columnName + " " + op + " ?"; 232 } 233 wrapWithSpaces(String s)234 static String wrapWithSpaces(String s) { 235 return " " + s + " "; 236 } 237 } 238 239 /** 240 * Builds the QueryParam. 241 */ toQueryParam()242 public QueryParam toQueryParam() { 243 String[] projection = mProjectionColumns.isEmpty() 244 ? null 245 : mProjectionColumns.stream().toArray(String[]::new); 246 String orderBy = mOrderBy.stream().collect(Collectors.joining(",")); 247 248 return new QueryParam( 249 mUri, 250 projection, 251 mWhere.getSelection(), 252 mWhere.getWhereArgs(), 253 orderBy, 254 mPermission); 255 } 256 } 257 } 258