diff --git a/api/src/com/todoroo/astrid/data/TaskToTag.java b/api/src/com/todoroo/astrid/data/TaskToTag.java new file mode 100644 index 000000000..f7a4b57d5 --- /dev/null +++ b/api/src/com/todoroo/astrid/data/TaskToTag.java @@ -0,0 +1,76 @@ +package com.todoroo.astrid.data; + +import android.content.ContentValues; +import android.net.Uri; + +import com.todoroo.andlib.data.AbstractModel; +import com.todoroo.andlib.data.Property; +import com.todoroo.andlib.data.Property.LongProperty; +import com.todoroo.andlib.data.Table; +import com.todoroo.astrid.api.AstridApiConstants; + +@SuppressWarnings("nls") +public class TaskToTag extends AbstractModel { + + /** table for this model */ + public static final Table TABLE = new Table("tasks_to_tags", TaskToTag.class); + + /** content uri for this model */ + public static final Uri CONTENT_URI = Uri.parse("content://" + AstridApiConstants.PACKAGE + "/" + + TABLE.name); + + // --- properties + + /** ID */ + public static final LongProperty ID = new LongProperty( + TABLE, ID_PROPERTY_NAME); + + public static final LongProperty TASK_ID = new LongProperty( + TABLE, "taskId"); + + public static final LongProperty TASK_UUID = new LongProperty( + TABLE, "taskUuid"); + + public static final LongProperty TAG_ID = new LongProperty( + TABLE, "tagId"); + + public static final LongProperty TAG_UUID = new LongProperty( + TABLE, "tagUuid"); + + public static final LongProperty DELETED_AT = new LongProperty( + TABLE, "deletedAt"); + + public static final LongProperty PUSHED_AT = new LongProperty( + TABLE, "pushedAt"); + + /** List of all properties for this model */ + public static final Property[] PROPERTIES = generateProperties(TaskToTag.class); + + /** Default values container */ + private static final ContentValues defaultValues = new ContentValues(); + + static { + defaultValues.put(DELETED_AT.name, 0L); + defaultValues.put(PUSHED_AT.name, 0L); + } + + @Override + public ContentValues getDefaultValues() { + return defaultValues; + } + + @Override + public long getId() { + return getIdHelper(ID); + }; + + // --- parcelable helpers + + private static final Creator CREATOR = new ModelCreator(TaskToTag.class); + + @Override + protected Creator getCreator() { + return CREATOR; + } + +} diff --git a/astrid/plugin-src/com/todoroo/astrid/tags/TagsTableMigrator.java b/astrid/plugin-src/com/todoroo/astrid/tags/TagsTableMigrator.java new file mode 100644 index 000000000..31120093e --- /dev/null +++ b/astrid/plugin-src/com/todoroo/astrid/tags/TagsTableMigrator.java @@ -0,0 +1,81 @@ +package com.todoroo.astrid.tags; + +import com.todoroo.andlib.data.TodorooCursor; +import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.DependencyInjectionService; +import com.todoroo.andlib.sql.Criterion; +import com.todoroo.andlib.sql.Join; +import com.todoroo.andlib.sql.Query; +import com.todoroo.andlib.utility.Preferences; +import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria; +import com.todoroo.astrid.dao.TaskToTagDao; +import com.todoroo.astrid.data.Metadata; +import com.todoroo.astrid.data.TagData; +import com.todoroo.astrid.data.TaskToTag; +import com.todoroo.astrid.service.MetadataService; +import com.todoroo.astrid.service.TagDataService; + +public class TagsTableMigrator { + + @Autowired private MetadataService metadataService; + @Autowired private TagDataService tagDataService; + @Autowired private TaskToTagDao taskToTagDao; + + private static final String PREF_MIGRATED_TASKS_TO_TAGS = "tasks_to_tags_migration"; //$NON-NLS-1$ + + public TagsTableMigrator() { + DependencyInjectionService.getInstance().inject(this); + } + + public void migrateTagMetadataToTable() { + if (Preferences.getBoolean(PREF_MIGRATED_TASKS_TO_TAGS, false)) + return; + + // First assert that a TagData object exists for each tag metadata + Query noTagDataQuery = Query.select(Metadata.PROPERTIES).where(Criterion.and( + MetadataCriteria.withKey(TagService.KEY), + Criterion.not(TagService.TAG.in(Query.select(TagData.NAME).from(TagData.TABLE))))).groupBy(TagService.TAG); + + TodorooCursor noTagData = metadataService.query(noTagDataQuery); + try { + Metadata tag = new Metadata(); + for (noTagData.moveToFirst(); !noTagData.isAfterLast(); noTagData.moveToNext()) { + tag.readFromCursor(noTagData); + + System.err.println("CREATING TAG DATA " + tag.getValue(TagService.TAG)); + + TagData newTagData = new TagData(); + newTagData.setValue(TagData.NAME, tag.getValue(TagService.TAG)); + tagDataService.save(newTagData); + } + } finally { + noTagData.close(); + } + + // Then move all tag metadata to the new table + Query joinedTagData = Query.select(Metadata.TASK, TagService.TAG, TagData.ID) + .join(Join.left(TagData.TABLE, + Criterion.and(MetadataCriteria.withKey(TagService.KEY), TagService.TAG.eq(TagData.NAME)))); + + TodorooCursor allTagLinks = metadataService.query(joinedTagData); + try { + Metadata tag = new Metadata(); + for (allTagLinks.moveToFirst(); !allTagLinks.isAfterLast(); allTagLinks.moveToNext()) { + tag.readFromCursor(allTagLinks); + + // Create new tag links + TaskToTag link = new TaskToTag(); + System.err.println("LINK from task " + tag.getValue(Metadata.TASK) + " to " + tag.getValue(TagService.TAG)); + link.setValue(TaskToTag.TASK_ID, tag.getValue(Metadata.TASK)); + link.setValue(TaskToTag.TAG_ID, tag.getValue(TagData.ID)); + + taskToTagDao.createNew(link); + } + } finally { + allTagLinks.close(); + } + + Preferences.setBoolean(PREF_MIGRATED_TASKS_TO_TAGS, true); + } + +} diff --git a/astrid/src/com/todoroo/astrid/dao/Database.java b/astrid/src/com/todoroo/astrid/dao/Database.java index c478010b8..194488bcb 100644 --- a/astrid/src/com/todoroo/astrid/dao/Database.java +++ b/astrid/src/com/todoroo/astrid/dao/Database.java @@ -20,6 +20,7 @@ import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TagOutstanding; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.TaskOutstanding; +import com.todoroo.astrid.data.TaskToTag; import com.todoroo.astrid.data.Update; import com.todoroo.astrid.data.User; import com.todoroo.astrid.provider.Astrid2TaskProvider; @@ -62,7 +63,8 @@ public class Database extends AbstractDatabase { ABTestEvent.TABLE, TaskOutstanding.TABLE, - TagOutstanding.TABLE + TagOutstanding.TABLE, + TaskToTag.TABLE }; // --- listeners @@ -337,6 +339,7 @@ public class Database extends AbstractDatabase { case 25: try { database.execSQL(createTableSql(visitor, TaskOutstanding.TABLE.name, TaskOutstanding.PROPERTIES)); database.execSQL(createTableSql(visitor, TagOutstanding.TABLE.name, TagOutstanding.PROPERTIES)); + database.execSQL(createTableSql(visitor, TaskToTag.TABLE.name, TaskToTag.PROPERTIES)); database.execSQL(addColumnSql(TagData.TABLE, TagData.UUID, visitor)); database.execSQL(addColumnSql(Task.TABLE, Task.UUID, visitor)); diff --git a/astrid/src/com/todoroo/astrid/dao/TaskToTagDao.java b/astrid/src/com/todoroo/astrid/dao/TaskToTagDao.java new file mode 100644 index 000000000..e88c49d68 --- /dev/null +++ b/astrid/src/com/todoroo/astrid/dao/TaskToTagDao.java @@ -0,0 +1,19 @@ +package com.todoroo.astrid.dao; + +import com.todoroo.andlib.data.DatabaseDao; +import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.DependencyInjectionService; +import com.todoroo.astrid.data.TaskToTag; + +public class TaskToTagDao extends DatabaseDao { + + @Autowired + private Database database; + + public TaskToTagDao() { + super(TaskToTag.class); + DependencyInjectionService.getInstance().inject(this); + setDatabase(database); + } + +} diff --git a/astrid/src/com/todoroo/astrid/service/AstridDependencyInjector.java b/astrid/src/com/todoroo/astrid/service/AstridDependencyInjector.java index 2c0c3e7b5..ccb1d3811 100644 --- a/astrid/src/com/todoroo/astrid/service/AstridDependencyInjector.java +++ b/astrid/src/com/todoroo/astrid/service/AstridDependencyInjector.java @@ -20,6 +20,7 @@ import com.todoroo.astrid.dao.MetadataDao; import com.todoroo.astrid.dao.StoreObjectDao; import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.dao.TaskDao; +import com.todoroo.astrid.dao.TaskToTagDao; import com.todoroo.astrid.dao.UpdateDao; import com.todoroo.astrid.dao.UserDao; import com.todoroo.astrid.gtasks.GtasksListService; @@ -72,6 +73,7 @@ public class AstridDependencyInjector extends AbstractDependencyInjector { injectables.put("storeObjectDao", StoreObjectDao.class); injectables.put("updateDao", UpdateDao.class); injectables.put("userDao", UserDao.class); + injectables.put("taskToTagDao", TaskToTagDao.class); // com.todoroo.astrid.service injectables.put("taskService", TaskService.class); diff --git a/astrid/src/com/todoroo/astrid/service/UpgradeService.java b/astrid/src/com/todoroo/astrid/service/UpgradeService.java index 8c8731162..8d16329a2 100644 --- a/astrid/src/com/todoroo/astrid/service/UpgradeService.java +++ b/astrid/src/com/todoroo/astrid/service/UpgradeService.java @@ -41,6 +41,7 @@ import com.todoroo.astrid.notes.NoteMetadata; import com.todoroo.astrid.producteev.sync.ProducteevDataService; import com.todoroo.astrid.service.abtesting.ABChooser; import com.todoroo.astrid.tags.TagCaseMigrator; +import com.todoroo.astrid.tags.TagsTableMigrator; import com.todoroo.astrid.utility.AstridPreferences; @@ -194,6 +195,8 @@ public final class UpgradeService { if (from < V4_0_6) new DueDateTimeMigrator().migrateDueTimes(); + new TagsTableMigrator().migrateTagMetadataToTable(); + } finally { DialogUtilities.dismissDialog((Activity)context, dialog); context.sendBroadcast(new Intent(AstridApiConstants.BROADCAST_EVENT_REFRESH));