package com.code44.finance.data; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.support.v4.content.CursorLoader; import android.text.TextUtils; import com.code44.finance.common.utils.StringUtils; import com.code44.finance.data.db.Column; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @SuppressWarnings("UnusedDeclaration") public class Query { private final Set<String> projection = new HashSet<>(); private final List<String> selection = new ArrayList<>(); private final List<String> selectionArgs = new ArrayList<>(); private final List<String> sortOrder = new ArrayList<>(); private final List<String> groupBy = new ArrayList<>(); private int limit = 0; private Query() { } public static Query create() { return new Query(); } private static String getSelectionWithGroupBy(Query query) { final String groupBy = query.getGroupBy(); final String selection; if (StringUtils.isEmpty(groupBy)) { selection = query.getSelection(); } else { selection = query.getSelection() + ") group by (" + groupBy; } return selection; } private static String getSortOrderWithLimit(Query query) { final int limit = query.getLimit(); String sortOrder = query.getSortOrder(); if (limit >= 0) { sortOrder = StringUtils.isEmpty(sortOrder) ? "1" : sortOrder + " limit " + limit; } return sortOrder; } public String[] getProjection() { if (projection.size() == 0) { return null; } return projection.toArray(new String[projection.size()]); } public String getSelection() { if (selection.size() == 0) { return null; } final StringBuilder sb = new StringBuilder(); for (String clause : selection) { sb.append(" ").append(clause); } return sb.toString(); } public String[] getSelectionArgs() { if (selectionArgs.size() == 0) { return null; } return selectionArgs.toArray(new String[selectionArgs.size()]); } public String getSortOrder() { if (sortOrder.size() == 0) { return null; } final StringBuilder sb = new StringBuilder(); for (String order : sortOrder) { if (sb.length() > 0) { sb.append(","); } sb.append(order); } return sb.toString(); } public String getGroupBy() { if (groupBy.size() == 0) { return null; } final StringBuilder sb = new StringBuilder(); for (String grouping : groupBy) { if (sb.length() > 0) { sb.append(","); } sb.append(grouping); } return sb.toString(); } public int getLimit() { return limit; } public CursorLoader asCursorLoader(Context context, Uri uri) { return new CursorLoader(context, uri, getProjection(), getSelectionWithGroupBy(this), getSelectionArgs(), getSortOrder()); } public ContentProviderQuery from(Context context, Uri uri) { return new ContentProviderQuery(this, context, uri); } public DatabaseQuery from(SQLiteDatabase database, String table) { return new DatabaseQuery(this, database, table); } public Query projectionLocalId(Column idColumn) { projection(idColumn.getNameWithTable()); return this; } public Query projection(String column) { projection.add(column); return this; } public Query projection(String... columns) { return projection(Arrays.asList(columns)); } public Query projection(List<String> columns) { projection.addAll(columns); return this; } public Query selection(String clause) { selection.add(clause); return this; } public Query selection(String clause, String... args) { selection(clause); args(args); return this; } public Query selectionInClause(String clause, int count) { return selection(makeInClause(clause, count)); } public Query selectionInClause(String clause, int count, String... args) { selection(makeInClause(clause, count)); args(args); return this; } public Query selectionInClause(String clause, List<String> ids) { selection(makeInClause(clause, ids.size())); for (String id : ids) { args(id); } return this; } public Query args(String arg) { selectionArgs.add(arg); return this; } public Query args(String... args) { return args(Arrays.asList(args)); } public Query args(List<String> args) { selectionArgs.addAll(args); return this; } public Query groupBy(String group) { groupBy.add(group); return this; } public Query groupBy(String... groups) { return groupBy(Arrays.asList(groups)); } public Query groupBy(List<String> groups) { groupBy.addAll(groups); return this; } public Query sortOrder(String order) { sortOrder.add(order); return this; } public Query sortOrder(String... orders) { return sortOrder(Arrays.asList(orders)); } public Query sortOrder(List<String> orders) { sortOrder.addAll(orders); return this; } public Query limit(int limit) { this.limit = limit; return this; } public Query clearSelection() { selection.clear(); return this; } public Query clearArgs() { selectionArgs.clear(); return this; } public Query clearSort() { sortOrder.clear(); return this; } private String makeInClause(String value, int count) { final StringBuilder sb = new StringBuilder(); sb.append(value).append(" in ("); for (int i = 0; i < count; i++) { if (i > 0) { sb.append(","); } sb.append("?"); } sb.append(")"); return sb.toString(); } public static class ContentProviderQuery { private final Query query; private final Context context; private final Uri uri; private ContentProviderQuery(Query query, Context context, Uri uri) { this.query = query; this.context = context; this.uri = uri; } public Cursor execute() { return context.getContentResolver().query(uri, query.getProjection(), getSelectionWithGroupBy(query), query.getSelectionArgs(), query.getSortOrder()); } } public static class DatabaseQuery { private final Query query; private final SQLiteDatabase database; private final List<String> tables; private DatabaseQuery(Query query, SQLiteDatabase database, String table) { this.query = query; this.database = database; this.tables = new ArrayList<>(); tables.add(table); } public String getTables() { return TextUtils.join("", tables); } public DatabaseQuery innerJoin(String table, String on) { tables.add(" inner join " + table + " on (" + on + ")"); return this; } public DatabaseQuery leftJoin(String table, String on) { tables.add(" left join " + table + " on (" + on + ")"); return this; } public Cursor execute() { String tables = getTables(); String[] projection = query.getProjection(); String selection = query.getSelection(); String[] selectionArgs = query.getSelectionArgs(); String groupBy = query.getGroupBy(); String sortOrder = query.getSortOrder(); Cursor cursor = database.query(tables, projection, selection, selectionArgs, groupBy, null, sortOrder); cursor.moveToFirst(); return cursor; } } }