Merge branch 'prep-providers-for-download-progress' into 'master'

Improve order by/selection logic for database layer.

This was extracted from the postponed !311.

The order by stuff previously only allowed specifying a particular field. We should also be able to sort based on arbitrary expressions, and such expressions will require the ability to bind arguments using the "?" syntax. This change provides a Java abstraction for the order by, and improves the handling of selection arguments that need to bind to "?" so that both the selection (i.e. `WHERE` clause) and the `ORDER BY` clause can provide arguments as required.

See merge request !329
This commit is contained in:
Daniel Martí 2016-06-16 13:00:45 +00:00
commit e285fd6f38
5 changed files with 83 additions and 19 deletions

View File

@ -488,10 +488,10 @@ public class ApkProvider extends FDroidProvider {
for (final String field : projection) {
queryBuilder.addField(field);
}
queryBuilder.addSelection(query.getSelection());
queryBuilder.addSelection(query);
queryBuilder.addOrderBy(sortOrder);
Cursor cursor = db().rawQuery(queryBuilder.toString(), query.getArgs());
Cursor cursor = db().rawQuery(queryBuilder.toString(), queryBuilder.getArgs());
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}

View File

@ -317,7 +317,7 @@ public class AppProvider extends FDroidProvider {
}
public void addSelection(AppQuerySelection selection) {
addSelection(selection.getSelection());
super.addSelection(selection);
if (selection.naturalJoinToInstalled()) {
naturalJoinToInstalledTable();
}
@ -828,12 +828,11 @@ public class AppProvider extends FDroidProvider {
}
Query query = new Query();
query.addSelection(selection);
query.addFields(projection); // TODO: Make the order of addFields/addSelection not dependent on each other...
query.addOrderBy(sortOrder);
Cursor cursor = db().rawQuery(query.toString(), selection.getArgs());
Cursor cursor = db().rawQuery(query.toString(), query.getArgs());
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}

View File

@ -0,0 +1,25 @@
package org.fdroid.fdroid.data;
public class OrderClause {
public final String expression;
private String[] args;
public OrderClause(String expression) {
this.expression = expression;
}
public OrderClause(String field, String[] args, boolean isAscending) {
this.expression = field + " " + (isAscending ? "ASC" : "DESC");
this.args = args;
}
@Override
public String toString() {
return expression;
}
public String[] getArgs() {
return args;
}
}

View File

@ -1,5 +1,8 @@
package org.fdroid.fdroid.data;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.List;
@ -8,7 +11,8 @@ abstract class QueryBuilder {
private final List<String> fields = new ArrayList<>();
private final StringBuilder tables = new StringBuilder(getRequiredTables());
private String selection;
private String orderBy;
private String[] selectionArgs;
private final List<OrderClause> orderBys = new ArrayList<>();
protected abstract String getRequiredTables();
@ -58,12 +62,51 @@ abstract class QueryBuilder {
fields.add(fieldBuilder.toString());
}
public void addSelection(String selection) {
this.selection = selection;
public void addSelection(@Nullable QuerySelection selection) {
if (selection == null) {
this.selection = null;
this.selectionArgs = null;
} else {
this.selection = selection.getSelection();
this.selectionArgs = selection.getArgs();
}
}
/**
* Add an order by, which includes an expression and optionally ASC or DESC afterward.
*/
public void addOrderBy(String orderBy) {
this.orderBy = orderBy;
if (orderBy != null) {
orderBys.add(new OrderClause(orderBy));
}
}
public void addOrderBy(@Nullable OrderClause orderClause) {
if (orderClause != null) {
orderBys.add(orderClause);
}
}
public String[] getArgs() {
List<String> args = new ArrayList<>();
if (selectionArgs != null) {
for (String arg : selectionArgs) {
args.add(arg);
}
}
for (OrderClause orderBy : orderBys) {
if (orderBy.getArgs() != null) {
for (String arg : orderBy.getArgs()) {
args.add(arg);
}
}
}
String[] strings = new String[args.size()];
args.toArray(strings);
return strings;
}
protected final void leftJoin(String table, String alias, String condition) {
@ -94,14 +137,7 @@ abstract class QueryBuilder {
}
private String fieldsSql() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < fields.size(); i++) {
if (i > 0) {
sb.append(',');
}
sb.append(fields.get(i));
}
return sb.toString();
return TextUtils.join(", ", fields);
}
private String whereSql() {
@ -109,7 +145,11 @@ abstract class QueryBuilder {
}
private String orderBySql() {
return orderBy != null ? " ORDER BY " + orderBy : "";
if (orderBys.size() == 0) {
return "";
} else {
return " ORDER BY " + TextUtils.join(", ", orderBys);
}
}
private String groupBySql() {

View File

@ -19,7 +19,7 @@ public class QuerySelection {
public QuerySelection(String selection) {
this.selection = selection;
this.args = null;
this.args = new String[] {};
}
public QuerySelection(String selection, String[] args) {