summaryrefslogtreecommitdiffstats
path: root/java/com/android/dialer/common/database/Selection.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/android/dialer/common/database/Selection.java')
-rw-r--r--java/com/android/dialer/common/database/Selection.java260
1 files changed, 0 insertions, 260 deletions
diff --git a/java/com/android/dialer/common/database/Selection.java b/java/com/android/dialer/common/database/Selection.java
deleted file mode 100644
index b61472d2f..000000000
--- a/java/com/android/dialer/common/database/Selection.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.dialer.common.database;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import com.android.dialer.common.Assert;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Utility to build SQL selections. Handles string concatenation, nested statements, empty
- * statements, and tracks the selection arguments.
- *
- * <p>A selection can be build from a string, factory methods like {@link #column(String)}, or use
- * {@link Builder} to build complex nested selection with multiple operators. The Selection manages
- * the {@code selection} and {@code selectionArgs} passed into {@link
- * android.content.ContentResolver#query(android.net.Uri, String[], String, String[], String)}.
- *
- * <p>Example:
- *
- * <pre><code>
- * fromString("foo = 1")
- * </code></pre>
- *
- * expands into "(foo = 1)", {}
- *
- * <p>
- *
- * <pre><code>
- * column("foo").is("LIKE", "bar")
- * </code></pre>
- *
- * expands into "(foo LIKE ?)", {"bar"}
- *
- * <p>
- *
- * <pre><code>
- * builder()
- * .and(
- * fromString("foo = ?", "1").buildUpon()
- * .or(column("bar").is("<", 2))
- * .build())
- * .and(not(column("baz").is("!= 3")))
- * .build();
- * </code></pre>
- *
- * expands into "(((foo = ?) OR (bar < ?)) AND (NOT (baz != 3)))", {"1", "2"}
- */
-public final class Selection {
-
- private final String selection;
- private final String[] selectionArgs;
-
- private Selection(@NonNull String selection, @NonNull String[] selectionArgs) {
- this.selection = selection;
- this.selectionArgs = selectionArgs;
- }
-
- @NonNull
- public String getSelection() {
- return selection;
- }
-
- @NonNull
- public String[] getSelectionArgs() {
- return selectionArgs;
- }
-
- public boolean isEmpty() {
- return selection.isEmpty();
- }
-
- /**
- * @return a mutable builder that appends to the selection. The selection will be parenthesized
- * before anything is appended to it.
- */
- @NonNull
- public Builder buildUpon() {
- return new Builder(this);
- }
-
- /** @return a builder that is empty. */
- @NonNull
- public static Builder builder() {
- return new Builder();
- }
-
- /**
- * @return a Selection built from regular selection string/args pair. The result selection will be
- * enclosed in a parenthesis.
- */
- @NonNull
- public static Selection fromString(@Nullable String selection, @Nullable String... args) {
- return new Builder(selection, args).build();
- }
-
- /** @return a selection that is negated */
- @NonNull
- public static Selection not(@NonNull Selection selection) {
- Assert.checkArgument(!selection.isEmpty());
- return fromString("NOT " + selection.getSelection(), selection.getSelectionArgs());
- }
-
- /**
- * Build a selection based on condition upon a column. is() should be called to complete the
- * selection.
- */
- @NonNull
- public static Column column(@NonNull String column) {
- return new Column(column);
- }
-
- /** Helper class to build a selection based on condition upon a column. */
- public static class Column {
-
- @NonNull private final String column;
-
- private Column(@NonNull String column) {
- this.column = Assert.isNotNull(column);
- }
-
- /** Expands to "<column> <operator> ?" and add {@code value} to the arguments. */
- @NonNull
- public Selection is(@NonNull String operator, @NonNull Object value) {
- return fromString(column + " " + Assert.isNotNull(operator) + " ?", value.toString());
- }
-
- /**
- * Expands to "<column> <operator>". {@link #is(String, Object)} should be used if the condition
- * is comparing to a string or a user input value, which must be sanitized.
- */
- @NonNull
- public Selection is(@NonNull String condition) {
- return fromString(column + " " + Assert.isNotNull(condition));
- }
- }
-
- /** Builder for {@link Selection} */
- public static final class Builder {
-
- private final StringBuilder selection = new StringBuilder();
- private final List<String> selectionArgs = new ArrayList<>();
-
- private Builder() {}
-
- private Builder(@Nullable String selection, @Nullable String... args) {
- if (selection == null) {
- return;
- }
- checkArgsCount(selection, args);
- this.selection.append(parenthesized(selection));
- if (args != null) {
- Collections.addAll(selectionArgs, args);
- }
- }
-
- private Builder(@NonNull Selection selection) {
- this.selection.append(selection.getSelection());
- Collections.addAll(selectionArgs, selection.selectionArgs);
- }
-
- @NonNull
- public Selection build() {
- if (selection.length() == 0) {
- return new Selection("", new String[] {});
- }
- return new Selection(
- parenthesized(selection.toString()),
- selectionArgs.toArray(new String[selectionArgs.size()]));
- }
-
- @NonNull
- public Builder and(@NonNull Selection selection) {
- if (selection.isEmpty()) {
- return this;
- }
-
- if (this.selection.length() > 0) {
- this.selection.append(" AND ");
- }
- this.selection.append(selection.getSelection());
- Collections.addAll(selectionArgs, selection.getSelectionArgs());
- return this;
- }
-
- @NonNull
- public Builder or(@NonNull Selection selection) {
- if (selection.isEmpty()) {
- return this;
- }
-
- if (this.selection.length() > 0) {
- this.selection.append(" OR ");
- }
- this.selection.append(selection.getSelection());
- Collections.addAll(selectionArgs, selection.getSelectionArgs());
- return this;
- }
-
- private static void checkArgsCount(@NonNull String selection, @Nullable String... args) {
- int argsInSelection = 0;
- for (int i = 0; i < selection.length(); i++) {
- if (selection.charAt(i) == '?') {
- argsInSelection++;
- }
- }
- Assert.checkArgument(argsInSelection == (args == null ? 0 : args.length));
- }
- }
-
- /**
- * Parenthesized the {@code string}. Will not parenthesized if {@code string} is empty or is
- * already parenthesized (top level parenthesis encloses the whole string).
- */
- @NonNull
- private static String parenthesized(@NonNull String string) {
- if (string.isEmpty()) {
- return "";
- }
- if (!string.startsWith("(")) {
- return "(" + string + ")";
- }
- int depth = 1;
- for (int i = 1; i < string.length() - 1; i++) {
- switch (string.charAt(i)) {
- case '(':
- depth++;
- break;
- case ')':
- depth--;
- if (depth == 0) {
- // First '(' closed before the string has ended,need an additional level of nesting.
- // For example "(A) AND (B)" should become "((A) AND (B))"
- return "(" + string + ")";
- }
- break;
- default:
- continue;
- }
- }
- Assert.checkArgument(depth == 1);
- return string;
- }
-}