Replacing more queries with Room

pull/618/head
Alex Baker 6 years ago
parent 8a8ab611b2
commit 2711485dab

@ -33,13 +33,13 @@ public class TaskDaoTests extends InjectingTestCase {
*/
@Test
public void testTaskCreation() {
assertEquals(0, taskDao.toList(Query.select()).size());
assertEquals(0, taskDao.getAll().size());
// create task "happy"
Task task = new Task();
task.setTitle("happy");
taskDao.save(task);
assertEquals(1, taskDao.toList(Query.select()).size());
assertEquals(1, taskDao.getAll().size());
long happyId = task.getId();
assertNotSame(Task.NO_ID, happyId);
task = taskDao.fetch(happyId);
@ -49,14 +49,14 @@ public class TaskDaoTests extends InjectingTestCase {
task = new Task();
task.setTitle("sad");
taskDao.save(task);
assertEquals(2, taskDao.toList(Query.select()).size());
assertEquals(2, taskDao.getAll().size());
// rename sad to melancholy
long sadId = task.getId();
assertNotSame(Task.NO_ID, sadId);
task.setTitle("melancholy");
taskDao.save(task);
assertEquals(2, taskDao.toList(Query.select()).size());
assertEquals(2, taskDao.getAll().size());
// check state
task = taskDao.fetch(happyId);
@ -104,10 +104,10 @@ public class TaskDaoTests extends InjectingTestCase {
taskDao.save(task);
// check is active
assertEquals(5, taskDao.toList(Query.select().where(TaskCriteria.isActive())).size());
assertEquals(5, taskDao.getActiveTasks().size());
// check is visible
assertEquals(5, taskDao.toList(Query.select().where(TaskCriteria.isVisible())).size());
assertEquals(5, taskDao.getVisibleTasks().size());
}
/**
@ -115,18 +115,18 @@ public class TaskDaoTests extends InjectingTestCase {
*/
@Test
public void testTDeletion() {
assertEquals(0, taskDao.toList(Query.select()).size());
assertEquals(0, taskDao.getAll().size());
// create task "happy"
Task task = new Task();
task.setTitle("happy");
taskDao.save(task);
assertEquals(1, taskDao.toList(Query.select()).size());
assertEquals(1, taskDao.getAll().size());
// delete
long happyId = task.getId();
assertEquals(1, taskDao.deleteById(happyId));
assertEquals(0, taskDao.toList(Query.select()).size());
assertEquals(0, taskDao.getAll().size());
}
/**
@ -141,7 +141,7 @@ public class TaskDaoTests extends InjectingTestCase {
taskDao.save(task);
assertEquals(0, taskDao.toList(Query.select()).size());
assertEquals(0, taskDao.getAll().size());
}
/**
@ -149,14 +149,14 @@ public class TaskDaoTests extends InjectingTestCase {
*/
@Test
public void testInvalidIndex() {
assertEquals(0, taskDao.toList(Query.select()).size());
assertEquals(0, taskDao.getAll().size());
assertNull(taskDao.fetch(1));
assertEquals(0, taskDao.deleteById(1));
// make sure db still works
assertEquals(0, taskDao.toList(Query.select()).size());
assertEquals(0, taskDao.getAll().size());
}
@Override

@ -14,7 +14,6 @@ import org.tasks.injection.TestComponent;
import javax.inject.Inject;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static org.tasks.Freeze.freezeClock;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
@ -23,11 +22,6 @@ public class TaskTest extends InjectingTestCase {
@Inject TaskDao taskDao;
@Test
public void testNewTaskHasNoCreationDate() {
assertFalse(new Task().isModified(Task.CREATION_DATE));
}
@Test
public void testSavedTaskHasCreationDate() {
freezeClock().thawAfter(new Snippet() {{

@ -17,7 +17,6 @@ import org.tasks.data.UserActivityDao;
import org.tasks.notifications.NotificationDao;
import org.tasks.preferences.PermissionChecker;
import org.tasks.preferences.PermissivePermissionChecker;
import org.tasks.preferences.Preferences;
import dagger.Module;
import dagger.Provides;

@ -9,7 +9,6 @@ import com.todoroo.astrid.gtasks.GtasksTaskListUpdaterTest;
import com.todoroo.astrid.gtasks.GtasksTaskMovingTest;
import com.todoroo.astrid.model.TaskTest;
import com.todoroo.astrid.reminders.ReminderServiceTest;
import com.todoroo.astrid.repeats.NewRepeatTests;
import com.todoroo.astrid.repeats.RepeatTaskHelperTest;
import com.todoroo.astrid.service.QuickAddMarkupTest;
import com.todoroo.astrid.service.TitleParserTest;
@ -51,8 +50,6 @@ public interface TestComponent {
void inject(TitleParserTest titleParserTest);
void inject(NewRepeatTests newRepeatTests);
void inject(BackupServiceTests backupServiceTests);
void inject(AlarmJobServiceTest alarmServiceTest);

@ -31,10 +31,6 @@ import com.google.api.services.tasks.model.TaskList;
import com.google.api.services.tasks.model.TaskLists;
import com.google.api.services.tasks.model.Tasks;
import com.google.common.base.Strings;
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.utility.DateUtilities;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.SyncFlags;
@ -189,12 +185,7 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
}
private void pushLocalChanges() throws UserRecoverableAuthIOException {
List<Task> tasks = taskDao.toList(Query.select()
.join(Join.left(GoogleTask.TABLE.as("gt"), Task.ID.eq(Field.field("gt.task"))))
.where(Criterion.or(
Task.MODIFICATION_DATE.gt(Field.field("gt.last_sync")),
Field.field("gt.remote_id").eq(""),
Field.field("gt.remote_id").isNull())));
List<Task> tasks = taskDao.getTasksToPush();
for (Task task : tasks) {
try {
pushTask(task, gtasksInvoker);

@ -9,8 +9,6 @@ import com.todoroo.astrid.data.Task;
import org.tasks.injection.BroadcastComponent;
import org.tasks.injection.InjectingBroadcastReceiver;
import java.util.ArrayList;
import javax.inject.Inject;
public class PushReceiver extends InjectingBroadcastReceiver {

@ -8,15 +8,7 @@ package com.todoroo.andlib.data;
import android.database.Cursor;
import android.text.TextUtils;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Operator;
import com.todoroo.andlib.sql.UnaryCriterion;
import static com.todoroo.andlib.sql.SqlConstants.COMMA;
import static com.todoroo.andlib.sql.SqlConstants.LEFT_PARENTHESIS;
import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
/**
* Property represents a typed column in a database.
@ -117,16 +109,6 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
public Integer getValue(Cursor data) {
return data.getInt(data.getColumnIndexOrThrow(getColumnName()));
}
@Override
public IntegerProperty as(String newAlias) {
return (IntegerProperty) super.as(newAlias);
}
@Override
public IntegerProperty cloneAs(String tableAlias, String columnAlias) {
return this.cloneAs(tableAlias, columnAlias);
}
}
/**
@ -150,26 +132,6 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
public StringProperty as(String newAlias) {
return (StringProperty) super.as(newAlias);
}
@Override
public StringProperty cloneAs(String tableAlias, String columnAlias) {
return (StringProperty) super.cloneAs(tableAlias, columnAlias);
}
public Criterion in(final String[] value) {
final Field field = this;
return new Criterion(Operator.in) {
@Override
protected void populate(StringBuilder sb) {
sb.append(field).append(SPACE).append(Operator.in).append(SPACE).append(LEFT_PARENTHESIS).append(SPACE);
for (String s : value) {
sb.append("'").append(UnaryCriterion.sanitize(s)).append("'").append(COMMA);
}
sb.deleteCharAt(sb.length() - 1).append(RIGHT_PARENTHESIS);
}
};
}
}
/**
@ -189,11 +151,6 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
return data.getLong(data.getColumnIndexOrThrow(getColumnName()));
}
@Override
public LongProperty as(String newAlias) {
return (LongProperty) super.as(newAlias);
}
@Override
public LongProperty cloneAs(String tableAlias, String columnAlias) {
return (LongProperty) super.cloneAs(tableAlias, columnAlias);

@ -27,22 +27,6 @@ public class Field extends DBObject<Field> {
return UnaryCriterion.eq(this, value);
}
/**
* Adds the criterion that the field must be equal to the given string, ignoring case.
*
* Thanks to a sqlite bug, this will only work for ASCII values.
*
* @param value string which field must equal
* @return the criterion
*/
public Criterion eqCaseInsensitive(String value) {
if(value == null) {
return UnaryCriterion.isNull(this);
}
String escaped = value.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_");
return UnaryCriterion.like(this, escaped, "\\");
}
public Criterion neq(Object value) {
if(value == null) {
return UnaryCriterion.isNotNull(this);
@ -62,14 +46,6 @@ public class Field extends DBObject<Field> {
return UnaryCriterion.lte(this, value);
}
public Criterion isNull() {
return UnaryCriterion.isNull(this);
}
public Criterion isNotNull() {
return UnaryCriterion.isNotNull(this);
}
public Criterion like(final String value) {
return UnaryCriterion.like(this, value);
}

@ -5,11 +5,6 @@
*/
package com.todoroo.andlib.sql;
import com.todoroo.andlib.data.Property.StringProperty;
public final class Functions {
public static String caseStatement(Criterion when, Object ifTrue, Object ifFalse) {
@ -30,13 +25,4 @@ public final class Functions {
public static Field now() {
return new Field("(strftime('%s','now')*1000)");
}
public static Field cast(Field field, String newType) {
return new Field("CAST(" + field.toString() + " AS " +
newType + ")");
}
public static Field length(StringProperty field) {
return new Field("LENGTH(" + field.toString() + ")");
}
}

@ -9,12 +9,12 @@ public final class Operator {
private final String operator;
public static final Operator eq = new Operator("=");
public static final Operator neq = new Operator("<>");
static final Operator neq = new Operator("<>");
public static final Operator isNull = new Operator("IS NULL");
public static final Operator isNotNull = new Operator("IS NOT NULL");
public static final Operator gt = new Operator(">");
public static final Operator lt = new Operator("<");
public static final Operator lte = new Operator("<=");
static final Operator isNotNull = new Operator("IS NOT NULL");
static final Operator gt = new Operator(">");
static final Operator lt = new Operator("<");
static final Operator lte = new Operator("<=");
public static final Operator and = new Operator("AND");
public static final Operator or = new Operator("OR");
public static final Operator not = new Operator("NOT");

@ -5,7 +5,6 @@
*/
package com.todoroo.andlib.sql;
import com.todoroo.andlib.data.Property;
import com.todoroo.astrid.data.Task;
import java.util.ArrayList;
@ -150,13 +149,6 @@ public final class Query {
}
}
/**
* Gets a list of fields returned by this query
*/
public Property<?>[] getFields() {
return fields.toArray(new Property<?>[fields.size()]);
}
/**
* Add the SQL query template (comes after the "from")
* @return query

@ -9,16 +9,16 @@ public final class SqlConstants {
public static final String SELECT = "SELECT";
public static final String SPACE = " ";
public static final String AS = "AS";
public static final String COMMA = ",";
static final String COMMA = ",";
public static final String FROM = "FROM";
public static final String ON = "ON";
public static final String JOIN = "JOIN";
static final String JOIN = "JOIN";
public static final String ALL = "*";
public static final String LEFT_PARENTHESIS = "(";
public static final String RIGHT_PARENTHESIS = ")";
static final String LEFT_PARENTHESIS = "(";
static final String RIGHT_PARENTHESIS = ")";
public static final String AND = "AND";
public static final String OR = "OR";
public static final String ORDER_BY = "ORDER BY";
static final String ORDER_BY = "ORDER BY";
public static final String WHERE = "WHERE";
public static final String NOT = "NOT";
public static final String LIMIT = "LIMIT";

@ -58,19 +58,19 @@ public class UnaryCriterion extends Criterion {
return input.replace("'", "''");
}
public static Criterion neq(Field field, Object value) {
static Criterion neq(Field field, Object value) {
return new UnaryCriterion(field, Operator.neq, value);
}
public static Criterion gt(Field field, Object value) {
static Criterion gt(Field field, Object value) {
return new UnaryCriterion(field, Operator.gt, value);
}
public static Criterion lt(Field field, Object value) {
static Criterion lt(Field field, Object value) {
return new UnaryCriterion(field, Operator.lt, value);
}
public static Criterion lte(Field field, Object value) {
static Criterion lte(Field field, Object value) {
return new UnaryCriterion(field, Operator.lte, value);
}
@ -83,7 +83,7 @@ public class UnaryCriterion extends Criterion {
};
}
public static Criterion isNotNull(Field field) {
static Criterion isNotNull(Field field) {
return new UnaryCriterion(field, Operator.isNotNull, null) {
@Override
protected void populateOperator(StringBuilder sb) {
@ -100,18 +100,4 @@ public class UnaryCriterion extends Criterion {
}
};
}
public static Criterion like(Field field, String value, final String escape) {
return new UnaryCriterion(field, Operator.like, value) {
@Override
protected void populateOperator(StringBuilder sb) {
sb.append(SPACE).append(operator).append(SPACE);
}
@Override
protected void afterPopulateOperator(StringBuilder sb) {
super.afterPopulateOperator(sb);
sb.append(SPACE).append("ESCAPE").append(" '").append(sanitize(escape)).append("'");
}
};
}
}

@ -5,7 +5,6 @@ import android.os.Parcelable;
import java.util.Map;
import static com.todoroo.andlib.utility.AndroidUtilities.mapFromSerializedString;
import static com.todoroo.andlib.utility.AndroidUtilities.mapToSerializedString;
public class CustomFilter extends Filter {

@ -5,7 +5,6 @@
*/
package com.todoroo.astrid.api;
import android.content.ContentValues;
import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;

@ -13,16 +13,10 @@ import android.support.annotation.Nullable;
import android.util.Xml;
import android.widget.Toast;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import org.tasks.data.TagDataDao;
import com.todoroo.astrid.dao.TaskDao;
import org.tasks.data.UserActivityDao;
import org.tasks.data.TagData;
import com.todoroo.astrid.data.Task;
import org.tasks.data.UserActivity;
import org.tasks.R;
import org.tasks.backup.XmlWriter;
@ -34,6 +28,10 @@ import org.tasks.data.Location;
import org.tasks.data.LocationDao;
import org.tasks.data.Tag;
import org.tasks.data.TagDao;
import org.tasks.data.TagData;
import org.tasks.data.TagDataDao;
import org.tasks.data.UserActivity;
import org.tasks.data.UserActivityDao;
import org.tasks.preferences.Preferences;
import org.xmlpull.v1.XmlSerializer;
@ -121,10 +119,11 @@ public class TasksXmlExporter {
try {
String output = setupFile(backupDirectory,
exportType);
int tasks = taskDao.count(Query.select());
if(tasks > 0) {
doTasksExport(output);
List<Task> tasks = taskDao.getAll();
if(tasks.size() > 0) {
doTasksExport(output, tasks);
}
preferences.setLong(PREF_BACKUP_LAST_DATE, DateUtilities.now());
@ -144,7 +143,7 @@ public class TasksXmlExporter {
}).start();
}
private void doTasksExport(String output) throws IOException {
private void doTasksExport(String output, List<Task> tasks) throws IOException {
File xmlFile = new File(output);
xmlFile.createNewFile();
FileOutputStream fos = new FileOutputStream(xmlFile);
@ -160,7 +159,7 @@ public class TasksXmlExporter {
xml.attribute(null, BackupConstants.ASTRID_ATTR_FORMAT,
Integer.toString(FORMAT));
serializeTasks();
serializeTasks(tasks);
serializeTagDatas();
xml.endTag(null, BackupConstants.ASTRID_TAG);
@ -181,8 +180,7 @@ public class TasksXmlExporter {
}
}
private void serializeTasks() throws IOException {
List<Task> tasks = taskDao.toList(Query.select().orderBy(Order.asc(Task.ID)));
private void serializeTasks(List<Task> tasks) throws IOException {
int length = tasks.size();
for(int i = 0; i < length; i++) {
Task task = tasks.get(i);

@ -11,8 +11,6 @@ import android.content.res.Resources;
import android.os.Handler;
import android.text.TextUtils;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task;
@ -196,25 +194,15 @@ public class TasksXmlImporter {
taskCount++;
setProgressMessage(activity.getString(R.string.import_progress_read, taskCount));
String title = xpp.getAttributeValue(null, Task.TITLE.name);
String created = xpp.getAttributeValue(null, Task.CREATION_DATE.name);
currentTask = new Task(new XmlReader(xpp));
// if we don't have task name or creation date, skip
if (created == null || title == null) {
skipCount++;
return;
}
Task existingTask = taskDao.fetch(currentTask.getUuid());
// if the task's name and creation date match an existing task, skip
Query query = Query.select()
.where(Criterion.and(Task.TITLE.eq(title), Task.CREATION_DATE.eq(created)));
if (taskDao.count(query) > 0) {
skipCount++;
} else {
currentTask = new Task(new XmlReader(xpp));
// Save the task to the database.
if (existingTask == null) {
taskDao.save(currentTask);
importCount++;
} else {
skipCount++;
}
}

@ -7,11 +7,8 @@ package com.todoroo.astrid.core;
import android.os.Bundle;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.TaskDeleter;
import org.tasks.R;
@ -22,8 +19,6 @@ import org.tasks.injection.InjectingPreferenceActivity;
import org.tasks.preferences.Preferences;
import org.tasks.ui.ProgressDialogAsyncTask;
import java.util.List;
import javax.inject.Inject;
public class OldTaskPreferences extends InjectingPreferenceActivity {
@ -90,9 +85,8 @@ public class OldTaskPreferences extends InjectingPreferenceActivity {
@Override
protected Integer doInBackground(Void... params) {
int result = deleteCalendarEvents(Criterion.and(Task.COMPLETION_DATE.gt(0), Task.CALENDAR_URI.isNotNull()));
taskDao.clearCompletedCalendarEvents();
return result;
calendarEventProvider.deleteEvents(taskDao.getCompletedCalendarEvents());
return taskDao.clearCompletedCalendarEvents();
}
@Override
@ -109,9 +103,8 @@ public class OldTaskPreferences extends InjectingPreferenceActivity {
.setPositiveButton(android.R.string.ok, (dialog, which) -> new ProgressDialogAsyncTask(OldTaskPreferences.this, dialogBuilder) {
@Override
protected Integer doInBackground(Void... params) {
int result = deleteCalendarEvents(Task.CALENDAR_URI.isNotNull());
taskDao.clearAllCalendarEvents();
return result;
calendarEventProvider.deleteEvents(taskDao.getAllCalendarEvents());
return taskDao.clearAllCalendarEvents();
}
@Override
@ -123,17 +116,6 @@ public class OldTaskPreferences extends InjectingPreferenceActivity {
.show();
}
private int deleteCalendarEvents(Criterion criterion) {
int deletedEventCount = 0;
List<Task> tasks = taskDao.toList(Query.select().where(criterion));
for (Task task : tasks) {
if (calendarEventProvider.deleteEvent(task)) {
deletedEventCount++;
}
}
return deletedEventCount;
}
private void resetPreferences() {
dialogBuilder.newMessageDialog(R.string.EPr_reset_preferences_warning)
.setPositiveButton(R.string.EPr_reset_preferences, (dialog, which) -> {

@ -7,9 +7,7 @@ package com.todoroo.astrid.dao;
import android.arch.persistence.db.SupportSQLiteDatabase;
import android.arch.persistence.room.RoomDatabase;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.todoroo.astrid.data.Task;
@ -79,8 +77,6 @@ public abstract class Database extends RoomDatabase {
public static final String NAME = "database";
private static final String TABLE_NAME = Task.TABLE.name;
private SupportSQLiteDatabase database;
private Runnable onDatabaseUpdated;
@ -95,7 +91,7 @@ public abstract class Database extends RoomDatabase {
return this;
}
public void onDatabaseUpdated() {
void onDatabaseUpdated() {
if (onDatabaseUpdated != null) {
onDatabaseUpdated.run();
}
@ -175,11 +171,5 @@ public abstract class Database extends RoomDatabase {
public Cursor rawQuery(String sql) {
return getDatabase().query(sql, null);
}
public int update(ContentValues values, String whereClause) {
int result = getDatabase().update(TABLE_NAME, SQLiteDatabase.CONFLICT_REPLACE, values, whereClause, null);
onDatabaseUpdated();
return result;
}
}

@ -17,6 +17,7 @@ import com.todoroo.andlib.sql.Functions;
import com.todoroo.andlib.sql.Query;
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.BuildConfig;
@ -62,40 +63,27 @@ public abstract class TaskDao {
@android.arch.persistence.room.Query("SELECT * FROM tasks WHERE _id = :id LIMIT 1")
public abstract Task fetch(long id);
public int count(Filter filter) {
String query = PermaSql.replacePlaceholders(filter.getSqlQuery());
return count(Query.select(Task.ID).withQueryTemplate(query));
}
@android.arch.persistence.room.Query("SELECT * FROM tasks WHERE _id IN (:taskIds)")
public abstract List<Task> fetch(List<Long> taskIds);
public int count(Query query) {
Cursor cursor = query(query);
try {
return cursor.getCount();
} finally {
cursor.close();
}
}
@android.arch.persistence.room.Query("SELECT COUNT(1) FROM tasks WHERE timerStart > 0")
public abstract int activeTimers();
private List<Task> toList(Cursor cursor) {
List<Task> result = new ArrayList<>();
try {
for (cursor.moveToFirst() ; !cursor.isAfterLast() ; cursor.moveToNext()) {
result.add(new Task(cursor));
}
} finally {
cursor.close();
}
return result;
}
@android.arch.persistence.room.Query("SELECT tasks.* FROM tasks INNER JOIN notification ON tasks._id = notification.task")
public abstract List<Task> activeNotifications();
public List<Task> query(Filter filter) {
String query = PermaSql.replacePlaceholders(filter.getSqlQuery());
return toList(query(Query.select().withQueryTemplate(query)));
}
@android.arch.persistence.room.Query("SELECT * FROM tasks WHERE remoteId = :remoteId")
public abstract Task fetch(String remoteId);
public List<Task> toList(Query query) {
return toList(query(query));
}
@android.arch.persistence.room.Query("SELECT * FROM tasks WHERE completed = 0 AND deleted = 0")
abstract List<Task> getActiveTasks();
@android.arch.persistence.room.Query("SELECT * FROM tasks WHERE hideUntil < (strftime('%s','now')*1000)")
abstract List<Task> getVisibleTasks();
@android.arch.persistence.room.Query("SELECT * FROM tasks WHERE remoteId IN (:remoteIds) " +
"AND recurrence NOT NULL AND LENGTH(recurrence) > 0")
public abstract List<Task> getRecurringTasks(List<String> remoteIds);
@android.arch.persistence.room.Query("UPDATE tasks SET completed = :completionDate " +
"WHERE remoteId = :remoteId")
@ -104,6 +92,17 @@ public abstract class TaskDao {
@android.arch.persistence.room.Query("UPDATE tasks SET snoozeTime = :millis WHERE _id in (:taskIds)")
public abstract void snooze(List<Long> taskIds, long millis);
@android.arch.persistence.room.Query("SELECT tasks.* FROM tasks " +
"LEFT JOIN google_tasks ON tasks._id = google_tasks.task " +
"WHERE tasks.modified > google_tasks.last_sync " +
"OR google_tasks.remote_id = '' " +
"OR google_tasks.remote_id IS NULL")
public abstract List<Task> getTasksToPush();
@android.arch.persistence.room.Query("SELECT * FROM TASKS " +
"WHERE completed = 0 AND deleted = 0 AND (notificationFlags > 0 OR notifications > 0)")
public abstract List<Task> getTasksWithReminders();
// --- SQL clause generators
/**
@ -139,13 +138,24 @@ public abstract class TaskDao {
}
}
@android.arch.persistence.room.Query("SELECT * FROM tasks")
public abstract List<Task> getAll();
@android.arch.persistence.room.Query("SELECT calendarUri FROM tasks " +
"WHERE calendarUri NOT NULL AND calendarUri != ''")
public abstract List<String> getAllCalendarEvents();
@android.arch.persistence.room.Query("UPDATE tasks SET calendarUri = '' " +
"WHERE calendarUri NOT NULL AND calendarUri != ''")
public abstract void clearAllCalendarEvents();
public abstract int clearAllCalendarEvents();
@android.arch.persistence.room.Query("SELECT calendarUri FROM tasks " +
"WHERE completed > 0 AND calendarUri NOT NULL AND calendarUri != ''")
public abstract List<String> getCompletedCalendarEvents();
@android.arch.persistence.room.Query("UPDATE tasks SET calendarUri = '' " +
"WHERE completed > 0 AND calendarUri NOT NULL AND calendarUri != ''")
public abstract void clearCompletedCalendarEvents();
public abstract int clearCompletedCalendarEvents();
@android.arch.persistence.room.Query("SELECT * FROM tasks WHERE deleted > 0")
public abstract List<Task> getDeleted();
@ -196,6 +206,12 @@ public abstract class TaskDao {
return false;
}
public List<Task> getAstrid2TaskProviderTasks() {
return toList(query(Query.select()
.where(Criterion.and(TaskCriteria.isActive(), TaskCriteria.isVisible()))
.orderBy(SortHelper.defaultTaskOrder()).limit(100)));
}
/**
* Mark the given task as completed and save it.
*/
@ -209,19 +225,43 @@ public abstract class TaskDao {
save(item);
}
public Cursor fetchFiltered(String queryTemplate, Property<?>... properties) {
return query(Query.select(properties)
.withQueryTemplate(PermaSql.replacePlaceholders(queryTemplate)));
public int count(Filter filter) {
Cursor cursor = fetchFiltered(filter.getSqlQuery(), Task.ID);
try {
return cursor.getCount();
} finally {
cursor.close();
}
}
public List<Task> fetchFiltered(Filter filter) {
return fetchFiltered(filter.getSqlQuery());
}
public List<Task> fetchFiltered(String query) {
return toList(fetchFiltered(query, Task.PROPERTIES));
}
public Cursor fetchFiltered(String queryTemplate, Property<?>... properties) {
return query(Query.select(properties).withQueryTemplate(PermaSql.replacePlaceholders(queryTemplate)));
}
private List<Task> toList(Cursor cursor) {
List<Task> result = new ArrayList<>();
try {
for (cursor.moveToFirst() ; !cursor.isAfterLast() ; cursor.moveToNext()) {
result.add(new Task(cursor));
}
} finally {
cursor.close();
}
return result;
}
/**
* Construct a query with SQL DSL objects
*/
public Cursor query(Query query) {
private Cursor query(Query query) {
String queryString = query.from(Task.TABLE).toString();
if (BuildConfig.DEBUG) {
Timber.v(queryString);

@ -91,8 +91,6 @@ public class Task implements Parcelable {
/** Unixtime Task was created */
@ColumnInfo(name = "created")
public Long created = 0L;
public static final LongProperty CREATION_DATE = new LongProperty(
TABLE, "created");
/** Unixtime Task was last touched */
@ColumnInfo(name = "modified")
@ -133,14 +131,10 @@ public class Task implements Parcelable {
/** Flags for when to send reminders */
@ColumnInfo(name = "notificationFlags")
public Integer notificationFlags = 0;
public static final IntegerProperty REMINDER_FLAGS = new IntegerProperty(
TABLE, "notificationFlags");
/** Reminder period, in milliseconds. 0 means disabled */
@ColumnInfo(name = "notifications")
public Long notifications = 0L;
public static final LongProperty REMINDER_PERIOD = new LongProperty(
TABLE, "notifications");
/** Unixtime the last reminder was triggered */
@ColumnInfo(name = "lastNotified")
@ -152,16 +146,12 @@ public class Task implements Parcelable {
@ColumnInfo(name = "recurrence")
public String recurrence = "";
public static final StringProperty RECURRENCE = new StringProperty(
TABLE, "recurrence");
@ColumnInfo(name = "repeatUntil")
public Long repeatUntil = 0L;
@ColumnInfo(name = "calendarUri")
public String calendarUri = "";
public static final StringProperty CALENDAR_URI = new StringProperty(
TABLE, "calendarUri");
// --- for astrid.com
@ -176,9 +166,9 @@ public class Task implements Parcelable {
/** List of all properties for this model */
public static final Property<?>[] PROPERTIES = new Property<?>[] {
CALENDAR_URI,
new StringProperty(TABLE, "calendarUri"),
COMPLETION_DATE,
CREATION_DATE,
new LongProperty(TABLE, "created"),
DELETION_DATE,
DUE_DATE,
new IntegerProperty(TABLE, "elapsedSeconds"),
@ -188,10 +178,10 @@ public class Task implements Parcelable {
IMPORTANCE,
MODIFICATION_DATE,
NOTES,
RECURRENCE,
REMINDER_FLAGS,
new StringProperty(TABLE, "recurrence"),
new IntegerProperty(TABLE, "notificationFlags"),
new LongProperty(TABLE, "lastNotified"),
REMINDER_PERIOD,
new LongProperty(TABLE, "notifications"),
new LongProperty(TABLE, "snoozeTime"),
new LongProperty(TABLE, "repeatUntil"),
TIMER_START,

@ -14,16 +14,12 @@ import android.net.Uri;
import android.support.annotation.NonNull;
import com.google.common.base.Joiner;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.core.SortHelper;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import org.tasks.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.tags.TagService;
import org.tasks.data.TagDao;
import org.tasks.data.TagData;
import org.tasks.injection.ContentProviderComponent;
import org.tasks.injection.InjectingContentProvider;
import org.tasks.ui.CheckBoxes;
@ -167,10 +163,7 @@ public class Astrid2TaskProvider extends InjectingContentProvider {
private Cursor getTasks() {
MatrixCursor ret = new MatrixCursor(TASK_FIELD_LIST);
List<Integer> importanceColors = checkBoxes.get().getPriorityColors();
Query query = Query.select()
.where(Criterion.and(TaskCriteria.isActive(), TaskCriteria.isVisible()))
.orderBy(SortHelper.defaultTaskOrder()).limit(MAX_NUMBER_OF_TASKS);
for (Task task : taskDao.get().toList(query)) {
for (Task task : taskDao.get().getAstrid2TaskProviderTasks()) {
String taskTags = getTagsAsString(task.getId(), TAG_SEPARATOR);
Object[] values = new Object[7];

@ -5,11 +5,8 @@
*/
package com.todoroo.astrid.reminders;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.Task;
import org.tasks.injection.ApplicationScope;
@ -53,10 +50,7 @@ public final class ReminderService {
}
public void scheduleAllAlarms(TaskDao taskDao) {
Query query = Query.select().where(Criterion.and(
TaskCriteria.isActive(),
Criterion.or(Task.REMINDER_FLAGS.gt(0), Task.REMINDER_PERIOD.gt(0))));
for (Task task : taskDao.toList(query)) {
for (Task task : taskDao.getTasksWithReminders()) {
scheduleAlarm(task);
}
}

@ -1,6 +1,5 @@
package com.todoroo.astrid.service;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task;

@ -4,15 +4,13 @@ import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Functions;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.activity.TaskListFragment;
import com.todoroo.astrid.adapter.TaskAdapter;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task;
import org.tasks.data.TaskListMetadata;
import java.util.ArrayList;
@ -146,9 +144,7 @@ class AstridOrderedListFragmentHelper {
if(chained.size() > 0) {
// move recurring items to item parent
List<Task> tasks = taskDao.toList(Query.select().where(
Criterion.and(Task.UUID.in(chained.toArray(new String[chained.size()])),
Task.RECURRENCE.isNotNull(), Functions.length(Task.RECURRENCE).gt(0))));
List<Task> tasks = taskDao.getRecurringTasks(chained);
boolean madeChanges = false;
for (Task t : tasks) {

@ -116,7 +116,7 @@ public class SubtasksFilterUpdater {
}
Set<String> idsInQuery = new HashSet<>();
String sql = filter.getSqlQuery().replaceAll("ORDER BY .*", ""); //$NON-NLS-1$//$NON-NLS-2$
sql = sql + String.format(" ORDER BY %s", Task.CREATION_DATE); //$NON-NLS-1$
sql = sql + " ORDER BY created"; //$NON-NLS-1$
sql = sql.replace(
TaskDao.TaskCriteria.activeAndVisible().toString(),
TaskDao.TaskCriteria.notDeleted().toString());

@ -1,30 +1,28 @@
package com.todoroo.astrid.subtasks;
import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.GtasksFilter;
import com.todoroo.astrid.core.BuiltInFilterExposer;
import org.tasks.data.TagDataDao;
import com.todoroo.astrid.dao.TaskDao;
import org.tasks.data.TaskListMetadataDao;
import org.tasks.data.TagData;
import com.todoroo.astrid.data.Task;
import org.tasks.data.TaskListMetadata;
import com.todoroo.astrid.subtasks.SubtasksFilterUpdater.Node;
import org.tasks.R;
import org.tasks.data.TagData;
import org.tasks.data.TagDataDao;
import org.tasks.data.TaskListMetadata;
import org.tasks.data.TaskListMetadataDao;
import org.tasks.injection.ForApplication;
import org.tasks.preferences.Preferences;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
@ -127,7 +125,7 @@ public class SubtasksHelper {
*/
static String convertTreeToRemoteIds(TaskDao taskDao, String localTree) {
List<Long> localIds = getIdList(localTree);
HashMap<Long, String> idMap = getIdMap(taskDao, localIds, Task.ID, Task.UUID);
Map<Long, String> idMap = getIdMap(taskDao, localIds);
idMap.put(-1L, "-1"); //$NON-NLS-1$
Node tree = SubtasksFilterUpdater.buildTreeModel(localTree, null);
@ -139,7 +137,7 @@ public class SubtasksHelper {
T getKeyFromOldUuid(String uuid);
}
private static <T> void remapTree(Node root, HashMap<T, String> idMap, TreeRemapHelper<T> helper) {
private static <T> void remapTree(Node root, Map<T, String> idMap, TreeRemapHelper<T> helper) {
ArrayList<Node> children = root.children;
for (int i = 0; i < children.size(); i++) {
Node child = children.get(i);
@ -156,7 +154,7 @@ public class SubtasksHelper {
}
}
private static void remapLocalTreeToRemote(Node root, HashMap<Long, String> idMap) {
private static void remapLocalTreeToRemote(Node root, Map<Long, String> idMap) {
remapTree(root, idMap, uuid -> {
Long localId = -1L;
try {
@ -168,17 +166,11 @@ public class SubtasksHelper {
});
}
private static <A, B> HashMap<A, B> getIdMap(TaskDao taskDao, Iterable<A> keys, Property<A> keyProperty, Property<B> valueProperty) {
HashMap<A, B> map = new HashMap<>();
Cursor tasks = taskDao.query(Query.select(keyProperty, valueProperty).where(keyProperty.in(keys)));
try {
for (tasks.moveToFirst(); !tasks.isAfterLast(); tasks.moveToNext()) {
A key = keyProperty.getValue(tasks);
B value = valueProperty.getValue(tasks);
map.put(key, value);
}
} finally {
tasks.close();
private static Map<Long, String> getIdMap(TaskDao taskDao, List<Long> keys) {
List<Task> tasks = taskDao.fetch(keys);
Map<Long, String> map = new HashMap<>();
for (Task task : tasks) {
map.put(task.getId(), task.getUuid());
}
return map;
}

@ -8,7 +8,6 @@ package com.todoroo.astrid.timers;
import android.content.Context;
import android.content.res.Resources;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.dao.TaskDao;
@ -42,7 +41,7 @@ public final class TimerFilterExposer {
}
public List<Filter> getFilters() {
if(taskDao.count(Query.select(Task.ID).where(Task.TIMER_START.gt(0))) == 0) {
if(taskDao.activeTimers() == 0) {
return emptyList();
}

@ -11,7 +11,6 @@ import android.content.Intent;
import android.content.res.Resources;
import android.support.v4.app.NotificationCompat;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.dao.TaskDao;
@ -81,8 +80,7 @@ public class TimerPlugin {
}
private void updateNotifications() {
int count = taskDao.count(Query.select(Task.ID).
where(Task.TIMER_START.gt(0)));
int count = taskDao.activeTimers();
if(count == 0) {
notificationManager.cancel(Constants.NOTIFICATION_TIMER);
} else {

@ -7,7 +7,6 @@ package com.todoroo.astrid.utility;
import android.text.TextUtils;
import com.google.common.base.Strings;
import com.google.ical.values.Frequency;
import com.google.ical.values.RRule;
import com.mdimension.jchronic.AstridChronic;

@ -61,7 +61,7 @@ public class Notifier {
}
public void triggerFilterNotification(final Filter filter) {
List<Task> tasks = taskDao.query(filter);
List<Task> tasks = taskDao.fetchFiltered(filter);
int count = tasks.size();
if (count == 0) {
return;

@ -19,7 +19,6 @@ import org.tasks.time.DateTime;
import javax.inject.Inject;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop;
import static org.tasks.dialogs.NativeDatePickerDialog.newNativeDatePickerDialog;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;

@ -1,7 +1,5 @@
package org.tasks.backup;
import com.todoroo.astrid.backup.TasksXmlExporter;
import org.xmlpull.v1.XmlPullParser;
import static com.todoroo.astrid.backup.TasksXmlExporter.XML_NULL;

@ -58,6 +58,12 @@ public class CalendarEventProvider {
return events.isEmpty() ? null : events.get(0);
}
public void deleteEvents(List<String> calendarUris) {
for (String uri : calendarUris) {
deleteEvent(uri);
}
}
public boolean deleteEvent(Task task) {
String uri = task.getCalendarURI();
task.setCalendarUri("");

@ -79,7 +79,7 @@ public class DashClockExtension extends com.google.android.apps.dashclock.api.Da
.expandedBody(filter.listingTitle)
.clickIntent(clickIntent);
if (count == 1) {
List<Task> tasks = taskDao.query(filter);
List<Task> tasks = taskDao.fetchFiltered(filter);
if (!tasks.isEmpty()) {
extensionData.expandedTitle(tasks.get(0).getTitle());
}

@ -43,7 +43,7 @@ public class FilterCounter {
public void refreshFilterCounts(final Runnable onComplete) {
executorService.submit(() -> {
for (Filter filter : filterCounts.keySet()) {
int size = countTasks(filter);
int size = taskDao.count(filter);
filterCounts.put(filter, size);
}
if (onComplete != null) {
@ -66,9 +66,4 @@ public class FilterCounter {
return filterCounts.get(filter);
}
private int countTasks(Filter filter) {
Query query = Query.select(Task.ID)
.withQueryTemplate(PermaSql.replacePlaceholders(filter.getSqlQuery()));
return taskDao.count(query);
}
}

@ -5,7 +5,6 @@ import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import com.todoroo.astrid.activity.BeastModePreferences;
import com.todoroo.astrid.activity.TaskEditFragment;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.files.FilesControlSet;
import com.todoroo.astrid.repeats.RepeatControlSet;

@ -1,23 +0,0 @@
package org.tasks.injection;
import android.app.Activity;
import android.support.v4.app.ListFragment;
public abstract class InjectingListFragment extends ListFragment {
private boolean injected;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!injected) {
inject(((InjectingActivity) activity)
.getComponent()
.plus(new FragmentModule(this)));
injected = true;
}
}
protected abstract void inject(FragmentComponent component);
}

@ -29,8 +29,6 @@ import javax.inject.Inject;
import timber.log.Timber;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Sets.newHashSet;
import static com.todoroo.astrid.dao.TaskDao.TRANS_SUPPRESS_REFRESH;
public class AfterSaveIntentService extends InjectingJobIntentService {

@ -20,8 +20,6 @@ import org.tasks.R;
import java.text.NumberFormat;
import java.text.ParseException;
import timber.log.Timber;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastJellybeanMR1;
public class Locale {

@ -5,8 +5,6 @@ import android.os.Bundle;
import com.todoroo.andlib.utility.AndroidUtilities;
import org.tasks.injection.InjectingAppCompatActivity;
import org.tasks.injection.InjectingPreferenceActivity;
import org.tasks.injection.ThemedInjectingAppCompatActivity;
import timber.log.Timber;

@ -226,13 +226,10 @@ public class NotificationManager {
}
private void updateSummary(boolean notify, boolean nonStop, boolean fiveTimes, List<org.tasks.notifications.Notification> newNotifications) {
List<org.tasks.notifications.Notification> notifications = notificationDao.getAllOrdered();
int taskCount = notifications.size();
ArrayList<Long> taskIds = newArrayList(transform(notifications, n -> n.taskId));
QueryTemplate query = new QueryTemplate().where(Task.ID.in(taskIds));
Filter filter = new Filter(context.getString(R.string.notifications), query);
List<Task> tasks = taskDao.toList(Query.select()
.withQueryTemplate(query.toString()));
List<Task> tasks = taskDao.activeNotifications();
int taskCount = tasks.size();
ArrayList<Long> taskIds = newArrayList(transform(tasks, Task::getId));
Filter filter = new Filter(context.getString(R.string.notifications), new QueryTemplate().where(Task.ID.in(taskIds)));
long when = notificationDao.latestTimestamp();
int maxPriority = 3;
String summaryTitle = context.getResources().getQuantityString(R.plurals.task_count, taskCount, taskCount);
@ -240,11 +237,7 @@ public class NotificationManager {
.setBigContentTitle(summaryTitle);
List<String> titles = newArrayList();
List<String> ticker = newArrayList();
for (org.tasks.notifications.Notification notification : notifications) {
Task task = tryFind(tasks, t -> t.getId() == notification.taskId).orNull();
if (task == null) {
continue;
}
for (Task task : tasks) {
String title = task.getTitle();
style.addLine(title);
titles.add(title);

@ -6,7 +6,6 @@ import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task;
import org.tasks.activities.DateAndTimePickerActivity;
import org.tasks.activities.TimePickerActivity;

@ -7,7 +7,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import com.google.common.base.Strings;
import com.todoroo.astrid.data.Task;
import org.tasks.R;

Loading…
Cancel
Save