diff --git a/app/src/main/java/com/todoroo/andlib/sql/Query.java b/app/src/main/java/com/todoroo/andlib/sql/Query.java index 9983781da..a3452c323 100644 --- a/app/src/main/java/com/todoroo/andlib/sql/Query.java +++ b/app/src/main/java/com/todoroo/andlib/sql/Query.java @@ -23,7 +23,6 @@ public final class Query { private final ArrayList joins = new ArrayList<>(); private SqlTable table; private String queryTemplate = null; - private String preClause = null; private Query(Field... fields) { this.fields.addAll(asList(fields)); @@ -62,9 +61,6 @@ public final class Query { @Override public String toString() { StringBuilder sql = new StringBuilder(); - if (preClause != null) { - sql.append(preClause); - } visitSelectClause(sql); visitFromClause(sql); @@ -122,9 +118,4 @@ public final class Query { queryTemplate = template; return this; } - - public Query withPreClause(String clause) { - preClause = clause; - return this; - } } diff --git a/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java b/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java index bcd505983..c6647792d 100644 --- a/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java +++ b/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java @@ -13,8 +13,10 @@ import androidx.room.Dao; import androidx.room.Insert; import androidx.room.Query; import androidx.room.RawQuery; +import androidx.room.Transaction; import androidx.room.Update; import androidx.sqlite.db.SimpleSQLiteQuery; +import androidx.sqlite.db.SupportSQLiteDatabase; import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Functions; import com.todoroo.astrid.api.Filter; @@ -126,8 +128,18 @@ public abstract class TaskDao { + "WHERE completed > 0 AND calendarUri IS NOT NULL AND calendarUri != ''") public abstract int clearCompletedCalendarEvents(); + @Transaction + public List fetchTasks(List queries) { + SupportSQLiteDatabase db = database.getOpenHelper().getWritableDatabase(); + int last = queries.size() - 1; + for (int i = 0 ; i < last ; i++) { + db.execSQL(queries.get(i)); + } + return fetchTasks(new SimpleSQLiteQuery(queries.get(last))); + } + @RawQuery - public abstract List fetchTasks(SimpleSQLiteQuery query); + abstract List fetchTasks(SimpleSQLiteQuery query); @Query("UPDATE tasks SET modified = datetime('now', 'localtime') WHERE _id in (:ids)") public abstract void touch(List ids); diff --git a/app/src/main/java/org/tasks/ui/TaskListViewModel.java b/app/src/main/java/org/tasks/ui/TaskListViewModel.java index 35fa92621..9f4fd056a 100644 --- a/app/src/main/java/org/tasks/ui/TaskListViewModel.java +++ b/app/src/main/java/org/tasks/ui/TaskListViewModel.java @@ -1,5 +1,6 @@ package org.tasks.ui; +import static com.google.common.collect.Lists.newArrayList; import static com.todoroo.andlib.sql.Field.field; import static com.todoroo.andlib.utility.AndroidUtilities.assertMainThread; import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop; @@ -12,8 +13,7 @@ import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModel; -import androidx.sqlite.db.SimpleSQLiteQuery; -import com.google.common.collect.Lists; +import com.google.common.base.Joiner; import com.todoroo.andlib.data.Property.StringProperty; import com.todoroo.andlib.data.Table; import com.todoroo.andlib.sql.Criterion; @@ -27,7 +27,6 @@ import com.todoroo.astrid.api.GtasksFilter; import com.todoroo.astrid.api.PermaSql; import com.todoroo.astrid.api.TagFilter; import com.todoroo.astrid.core.SortHelper; -import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao.TaskCriteria; import com.todoroo.astrid.data.Task; @@ -74,7 +73,6 @@ public class TaskListViewModel extends ViewModel { @Inject Preferences preferences; @Inject TaskDao taskDao; - @Inject Database database; private MutableLiveData> tasks = new MutableLiveData<>(); private Filter filter; private boolean manualSort; @@ -95,8 +93,8 @@ public class TaskListViewModel extends ViewModel { tasks.observe(owner, observer); } - public static String getQuery(Preferences preferences, Filter filter) { - List fields = Lists.newArrayList(TASKS, GTASK, CALDAV, GEOFENCE, PLACE); + public static List getQuery(Preferences preferences, Filter filter) { + List fields = newArrayList(TASKS, GTASK, CALDAV, GEOFENCE, PLACE); Criterion tagsJoinCriterion = Criterion.and(Task.ID.eq(field(TAGS_METADATA_JOIN + ".task"))); Criterion gtaskJoinCriterion = @@ -145,7 +143,7 @@ public class TaskListViewModel extends ViewModel { fields.add(TAGS_RECURSIVE); fields.add(INDENT); - String joinedQuery = Join.inner(Task.TABLE, Task.ID.eq(RECURSIVE_TASK)) + joins; + String joinedQuery = Join.inner(RECURSIVE, Task.ID.eq(RECURSIVE_TASK)) + joins; String parentQuery; QueryTemplate subtaskQuery = new QueryTemplate(); if (filter instanceof CaldavFilter) { @@ -201,8 +199,8 @@ public class TaskListViewModel extends ViewModel { } String sortSelect = SortHelper.orderSelectForSortTypeRecursive(preferences.getSortMode()); - String withClause = - "WITH RECURSIVE recursive_tasks (task, indent, title, sortField) AS (\n" + String withClause = "CREATE TEMPORARY TABLE `recursive_tasks` AS\n" + + "WITH RECURSIVE recursive_tasks (task, indent, title, sortField) AS (\n" + " SELECT tasks._id, 0 AS sort_indent, UPPER(title) AS sort_title, " + sortSelect + " FROM tasks\n" @@ -213,13 +211,16 @@ public class TaskListViewModel extends ViewModel { + subtaskQuery + "\nORDER BY sort_indent DESC, " + SortHelper.orderForSortTypeRecursive(preferences) - + ")"; + + ") SELECT * FROM recursive_tasks"; - return Query.select(fields.toArray(new Field[0])) - .withPreClause(SortHelper.adjustQueryForFlags(preferences, withClause)) - .withQueryTemplate(PermaSql.replacePlaceholdersForQuery(joinedQuery)) - .from(RECURSIVE) - .toString(); + + return newArrayList( + "DROP TABLE IF EXISTS `temp`.`recursive_tasks`", + SortHelper.adjustQueryForFlags(preferences, withClause), + Query.select(fields.toArray(new Field[0])) + .withQueryTemplate(PermaSql.replacePlaceholdersForQuery(joinedQuery)) + .from(Task.TABLE) + .toString()); } else { fields.add(TAGS); @@ -239,10 +240,11 @@ public class TaskListViewModel extends ViewModel { ? query.replace("ORDER BY", "GROUP BY " + Task.ID + " ORDER BY") : query + " GROUP BY " + Task.ID; - return Query.select(fields.toArray(new Field[0])) + return newArrayList( + Query.select(fields.toArray(new Field[0])) .withQueryTemplate(PermaSql.replacePlaceholdersForQuery(groupedQuery)) .from(Task.TABLE) - .toString(); + .toString()); } } @@ -254,10 +256,10 @@ public class TaskListViewModel extends ViewModel { public void invalidate() { assertMainThread(); - SimpleSQLiteQuery query = new SimpleSQLiteQuery(getQuery(preferences, filter)); - Timber.v(query.getSql()); + List queries = getQuery(preferences, filter); + Timber.v(Joiner.on(";").join(queries)); disposable.add( - Single.fromCallable(() -> taskDao.fetchTasks(query)) + Single.fromCallable(() -> taskDao.fetchTasks(queries)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(tasks::setValue, Timber::e)); diff --git a/app/src/main/java/org/tasks/widget/ScrollableViewsFactory.java b/app/src/main/java/org/tasks/widget/ScrollableViewsFactory.java index 26444ce8a..98fa722a2 100644 --- a/app/src/main/java/org/tasks/widget/ScrollableViewsFactory.java +++ b/app/src/main/java/org/tasks/widget/ScrollableViewsFactory.java @@ -12,7 +12,6 @@ import android.util.DisplayMetrics; import android.view.View; import android.widget.RemoteViews; import android.widget.RemoteViewsService; -import androidx.sqlite.db.SimpleSQLiteQuery; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.dao.TaskDao; @@ -83,8 +82,7 @@ class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFactory { @Override public void onDataSetChanged() { updateSettings(); - String query = getQuery(filter); - tasks = taskDao.fetchTasks(new SimpleSQLiteQuery(query)); + tasks = taskDao.fetchTasks(getQuery(filter)); } @Override @@ -198,7 +196,7 @@ class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFactory { return position < tasks.size() ? tasks.get(position) : null; } - private String getQuery(Filter filter) { + private List getQuery(Filter filter) { AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.scrollable_widget); rv.setTextViewText(R.id.widget_title, filter.listingTitle); @@ -206,8 +204,10 @@ class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFactory { rv.setInt(R.id.widget, "setLayoutDirection", Locale.getInstance(context).getDirectionality()); } appWidgetManager.partiallyUpdateAppWidget(widgetId, rv); - String query = TaskListViewModel.getQuery(preferences, filter); - return subtasksHelper.applySubtasksToWidgetFilter(filter, query); + List queries = TaskListViewModel.getQuery(preferences, filter); + int last = queries.size() - 1; + queries.set(last, subtasksHelper.applySubtasksToWidgetFilter(filter, queries.get(last))); + return queries; } private void formatDueDate(RemoteViews row, Task task) {