Refactored transitory preservation to be structured better

pull/14/head
Sam Bosley 13 years ago
parent ea42bb828c
commit c44b884f3a

@ -11,8 +11,6 @@ import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import android.content.ContentValues; import android.content.ContentValues;
@ -319,7 +317,6 @@ public abstract class AbstractModel implements Parcelable, Cloneable {
public synchronized <TYPE> void mergeWith(ContentValues other) { public synchronized <TYPE> void mergeWith(ContentValues other) {
if (setValues == null) if (setValues == null)
setValues = new ContentValues(); setValues = new ContentValues();
restoreTransitories(other);
setValues.putAll(other); setValues.putAll(other);
} }
@ -378,76 +375,12 @@ public abstract class AbstractModel implements Parcelable, Cloneable {
return transitoryData.remove(key); return transitoryData.remove(key);
} }
/** public Set<String> getAllTransitoryKeys() {
* Move transitory values (those that can be saved) to setValues,
* to be restored later. This is useful for the api daos that go
* through the content provider
*/
public synchronized void retainTransitories() {
if (transitoryData == null)
return;
if (setValues == null)
setValues = new ContentValues();
Set<String> keys = transitoryData.keySet();
for (String key : keys) {
String newKey = RETAIN_TRANSITORY_PREFIX + key;
Object value = transitoryData.get(key);
putObjectInContentValues(newKey, value, setValues);
}
}
/**
* Read keys from ContentValues. Remove those that match the
* RETAIN_TRANSITORY_PREFIX pattern and set those values
* on transitory data
* @param cv
*/
private void restoreTransitories(ContentValues cv) {
if (transitoryData == null) if (transitoryData == null)
transitoryData = new HashMap<String, Object>(); return null;
Set<Entry<String, Object>> entries = cv.valueSet(); return transitoryData.keySet();
Set<String> keysToRemove = new HashSet<String>();
for (Entry<String, Object> entry: entries) {
String key = entry.getKey();
if (key.startsWith(RETAIN_TRANSITORY_PREFIX)) {
String newKey = key.substring(RETAIN_TRANSITORY_PREFIX.length());
Object value = cv.get(key);
transitoryData.put(newKey, value);
keysToRemove.add(key);
}
}
for (String key : keysToRemove) {
cv.remove(key);
}
}
/**
* If value is of a type that is puttable in ContentValues, cast and put it
* @param key
* @param value
* @param cv
*/
private void putObjectInContentValues(String key, Object value, ContentValues cv) {
if (value instanceof Boolean)
cv.put(key, (Boolean) value);
if (value instanceof Byte)
cv.put(key, (Byte) value);
if (value instanceof Double)
cv.put(key, (Double) value);
if (value instanceof Float)
cv.put(key, (Float) value);
if (value instanceof Integer)
cv.put(key, (Integer) value);
if (value instanceof Long)
cv.put(key, (Long) value);
if (value instanceof Short)
cv.put(key, (Short) value);
if (value instanceof String)
cv.put(key, (String) value);
} }
// --- Convenience wrappers for using transitories as flags // --- Convenience wrappers for using transitories as flags
public boolean checkTransitory(String flag) { public boolean checkTransitory(String flag) {
Object trans = getTransitory(flag); Object trans = getTransitory(flag);

@ -2,8 +2,10 @@ package com.todoroo.andlib.data;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.Set;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
@ -13,6 +15,7 @@ import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.AndroidUtilities;
/** /**
@ -95,13 +98,13 @@ public class ContentResolverDao<TYPE extends AbstractModel> {
if(model.isSaved()) { if(model.isSaved()) {
if(model.getSetValues() == null) if(model.getSetValues() == null)
return false; return false;
model.retainTransitories(); writeTransitoriesToModelContentValues(model);
retainedTransitories = true; retainedTransitories = true;
if(cr.update(uriWithId(model.getId()), model.getSetValues(), null, null) != 0) if(cr.update(uriWithId(model.getId()), model.getSetValues(), null, null) != 0)
return true; return true;
} }
if (!retainedTransitories) if (!retainedTransitories)
model.retainTransitories(); writeTransitoriesToModelContentValues(model);
Uri uri = cr.insert(baseUri, model.getMergedValues()); Uri uri = cr.insert(baseUri, model.getMergedValues());
long id = Long.parseLong(uri.getLastPathSegment()); long id = Long.parseLong(uri.getLastPathSegment());
model.setId(id); model.setId(id);
@ -109,6 +112,19 @@ public class ContentResolverDao<TYPE extends AbstractModel> {
return true; return true;
} }
private void writeTransitoriesToModelContentValues(AbstractModel model) {
Set<String> keys = model.getAllTransitoryKeys();
if (keys != null) {
ContentValues transitories = new ContentValues();
for (String key : keys) {
String newKey = AbstractModel.RETAIN_TRANSITORY_PREFIX + key;
Object value = model.getTransitory(key);
AndroidUtilities.putInto(transitories, newKey, value, false);
}
model.mergeWith(transitories);
}
}
/** /**
* Returns object corresponding to the given identifier * Returns object corresponding to the given identifier
* *

@ -150,16 +150,24 @@ public class AndroidUtilities {
* @param key * @param key
* @param value * @param value
*/ */
public static void putInto(ContentValues target, String key, Object value) { public static void putInto(ContentValues target, String key, Object value, boolean errorOnFail) {
if(value instanceof String) if (value instanceof Boolean)
target.put(key, (String) value); target.put(key, (Boolean) value);
else if(value instanceof Long) else if (value instanceof Byte)
target.put(key, (Long) value); target.put(key, (Byte) value);
else if(value instanceof Integer)
target.put(key, (Integer) value);
else if (value instanceof Double) else if (value instanceof Double)
target.put(key, (Double) value); target.put(key, (Double) value);
else else if (value instanceof Float)
target.put(key, (Float) value);
else if (value instanceof Integer)
target.put(key, (Integer) value);
else if (value instanceof Long)
target.put(key, (Long) value);
else if (value instanceof Short)
target.put(key, (Short) value);
else if (value instanceof String)
target.put(key, (String) value);
else if (errorOnFail)
throw new UnsupportedOperationException("Could not handle type " + //$NON-NLS-1$ throw new UnsupportedOperationException("Could not handle type " + //$NON-NLS-1$
value.getClass()); value.getClass());
} }

@ -3,6 +3,10 @@
*/ */
package com.todoroo.astrid.provider; package com.todoroo.astrid.provider;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Set;
import android.content.ContentProvider; import android.content.ContentProvider;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.ContentUris; import android.content.ContentUris;
@ -266,6 +270,7 @@ public class Astrid3ContentProvider extends ContentProvider {
case URI_DIR: { case URI_DIR: {
helper.model.mergeWith(values); helper.model.mergeWith(values);
readTransitoriesFromModelContentValues(helper.model);
if(!helper.create()) if(!helper.create())
throw new SQLException("Could not insert row into database (constraint failed?)"); throw new SQLException("Could not insert row into database (constraint failed?)");
@ -321,6 +326,7 @@ public class Astrid3ContentProvider extends ContentProvider {
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
long id = cursor.getLong(0); long id = cursor.getLong(0);
helper.model.mergeWith(values); helper.model.mergeWith(values);
readTransitoriesFromModelContentValues(helper.model);
helper.model.setId(id); helper.model.setId(id);
helper.update(); helper.update();
helper.model.clear(); helper.model.clear();
@ -333,6 +339,27 @@ public class Astrid3ContentProvider extends ContentProvider {
} }
} }
private void readTransitoriesFromModelContentValues(AbstractModel model) {
ContentValues setValues = model.getSetValues();
if (setValues != null) {
Set<Entry<String, Object>> entries = setValues.valueSet();
Set<String> keysToRemove = new HashSet<String>();
for (Entry<String, Object> entry: entries) {
String key = entry.getKey();
if (key.startsWith(AbstractModel.RETAIN_TRANSITORY_PREFIX)) {
String newKey = key.substring(AbstractModel.RETAIN_TRANSITORY_PREFIX.length());
Object value = setValues.get(key);
model.putTransitory(newKey, value);
keysToRemove.add(key);
}
}
for (String key : keysToRemove) {
setValues.remove(key);
}
}
}
/* ====================================================================== /* ======================================================================
* ============================================================ query === * ============================================================ query ===
* ====================================================================== */ * ====================================================================== */

@ -437,11 +437,11 @@ public class TaskService {
for (Property<?> property : Metadata.PROPERTIES) for (Property<?> property : Metadata.PROPERTIES)
if (property.name.equals(key)) { if (property.name.equals(key)) {
AndroidUtilities.putInto(forMetadata, key, value); AndroidUtilities.putInto(forMetadata, key, value, true);
continue outer; continue outer;
} }
AndroidUtilities.putInto(forTask, key, value); AndroidUtilities.putInto(forTask, key, value, true);
} }
task.mergeWith(forTask); task.mergeWith(forTask);
} }

Loading…
Cancel
Save