1/*
2 * Copyright (C) 2010 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
17package com.android.internal.content;
18
19import android.content.ContentValues;
20import android.database.Cursor;
21import android.database.sqlite.SQLiteDatabase;
22import android.text.TextUtils;
23
24import java.util.ArrayList;
25
26/**
27 * Helper for building selection clauses for {@link SQLiteDatabase}. Each
28 * appended clause is combined using {@code AND}. This class is <em>not</em>
29 * thread safe.
30 *
31 * @hide
32 */
33public class SelectionBuilder {
34    private StringBuilder mSelection = new StringBuilder();
35    private ArrayList<String> mSelectionArgs = new ArrayList<String>();
36
37    /**
38     * Reset any internal state, allowing this builder to be recycled.
39     */
40    public SelectionBuilder reset() {
41        mSelection.setLength(0);
42        mSelectionArgs.clear();
43        return this;
44    }
45
46    /**
47     * Append the given selection clause to the internal state. Each clause is
48     * surrounded with parenthesis and combined using {@code AND}.
49     */
50    public SelectionBuilder append(String selection, Object... selectionArgs) {
51        if (TextUtils.isEmpty(selection)) {
52            if (selectionArgs != null && selectionArgs.length > 0) {
53                throw new IllegalArgumentException(
54                        "Valid selection required when including arguments");
55            }
56
57            // Shortcut when clause is empty
58            return this;
59        }
60
61        if (mSelection.length() > 0) {
62            mSelection.append(" AND ");
63        }
64
65        mSelection.append("(").append(selection).append(")");
66        if (selectionArgs != null) {
67            for (Object arg : selectionArgs) {
68                // TODO: switch to storing direct Object instances once
69                // http://b/2464440 is fixed
70                mSelectionArgs.add(String.valueOf(arg));
71            }
72        }
73
74        return this;
75    }
76
77    /**
78     * Return selection string for current internal state.
79     *
80     * @see #getSelectionArgs()
81     */
82    public String getSelection() {
83        return mSelection.toString();
84    }
85
86    /**
87     * Return selection arguments for current internal state.
88     *
89     * @see #getSelection()
90     */
91    public String[] getSelectionArgs() {
92        return mSelectionArgs.toArray(new String[mSelectionArgs.size()]);
93    }
94
95    /**
96     * Execute query using the current internal state as {@code WHERE} clause.
97     * Missing arguments as treated as {@code null}.
98     */
99    public Cursor query(SQLiteDatabase db, String table, String[] columns, String orderBy) {
100        return query(db, table, columns, null, null, orderBy, null);
101    }
102
103    /**
104     * Execute query using the current internal state as {@code WHERE} clause.
105     */
106    public Cursor query(SQLiteDatabase db, String table, String[] columns, String groupBy,
107            String having, String orderBy, String limit) {
108        return db.query(table, columns, getSelection(), getSelectionArgs(), groupBy, having,
109                orderBy, limit);
110    }
111
112    /**
113     * Execute update using the current internal state as {@code WHERE} clause.
114     */
115    public int update(SQLiteDatabase db, String table, ContentValues values) {
116        return db.update(table, values, getSelection(), getSelectionArgs());
117    }
118
119    /**
120     * Execute delete using the current internal state as {@code WHERE} clause.
121     */
122    public int delete(SQLiteDatabase db, String table) {
123        return db.delete(table, getSelection(), getSelectionArgs());
124    }
125}
126