• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 androidx.sqlite.db;
18 
19 import java.util.regex.Pattern;
20 
21 /**
22  * A simple query builder to create SQL SELECT queries.
23  */
24 @SuppressWarnings("unused")
25 public final class SupportSQLiteQueryBuilder {
26     private static final Pattern sLimitPattern =
27             Pattern.compile("\\s*\\d+\\s*(,\\s*\\d+\\s*)?");
28 
29     private boolean mDistinct = false;
30     private final String mTable;
31     private String[] mColumns = null;
32     private String mSelection;
33     private Object[] mBindArgs;
34     private String mGroupBy = null;
35     private String mHaving = null;
36     private String mOrderBy = null;
37     private String mLimit = null;
38 
39     /**
40      * Creates a query for the given table name.
41      *
42      * @param tableName The table name(s) to query.
43      *
44      * @return A builder to create a query.
45      */
builder(String tableName)46     public static SupportSQLiteQueryBuilder builder(String tableName) {
47         return new SupportSQLiteQueryBuilder(tableName);
48     }
49 
SupportSQLiteQueryBuilder(String table)50     private SupportSQLiteQueryBuilder(String table) {
51         mTable = table;
52     }
53 
54     /**
55      * Adds DISTINCT keyword to the query.
56      *
57      * @return this
58      */
distinct()59     public SupportSQLiteQueryBuilder distinct() {
60         mDistinct = true;
61         return this;
62     }
63 
64     /**
65      * Sets the given list of columns as the columns that will be returned.
66      *
67      * @param columns The list of column names that should be returned.
68      *
69      * @return this
70      */
columns(String[] columns)71     public SupportSQLiteQueryBuilder columns(String[] columns) {
72         mColumns = columns;
73         return this;
74     }
75 
76     /**
77      * Sets the arguments for the WHERE clause.
78      *
79      * @param selection The list of selection columns
80      * @param bindArgs The list of bind arguments to match against these columns
81      *
82      * @return this
83      */
selection(String selection, Object[] bindArgs)84     public SupportSQLiteQueryBuilder selection(String selection, Object[] bindArgs) {
85         mSelection = selection;
86         mBindArgs = bindArgs;
87         return this;
88     }
89 
90     /**
91      * Adds a GROUP BY statement.
92      *
93      * @param groupBy The value of the GROUP BY statement.
94      *
95      * @return this
96      */
97     @SuppressWarnings("WeakerAccess")
groupBy(String groupBy)98     public SupportSQLiteQueryBuilder groupBy(String groupBy) {
99         mGroupBy = groupBy;
100         return this;
101     }
102 
103     /**
104      * Adds a HAVING statement. You must also provide {@link #groupBy(String)} for this to work.
105      *
106      * @param having The having clause.
107      *
108      * @return this
109      */
having(String having)110     public SupportSQLiteQueryBuilder having(String having) {
111         mHaving = having;
112         return this;
113     }
114 
115     /**
116      * Adds an ORDER BY statement.
117      *
118      * @param orderBy The order clause.
119      *
120      * @return this
121      */
orderBy(String orderBy)122     public SupportSQLiteQueryBuilder orderBy(String orderBy) {
123         mOrderBy = orderBy;
124         return this;
125     }
126 
127     /**
128      * Adds a LIMIT statement.
129      *
130      * @param limit The limit value.
131      *
132      * @return this
133      */
limit(String limit)134     public SupportSQLiteQueryBuilder limit(String limit) {
135         if (!isEmpty(limit) && !sLimitPattern.matcher(limit).matches()) {
136             throw new IllegalArgumentException("invalid LIMIT clauses:" + limit);
137         }
138         mLimit = limit;
139         return this;
140     }
141 
142     /**
143      * Creates the {@link SupportSQLiteQuery} that can be passed into
144      * {@link SupportSQLiteDatabase#query(SupportSQLiteQuery)}.
145      *
146      * @return a new query
147      */
create()148     public SupportSQLiteQuery create() {
149         if (isEmpty(mGroupBy) && !isEmpty(mHaving)) {
150             throw new IllegalArgumentException(
151                     "HAVING clauses are only permitted when using a groupBy clause");
152         }
153         StringBuilder query = new StringBuilder(120);
154 
155         query.append("SELECT ");
156         if (mDistinct) {
157             query.append("DISTINCT ");
158         }
159         if (mColumns != null && mColumns.length != 0) {
160             appendColumns(query, mColumns);
161         } else {
162             query.append(" * ");
163         }
164         query.append(" FROM ");
165         query.append(mTable);
166         appendClause(query, " WHERE ", mSelection);
167         appendClause(query, " GROUP BY ", mGroupBy);
168         appendClause(query, " HAVING ", mHaving);
169         appendClause(query, " ORDER BY ", mOrderBy);
170         appendClause(query, " LIMIT ", mLimit);
171 
172         return new SimpleSQLiteQuery(query.toString(), mBindArgs);
173     }
174 
appendClause(StringBuilder s, String name, String clause)175     private static void appendClause(StringBuilder s, String name, String clause) {
176         if (!isEmpty(clause)) {
177             s.append(name);
178             s.append(clause);
179         }
180     }
181 
182     /**
183      * Add the names that are non-null in columns to s, separating
184      * them with commas.
185      */
appendColumns(StringBuilder s, String[] columns)186     private static void appendColumns(StringBuilder s, String[] columns) {
187         int n = columns.length;
188 
189         for (int i = 0; i < n; i++) {
190             String column = columns[i];
191             if (i > 0) {
192                 s.append(", ");
193             }
194             s.append(column);
195         }
196         s.append(' ');
197     }
198 
isEmpty(String input)199     private static boolean isEmpty(String input) {
200         return input == null || input.length() == 0;
201     }
202 }
203