/*
* Copyright (C) Tony Green, Litepal Framework 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 org.litepal.crud;
import java.util.List;
import org.litepal.tablemanager.Connector;
import org.litepal.util.BaseUtility;
/**
* Allows developers to query tables with cluster style.
*
* @author Tony Green
* @since 1.1
*/
public class ClusterQuery {
/**
* Representing the selected columns in SQL.
*/
String[] mColumns;
/**
* Representing the where clause in SQL.
*/
String[] mConditions;
/**
* Representing the order by clause in SQL.
*/
String mOrderBy;
/**
* Representing the limit clause in SQL.
*/
String mLimit;
/**
* Representing the offset in SQL.
*/
String mOffset;
/**
* Do not allow to create instance by developers.
*/
ClusterQuery() {
}
/**
* Declaring to query which columns in table.
*
* <pre>
* DataSupport.select("name", "age").find(Person.class);
* </pre>
*
* This will find all rows with name and age columns in Person table.
*
* @param columns
* A String array of which columns to return. Passing null will
* return all columns.
*
* @return A ClusterQuery instance.
*/
public ClusterQuery select(String... columns) {
mColumns = columns;
return this;
}
/**
* Declaring to query which rows in table.
*
* <pre>
* DataSupport.where("name = ? or age > ?", "Tom", "14").find(Person.class);
* </pre>
*
* This will find rows which name is Tom or age greater than 14 in Person
* table.
*
* @param conditions
* A filter declaring which rows to return, formatted as an SQL
* WHERE clause. Passing null will return all rows.
* @return A ClusterQuery instance.
*/
public ClusterQuery where(String... conditions) {
mConditions = conditions;
return this;
}
/**
* Declaring how to order the rows queried from table.
*
* <pre>
* DataSupport.order("name desc").find(Person.class);
* </pre>
*
* This will find all rows in Person table sorted by name with inverted
* order.
*
* @param column
* How to order the rows, formatted as an SQL ORDER BY clause.
* Passing null will use the default sort order, which may be
* unordered.
* @return A ClusterQuery instance.
*/
public ClusterQuery order(String column) {
mOrderBy = column;
return this;
}
/**
* Limits the number of rows returned by the query.
*
* <pre>
* DataSupport.limit(2).find(Person.class);
* </pre>
*
* This will find the top 2 rows in Person table.
*
* @param value
* Limits the number of rows returned by the query, formatted as
* LIMIT clause.
* @return A ClusterQuery instance.
*/
public ClusterQuery limit(int value) {
mLimit = String.valueOf(value);
return this;
}
/**
* Declaring the offset of rows returned by the query. This method must be
* used with {@link #limit(int)}, or nothing will return.
*
* <pre>
* DataSupport.limit(1).offset(2).find(Person.class);
* </pre>
*
* This will find the third row in Person table.
*
* @param value
* The offset amount of rows returned by the query.
* @return A ClusterQuery instance.
*/
public ClusterQuery offset(int value) {
mOffset = String.valueOf(value);
return this;
}
/**
* Finds multiple records by the cluster parameters. You can use the below
* way to finish a complicated query:
*
* <pre>
* DataSupport.select("name").where("age > ?", "14").order("age").limit(1).offset(2)
* .find(Person.class);
* </pre>
*
* You can also do the same job with SQLiteDatabase like this:
*
* <pre>
* getSQLiteDatabase().query("Person", "name", "age > ?", new String[] { "14" }, null, null, "age",
* "2,1");
* </pre>
*
* Obviously, the first way is much more semantic.<br>
* Note that the associated models won't be loaded by default considering
* the efficiency, but you can do that by using
* {@link ClusterQuery#find(Class, boolean)}.
*
* @param modelClass
* Which table to query and the object type to return as a list.
* @return An object list with founded data from database, or an empty list.
*/
public <T> List<T> find(Class<T> modelClass) {
return find(modelClass, false);
}
/**
* It is mostly same as {@link ClusterQuery#find(Class)} but an isEager
* parameter. If set true the associated models will be loaded as well.
*
* @param modelClass
* Which table to query and the object type to return as a list.
* @param isEager
* True to load the associated models, false not.
* @return An object list with founded data from database, or an empty list.
*/
public synchronized <T> List<T> find(Class<T> modelClass, boolean isEager) {
QueryHandler queryHandler = new QueryHandler(Connector.getDatabase());
String limit;
if (mOffset == null) {
limit = mLimit;
} else {
if (mLimit == null) {
mLimit = "0";
}
limit = mOffset + "," + mLimit;
}
return queryHandler.onFind(modelClass, mColumns, mConditions, mOrderBy, limit, isEager);
}
/**
* Count the records.
*
* <pre>
* DataSupport.count(Person.class);
* </pre>
*
* This will count all rows in person table.<br>
* You can also specify a where clause when counting.
*
* <pre>
* DataSupport.where("age > ?", "15").count(Person.class);
* </pre>
*
* @param modelClass
* Which table to query from by class.
* @return Count of the specified table.
*/
public synchronized int count(Class<?> modelClass) {
return count(BaseUtility.changeCase(modelClass.getSimpleName()));
}
/**
* Count the records.
*
* <pre>
* DataSupport.count("person");
* </pre>
*
* This will count all rows in person table.<br>
* You can also specify a where clause when counting.
*
* <pre>
* DataSupport.where("age > ?", "15").count("person");
* </pre>
*
* @param tableName
* Which table to query from.
* @return Count of the specified table.
*/
public synchronized int count(String tableName) {
QueryHandler queryHandler = new QueryHandler(Connector.getDatabase());
return queryHandler.onCount(tableName, mConditions);
}
/**
* Calculates the average value on a given column.
*
* <pre>
* DataSupport.average(Person.class, "age");
* </pre>
*
* You can also specify a where clause when calculating.
*
* <pre>
* DataSupport.where("age > ?", "15").average(Person.class, "age");
* </pre>
*
* @param modelClass
* Which table to query from by class.
* @param column
* The based on column to calculate.
* @return The average value on a given column.
*/
public synchronized double average(Class<?> modelClass, String column) {
return average(BaseUtility.changeCase(modelClass.getSimpleName()), column);
}
/**
* Calculates the average value on a given column.
*
* <pre>
* DataSupport.average("person", "age");
* </pre>
*
* You can also specify a where clause when calculating.
*
* <pre>
* DataSupport.where("age > ?", "15").average("person", "age");
* </pre>
*
* @param tableName
* Which table to query from.
* @param column
* The based on column to calculate.
* @return The average value on a given column.
*/
public synchronized double average(String tableName, String column) {
QueryHandler queryHandler = new QueryHandler(Connector.getDatabase());
return queryHandler.onAverage(tableName, column, mConditions);
}
/**
* Calculates the maximum value on a given column. The value is returned
* with the same data type of the column.
*
* <pre>
* DataSupport.max(Person.class, "age", int.class);
* </pre>
*
* You can also specify a where clause when calculating.
*
* <pre>
* DataSupport.where("age > ?", "15").max(Person.class, "age", Integer.TYPE);
* </pre>
*
* @param modelClass
* Which table to query from by class.
* @param columnName
* The based on column to calculate.
* @param columnType
* The type of the based on column.
* @return The maximum value on a given column.
*/
public synchronized <T> T max(Class<?> modelClass, String columnName, Class<T> columnType) {
return max(BaseUtility.changeCase(modelClass.getSimpleName()), columnName, columnType);
}
/**
* Calculates the maximum value on a given column. The value is returned
* with the same data type of the column.
*
* <pre>
* DataSupport.max("person", "age", int.class);
* </pre>
*
* You can also specify a where clause when calculating.
*
* <pre>
* DataSupport.where("age > ?", "15").max("person", "age", Integer.TYPE);
* </pre>
*
* @param tableName
* Which table to query from.
* @param columnName
* The based on column to calculate.
* @param columnType
* The type of the based on column.
* @return The maximum value on a given column.
*/
public synchronized <T> T max(String tableName, String columnName, Class<T> columnType) {
QueryHandler queryHandler = new QueryHandler(Connector.getDatabase());
return queryHandler.onMax(tableName, columnName, mConditions, columnType);
}
/**
* Calculates the minimum value on a given column. The value is returned
* with the same data type of the column.
*
* <pre>
* DataSupport.min(Person.class, "age", int.class);
* </pre>
*
* You can also specify a where clause when calculating.
*
* <pre>
* DataSupport.where("age > ?", "15").min(Person.class, "age", Integer.TYPE);
* </pre>
*
* @param modelClass
* Which table to query from by class.
* @param columnName
* The based on column to calculate.
* @param columnType
* The type of the based on column.
* @return The minimum value on a given column.
*/
public synchronized <T> T min(Class<?> modelClass, String columnName, Class<T> columnType) {
return min(BaseUtility.changeCase(modelClass.getSimpleName()), columnName, columnType);
}
/**
* Calculates the minimum value on a given column. The value is returned
* with the same data type of the column.
*
* <pre>
* DataSupport.min("person", "age", int.class);
* </pre>
*
* You can also specify a where clause when calculating.
*
* <pre>
* DataSupport.where("age > ?", "15").min("person", "age", Integer.TYPE);
* </pre>
*
* @param tableName
* Which table to query from.
* @param columnName
* The based on column to calculate.
* @param columnType
* The type of the based on column.
* @return The minimum value on a given column.
*/
public synchronized <T> T min(String tableName, String columnName, Class<T> columnType) {
QueryHandler queryHandler = new QueryHandler(Connector.getDatabase());
return queryHandler.onMin(tableName, columnName, mConditions, columnType);
}
/**
* Calculates the sum of values on a given column. The value is returned
* with the same data type of the column.
*
* <pre>
* DataSupport.sum(Person.class, "age", int.class);
* </pre>
*
* You can also specify a where clause when calculating.
*
* <pre>
* DataSupport.where("age > ?", "15").sum(Person.class, "age", Integer.TYPE);
* </pre>
*
* @param modelClass
* Which table to query from by class.
* @param columnName
* The based on column to calculate.
* @param columnType
* The type of the based on column.
* @return The sum value on a given column.
*/
public synchronized <T> T sum(Class<?> modelClass, String columnName, Class<T> columnType) {
return sum(BaseUtility.changeCase(modelClass.getSimpleName()), columnName, columnType);
}
/**
* Calculates the sum of values on a given column. The value is returned
* with the same data type of the column.
*
* <pre>
* DataSupport.sum("person", "age", int.class);
* </pre>
*
* You can also specify a where clause when calculating.
*
* <pre>
* DataSupport.where("age > ?", "15").sum("person", "age", Integer.TYPE);
* </pre>
*
* @param tableName
* Which table to query from.
* @param columnName
* The based on column to calculate.
* @param columnType
* The type of the based on column.
* @return The sum value on a given column.
*/
public synchronized <T> T sum(String tableName, String columnName, Class<T> columnType) {
QueryHandler queryHandler = new QueryHandler(Connector.getDatabase());
return queryHandler.onSum(tableName, columnName, mConditions, columnType);
}
}