mirror of https://github.com/tasks/tasks
Temporary commit with add
parent
4287d13969
commit
0f0fcfb9ba
@ -0,0 +1,296 @@
|
||||
package com.todoroo.astrid.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.database.sqlite.SQLiteDatabase.CursorFactory;
|
||||
import android.util.Log;
|
||||
|
||||
import com.timsu.astrid.data.AbstractController;
|
||||
import com.timsu.astrid.data.alerts.Alert;
|
||||
import com.timsu.astrid.data.task.AbstractTaskModel;
|
||||
import com.todoroo.andlib.data.AbstractModel;
|
||||
import com.todoroo.andlib.data.GenericDao;
|
||||
import com.todoroo.andlib.data.Property;
|
||||
import com.todoroo.andlib.data.Property.PropertyVisitor;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||
import com.todoroo.astrid.alarms.Alarm;
|
||||
import com.todoroo.astrid.alarms.AlarmsDatabase;
|
||||
import com.todoroo.astrid.dao.Database;
|
||||
import com.todoroo.astrid.dao.MetadataDao;
|
||||
import com.todoroo.astrid.dao.TaskDao;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
import com.todoroo.astrid.tags.DataService;
|
||||
|
||||
public class Astrid2To3UpgradeHelper {
|
||||
|
||||
@Autowired
|
||||
private TaskDao taskDao;
|
||||
|
||||
@Autowired
|
||||
private MetadataDao metadataDao;
|
||||
|
||||
@Autowired
|
||||
private Database database;
|
||||
|
||||
@Autowired
|
||||
private String tasksTable;
|
||||
|
||||
@Autowired
|
||||
private String tagsTable;
|
||||
|
||||
@Autowired
|
||||
private String tagTaskTable;
|
||||
|
||||
@Autowired
|
||||
private String alertsTable;
|
||||
|
||||
// --- implementation
|
||||
|
||||
public Astrid2To3UpgradeHelper() {
|
||||
DependencyInjectionService.getInstance().inject(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Upgrade helper class that reads a database
|
||||
*/
|
||||
private static class Astrid2UpgradeHelper extends SQLiteOpenHelper {
|
||||
|
||||
public Astrid2UpgradeHelper(Context context, String name,
|
||||
CursorFactory factory, int version) {
|
||||
super(context, name, factory, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the upgrade from Astrid 2 to Astrid 3
|
||||
*/
|
||||
public void upgrade2To3() {
|
||||
Context context = ContextManager.getContext();
|
||||
|
||||
database.openForWriting();
|
||||
|
||||
// --- upgrade tasks table
|
||||
HashMap<String, Property<?>> propertyMap =
|
||||
new HashMap<String, Property<?>>();
|
||||
propertyMap.put(AbstractController.KEY_ROWID, Task.ID);
|
||||
propertyMap.put(AbstractTaskModel.NAME, Task.TITLE);
|
||||
propertyMap.put(AbstractTaskModel.NOTES, Task.NOTES);
|
||||
// don't update progress percentage, we don't use this anymore
|
||||
propertyMap.put(AbstractTaskModel.IMPORTANCE, Task.IMPORTANCE);
|
||||
propertyMap.put(AbstractTaskModel.ESTIMATED_SECONDS, Task.ESTIMATED_SECONDS);
|
||||
propertyMap.put(AbstractTaskModel.ELAPSED_SECONDS, Task.ELAPSED_SECONDS);
|
||||
propertyMap.put(AbstractTaskModel.TIMER_START, Task.TIMER_START);
|
||||
propertyMap.put(AbstractTaskModel.DEFINITE_DUE_DATE, Task.DUE_DATE);
|
||||
propertyMap.put(AbstractTaskModel.PREFERRED_DUE_DATE, Task.PREFERRED_DUE_DATE);
|
||||
propertyMap.put(AbstractTaskModel.HIDDEN_UNTIL, Task.HIDDEN_UNTIL);
|
||||
propertyMap.put(AbstractTaskModel.POSTPONE_COUNT, Task.POSTPONE_COUNT);
|
||||
propertyMap.put(AbstractTaskModel.NOTIFICATIONS, Task.NOTIFICATIONS);
|
||||
propertyMap.put(AbstractTaskModel.NOTIFICATION_FLAGS, Task.NOTIFICATION_FLAGS);
|
||||
propertyMap.put(AbstractTaskModel.LAST_NOTIFIED, Task.LAST_NOTIFIED);
|
||||
propertyMap.put(AbstractTaskModel.REPEAT, Task.REPEAT);
|
||||
propertyMap.put(AbstractTaskModel.CREATION_DATE, Task.CREATION_DATE);
|
||||
propertyMap.put(AbstractTaskModel.COMPLETION_DATE, Task.COMPLETION_DATE);
|
||||
propertyMap.put(AbstractTaskModel.CALENDAR_URI, Task.CALENDAR_URI);
|
||||
propertyMap.put(AbstractTaskModel.FLAGS, Task.FLAGS);
|
||||
upgradeTable(context, tasksTable,
|
||||
propertyMap, new Task(), taskDao);
|
||||
|
||||
// --- upgrade tags tables
|
||||
migrateTagsToMetadata();
|
||||
|
||||
// --- upgrade alerts
|
||||
AlarmsDatabase alarmsDatabase = new AlarmsDatabase();
|
||||
alarmsDatabase.openForWriting();
|
||||
propertyMap.clear();
|
||||
propertyMap.put(AbstractController.KEY_ROWID, Alarm.ID);
|
||||
propertyMap.put(Alert.TASK, Alarm.TASK);
|
||||
propertyMap.put(Alert.DATE, Alarm.TIME);
|
||||
upgradeTable(context, alertsTable, propertyMap, new Alarm(),
|
||||
alarmsDatabase.getDao());
|
||||
alarmsDatabase.close();
|
||||
|
||||
// --- upgrade RTM sync mappings (?)
|
||||
|
||||
database.close();
|
||||
}
|
||||
|
||||
// --- database upgrade helpers
|
||||
|
||||
protected static final class UpgradeVisitorContainer {
|
||||
public int columnIndex;
|
||||
public Cursor cursor;
|
||||
public AbstractModel model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visitor that reads from a visitor container and writes to the model
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
protected static final class ColumnUpgradeVisitor implements PropertyVisitor<Void, UpgradeVisitorContainer> {
|
||||
@Override
|
||||
public Void visitDouble(Property<Double> property, UpgradeVisitorContainer data) {
|
||||
double value = data.cursor.getDouble(data.columnIndex);
|
||||
data.model.setValue(property, value);
|
||||
Log.d("upgrade", "wrote " + value + " to -> " + property + " of model id " + data.cursor.getLong(1));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitInteger(Property<Integer> property, UpgradeVisitorContainer data) {
|
||||
int value;
|
||||
|
||||
// convert long date -> integer
|
||||
if(property == Task.COMPLETION_DATE ||
|
||||
property == Task.CREATION_DATE ||
|
||||
property == Task.DELETION_DATE ||
|
||||
property == Task.DUE_DATE ||
|
||||
property == Task.HIDDEN_UNTIL ||
|
||||
property == Task.LAST_NOTIFIED ||
|
||||
property == Task.MODIFICATION_DATE ||
|
||||
property == Task.PREFERRED_DUE_DATE ||
|
||||
property == Alarm.TIME)
|
||||
value = (int) (data.cursor.getLong(data.columnIndex) / 1000L);
|
||||
else
|
||||
value = data.cursor.getInt(data.columnIndex);
|
||||
|
||||
data.model.setValue(property, value);
|
||||
Log.d("upgrade", "wrote " + value + " to -> " + property + " of model id " + data.cursor.getLong(1));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitLong(Property<Long> property, UpgradeVisitorContainer data) {
|
||||
long value = data.cursor.getLong(data.columnIndex);
|
||||
data.model.setValue(property, value);
|
||||
Log.d("upgrade", "wrote " + value + " to -> " + property + " of model id " + data.cursor.getLong(1));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitString(Property<String> property, UpgradeVisitorContainer data) {
|
||||
String value = data.cursor.getString(data.columnIndex);
|
||||
data.model.setValue(property, value);
|
||||
Log.d("upgrade", "wrote " + value + " to -> " + property + " of model id " + data.cursor.getLong(1));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper that reads entries from legacy database and row-by-row
|
||||
* creates new models and saves them.
|
||||
*
|
||||
* @param context
|
||||
* @param legacyTable
|
||||
* @param propertyMap
|
||||
* @param model
|
||||
* @param dao
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
private static final <TYPE extends AbstractModel> void upgradeTable(Context context, String legacyTable,
|
||||
HashMap<String, Property<?>> propertyMap, TYPE model,
|
||||
GenericDao<TYPE> dao) {
|
||||
|
||||
if(!checkIfDatabaseExists(context, legacyTable))
|
||||
return;
|
||||
|
||||
SQLiteDatabase upgradeDb = new Astrid2UpgradeHelper(context, legacyTable,
|
||||
null, 1).getReadableDatabase();
|
||||
|
||||
Cursor cursor = upgradeDb.rawQuery("SELECT * FROM " + legacyTable, null);
|
||||
UpgradeVisitorContainer container = new UpgradeVisitorContainer();
|
||||
container.cursor = cursor;
|
||||
container.model = model;
|
||||
ColumnUpgradeVisitor visitor = new ColumnUpgradeVisitor();
|
||||
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
|
||||
model.clear();
|
||||
for(Entry<String, Property<?>> entry : propertyMap.entrySet()) {
|
||||
container.columnIndex = cursor.getColumnIndex(entry.getKey());
|
||||
entry.getValue().accept(visitor, container);
|
||||
}
|
||||
dao.createItem(container.model);
|
||||
}
|
||||
|
||||
upgradeDb.close();
|
||||
}
|
||||
|
||||
private static boolean checkIfDatabaseExists(Context context, String legacyTable) {
|
||||
return context.getDatabasePath(legacyTable).exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Move data from tags tables into metadata table. We do this by looping
|
||||
* through both the tags and tagTaskMap databases, reading data from
|
||||
* both and adding to the Metadata table. This way, we are able to
|
||||
* do everything in one pass without loading too much into memory
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
private void migrateTagsToMetadata() {
|
||||
Context context = ContextManager.getContext();
|
||||
|
||||
if(!checkIfDatabaseExists(context, tagsTable) ||
|
||||
!checkIfDatabaseExists(context, tagTaskTable))
|
||||
return;
|
||||
|
||||
SQLiteDatabase tagsDb = new Astrid2UpgradeHelper(context, tagsTable,
|
||||
null, 1).getReadableDatabase();
|
||||
SQLiteDatabase tagTaskDb = new Astrid2UpgradeHelper(context, tagTaskTable,
|
||||
null, 1).getReadableDatabase();
|
||||
|
||||
Cursor tagCursor = tagsDb.rawQuery("SELECT _id, name FROM " + tagsTable +
|
||||
" ORDER BY _id ASC", null);
|
||||
Cursor mapCursor = tagTaskDb.rawQuery("SELECT tag, task FROM " + tagTaskTable +
|
||||
" ORDER BY tag ASC", null);
|
||||
|
||||
if(tagCursor.getCount() == 0)
|
||||
return;
|
||||
|
||||
Metadata metadata = new Metadata();
|
||||
metadata.setValue(Metadata.KEY, DataService.KEY);
|
||||
long tagId = -1;
|
||||
String tag = null;
|
||||
for(mapCursor.moveToFirst(); !mapCursor.isAfterLast(); mapCursor.moveToNext()) {
|
||||
long mapTagId = mapCursor.getLong(1);
|
||||
|
||||
while(mapTagId > tagId && !tagCursor.isLast()) {
|
||||
tagCursor.moveToNext();
|
||||
tagId = tagCursor.getLong(1);
|
||||
}
|
||||
|
||||
if(mapTagId == tagId) {
|
||||
if(tag == null)
|
||||
tag = tagCursor.getString(2);
|
||||
long task = mapCursor.getLong(2);
|
||||
metadata.setValue(Metadata.TASK, task);
|
||||
metadata.setValue(Metadata.VALUE, tag);
|
||||
metadataDao.createItem(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
tagCursor.close();
|
||||
mapCursor.close();
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue