From f023cd77573e499333bcb21e8083d485b8b25217 Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Thu, 2 Jun 2016 21:51:18 +1000 Subject: [PATCH] Improve order by/selection logic. 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 changes 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. --- .../org/fdroid/fdroid/data/ApkProvider.java | 4 +- .../org/fdroid/fdroid/data/AppProvider.java | 5 +- .../org/fdroid/fdroid/data/OrderClause.java | 25 +++++++ .../org/fdroid/fdroid/data/QueryBuilder.java | 66 +++++++++++++++---- .../fdroid/fdroid/data/QuerySelection.java | 2 +- 5 files changed, 83 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/org/fdroid/fdroid/data/OrderClause.java diff --git a/app/src/main/java/org/fdroid/fdroid/data/ApkProvider.java b/app/src/main/java/org/fdroid/fdroid/data/ApkProvider.java index ef0ffb01f..a69dc5155 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/ApkProvider.java +++ b/app/src/main/java/org/fdroid/fdroid/data/ApkProvider.java @@ -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; } diff --git a/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java b/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java index f67803ecf..396c6cf63 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java +++ b/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java @@ -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; } diff --git a/app/src/main/java/org/fdroid/fdroid/data/OrderClause.java b/app/src/main/java/org/fdroid/fdroid/data/OrderClause.java new file mode 100644 index 000000000..eb888f4cf --- /dev/null +++ b/app/src/main/java/org/fdroid/fdroid/data/OrderClause.java @@ -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; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/fdroid/fdroid/data/QueryBuilder.java b/app/src/main/java/org/fdroid/fdroid/data/QueryBuilder.java index 862fcf859..ac1584a28 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/QueryBuilder.java +++ b/app/src/main/java/org/fdroid/fdroid/data/QueryBuilder.java @@ -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 fields = new ArrayList<>(); private final StringBuilder tables = new StringBuilder(getRequiredTables()); private String selection; - private String orderBy; + private String[] selectionArgs; + private final List 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 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() { diff --git a/app/src/main/java/org/fdroid/fdroid/data/QuerySelection.java b/app/src/main/java/org/fdroid/fdroid/data/QuerySelection.java index c6f7a9631..b7a37ca51 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/QuerySelection.java +++ b/app/src/main/java/org/fdroid/fdroid/data/QuerySelection.java @@ -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) {