/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.andlib.data;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Set;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.AndroidUtilities;
/**
* DAO for reading and writing values from an Android ContentResolver
*
* @author Tim Su <tim@todoroo.com>
*
* @param <TYPE> model type
*/
public class ContentResolverDao<TYPE extends AbstractModel> {
/** class of model */
private final Class<TYPE> modelClass;
/** base content uri */
private final Uri baseUri;
/** content resolver */
private final ContentResolver cr;
@Autowired
protected Boolean debug;
public ContentResolverDao(Class<TYPE> modelClass, Context context, Uri baseUri) {
DependencyInjectionService.getInstance().inject(this);
this.modelClass = modelClass;
if(debug == null)
debug = false;
this.baseUri = baseUri;
cr = context.getContentResolver();
}
/**
* Returns a URI for a single id
* @param id
* @return
*/
private Uri uriWithId(long id) {
return Uri.withAppendedPath(baseUri, Long.toString(id));
}
/**
* Delete specific item from the given table
* @param id
* @return number of rows affected
*/
public int delete(long id) {
return cr.delete(uriWithId(id), null, null);
}
/**
* Delete by criteria
* @param where
* @return number of rows affected
*/
public int deleteWhere(Criterion where) {
return cr.delete(baseUri, where.toString(), null);
}
/**
* Query content provider
* @param query
* @return
*/
public TodorooCursor<TYPE> query(Query query) {
if(debug)
Log.i("SQL-" + modelClass.getSimpleName(), query.toString()); //$NON-NLS-1$
Cursor cursor = query.queryContentResolver(cr, baseUri);
return new TodorooCursor<TYPE>(cursor, query.getFields());
}
/**
* Create new or save existing model
* @param model
* @return true if data was written to the db, false otherwise
*/
public boolean save(TYPE model) {
writeTransitoriesToModelContentValues(model);
if(model.isSaved()) {
if(model.getSetValues() == null)
return false;
if(cr.update(uriWithId(model.getId()), model.getSetValues(), null, null) != 0)
return true;
}
Uri uri = cr.insert(baseUri, model.getMergedValues());
long id = Long.parseLong(uri.getLastPathSegment());
model.setId(id);
model.markSaved();
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
*
* @param database
* @param table
* name of table
* @param properties
* properties to read
* @param id
* id of item
* @return null if no item found
*/
public TYPE fetch(long id, Property<?>... properties) {
TodorooCursor<TYPE> cursor = query(
Query.select(properties).where(AbstractModel.ID_PROPERTY.eq(id)));
try {
if (cursor.getCount() == 0)
return null;
cursor.moveToFirst();
Constructor<TYPE> constructor = modelClass.getConstructor(TodorooCursor.class);
return constructor.newInstance(cursor);
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} finally {
try {
cursor.close();
} catch (NullPointerException e) {
// cursor was not open
}
}
}
}