mirror of https://github.com/tasks/tasks
Convert task list queries to Kotlin
parent
f4d1410e3e
commit
13e60d72d2
@ -1,263 +0,0 @@
|
|||||||
package org.tasks.data;
|
|
||||||
|
|
||||||
import static com.google.common.collect.Lists.newArrayList;
|
|
||||||
import static com.todoroo.andlib.sql.Field.field;
|
|
||||||
import static com.todoroo.astrid.activity.TaskListFragment.CALDAV_METADATA_JOIN;
|
|
||||||
import static com.todoroo.astrid.activity.TaskListFragment.GTASK_METADATA_JOIN;
|
|
||||||
import static com.todoroo.astrid.activity.TaskListFragment.TAGS_METADATA_JOIN;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.todoroo.andlib.data.Property.StringProperty;
|
|
||||||
import com.todoroo.andlib.data.Table;
|
|
||||||
import com.todoroo.andlib.sql.Criterion;
|
|
||||||
import com.todoroo.andlib.sql.Field;
|
|
||||||
import com.todoroo.andlib.sql.Join;
|
|
||||||
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;
|
|
||||||
import com.todoroo.astrid.api.PermaSql;
|
|
||||||
import com.todoroo.astrid.core.SortHelper;
|
|
||||||
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
|
|
||||||
import com.todoroo.astrid.data.Task;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import org.tasks.preferences.Preferences;
|
|
||||||
|
|
||||||
public class TaskListQuery {
|
|
||||||
|
|
||||||
private static final Criterion JOIN_GTASK =
|
|
||||||
Criterion.and(
|
|
||||||
Task.ID.eq(field(GTASK_METADATA_JOIN + ".gt_task")),
|
|
||||||
field(GTASK_METADATA_JOIN + ".gt_deleted").eq(0));
|
|
||||||
private static final Criterion JOIN_CALDAV =
|
|
||||||
Criterion.and(
|
|
||||||
Task.ID.eq(field(CALDAV_METADATA_JOIN + ".cd_task")),
|
|
||||||
field(CALDAV_METADATA_JOIN + ".cd_deleted").eq(0));
|
|
||||||
private static final Criterion JOIN_TAGS = Task.ID.eq(field(TAGS_METADATA_JOIN + ".task"));
|
|
||||||
private static final String JOINS =
|
|
||||||
Join.left(GoogleTask.TABLE.as(GTASK_METADATA_JOIN), JOIN_GTASK).toString()
|
|
||||||
+ Join.left(CaldavTask.TABLE.as(CALDAV_METADATA_JOIN), JOIN_CALDAV)
|
|
||||||
+ Join.left(Geofence.TABLE, Geofence.TASK.eq(Task.ID))
|
|
||||||
+ Join.left(Place.TABLE, Place.UID.eq(Geofence.PLACE));
|
|
||||||
|
|
||||||
private static final Table RECURSIVE = new Table("recursive_tasks");
|
|
||||||
private static final Field RECURSIVE_TASK = field(RECURSIVE + ".task");
|
|
||||||
private static final Field TASKS = field("tasks.*");
|
|
||||||
private static final Field GTASK = field(GTASK_METADATA_JOIN + ".*");
|
|
||||||
private static final Field GEOFENCE = field("geofences.*");
|
|
||||||
private static final Field PLACE = field("places.*");
|
|
||||||
private static final Field CALDAV = field(CALDAV_METADATA_JOIN + ".*");
|
|
||||||
private static final Field CHILDREN = field("children");
|
|
||||||
private static final Field PRIMARY_SORT = field("primary_sort").as("primarySort");
|
|
||||||
private static final Field SECONDARY_SORT = field("secondary_sort").as("secondarySort");
|
|
||||||
private static final Field INDENT = field("indent");
|
|
||||||
private static final Field TAG_QUERY =
|
|
||||||
field(
|
|
||||||
"("
|
|
||||||
+ Query.select(field("group_concat(distinct(tag_uid))"))
|
|
||||||
.from(Tag.TABLE)
|
|
||||||
.where(Task.ID.eq(Tag.TASK))
|
|
||||||
.toString()
|
|
||||||
+ " GROUP BY "
|
|
||||||
+ Tag.TASK
|
|
||||||
+ ")")
|
|
||||||
.as("tags");
|
|
||||||
private static final StringProperty TAGS =
|
|
||||||
new StringProperty(null, "group_concat(distinct(" + TAGS_METADATA_JOIN + ".tag_uid)" + ")")
|
|
||||||
.as("tags");
|
|
||||||
private static final List<Field> FIELDS = ImmutableList.of(TASKS, GTASK, CALDAV, GEOFENCE, PLACE);
|
|
||||||
|
|
||||||
public static List<String> getQuery(
|
|
||||||
Preferences preferences, com.todoroo.astrid.api.Filter filter, SubtaskInfo subtasks) {
|
|
||||||
|
|
||||||
if (filter.supportsManualSort() && preferences.isManualSort()) {
|
|
||||||
return filter instanceof GtasksFilter || filter instanceof CaldavFilter
|
|
||||||
? getRecursiveQuery(filter, preferences, subtasks)
|
|
||||||
: getNonRecursiveQuery(filter, preferences);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filter.supportSubtasks() && subtasks.usesSubtasks() && preferences.showSubtasks()) {
|
|
||||||
return getRecursiveQuery(filter, preferences, subtasks);
|
|
||||||
} else {
|
|
||||||
return getNonRecursiveQuery(filter, preferences);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<String> getRecursiveQuery(
|
|
||||||
com.todoroo.astrid.api.Filter filter,
|
|
||||||
Preferences preferences,
|
|
||||||
SubtaskInfo subtasks) {
|
|
||||||
List<Field> fields = new ArrayList<>(FIELDS);
|
|
||||||
fields.add(TAG_QUERY);
|
|
||||||
fields.add(INDENT);
|
|
||||||
fields.add(CHILDREN);
|
|
||||||
fields.add(PRIMARY_SORT);
|
|
||||||
fields.add(SECONDARY_SORT);
|
|
||||||
|
|
||||||
String joinedQuery =
|
|
||||||
Join.inner(RECURSIVE, Task.ID.eq(RECURSIVE_TASK))
|
|
||||||
+ " LEFT JOIN (SELECT parent, count(distinct recursive_tasks.task) AS children FROM recursive_tasks GROUP BY parent) AS recursive_children ON recursive_children.parent = tasks._id "
|
|
||||||
+ JOINS;
|
|
||||||
String where = " WHERE recursive_tasks.hidden = 0";
|
|
||||||
String parentQuery;
|
|
||||||
QueryTemplate subtaskQuery = new QueryTemplate();
|
|
||||||
if (filter instanceof CaldavFilter) {
|
|
||||||
CaldavCalendar calendar = ((CaldavFilter) filter).getCalendar();
|
|
||||||
parentQuery =
|
|
||||||
new QueryTemplate()
|
|
||||||
.join(
|
|
||||||
Join.inner(
|
|
||||||
CaldavTask.TABLE,
|
|
||||||
Criterion.and(
|
|
||||||
CaldavTask.CALENDAR.eq(calendar.getUuid()),
|
|
||||||
CaldavTask.TASK.eq(Task.ID),
|
|
||||||
CaldavTask.DELETED.eq(0))))
|
|
||||||
.where(Criterion.and(TaskCriteria.activeAndVisible(), Task.PARENT.eq(0)))
|
|
||||||
.toString();
|
|
||||||
subtaskQuery
|
|
||||||
.join(Join.inner(RECURSIVE, Task.PARENT.eq(RECURSIVE_TASK)))
|
|
||||||
.join(
|
|
||||||
Join.inner(CaldavTask.TABLE,
|
|
||||||
Criterion.and(CaldavTask.TASK.eq(Task.ID), CaldavTask.DELETED.eq(0))))
|
|
||||||
.where(TaskCriteria.activeAndVisible());
|
|
||||||
} else if (filter instanceof GtasksFilter) {
|
|
||||||
GoogleTaskList list = ((GtasksFilter) filter).getList();
|
|
||||||
parentQuery =
|
|
||||||
new QueryTemplate()
|
|
||||||
.join(
|
|
||||||
Join.inner(
|
|
||||||
GoogleTask.TABLE,
|
|
||||||
Criterion.and(
|
|
||||||
GoogleTask.LIST.eq(list.getRemoteId()),
|
|
||||||
GoogleTask.PARENT.eq(0),
|
|
||||||
GoogleTask.TASK.eq(Task.ID),
|
|
||||||
GoogleTask.DELETED.eq(0))))
|
|
||||||
.where(TaskCriteria.activeAndVisible())
|
|
||||||
.toString();
|
|
||||||
subtaskQuery
|
|
||||||
.join(Join.inner(RECURSIVE, GoogleTask.PARENT.eq(RECURSIVE_TASK)))
|
|
||||||
.join(
|
|
||||||
Join.inner(
|
|
||||||
GoogleTask.TABLE,
|
|
||||||
Criterion.and(GoogleTask.TASK.eq(Task.ID), GoogleTask.DELETED.eq(0))))
|
|
||||||
.where(TaskCriteria.activeAndVisible());
|
|
||||||
} else {
|
|
||||||
parentQuery = PermaSql.replacePlaceholdersForQuery(filter.getSqlQuery());
|
|
||||||
if (subtasks.hasGoogleSubtasks && subtasks.hasSubtasks) {
|
|
||||||
addGoogleAndCaldavSubtasks(subtaskQuery);
|
|
||||||
} else if (subtasks.hasGoogleSubtasks) {
|
|
||||||
addGoogleSubtasks(subtaskQuery);
|
|
||||||
} else {
|
|
||||||
addCaldavSubtasks(subtaskQuery);
|
|
||||||
}
|
|
||||||
subtaskQuery.where(TaskCriteria.activeAndVisible());
|
|
||||||
joinedQuery +=
|
|
||||||
" LEFT JOIN (SELECT task, max(indent) AS max_indent FROM recursive_tasks GROUP BY task) AS recursive_indents ON recursive_indents.task = tasks._id ";
|
|
||||||
where += " AND indent = max_indent ";
|
|
||||||
}
|
|
||||||
joinedQuery += where;
|
|
||||||
|
|
||||||
boolean manualSort = preferences.isManualSort();
|
|
||||||
boolean manualGtasks = manualSort && filter instanceof GtasksFilter;
|
|
||||||
boolean manualCaldav = manualSort && filter instanceof CaldavFilter;
|
|
||||||
int sortMode;
|
|
||||||
String sortField;
|
|
||||||
if (manualGtasks) {
|
|
||||||
sortMode = SortHelper.SORT_GTASKS;
|
|
||||||
sortField = "google_tasks.gt_order";
|
|
||||||
} else if (manualCaldav) {
|
|
||||||
sortMode = SortHelper.SORT_CALDAV;
|
|
||||||
sortField = SortHelper.CALDAV_ORDER_COLUMN;
|
|
||||||
} else {
|
|
||||||
sortMode = preferences.getSortMode();
|
|
||||||
sortField = "NULL";
|
|
||||||
}
|
|
||||||
boolean reverseSort = preferences.isReverseSort() && sortMode != SortHelper.SORT_GTASKS;
|
|
||||||
String sortSelect = SortHelper.orderSelectForSortTypeRecursive(sortMode);
|
|
||||||
String withClause =
|
|
||||||
"CREATE TEMPORARY TABLE `recursive_tasks` AS\n"
|
|
||||||
+ "WITH RECURSIVE recursive_tasks (task, parent, collapsed, hidden, indent, title, sortField, primary_sort, secondary_sort) AS (\n"
|
|
||||||
+ " SELECT tasks._id, 0 as parent, tasks.collapsed as collapsed, 0 as hidden, 0 AS sort_indent, UPPER(tasks.title) AS sort_title, "
|
|
||||||
+ sortSelect
|
|
||||||
+ ", " + sortField + " as primary_sort, NULL as secondarySort"
|
|
||||||
+ " FROM tasks\n"
|
|
||||||
+ parentQuery
|
|
||||||
+ "\nUNION ALL SELECT tasks._id, recursive_tasks.task as parent, tasks.collapsed as collapsed, CASE WHEN recursive_tasks.collapsed > 0 OR recursive_tasks.hidden > 0 THEN 1 ELSE 0 END as hidden, recursive_tasks.indent+1 AS sort_indent, UPPER(tasks.title) AS sort_title, "
|
|
||||||
+ sortSelect
|
|
||||||
+ ", recursive_tasks.primary_sort as primary_sort, " + sortField + " as secondary_sort"
|
|
||||||
+ " FROM tasks\n"
|
|
||||||
+ subtaskQuery
|
|
||||||
+ "\nORDER BY sort_indent DESC, "
|
|
||||||
+ SortHelper.orderForSortTypeRecursive(sortMode, reverseSort)
|
|
||||||
+ ") SELECT * FROM recursive_tasks";
|
|
||||||
|
|
||||||
return newArrayList(
|
|
||||||
"DROP TABLE IF EXISTS `temp`.`recursive_tasks`",
|
|
||||||
SortHelper.adjustQueryForFlags(preferences, withClause),
|
|
||||||
"CREATE INDEX `r_tasks` ON `recursive_tasks` (`task`)",
|
|
||||||
"CREATE INDEX `r_parents` ON `recursive_tasks` (`parent`)",
|
|
||||||
Query.select(fields.toArray(new Field[0]))
|
|
||||||
.withQueryTemplate(PermaSql.replacePlaceholdersForQuery(joinedQuery))
|
|
||||||
.from(Task.TABLE)
|
|
||||||
.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<String> getNonRecursiveQuery(Filter filter, Preferences preferences) {
|
|
||||||
List<Field> fields = new ArrayList<>(FIELDS);
|
|
||||||
fields.add(TAGS);
|
|
||||||
|
|
||||||
// TODO: For now, we'll modify the query to join and include the things like tag data here.
|
|
||||||
// Eventually, we might consider restructuring things so that this query is constructed
|
|
||||||
// elsewhere.
|
|
||||||
|
|
||||||
String joinedQuery =
|
|
||||||
Join.left(Tag.TABLE.as(TAGS_METADATA_JOIN), JOIN_TAGS).toString()
|
|
||||||
+ JOINS
|
|
||||||
+ filter.getSqlQuery();
|
|
||||||
|
|
||||||
String query =
|
|
||||||
SortHelper.adjustQueryForFlagsAndSort(preferences, joinedQuery, preferences.getSortMode());
|
|
||||||
|
|
||||||
String groupedQuery =
|
|
||||||
query.contains("ORDER BY")
|
|
||||||
? query.replace("ORDER BY", "GROUP BY " + Task.ID + " ORDER BY")
|
|
||||||
: query + " GROUP BY " + Task.ID;
|
|
||||||
|
|
||||||
return newArrayList(
|
|
||||||
Query.select(fields.toArray(new Field[0]))
|
|
||||||
.withQueryTemplate(PermaSql.replacePlaceholdersForQuery(groupedQuery))
|
|
||||||
.from(Task.TABLE)
|
|
||||||
.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addGoogleSubtasks(QueryTemplate subtaskQuery) {
|
|
||||||
subtaskQuery
|
|
||||||
.join(Join.inner(RECURSIVE, GoogleTask.PARENT.eq(RECURSIVE_TASK)))
|
|
||||||
.join(
|
|
||||||
Join.inner(
|
|
||||||
GoogleTask.TABLE,
|
|
||||||
Criterion.and(GoogleTask.TASK.eq(Task.ID), GoogleTask.DELETED.eq(0))));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addCaldavSubtasks(QueryTemplate subtaskQuery) {
|
|
||||||
subtaskQuery.join(Join.inner(RECURSIVE, Task.PARENT.eq(RECURSIVE_TASK)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addGoogleAndCaldavSubtasks(QueryTemplate subtaskQuery) {
|
|
||||||
subtaskQuery
|
|
||||||
.join(
|
|
||||||
Join.inner(
|
|
||||||
RECURSIVE,
|
|
||||||
Criterion.or(GoogleTask.PARENT.eq(RECURSIVE_TASK), Task.PARENT.eq(RECURSIVE_TASK))))
|
|
||||||
.join(
|
|
||||||
Join.left(
|
|
||||||
GoogleTask.TABLE,
|
|
||||||
Criterion.and(GoogleTask.TASK.eq(Task.ID), GoogleTask.DELETED.eq(0))))
|
|
||||||
.join(
|
|
||||||
Join.left(
|
|
||||||
CaldavTask.TABLE,
|
|
||||||
Criterion.and(CaldavTask.TASK.eq(Task.ID), CaldavTask.DELETED.eq(0))));
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,51 @@
|
|||||||
|
package org.tasks.data
|
||||||
|
|
||||||
|
import com.todoroo.andlib.sql.Criterion
|
||||||
|
import com.todoroo.andlib.sql.Field.field
|
||||||
|
import com.todoroo.andlib.sql.Join
|
||||||
|
import com.todoroo.astrid.activity.TaskListFragment
|
||||||
|
import com.todoroo.astrid.api.CaldavFilter
|
||||||
|
import com.todoroo.astrid.api.Filter
|
||||||
|
import com.todoroo.astrid.api.GtasksFilter
|
||||||
|
import com.todoroo.astrid.data.Task
|
||||||
|
import okhttp3.internal.immutableListOf
|
||||||
|
import org.tasks.data.TaskListQueryNonRecursive.getNonRecursiveQuery
|
||||||
|
import org.tasks.data.TaskListQueryRecursive.getRecursiveQuery
|
||||||
|
import org.tasks.preferences.Preferences
|
||||||
|
|
||||||
|
object TaskListQuery {
|
||||||
|
private val JOIN_GTASK = Criterion.and(
|
||||||
|
Task.ID.eq(field("${TaskListFragment.GTASK_METADATA_JOIN}.gt_task")),
|
||||||
|
field("${TaskListFragment.GTASK_METADATA_JOIN}.gt_deleted").eq(0))
|
||||||
|
private val JOIN_CALDAV = Criterion.and(
|
||||||
|
Task.ID.eq(field("${TaskListFragment.CALDAV_METADATA_JOIN}.cd_task")),
|
||||||
|
field("${TaskListFragment.CALDAV_METADATA_JOIN}.cd_deleted").eq(0))
|
||||||
|
val JOINS = """
|
||||||
|
${Join.left(GoogleTask.TABLE.`as`(TaskListFragment.GTASK_METADATA_JOIN), JOIN_GTASK)}
|
||||||
|
${Join.left(CaldavTask.TABLE.`as`(TaskListFragment.CALDAV_METADATA_JOIN), JOIN_CALDAV)}
|
||||||
|
${Join.left(Geofence.TABLE, Geofence.TASK.eq(Task.ID))}
|
||||||
|
${Join.left(Place.TABLE, Place.UID.eq(Geofence.PLACE))}
|
||||||
|
""".trimIndent()
|
||||||
|
val FIELDS = immutableListOf(
|
||||||
|
field("tasks.*"),
|
||||||
|
field("${TaskListFragment.GTASK_METADATA_JOIN}.*"),
|
||||||
|
field("${TaskListFragment.CALDAV_METADATA_JOIN}.*"),
|
||||||
|
field("geofences.*"),
|
||||||
|
field("places.*"))
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getQuery(preferences: Preferences, filter: Filter, subtasks: SubtaskInfo): List<String> {
|
||||||
|
if (filter.supportsManualSort() && preferences.isManualSort) {
|
||||||
|
return if (filter is GtasksFilter || filter is CaldavFilter) {
|
||||||
|
getRecursiveQuery(filter, preferences, subtasks)
|
||||||
|
} else {
|
||||||
|
getNonRecursiveQuery(filter, preferences)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return if (filter.supportSubtasks() && subtasks.usesSubtasks() && preferences.showSubtasks()) {
|
||||||
|
getRecursiveQuery(filter, preferences, subtasks)
|
||||||
|
} else {
|
||||||
|
getNonRecursiveQuery(filter, preferences)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package org.tasks.data
|
||||||
|
|
||||||
|
import com.todoroo.andlib.data.Property.StringProperty
|
||||||
|
import com.todoroo.andlib.sql.Field
|
||||||
|
import com.todoroo.andlib.sql.Join
|
||||||
|
import com.todoroo.andlib.sql.Query
|
||||||
|
import com.todoroo.astrid.activity.TaskListFragment
|
||||||
|
import com.todoroo.astrid.api.Filter
|
||||||
|
import com.todoroo.astrid.api.PermaSql
|
||||||
|
import com.todoroo.astrid.core.SortHelper
|
||||||
|
import com.todoroo.astrid.data.Task
|
||||||
|
import org.tasks.preferences.Preferences
|
||||||
|
|
||||||
|
internal object TaskListQueryNonRecursive {
|
||||||
|
private val JOIN_TAGS = Task.ID.eq(Field.field("${TaskListFragment.TAGS_METADATA_JOIN}.task"))
|
||||||
|
private val JOINS = """
|
||||||
|
${Join.left(Tag.TABLE.`as`(TaskListFragment.TAGS_METADATA_JOIN), JOIN_TAGS)}
|
||||||
|
${TaskListQuery.JOINS}
|
||||||
|
""".trimIndent()
|
||||||
|
private val TAGS =
|
||||||
|
StringProperty(
|
||||||
|
null,
|
||||||
|
"group_concat(distinct(${TaskListFragment.TAGS_METADATA_JOIN}.tag_uid))")
|
||||||
|
.`as`("tags")
|
||||||
|
private val FIELDS = TaskListQuery.FIELDS.plus(TAGS).toTypedArray()
|
||||||
|
|
||||||
|
fun getNonRecursiveQuery(filter: Filter, preferences: Preferences): List<String> {
|
||||||
|
val joinedQuery = JOINS + filter.getSqlQuery()
|
||||||
|
val query = SortHelper.adjustQueryForFlagsAndSort(preferences, joinedQuery, preferences.sortMode)
|
||||||
|
val groupedQuery = if (query.contains("ORDER BY")) {
|
||||||
|
query.replace("ORDER BY", "GROUP BY ${Task.ID} ORDER BY")
|
||||||
|
} else {
|
||||||
|
"$query GROUP BY ${Task.ID}"
|
||||||
|
}
|
||||||
|
return listOf(
|
||||||
|
Query.select(*FIELDS)
|
||||||
|
.withQueryTemplate(PermaSql.replacePlaceholdersForQuery(groupedQuery))
|
||||||
|
.from(Task.TABLE)
|
||||||
|
.toString())
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,139 @@
|
|||||||
|
package org.tasks.data
|
||||||
|
|
||||||
|
import com.todoroo.andlib.data.Table
|
||||||
|
import com.todoroo.andlib.sql.Criterion
|
||||||
|
import com.todoroo.andlib.sql.Field.field
|
||||||
|
import com.todoroo.andlib.sql.Join
|
||||||
|
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
|
||||||
|
import com.todoroo.astrid.api.PermaSql
|
||||||
|
import com.todoroo.astrid.core.SortHelper
|
||||||
|
import com.todoroo.astrid.dao.TaskDao.TaskCriteria.activeAndVisible
|
||||||
|
import com.todoroo.astrid.data.Task
|
||||||
|
import org.tasks.preferences.Preferences
|
||||||
|
|
||||||
|
internal object TaskListQueryRecursive {
|
||||||
|
private val RECURSIVE = Table("recursive_tasks")
|
||||||
|
private val RECURSIVE_TASK = field("$RECURSIVE.task")
|
||||||
|
private val FIELDS =
|
||||||
|
TaskListQuery.FIELDS.plus(listOf(
|
||||||
|
field("(${Query.select(field("group_concat(distinct(tag_uid))")).from(Tag.TABLE).where(Task.ID.eq(Tag.TASK))} GROUP BY ${Tag.TASK})").`as`("tags"),
|
||||||
|
field("indent"),
|
||||||
|
field("children"),
|
||||||
|
field("primary_sort").`as`("primarySort"),
|
||||||
|
field("secondary_sort").`as`("secondarySort"))).toTypedArray()
|
||||||
|
private val JOINS = """
|
||||||
|
${Join.inner(RECURSIVE, Task.ID.eq(RECURSIVE_TASK))}
|
||||||
|
LEFT JOIN (SELECT parent, count(distinct recursive_tasks.task) AS children FROM recursive_tasks GROUP BY parent) AS recursive_children ON recursive_children.parent = tasks._id
|
||||||
|
${TaskListQuery.JOINS}
|
||||||
|
""".trimIndent()
|
||||||
|
private val GOOGLE_SUBTASKS =
|
||||||
|
QueryTemplate()
|
||||||
|
.join(Join.inner(RECURSIVE, GoogleTask.PARENT.eq(RECURSIVE_TASK)))
|
||||||
|
.join(Join.inner(GoogleTask.TABLE, Criterion.and(GoogleTask.TASK.eq(Task.ID), GoogleTask.DELETED.eq(0))))
|
||||||
|
.where(activeAndVisible())
|
||||||
|
private val CALDAV_SUBTASKS =
|
||||||
|
QueryTemplate()
|
||||||
|
.join(Join.inner(RECURSIVE, Task.PARENT.eq(RECURSIVE_TASK)))
|
||||||
|
.join(Join.inner(CaldavTask.TABLE, Criterion.and(CaldavTask.TASK.eq(Task.ID), CaldavTask.DELETED.eq(0))))
|
||||||
|
.where(activeAndVisible())
|
||||||
|
private val GOOGLE_AND_CALDAV_SUBTASKS =
|
||||||
|
QueryTemplate()
|
||||||
|
.join(Join.inner(RECURSIVE, Criterion.or(GoogleTask.PARENT.eq(RECURSIVE_TASK), Task.PARENT.eq(RECURSIVE_TASK))))
|
||||||
|
.join(Join.left(GoogleTask.TABLE, Criterion.and(GoogleTask.TASK.eq(Task.ID), GoogleTask.DELETED.eq(0))))
|
||||||
|
.join(Join.left(CaldavTask.TABLE, Criterion.and(CaldavTask.TASK.eq(Task.ID), CaldavTask.DELETED.eq(0))))
|
||||||
|
.where(activeAndVisible())
|
||||||
|
|
||||||
|
fun getRecursiveQuery(filter: Filter, preferences: Preferences, subtasks: SubtaskInfo): List<String> {
|
||||||
|
var joinedQuery = JOINS
|
||||||
|
var where = " WHERE recursive_tasks.hidden = 0"
|
||||||
|
val parentQuery: String
|
||||||
|
val subtaskQuery: QueryTemplate
|
||||||
|
when (filter) {
|
||||||
|
is CaldavFilter -> {
|
||||||
|
parentQuery = newCaldavQuery(filter)
|
||||||
|
subtaskQuery = CALDAV_SUBTASKS
|
||||||
|
}
|
||||||
|
is GtasksFilter -> {
|
||||||
|
parentQuery = newGoogleTaskQuery(filter)
|
||||||
|
subtaskQuery = GOOGLE_SUBTASKS
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
parentQuery = PermaSql.replacePlaceholdersForQuery(filter.getSqlQuery())
|
||||||
|
subtaskQuery = when {
|
||||||
|
subtasks.hasGoogleSubtasks && subtasks.hasSubtasks -> GOOGLE_AND_CALDAV_SUBTASKS
|
||||||
|
subtasks.hasGoogleSubtasks -> GOOGLE_SUBTASKS
|
||||||
|
else -> CALDAV_SUBTASKS
|
||||||
|
}
|
||||||
|
joinedQuery += " LEFT JOIN (SELECT task, max(indent) AS max_indent FROM recursive_tasks GROUP BY task) AS recursive_indents ON recursive_indents.task = tasks._id "
|
||||||
|
where += " AND indent = max_indent "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
joinedQuery += where
|
||||||
|
val manualSort = preferences.isManualSort
|
||||||
|
val sortMode: Int
|
||||||
|
val sortField: String
|
||||||
|
when {
|
||||||
|
manualSort && filter is GtasksFilter -> {
|
||||||
|
sortMode = SortHelper.SORT_GTASKS
|
||||||
|
sortField = "google_tasks.gt_order"
|
||||||
|
}
|
||||||
|
manualSort && filter is CaldavFilter -> {
|
||||||
|
sortMode = SortHelper.SORT_CALDAV
|
||||||
|
sortField = SortHelper.CALDAV_ORDER_COLUMN
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
sortMode = preferences.sortMode
|
||||||
|
sortField = "NULL"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val reverseSort = preferences.isReverseSort && sortMode != SortHelper.SORT_GTASKS && sortMode != SortHelper.SORT_CALDAV
|
||||||
|
val sortSelect = SortHelper.orderSelectForSortTypeRecursive(sortMode)
|
||||||
|
val withClause ="""
|
||||||
|
CREATE TEMPORARY TABLE `recursive_tasks` AS
|
||||||
|
WITH RECURSIVE recursive_tasks (task, parent, collapsed, hidden, indent, title, sortField, primary_sort, secondary_sort) AS (
|
||||||
|
SELECT tasks._id, 0 as parent, tasks.collapsed as collapsed, 0 as hidden, 0 AS sort_indent, UPPER(tasks.title) AS sort_title, $sortSelect, $sortField as primary_sort, NULL as secondarySort FROM tasks
|
||||||
|
$parentQuery
|
||||||
|
UNION ALL SELECT tasks._id, recursive_tasks.task as parent, tasks.collapsed as collapsed, CASE WHEN recursive_tasks.collapsed > 0 OR recursive_tasks.hidden > 0 THEN 1 ELSE 0 END as hidden, recursive_tasks.indent+1 AS sort_indent, UPPER(tasks.title) AS sort_title, $sortSelect, recursive_tasks.primary_sort as primary_sort, $sortField as secondary_sort FROM tasks
|
||||||
|
$subtaskQuery
|
||||||
|
ORDER BY sort_indent DESC, ${SortHelper.orderForSortTypeRecursive(sortMode, reverseSort)}
|
||||||
|
) SELECT * FROM recursive_tasks
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
return listOf(
|
||||||
|
"DROP TABLE IF EXISTS `temp`.`recursive_tasks`",
|
||||||
|
SortHelper.adjustQueryForFlags(preferences, withClause),
|
||||||
|
"CREATE INDEX `r_tasks` ON `recursive_tasks` (`task`)",
|
||||||
|
"CREATE INDEX `r_parents` ON `recursive_tasks` (`parent`)",
|
||||||
|
Query.select(*FIELDS)
|
||||||
|
.withQueryTemplate(PermaSql.replacePlaceholdersForQuery(joinedQuery))
|
||||||
|
.from(Task.TABLE)
|
||||||
|
.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun newCaldavQuery(filter: CaldavFilter) =
|
||||||
|
QueryTemplate()
|
||||||
|
.join(Join.inner(
|
||||||
|
CaldavTask.TABLE,
|
||||||
|
Criterion.and(
|
||||||
|
CaldavTask.CALENDAR.eq(filter.uuid),
|
||||||
|
CaldavTask.TASK.eq(Task.ID),
|
||||||
|
CaldavTask.DELETED.eq(0))))
|
||||||
|
.where(Criterion.and(activeAndVisible(), Task.PARENT.eq(0)))
|
||||||
|
.toString()
|
||||||
|
|
||||||
|
private fun newGoogleTaskQuery(filter: GtasksFilter) =
|
||||||
|
QueryTemplate()
|
||||||
|
.join(Join.inner(
|
||||||
|
GoogleTask.TABLE,
|
||||||
|
Criterion.and(
|
||||||
|
GoogleTask.LIST.eq(filter.remoteId),
|
||||||
|
GoogleTask.PARENT.eq(0),
|
||||||
|
GoogleTask.TASK.eq(Task.ID),
|
||||||
|
GoogleTask.DELETED.eq(0))))
|
||||||
|
.where(activeAndVisible())
|
||||||
|
.toString()
|
||||||
|
}
|
Loading…
Reference in New Issue