diff --git a/app/schemas/com.todoroo.astrid.dao.Database/44.json b/app/schemas/com.todoroo.astrid.dao.Database/44.json new file mode 100644 index 000000000..906c9972c --- /dev/null +++ b/app/schemas/com.todoroo.astrid.dao.Database/44.json @@ -0,0 +1,344 @@ +{ + "formatVersion": 1, + "database": { + "version": 44, + "identityHash": "a3aee725239a54e743d9ccb9653d73ed", + "entities": [ + { + "tableName": "notification", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `type` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "taskId", + "columnName": "task", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_notification_task", + "unique": true, + "columnNames": [ + "task" + ], + "createSql": "CREATE UNIQUE INDEX `index_notification_task` ON `${TABLE_NAME}` (`task`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "tagdata", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `name` TEXT, `color` INTEGER, `tagOrdering` TEXT, `deleted` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "tagOrdering", + "columnName": "tagOrdering", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "deleted", + "columnName": "deleted", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "_id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "userActivity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `action` TEXT, `message` TEXT, `picture` TEXT, `target_id` TEXT, `created_at` INTEGER, `deleted_at` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "action", + "columnName": "action", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "message", + "columnName": "message", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "picture", + "columnName": "picture", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "targetId", + "columnName": "target_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "created", + "columnName": "created_at", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "deleted", + "columnName": "deleted_at", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "_id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "task_attachments", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `task_id` TEXT, `name` TEXT, `path` TEXT, `content_type` TEXT, `deleted_at` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "taskId", + "columnName": "task_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "path", + "columnName": "path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "contentType", + "columnName": "content_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "deleted", + "columnName": "deleted_at", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "_id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "task_list_metadata", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `tag_uuid` TEXT, `filter` TEXT, `task_ids` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "tagUuid", + "columnName": "tag_uuid", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "filter", + "columnName": "filter", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "taskIds", + "columnName": "task_ids", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "_id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "store", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `type` TEXT, `item` TEXT, `value` TEXT, `value2` TEXT, `value3` TEXT, `value4` TEXT, `deleted` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "item", + "columnName": "item", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "value2", + "columnName": "value2", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "value3", + "columnName": "value3", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "value4", + "columnName": "value4", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "deleted", + "columnName": "deleted", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "_id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "so_id", + "unique": false, + "columnNames": [ + "type", + "item" + ], + "createSql": "CREATE INDEX `so_id` ON `${TABLE_NAME}` (`type`, `item`)" + } + ], + "foreignKeys": [] + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"a3aee725239a54e743d9ccb9653d73ed\")" + ] + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/org/tasks/injection/TestModule.java b/app/src/androidTest/java/org/tasks/injection/TestModule.java index 5ef220ae1..e318d2c9e 100644 --- a/app/src/androidTest/java/org/tasks/injection/TestModule.java +++ b/app/src/androidTest/java/org/tasks/injection/TestModule.java @@ -4,6 +4,7 @@ import android.arch.persistence.room.Room; import android.content.Context; import com.todoroo.astrid.dao.Database; +import com.todoroo.astrid.dao.StoreObjectDao; import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.dao.TaskListMetadataDao; import com.todoroo.astrid.dao.UserActivityDao; @@ -53,6 +54,11 @@ public class TestModule { return database.getTaskListMetadataDao(); } + @Provides + public StoreObjectDao getStoreObjectDao(Database database) { + return database.getStoreObjectDao(); + } + @ApplicationScope @Provides @ForApplication diff --git a/app/src/androidTest/java/org/tasks/makers/GtaskListMaker.java b/app/src/androidTest/java/org/tasks/makers/GtaskListMaker.java index afcca23ad..7eb36f74b 100644 --- a/app/src/androidTest/java/org/tasks/makers/GtaskListMaker.java +++ b/app/src/androidTest/java/org/tasks/makers/GtaskListMaker.java @@ -16,7 +16,6 @@ public class GtaskListMaker { public static final Property REMOTE_ID = newProperty(); public static final Property LAST_SYNC = newProperty(); public static final Property NAME = newProperty(); - public static final Property SAVED = newProperty(); public static GtasksList newGtaskList(PropertyValue... properties) { return make(instantiator, properties); @@ -25,16 +24,13 @@ public class GtaskListMaker { private static final Instantiator instantiator = lookup -> { StoreObject storeObject = new StoreObject() {{ setType(GtasksList.TYPE); - setValue(StoreObject.DELETION_DATE, 0L); - setValue(StoreObject.ID, lookup.valueOf(GtaskListMaker.ID, 0L)); - setValue(StoreObject.ITEM, lookup.valueOf(REMOTE_ID, "1")); - setValue(StoreObject.VALUE1, lookup.valueOf(NAME, "Default")); - setValue(StoreObject.VALUE2, String.valueOf(lookup.valueOf(ORDER, 0))); - setValue(StoreObject.VALUE3, String.valueOf(lookup.valueOf(LAST_SYNC, 0L))); + setDeleted(0L); + setId(lookup.valueOf(GtaskListMaker.ID, 0L)); + setItem(lookup.valueOf(REMOTE_ID, "1")); + setValue(lookup.valueOf(NAME, "Default")); + setValue2(String.valueOf(lookup.valueOf(ORDER, 0))); + setValue3(String.valueOf(lookup.valueOf(LAST_SYNC, 0L))); }}; - if (lookup.valueOf(SAVED, false)) { - storeObject.markSaved(); - } return new GtasksList(storeObject); }; } diff --git a/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksListServiceTest.java b/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksListServiceTest.java index 4354a3fac..5da7d7663 100644 --- a/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksListServiceTest.java +++ b/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksListServiceTest.java @@ -21,15 +21,13 @@ import javax.inject.Inject; import static com.natpryce.makeiteasy.MakeItEasy.with; import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; import static org.tasks.makers.GtaskListMaker.ID; import static org.tasks.makers.GtaskListMaker.LAST_SYNC; import static org.tasks.makers.GtaskListMaker.NAME; import static org.tasks.makers.GtaskListMaker.REMOTE_ID; -import static org.tasks.makers.GtaskListMaker.SAVED; import static org.tasks.makers.GtaskListMaker.newGtaskList; import static org.tasks.makers.RemoteGtaskListMaker.newRemoteList; import static org.tasks.time.DateTimeUtils.currentTimeMillis; @@ -43,13 +41,12 @@ public class GtasksListServiceTest extends InjectingTestCase { @Inject MetadataDao metadataDao; @Inject LocalBroadcastManager localBroadcastManager; - private StoreObjectDao storeObjectDao; + @Inject StoreObjectDao storeObjectDao; private GtasksListService gtasksListService; @Override public void setUp() { super.setUp(); - storeObjectDao = spy(new StoreObjectDao(database)); gtasksListService = new GtasksListService(storeObjectDao, taskListDataProvider, taskDeleter, metadataDao, localBroadcastManager); } @@ -69,8 +66,7 @@ public class GtasksListServiceTest extends InjectingTestCase { newGtaskList( with(ID, 1L), with(REMOTE_ID, "1"), - with(NAME, "Default"), - with(SAVED, true)), + with(NAME, "Default")), storeObjectDao.getGtasksList(1L)); } @@ -89,16 +85,20 @@ public class GtasksListServiceTest extends InjectingTestCase { @Test public void testDeleteMissingList() { - storeObjectDao.persist(newGtaskList(with(REMOTE_ID, "1"))); + storeObjectDao.persist(newGtaskList(with(ID, 1L), with(REMOTE_ID, "1"))); - setLists(newRemoteList(with(RemoteGtaskListMaker.REMOTE_ID, "2"))); + TaskList taskList = newRemoteList(with(RemoteGtaskListMaker.REMOTE_ID, "2")); - verify(storeObjectDao).delete(1L); + setLists(taskList); + + assertEquals(singletonList(newGtaskList(with(ID, 2L), with(REMOTE_ID, "2")).getStoreObject()), + storeObjectDao.getGtasksLists()); } @Test public void testUpdateListName() { storeObjectDao.persist(newGtaskList( + with(ID, 1L), with(REMOTE_ID, "1"), with(NAME, "oldName"))); @@ -123,7 +123,7 @@ public class GtasksListServiceTest extends InjectingTestCase { setLists(taskList); assertEquals( - asList(newGtaskList(with(ID, 1L), with(REMOTE_ID, "1"), with(LAST_SYNC, 0L), with(SAVED, true))), + asList(newGtaskList(with(ID, 1L), with(REMOTE_ID, "1"), with(LAST_SYNC, 0L))), gtasksListService.getListsToUpdate(asList(taskList))); } diff --git a/app/src/main/java/com/todoroo/andlib/data/Property.java b/app/src/main/java/com/todoroo/andlib/data/Property.java index defaa2ca0..ac3255b37 100644 --- a/app/src/main/java/com/todoroo/andlib/data/Property.java +++ b/app/src/main/java/com/todoroo/andlib/data/Property.java @@ -43,8 +43,6 @@ public abstract class Property extends Field implements Cloneable { public static final int PROP_FLAG_NULLABLE = 1; /** Is this field a date? */ public static final int PROP_FLAG_DATE = 1 << 1; - /** Is this field a serialized JSON object? */ - public static final int PROP_FLAG_JSON = 1 << 4; private int flags = 0; @@ -226,15 +224,6 @@ public abstract class Property extends Field implements Cloneable { super(table, name); } - public DoubleProperty(Table table, String name, int flags) { - super(table, name, flags); - } - - protected DoubleProperty(Table table, String name, String expression) { - super(table, name, expression); - } - - @Override public RETURN accept( PropertyVisitor visitor, PARAMETER data) { diff --git a/app/src/main/java/com/todoroo/astrid/api/CustomFilter.java b/app/src/main/java/com/todoroo/astrid/api/CustomFilter.java index bed029496..7538f2828 100644 --- a/app/src/main/java/com/todoroo/astrid/api/CustomFilter.java +++ b/app/src/main/java/com/todoroo/astrid/api/CustomFilter.java @@ -5,7 +5,6 @@ import android.os.Parcel; import android.os.Parcelable; import com.todoroo.andlib.utility.AndroidUtilities; -import com.todoroo.astrid.core.SavedFilter; import com.todoroo.astrid.data.StoreObject; public class CustomFilter extends Filter { @@ -23,10 +22,10 @@ public class CustomFilter extends Filter { public StoreObject toStoreObject() { StoreObject storeObject = new StoreObject(); storeObject.setId(id); - storeObject.setValue(SavedFilter.NAME, listingTitle); - storeObject.setValue(SavedFilter.SQL, sqlQuery); + storeObject.setItem(listingTitle); + storeObject.setValue(sqlQuery); if (valuesForNewTasks != null && valuesForNewTasks.size() > 0) { - storeObject.setValue(SavedFilter.VALUES, AndroidUtilities.contentValuesToSerializedString(valuesForNewTasks)); + storeObject.setValue2(AndroidUtilities.contentValuesToSerializedString(valuesForNewTasks)); } return storeObject; } diff --git a/app/src/main/java/com/todoroo/astrid/core/CustomFilterExposer.java b/app/src/main/java/com/todoroo/astrid/core/CustomFilterExposer.java index bd01824ce..9e82ab211 100644 --- a/app/src/main/java/com/todoroo/astrid/core/CustomFilterExposer.java +++ b/app/src/main/java/com/todoroo/astrid/core/CustomFilterExposer.java @@ -47,9 +47,9 @@ public final class CustomFilterExposer { return null; } - String title = savedFilter.getValue(SavedFilter.NAME); - String sql = savedFilter.getValue(SavedFilter.SQL); - String values = savedFilter.getValue(SavedFilter.VALUES); + String title = savedFilter.getItem(); + String sql = savedFilter.getValue(); + String values = savedFilter.getValue2(); ContentValues contentValues = null; if(!TextUtils.isEmpty(values)) { diff --git a/app/src/main/java/com/todoroo/astrid/core/SavedFilter.java b/app/src/main/java/com/todoroo/astrid/core/SavedFilter.java index 309466a70..26fd78968 100644 --- a/app/src/main/java/com/todoroo/astrid/core/SavedFilter.java +++ b/app/src/main/java/com/todoroo/astrid/core/SavedFilter.java @@ -7,7 +7,6 @@ package com.todoroo.astrid.core; import android.content.ContentValues; -import com.todoroo.andlib.data.Property.StringProperty; import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.astrid.core.CustomFilterActivity.CriterionInstance; import com.todoroo.astrid.dao.StoreObjectDao; @@ -21,26 +20,7 @@ import com.todoroo.astrid.data.StoreObject; */ public class SavedFilter { - /** type */ - public static final String TYPE = "filter"; //$NON-NLS-1$ - - /** saved filter name */ - public static final StringProperty NAME = new StringProperty(StoreObject.TABLE, - StoreObject.ITEM.name); - - /** perma-sql */ - public static final StringProperty SQL = new StringProperty(StoreObject.TABLE, - StoreObject.VALUE1.name); - - /** serialized new task content values */ - public static final StringProperty VALUES = new StringProperty(StoreObject.TABLE, - StoreObject.VALUE2.name); - - /** serialized list of filters applied */ - private static final StringProperty FILTERS = new StringProperty(StoreObject.TABLE, - StoreObject.VALUE3.name); - - // --- data storage and retrieval methods + private static final String TYPE = "filter"; //$NON-NLS-1$ /** * Save a filter @@ -60,17 +40,17 @@ public class SavedFilter { // populate saved filter properties storeObject.setType(TYPE); - storeObject.setValue(NAME, title); - storeObject.setValue(SQL, sql); + storeObject.setItem(title); + storeObject.setValue(sql); if(values == null) { - storeObject.setValue(VALUES, ""); //$NON-NLS-1$ + storeObject.setValue2(""); //$NON-NLS-1$ } else { - storeObject.setValue(VALUES, AndroidUtilities.contentValuesToSerializedString(values)); + storeObject.setValue2(AndroidUtilities.contentValuesToSerializedString(values)); } String filters = serializeFilters(adapter); - storeObject.setValue(FILTERS, filters); + storeObject.setValue3(filters); if (dao.persist(storeObject)) { return storeObject; diff --git a/app/src/main/java/com/todoroo/astrid/dao/Database.java b/app/src/main/java/com/todoroo/astrid/dao/Database.java index dc613cd1b..90a4a2266 100644 --- a/app/src/main/java/com/todoroo/astrid/dao/Database.java +++ b/app/src/main/java/com/todoroo/astrid/dao/Database.java @@ -42,9 +42,10 @@ import timber.log.Timber; TagData.class, UserActivity.class, TaskAttachment.class, - TaskListMetadata.class + TaskListMetadata.class, + StoreObject.class }, - version = 43) + version = 44) public abstract class Database extends RoomDatabase { public abstract NotificationDao notificationDao(); @@ -52,13 +53,13 @@ public abstract class Database extends RoomDatabase { public abstract UserActivityDao getUserActivityDao(); public abstract TaskAttachmentDao getTaskAttachmentDao(); public abstract TaskListMetadataDao getTaskListMetadataDao(); + public abstract StoreObjectDao getStoreObjectDao(); public static final String NAME = "database"; public static final Table[] TABLES = new Table[] { Task.TABLE, - Metadata.TABLE, - StoreObject.TABLE, + Metadata.TABLE }; private SupportSQLiteDatabase database; diff --git a/app/src/main/java/com/todoroo/astrid/dao/StoreObjectDao.java b/app/src/main/java/com/todoroo/astrid/dao/StoreObjectDao.java index 1f5f34454..409d67225 100644 --- a/app/src/main/java/com/todoroo/astrid/dao/StoreObjectDao.java +++ b/app/src/main/java/com/todoroo/astrid/dao/StoreObjectDao.java @@ -5,44 +5,31 @@ */ package com.todoroo.astrid.dao; -import com.todoroo.andlib.data.DatabaseDao; -import com.todoroo.andlib.sql.Criterion; -import com.todoroo.andlib.sql.Order; -import com.todoroo.astrid.core.SavedFilter; +import android.arch.persistence.room.Dao; +import android.arch.persistence.room.Insert; +import android.arch.persistence.room.OnConflictStrategy; +import android.arch.persistence.room.Query; +import android.arch.persistence.room.Update; + import com.todoroo.astrid.data.StoreObject; import com.todoroo.astrid.gtasks.GtasksList; import java.util.List; -import javax.inject.Inject; - -import static com.todoroo.andlib.sql.Criterion.and; -import static com.todoroo.andlib.sql.Query.select; +@Dao +public abstract class StoreObjectDao { -public class StoreObjectDao { + @Query("SELECT * FROM store WHERE type = 'filter' ORDER BY item ASC") + public abstract List getSavedFilters(); - private final DatabaseDao dao; + @Query("SELECT * FROM store WHERE type = 'filter' AND _id = :id LIMIT 1") + public abstract StoreObject getSavedFilterById(long id); - private static final Criterion isSavedFilter = StoreObject.TYPE.eq(SavedFilter.TYPE); - - @Inject - public StoreObjectDao(Database database) { - dao = new DatabaseDao<>(database, StoreObject.class); - } - - public List getSavedFilters() { - return dao.toList(select(StoreObject.PROPERTIES) - .where(isSavedFilter) - .orderBy(Order.asc(SavedFilter.NAME))); - } - - public StoreObject getSavedFilterById(long id) { - return dao.getFirst(select(StoreObject.PROPERTIES) - .where(and(isSavedFilter, StoreObject.ID.eq(id)))); - } + @Query("SELECT * FROM store WHERE _id = :id LIMIT 1") + abstract StoreObject getById(long id); public GtasksList getGtasksList(long id) { - StoreObject result = dao.fetch(id, StoreObject.PROPERTIES); + StoreObject result = getById(id); if (result == null) { throw new RuntimeException(String.format("No store object found [id=%s]", id)); } else if (!result.getType().equals(GtasksList.TYPE)) { @@ -51,31 +38,27 @@ public class StoreObjectDao { return new GtasksList(result); } - public List getGtasksLists() { - return dao.toList(select(StoreObject.PROPERTIES) - .where(and(StoreObject.DELETION_DATE.eq(0), StoreObject.TYPE.eq(GtasksList.TYPE))) - .orderBy(Order.asc(StoreObject.VALUE1))); - } + @Query("SELECT * FROM store WHERE deleted = 0 AND type = 'gtasks-list' ORDER BY value ASC") + public abstract List getGtasksLists(); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + public abstract long insert(StoreObject storeObject); public boolean persist(StoreObject storeObject) { - return dao.persist(storeObject); + return insert(storeObject) > 0; } public void persist(GtasksList list) { persist(list.getStoreObject()); } - public void update(StoreObject storeObject) { - dao.saveExisting(storeObject); - } + @Update + public abstract void update(StoreObject storeObject); - public StoreObject getSavedFilterByName(String title) { - return dao.getFirst(select(StoreObject.ID) - .where(and(isSavedFilter, SavedFilter.NAME.eq(title)))); - } + @Query("SELECT * FROM store WHERE type = 'filter' AND item = :title LIMIT 1") + public abstract StoreObject getSavedFilterByName(String title); - public void delete(long id) { - dao.delete(id); - } + @Query("DELETE FROM store WHERE _id = :id") + public abstract void delete(long id); } diff --git a/app/src/main/java/com/todoroo/astrid/data/StoreObject.java b/app/src/main/java/com/todoroo/astrid/data/StoreObject.java index b21f3df19..5ade3a56a 100644 --- a/app/src/main/java/com/todoroo/astrid/data/StoreObject.java +++ b/app/src/main/java/com/todoroo/astrid/data/StoreObject.java @@ -6,102 +6,193 @@ package com.todoroo.astrid.data; -import android.content.ContentValues; +import android.arch.persistence.room.ColumnInfo; +import android.arch.persistence.room.Entity; +import android.arch.persistence.room.Ignore; +import android.arch.persistence.room.Index; +import android.arch.persistence.room.PrimaryKey; +import android.os.Parcel; +import android.os.Parcelable; -import com.todoroo.andlib.data.AbstractModel; -import com.todoroo.andlib.data.Property; -import com.todoroo.andlib.data.Property.LongProperty; -import com.todoroo.andlib.data.Property.StringProperty; -import com.todoroo.andlib.data.Table; +@Entity(tableName = "store", + indices = @Index(name = "so_id", value = {"type", "item"})) +public class StoreObject implements Parcelable{ -/** - * Data Model which represents a piece of data unrelated to a task - * - * @author Tim Su - * - */ -public class StoreObject extends AbstractModel { + @PrimaryKey(autoGenerate = true) + @ColumnInfo(name = "_id") + private Long id; - // --- table + @ColumnInfo(name = "type") + private String type; - /** table for this model */ - public static final Table TABLE = new Table("store", StoreObject.class); + @ColumnInfo(name = "item") + private String item; - // --- properties + @ColumnInfo(name = "value") + private String value; - /** ID */ - public static final LongProperty ID = new LongProperty( - TABLE, ID_PROPERTY_NAME); + @ColumnInfo(name = "value2") + private String value2; - /** Store Type Key */ - public static final StringProperty TYPE = new StringProperty( - TABLE, "type"); + @ColumnInfo(name = "value3") + private String value3; - /** Store Item Key */ - public static final StringProperty ITEM= new StringProperty( - TABLE, "item"); + @ColumnInfo(name = "value4") + private String value4; - /** Store Value Column 1 */ - public static final StringProperty VALUE1 = new StringProperty( - TABLE, "value"); + @ColumnInfo(name = "deleted") + private Long deleted = 0L; - /** Store Value Column 2 */ - public static final StringProperty VALUE2 = new StringProperty( - TABLE, "value2"); + public StoreObject() { - /** Store Value Column 3 */ - public static final StringProperty VALUE3 = new StringProperty( - TABLE, "value3"); + } - /** Store Value Column 3 */ - public static final StringProperty VALUE4 = new StringProperty( - TABLE, "value4"); + @Ignore + public StoreObject(Parcel source) { + id = source.readLong(); + type = source.readString(); + item = source.readString(); + value = source.readString(); + value2 = source.readString(); + value3 = source.readString(); + value4 = source.readString(); + deleted = source.readLong(); + } - /** Unixtime Task was deleted. 0 means not deleted */ - public static final LongProperty DELETION_DATE = new LongProperty( - TABLE, "deleted", Property.PROP_FLAG_DATE); + public Long getId() { + return id; + } - /** List of all properties for this model */ - public static final Property[] PROPERTIES = generateProperties(StoreObject.class); + public void setId(Long id) { + this.id = id; + } - // --- defaults + public String getType() { + return type; + } - /** Default values container */ - private static final ContentValues defaultValues = new ContentValues(); + public void setType(String type) { + this.type = type; + } - static { - defaultValues.put(DELETION_DATE.name, 0); + public String getItem() { + return item; } - @Override - public ContentValues getDefaultValues() { - return defaultValues; + public void setItem(String item) { + this.item = item; } - @Override - public long getId() { - return getIdHelper(ID); + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; } - // --- parcelable helpers + public String getValue2() { + return value2; + } - public static final Creator CREATOR = new ModelCreator<>(StoreObject.class); + public void setValue2(String value2) { + this.value2 = value2; + } - public String getType() { - return getValue(TYPE); + public String getValue3() { + return value3; } - public void setType(String type) { - setValue(TYPE, type); + public void setValue3(String value3) { + this.value3 = value3; + } + + public String getValue4() { + return value4; + } + + public void setValue4(String value4) { + this.value4 = value4; + } + + public Long getDeleted() { + return deleted; + } + + public void setDeleted(Long deleted) { + this.deleted = deleted; } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof StoreObject)) return false; + if (o == null || !(o instanceof StoreObject)) return false; StoreObject that = (StoreObject) o; - return getMergedValues().equals(that.getMergedValues()); + if (id != null ? !id.equals(that.id) : that.id != null) return false; + if (type != null ? !type.equals(that.type) : that.type != null) return false; + if (item != null ? !item.equals(that.item) : that.item != null) return false; + if (value != null ? !value.equals(that.value) : that.value != null) return false; + if (value2 != null ? !value2.equals(that.value2) : that.value2 != null) return false; + if (value3 != null ? !value3.equals(that.value3) : that.value3 != null) return false; + if (value4 != null ? !value4.equals(that.value4) : that.value4 != null) return false; + return deleted != null ? deleted.equals(that.deleted) : that.deleted == null; + } + + @Override + public int hashCode() { + int result = id != null ? id.hashCode() : 0; + result = 31 * result + (type != null ? type.hashCode() : 0); + result = 31 * result + (item != null ? item.hashCode() : 0); + result = 31 * result + (value != null ? value.hashCode() : 0); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (deleted != null ? deleted.hashCode() : 0); + return result; + } + + public static Creator CREATOR = new Creator() { + @Override + public StoreObject createFromParcel(Parcel source) { + return new StoreObject(source); + } + + @Override + public StoreObject[] newArray(int size) { + return new StoreObject[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(id); + dest.writeString(type); + dest.writeString(item); + dest.writeString(value); + dest.writeString(value2); + dest.writeString(value3); + dest.writeString(value4); + dest.writeLong(deleted); + } + + @Override + public String toString() { + return "StoreObject{" + + "id=" + id + + ", type='" + type + '\'' + + ", item='" + item + '\'' + + ", value='" + value + '\'' + + ", value2='" + value2 + '\'' + + ", value3='" + value3 + '\'' + + ", value4='" + value4 + '\'' + + ", deleted=" + deleted + + '}'; } } diff --git a/app/src/main/java/com/todoroo/astrid/gtasks/GtasksList.java b/app/src/main/java/com/todoroo/astrid/gtasks/GtasksList.java index a1a463df4..bc2fb617e 100644 --- a/app/src/main/java/com/todoroo/astrid/gtasks/GtasksList.java +++ b/app/src/main/java/com/todoroo/astrid/gtasks/GtasksList.java @@ -5,6 +5,7 @@ */ package com.todoroo.astrid.gtasks; +import com.google.common.base.Strings; import com.todoroo.astrid.data.StoreObject; /** @@ -45,43 +46,41 @@ public class GtasksList { } public String getRemoteId() { - return storeObject.getValue(StoreObject.ITEM); + return storeObject.getItem(); } private void setRemoteId(String remoteId) { - storeObject.setValue(StoreObject.ITEM, remoteId); + storeObject.setItem(remoteId); } public String getName() { - return storeObject.getValue(StoreObject.VALUE1); + return storeObject.getValue(); } public void setName(String name) { - storeObject.setValue(StoreObject.VALUE1, name); + storeObject.setValue(name); } public void setOrder(int order) { - storeObject.setValue(StoreObject.VALUE2, Integer.toString(order)); + storeObject.setValue2(Integer.toString(order)); } public int getColor() { - return storeObject.containsNonNullValue(StoreObject.VALUE4) - ? Integer.parseInt(storeObject.getValue(StoreObject.VALUE4)) - : -1; + String color = storeObject.getValue4(); + return Strings.isNullOrEmpty(color) ? -1 : Integer.parseInt(storeObject.getValue4()); } public void setColor(int color) { - storeObject.setValue(StoreObject.VALUE4, Integer.toString(color)); + storeObject.setValue4(Integer.toString(color)); } public long getLastSync() { - return storeObject.containsNonNullValue(StoreObject.VALUE3) - ? Long.parseLong(storeObject.getValue(StoreObject.VALUE3)) - : 0; + String lastSync = storeObject.getValue3(); + return Strings.isNullOrEmpty(lastSync) ? 0 : Long.parseLong(lastSync); } public void setLastSync(long timestamp) { - storeObject.setValue(StoreObject.VALUE3, Long.toString(timestamp)); + storeObject.setValue3(Long.toString(timestamp)); } public StoreObject getStoreObject() { @@ -91,14 +90,11 @@ public class GtasksList { @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof GtasksList)) return false; + if (o == null || !(o instanceof GtasksList)) return false; GtasksList that = (GtasksList) o; - if (storeObject != null ? !storeObject.equals(that.storeObject) : that.storeObject != null) - return false; - - return true; + return storeObject != null ? storeObject.equals(that.storeObject) : that.storeObject == null; } @Override diff --git a/app/src/main/java/org/tasks/db/Migrations.java b/app/src/main/java/org/tasks/db/Migrations.java index 649b663ea..616422653 100644 --- a/app/src/main/java/org/tasks/db/Migrations.java +++ b/app/src/main/java/org/tasks/db/Migrations.java @@ -61,7 +61,8 @@ public class Migrations { NOOP(39, 40), NOOP(40, 41), NOOP(41, 42), - NOOP(42, 43) + NOOP(42, 43), + NOOP(43, 44) }; public static RoomDatabase.Callback ON_CREATE = new RoomDatabase.Callback() { @@ -101,14 +102,6 @@ public class Migrations { db.execSQL(sql.toString()); sql.setLength(0); - sql.append("CREATE INDEX IF NOT EXISTS so_id ON "). - append(StoreObject.TABLE).append('('). - append(StoreObject.TYPE.name).append(','). - append(StoreObject.ITEM.name). - append(')'); - db.execSQL(sql.toString()); - sql.setLength(0); - sql.append("CREATE UNIQUE INDEX IF NOT EXISTS t_rid ON "). append(Task.TABLE).append('('). append(Task.UUID.name). diff --git a/app/src/main/java/org/tasks/injection/ApplicationModule.java b/app/src/main/java/org/tasks/injection/ApplicationModule.java index c48ecf999..464b0f283 100644 --- a/app/src/main/java/org/tasks/injection/ApplicationModule.java +++ b/app/src/main/java/org/tasks/injection/ApplicationModule.java @@ -4,6 +4,7 @@ import android.arch.persistence.room.Room; import android.content.Context; import com.todoroo.astrid.dao.Database; +import com.todoroo.astrid.dao.StoreObjectDao; import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.dao.TaskAttachmentDao; import com.todoroo.astrid.dao.TaskListMetadataDao; @@ -85,4 +86,9 @@ public class ApplicationModule { public TaskListMetadataDao getTaskListMetadataDao(Database database) { return database.getTaskListMetadataDao(); } + + @Provides + public StoreObjectDao getStoreObjectDao(Database database) { + return database.getStoreObjectDao(); + } }