Reuse recursive query for GtasksFilter

gtask_related_email
Alex Baker 5 years ago
parent 7bbc9fe279
commit aaa82447b0

@ -22,11 +22,6 @@ public final class CaldavTaskAdapter extends TaskAdapter {
this.caldavDao = caldavDao;
}
@Override
public int getIndent(TaskContainer task) {
return task.getIndent();
}
@Override
public boolean canMove(ViewHolder sourceVh, ViewHolder targetVh) {
TaskContainer source = sourceVh.task;

@ -21,11 +21,6 @@ public class GoogleTaskManualSortAdapter extends TaskAdapter {
this.googleTaskDao = googleTaskDao;
}
@Override
public int getIndent(TaskContainer task) {
return task.getIndent();
}
@Override
public boolean canMove(ViewHolder sourceVh, ViewHolder targetVh) {
TaskContainer source = sourceVh.task;

@ -53,7 +53,7 @@ public class TaskAdapter {
}
public int getIndent(TaskContainer task) {
return 0;
return task.getIndent();
}
public boolean canMove(ViewHolder source, ViewHolder target) {

@ -104,7 +104,7 @@ public class TaskAdapterProvider {
}
private TaskAdapter createGoogleTaskAdapter(GtasksFilter filter) {
String query = GtasksFilter.toSubtaskQuery(preferences, filter.getSqlQuery());
String query = GtasksFilter.toManualOrder(filter.getSqlQuery());
filter.setFilterQueryOverride(query);
return preferences.isManualSort()
? new GoogleTaskManualSortAdapter(taskDao, googleTaskDao)

@ -51,12 +51,15 @@ public class CaldavFilter extends Filter {
private static QueryTemplate queryTemplate(CaldavCalendar caldavCalendar) {
return new QueryTemplate()
.join(getJoin())
.where(
Criterion.and(
TaskDao.TaskCriteria.activeAndVisible(),
Field.field("caldav_tasks.cd_deleted").eq(0),
Field.field("caldav_tasks.cd_calendar").eq(caldavCalendar.getUuid())));
.join(Join.left(CaldavTask.TABLE, Task.ID.eq(Field.field("caldav_tasks.cd_task"))))
.where(getCriterion(caldavCalendar));
}
public static Criterion getCriterion(CaldavCalendar caldavCalendar) {
return Criterion.and(
TaskDao.TaskCriteria.activeAndVisible(),
Field.field("caldav_tasks.cd_deleted").eq(0),
Field.field("caldav_tasks.cd_calendar").eq(caldavCalendar.getUuid()));
}
private static Map<String, Object> getValuesForNewTask(CaldavCalendar caldavCalendar) {
@ -106,12 +109,4 @@ public class CaldavFilter extends Filter {
public boolean areContentsTheSame(@NonNull FilterListItem other) {
return calendar.equals(((CaldavFilter) other).calendar);
}
private static Join getJoin() {
return Join.left(CaldavTask.TABLE, Task.ID.eq(Field.field("caldav_tasks.cd_task")));
}
public static String getJoinSql() {
return getJoin().toString();
}
}

@ -6,9 +6,7 @@ import androidx.annotation.NonNull;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.OrderType;
import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.astrid.core.SortHelper;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task;
import java.util.HashMap;
@ -16,7 +14,6 @@ import java.util.Map;
import org.tasks.R;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskList;
import org.tasks.preferences.Preferences;
public class GtasksFilter extends Filter {
@ -52,67 +49,36 @@ public class GtasksFilter extends Filter {
icon = list.getIcon();
}
public static String toSubtaskQuery(Preferences preferences, String query) {
boolean manualSort = preferences.isManualSort();
String parentSort, childPrimarySort, childSecondarySort;
OrderType sortOrder;
OrderType titleOrder = OrderType.ASC;
if (manualSort) {
parentSort = "google_tasks.gt_order";
childPrimarySort = "p.gt_order";
childSecondarySort = "c.gt_order";
sortOrder = OrderType.ASC;
} else {
int sortMode = preferences.getSortMode();
parentSort = SortHelper.orderSelectForSortTypeRecursive(sortMode)
.replaceFirst("AS .*", "");
childPrimarySort = SortHelper.orderSelectForSortTypeRecursive(sortMode)
.replaceFirst("AS .*", "")
.replaceAll("tasks\\.", "parent_tasks.");
childSecondarySort = SortHelper.orderSelectForSortTypeRecursive(sortMode)
.replaceFirst("AS .*", "")
.replaceAll("tasks\\.", "child_tasks.");
sortOrder = sortMode == SortHelper.SORT_MODIFIED ? OrderType.DESC : OrderType.ASC;
if (preferences.isReverseSort() && sortMode == SortHelper.SORT_ALPHA) {
titleOrder = OrderType.DESC;
}
}
if (preferences.isReverseSort()) {
sortOrder = sortOrder == OrderType.DESC ? OrderType.ASC : OrderType.DESC;
}
public static String toManualOrder(String query) {
query =
query.replace(
"WHERE",
"JOIN ("
+ "SELECT 0 AS indent, google_tasks.*, COUNT(c.gt_id) AS children, 0 AS siblings, " + parentSort + " AS primary_sort, NULL AS secondary_sort, UPPER(tasks.title) AS primary_title, NULL AS secondary_title "
+ "FROM google_tasks "
+ "LEFT JOIN google_tasks AS c ON c.gt_parent = google_tasks.gt_task "
+ "LEFT JOIN tasks ON tasks._id = google_tasks.gt_task "
+ "WHERE google_tasks.gt_parent = 0 "
+ "GROUP BY google_tasks.gt_task "
+ "UNION "
+ "SELECT 1 AS indent, c.*, 0 AS children, COUNT(s.gt_id) AS siblings, " + childPrimarySort + " AS primary_sort, " + childSecondarySort + " AS secondary_sort, UPPER(parent_tasks.title) AS primary_title, UPPER(child_tasks.title) AS secondary_title "
+ "FROM google_tasks AS c "
+ "LEFT JOIN google_tasks AS p ON c.gt_parent = p.gt_task "
+ "LEFT JOIN tasks AS parent_tasks ON c.gt_parent = parent_tasks._id "
+ "LEFT JOIN tasks AS child_tasks ON c.gt_task = child_tasks._id "
+ "LEFT JOIN google_tasks AS s ON s.gt_parent = p.gt_task "
+ "WHERE c.gt_parent > 0 AND ((parent_tasks.completed=0) AND (parent_tasks.deleted=0) AND (parent_tasks.hideUntil<(strftime('%s','now')*1000))) "
+ "GROUP BY c.gt_task"
+ ") as g2 ON g2.gt_id = google_tasks.gt_id WHERE");
"JOIN (SELECT 0 as indent, google_tasks.*, COUNT(c.gt_id) AS children, 0 AS siblings, google_tasks.gt_order AS primary_sort, NULL AS secondary_sort"
+ " FROM google_tasks LEFT JOIN google_tasks AS c ON c.gt_parent = google_tasks.gt_task"
+ " WHERE google_tasks.gt_parent = 0 GROUP BY google_tasks.gt_task"
+ " UNION SELECT 1 as indent, c.*, 0 AS children, COUNT(s.gt_id) AS siblings, p.gt_order AS primary_sort, c.gt_order AS secondary_sort"
+ " FROM google_tasks AS c LEFT JOIN google_tasks AS p ON c.gt_parent = p.gt_task"
+ " LEFT JOIN tasks ON c.gt_parent = tasks._id"
+ " LEFT JOIN google_tasks AS s ON s.gt_parent = p.gt_task"
+ " WHERE c.gt_parent > 0 AND ((tasks.completed=0) AND (tasks.deleted=0)"
+ " AND (tasks.hideUntil<(strftime('%s','now')*1000)))"
+ " GROUP BY c.gt_task) as g2 ON g2.gt_id = google_tasks.gt_id WHERE");
query = query.replaceAll("ORDER BY .*", "");
query = query + "ORDER BY primary_sort " + sortOrder + ", primary_title " + titleOrder + ", indent ASC" + ", secondary_sort " + sortOrder + ", secondary_title " + titleOrder;
query = query + "ORDER BY primary_sort ASC, secondary_sort ASC";
return query;
}
private static QueryTemplate getQueryTemplate(GoogleTaskList list) {
return new QueryTemplate()
.join(Join.left(GoogleTask.TABLE, Task.ID.eq(Field.field("google_tasks.gt_task"))))
.where(
Criterion.and(
TaskDao.TaskCriteria.activeAndVisible(),
Field.field("google_tasks.gt_deleted").eq(0),
Field.field("google_tasks.gt_list_id").eq(list.getRemoteId())));
.where(getCriterion(list));
}
public static Criterion getCriterion(GoogleTaskList list) {
return Criterion.and(
TaskDao.TaskCriteria.activeAndVisible(),
Field.field("google_tasks.gt_deleted").eq(0),
Field.field("google_tasks.gt_list_id").eq(list.getRemoteId()));
}
private static Map<String, Object> getValuesForNewTasks(GoogleTaskList list) {

@ -136,7 +136,7 @@ public class SubtasksHelper {
if (shouldUseSubtasksFragmentForFilter(filter)) {
if (filter instanceof GtasksFilter) {
query = GtasksFilter.toSubtaskQuery(preferences, query);
query = GtasksFilter.toManualOrder(query);
} else {
TagData tagData = tagDataDao.getTagByName(filter.listingTitle);
TaskListMetadata tlm = null;

@ -6,6 +6,7 @@ import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Table;
@Entity(tableName = "caldav_tasks")
@ -15,6 +16,12 @@ public class CaldavTask {
@Deprecated public static final Table TABLE = new Table("caldav_tasks");
public static final Property.IntegerProperty PARENT =
new Property.IntegerProperty(TABLE, "cd_parent");
public static final Property.IntegerProperty TASK =
new Property.IntegerProperty(TABLE, "cd_task");
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "cd_id")
private long id;

@ -18,6 +18,12 @@ public class GoogleTask {
public static final Property.IntegerProperty ORDER =
new Property.IntegerProperty(GoogleTask.TABLE, "gt_order");
public static final Property.IntegerProperty PARENT =
new Property.IntegerProperty(TABLE, "gt_parent");
public static final Property.IntegerProperty TASK =
new Property.IntegerProperty(TABLE, "gt_task");
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "gt_id")
private transient long id;

@ -13,7 +13,7 @@ public class TaskContainer {
public int siblings;
public long primarySort;
public long secondarySort;
@Deprecated public int indent;
public int indent;
private int targetIndent;
public String getTagsString() {
@ -85,9 +85,6 @@ public class TaskContainer {
}
public int getIndent() {
if (googletask != null) {
return getParent() > 0 ? 1 : 0;
}
return indent;
}

@ -25,6 +25,7 @@ import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.astrid.api.CaldavFilter;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.GtasksFilter;
@ -55,6 +56,7 @@ public class TaskListViewModel extends ViewModel implements Observer<PagedList<T
private static final PagedList.Config PAGED_LIST_CONFIG =
new PagedList.Config.Builder().setPageSize(20).build();
private static final Table RECURSIVE = new Table("recursive_tasks");
private static final Field TASKS = field("tasks.*");
private static final Field GTASK = field(GTASK_METADATA_JOIN + ".*");
private static final Field GEOFENCE = field("geofences.*");
@ -115,7 +117,8 @@ public class TaskListViewModel extends ViewModel implements Observer<PagedList<T
tagsJoinCriterion =
Criterion.and(tagsJoinCriterion, field(TAGS_METADATA_JOIN + ".tag_uid").neq(uuid));
} else if (filter instanceof GtasksFilter) {
if (manualSort) {
if (preferences.isManualSort()) {
fields.add(INDENT);
fields.add(CHILDREN);
fields.add(SIBLINGS);
fields.add(PRIMARY_SORT);
@ -127,7 +130,9 @@ public class TaskListViewModel extends ViewModel implements Observer<PagedList<T
Criterion.and(caldavJoinCriterion, field(CALDAV_METADATA_JOIN + ".cd_calendar").eq(uuid));
}
if (filter instanceof CaldavFilter && atLeastLollipop()) {
if (atLeastLollipop()
&& (filter instanceof CaldavFilter
|| (!preferences.isManualSort() && filter instanceof GtasksFilter))) {
// TODO This is in some ways a proof of concept demonstrating a recursive query used to pull
// in CalDAV tasks providing parenting across different sort modes. Tags are implemented
// as a subquery, which is ugly, but aggregate recursive queries aren't supported. The
@ -148,26 +153,31 @@ public class TaskListViewModel extends ViewModel implements Observer<PagedList<T
String sortSelect = SortHelper.orderSelectForSortTypeRecursive(preferences.getSortMode());
Order order = SortHelper.orderForSortTypeRecursive(preferences);
String filterSql = filter.getSqlQuery();
// Remove unwanted join
filterSql = filterSql.replace(CaldavFilter.getJoinSql(), "");
Field parent;
QueryTemplate query;
if (filter instanceof CaldavFilter) {
query = new QueryTemplate()
.join(Join.left(CaldavTask.TABLE, Task.ID.eq(CaldavTask.TASK)))
.where(CaldavFilter.getCriterion(((CaldavFilter) filter).getCalendar()));
parent = CaldavTask.PARENT;
} else {
query = new QueryTemplate()
.join(Join.left(GoogleTask.TABLE, Task.ID.eq(GoogleTask.TASK)))
.where(GtasksFilter.getCriterion(((GtasksFilter) filter).getList()));
parent = GoogleTask.PARENT;
}
String filterSql = query.toString();
String withClause = "WITH RECURSIVE\n"
+ " recursive_tasks (task, indent, title, sortField) AS (\n"
+ " SELECT _id, 0 AS sort_indent, UPPER(title) AS sort_title, " + sortSelect + "\n"
+ " FROM tasks\n"
+ " INNER JOIN caldav_tasks ON tasks._id = cd_task\n"
+ filterSql + "\n"
+ " AND cd_parent = 0\n"
+ filterSql
+ " AND " + parent + " = 0\n"
+ " UNION ALL\n"
+ " SELECT _id, recursive_tasks.indent+1 AS sort_indent, UPPER(tasks.title) AS sort_title, " + sortSelect + "\n"
+ " FROM tasks\n"
+ " INNER JOIN caldav_tasks\n"
+ " ON tasks._id = caldav_tasks.cd_task\n"
+ " INNER JOIN recursive_tasks\n"
+ " ON recursive_tasks.task = caldav_tasks.cd_parent\n"
+ filterSql + "\n"
+ " INNER JOIN recursive_tasks ON " + parent + " = recursive_tasks.task\n"
+ filterSql
+ " ORDER BY sort_indent DESC, " + order + "\n"
+ " )\n";
@ -176,7 +186,7 @@ public class TaskListViewModel extends ViewModel implements Observer<PagedList<T
return Query.select(fields.toArray(new Field[0]))
.withQueryTemplate(PermaSql.replacePlaceholdersForQuery(joinedQuery))
.withPreClause(withClause)
.from(new Table("recursive_tasks"))
.from(RECURSIVE)
.toString();
} else {
fields.add(TAGS);

Loading…
Cancel
Save