From 897720f0ded809924ba0ac67d883d7d6ced01eac Mon Sep 17 00:00:00 2001 From: Andrew Grosner Date: Thu, 2 Jul 2015 14:49:52 -0400 Subject: [PATCH] escalated some methods in SQLUtils. Added hasCachingId() method, updated readme with the change --- .../processor/writer/LoadCursorWriter.java | 8 ++ .../raizlabs/android/dbflow/sql/SqlUtils.java | 131 ++++++++++++------ .../dbflow/structure/InternalAdapter.java | 5 + .../dbflow/structure/ModelAdapter.java | 5 + .../container/ModelContainerAdapter.java | 5 + README.md | 2 + 6 files changed, 115 insertions(+), 41 deletions(-) diff --git a/DBFlow-Compiler/src/main/java/com/raizlabs/android/dbflow/processor/writer/LoadCursorWriter.java b/DBFlow-Compiler/src/main/java/com/raizlabs/android/dbflow/processor/writer/LoadCursorWriter.java index 14860ba2a..416263d80 100644 --- a/DBFlow-Compiler/src/main/java/com/raizlabs/android/dbflow/processor/writer/LoadCursorWriter.java +++ b/DBFlow-Compiler/src/main/java/com/raizlabs/android/dbflow/processor/writer/LoadCursorWriter.java @@ -92,6 +92,14 @@ public void write(JavaWriter javaWriter) throws IOException { final TableDefinition tableDefinition = ((TableDefinition) baseTableDefinition); if (tableDefinition.hasCachingId) { + + WriterUtils.emitOverriddenMethod(javaWriter, new FlowWriter() { + @Override + public void write(JavaWriter javaWriter) throws IOException { + javaWriter.emitStatement("return true"); + } + }, "boolean", "hasCachingId", Sets.newHashSet(Modifier.PUBLIC)); + String[] params2 = new String[2]; params2[0] = ModelUtils.getParameter(isModelContainerDefinition, tableDefinition.getModelClassName()); params2[1] = ModelUtils.getVariable(isModelContainerDefinition); diff --git a/DBFlow/src/main/java/com/raizlabs/android/dbflow/sql/SqlUtils.java b/DBFlow/src/main/java/com/raizlabs/android/dbflow/sql/SqlUtils.java index 154354dea..6bd71b260 100644 --- a/DBFlow/src/main/java/com/raizlabs/android/dbflow/sql/SqlUtils.java +++ b/DBFlow/src/main/java/com/raizlabs/android/dbflow/sql/SqlUtils.java @@ -10,34 +10,38 @@ import com.raizlabs.android.dbflow.annotation.ConflictAction; import com.raizlabs.android.dbflow.config.BaseDatabaseDefinition; import com.raizlabs.android.dbflow.config.FlowManager; +import com.raizlabs.android.dbflow.runtime.DBTransactionQueue; import com.raizlabs.android.dbflow.runtime.FlowContentObserver; import com.raizlabs.android.dbflow.sql.language.Delete; -import com.raizlabs.android.dbflow.structure.BaseModel; +import com.raizlabs.android.dbflow.structure.BaseModel.Action; import com.raizlabs.android.dbflow.structure.InstanceAdapter; import com.raizlabs.android.dbflow.structure.InternalAdapter; import com.raizlabs.android.dbflow.structure.Model; import com.raizlabs.android.dbflow.structure.ModelAdapter; import com.raizlabs.android.dbflow.structure.RetrievalAdapter; import com.raizlabs.android.dbflow.structure.cache.BaseCacheableModel; +import com.raizlabs.android.dbflow.structure.cache.ModelCache; +import com.raizlabs.android.dbflow.structure.container.ModelContainer; +import com.raizlabs.android.dbflow.structure.container.ModelContainerAdapter; import java.util.ArrayList; import java.util.List; /** * Description: Provides some handy methods for dealing with SQL statements. It's purpose is to move the - * methods away from the {@link com.raizlabs.android.dbflow.structure.Model} class and let any class use these. + * methods away from the {@link Model} class and let any class use these. */ public class SqlUtils { /** - * Queries the DB for a {@link android.database.Cursor} and converts it into a list. + * Queries the DB for a {@link Cursor} and converts it into a list. * * @param modelClass The class to construct the data from the DB into * @param sql The SQL command to perform, must not be ; terminated. * @param args You may include ?s in where clause in the query, * which will be replaced by the values from selectionArgs. The * values will be bound as Strings. - * @param The class implements {@link com.raizlabs.android.dbflow.structure.Model} + * @param The class implements {@link Model} * @return a list of {@link ModelClass} */ @SuppressWarnings("unchecked") @@ -55,11 +59,27 @@ public static List queryList(Class List convertToCacheableList( - Class modelClass, Cursor cursor) { + /** + * Loops through a {@link Cursor} and builds a list of {@link CacheableClass} objects. If an item + * with the same id exists within the cache for that model, the cached object for that class is used. + * + * @param modelClass The class to convert the cursor into {@link CacheableClass} + * @param cursor The cursor from a query. + * @param modelCache The model cache to use when retrieving {@link CacheableClass}. + * @param The class that extends {@link BaseCacheableModel} + * @return A {@link List} of {@link CacheableClass}. + */ + public static List convertToCacheableList( + Class modelClass, Cursor cursor, ModelCache modelCache) { final List entities = new ArrayList<>(); ModelAdapter instanceAdapter = FlowManager.getModelAdapter(modelClass); if (instanceAdapter != null) { + if (!instanceAdapter.hasCachingId()) { + throw new IllegalArgumentException("You cannot call this method for a table that has no caching id. Either" + + "use one Primary Key or call convertToList()"); + } else if (modelCache == null) { + throw new IllegalArgumentException("ModelCache specified in convertToCacheableList() must not be null."); + } synchronized (cursor) { // Ensure that we aren't iterating over this cursor concurrently from different threads if (cursor.moveToFirst()) { @@ -67,7 +87,7 @@ private static List long id = cursor.getLong(cursor.getColumnIndex(instanceAdapter.getCachingColumnName())); // if it exists in cache no matter the query we will use that one - CacheableClass cacheable = BaseCacheableModel.getCache(modelClass).get(id); + CacheableClass cacheable = modelCache.get(id); if (cacheable != null) { entities.add(cacheable); } else { @@ -82,6 +102,20 @@ private static List return entities; } + /** + * Loops through a {@link Cursor} and builds a list of {@link CacheableClass} objects. If an item + * with the same id exists within the cache for that model, the cached object for that class is used. + * + * @param modelClass The class to convert the cursor into {@link CacheableClass} + * @param cursor The cursor from a query. + * @param The class that extends {@link BaseCacheableModel} + * @return A {@link List} of {@link CacheableClass}. + */ + public static List convertToCacheableList( + Class modelClass, Cursor cursor) { + return convertToCacheableList(modelClass, cursor, BaseCacheableModel.getCache(modelClass)); + } + /** * Loops through a cursor and builds a list of {@link ModelClass} objects. * @@ -117,8 +151,8 @@ public static List convertToList(Class The class that implements {@link com.raizlabs.android.dbflow.structure.Model} - * @return A model transformed from the {@link android.database.Cursor} + * @param The class that implements {@link Model} + * @return A model transformed from the {@link Cursor} */ @SuppressWarnings("unchecked") public static ModelClass convertToModel(boolean dontMoveToFirst, Class table, @@ -142,8 +176,8 @@ public static ModelClass convertToModel(boolean dontM * @param dontMoveToFirst If it's a list or at a specific position, do not reset the cursor * @param table The model class that we convert the cursor data into. * @param cursor The cursor from the DB - * @param The class that implements {@link com.raizlabs.android.dbflow.structure.Model} - * @return A model transformed from the {@link android.database.Cursor} + * @param The class that implements {@link Model} + * @return A model transformed from the {@link Cursor} */ @SuppressWarnings("unchecked") public static CacheableClass convertToCacheableModel( @@ -167,7 +201,7 @@ public static CacheableClass convert } /** - * Queries the DB and returns the first {@link com.raizlabs.android.dbflow.structure.Model} it finds. Note: + * Queries the DB and returns the first {@link Model} it finds. Note: * this may return more than one object, but only will return the first item in the list. * * @param modelClass The class to construct the data from the DB into @@ -175,7 +209,7 @@ public static CacheableClass convert * @param args You may include ?s in where clause in the query, * which will be replaced by the values from selectionArgs. The * values will be bound as Strings. - * @param The class implements {@link com.raizlabs.android.dbflow.structure.Model} + * @param The class implements {@link Model} * @return a single {@link ModelClass} */ @SuppressWarnings("unchecked") @@ -194,13 +228,13 @@ public static ModelClass querySingle(Class The class that implements {@link com.raizlabs.android.dbflow.structure.Model} + * @param The class that implements {@link Model} * @return */ public static boolean hasData(Class table, String sql, String... args) { @@ -234,10 +268,7 @@ void save(TableClass model, AdapterClass adapter, ModelAdapter model insert(model, adapter, modelAdapter); } - if (FlowContentObserver.shouldNotify()) { - notifyModelChanged(modelAdapter.getModelClass(), BaseModel.Action.SAVE, modelAdapter.getCachingColumnName(), - adapter.getCachingId(model)); - } + notifyModelChanged(model, adapter, modelAdapter, Action.SAVE); } /** @@ -246,7 +277,7 @@ void save(TableClass model, AdapterClass adapter, ModelAdapter model * @param model The model to update * @param modelAdapter The adapter to use * @return true if model was inserted, false if not. Also false could mean that it is placed on the - * {@link com.raizlabs.android.dbflow.runtime.DBTransactionQueue} using async to true. + * {@link DBTransactionQueue} using async to true. */ @SuppressWarnings("unchecked") public static @@ -263,15 +294,14 @@ boolean update(TableClass model, AdapterClass adapter, ModelAdapter if (!exists) { // insert insert(model, adapter, modelAdapter); - } else if (FlowContentObserver.shouldNotify()) { - notifyModelChanged(modelAdapter.getModelClass(), BaseModel.Action.UPDATE, - modelAdapter.getCachingColumnName(), adapter.getCachingId(model)); + } else { + notifyModelChanged(model, adapter, modelAdapter, Action.UPDATE); } return exists; } /** - * Will attempt to insert the {@link com.raizlabs.android.dbflow.structure.container.ModelContainer} into the DB. + * Will attempt to insert the {@link ModelContainer} into the DB. * * @param model The model to insert. * @param modelAdapter The adapter to use. @@ -283,15 +313,12 @@ void insert(TableClass model, AdapterClass adapter, ModelAdapter mod adapter.bindToStatement(insertStatement, model); long id = insertStatement.executeInsert(); adapter.updateAutoIncrement(model, id); - if (FlowContentObserver.shouldNotify()) { - notifyModelChanged(modelAdapter.getModelClass(), BaseModel.Action.INSERT, - modelAdapter.getCachingColumnName(), adapter.getCachingId(model)); - } + notifyModelChanged(model, adapter, modelAdapter, Action.INSERT); } /** - * Deletes {@link com.raizlabs.android.dbflow.structure.Model} from the database using the specfied {@link com.raizlabs.android.dbflow.config.FlowManager} + * Deletes {@link Model} from the database using the specfied {@link FlowManager} * * @param model The model to delete */ @@ -301,29 +328,51 @@ void delete(final TableClass model, AdapterClass adapter, ModelAdapter) adapter.getModelClass()).where( adapter.getPrimaryModelWhere(model)).query(); adapter.updateAutoIncrement(model, 0); - if (FlowContentObserver.shouldNotify()) { - notifyModelChanged(modelAdapter.getModelClass(), BaseModel.Action.DELETE, - modelAdapter.getCachingColumnName(), adapter.getCachingId(model)); - } + notifyModelChanged(model, adapter, modelAdapter, Action.DELETE); } /** * Notifies the {@link android.database.ContentObserver} that the model has changed. * - * @param action The {@link com.raizlabs.android.dbflow.structure.BaseModel.Action} enum + * @param action The {@link Action} enum * @param table The table of the model */ - public static void notifyModelChanged(Class table, BaseModel.Action action, String notifyKey, Object notifyValue) { + public static void notifyModelChanged(Class table, Action action, String notifyKey, Object notifyValue) { FlowManager.getContext().getContentResolver().notifyChange(getNotificationUri(table, action, notifyKey, notifyValue), null, true); } + /** + * Performs necessary logic to notify of {@link Model} changes. + * + * @param model The model to use to notify (if a caching id exists for that model). + * @param adapter The adapter to use thats either a {@link ModelAdapter} or {@link ModelContainerAdapter} + * to handle interactions. + * @param modelAdapter The actual {@link ModelAdapter} associated with the {@link ModelClass}/ + * @param action The {@link Action} that occured. + * @param The original model class. + * @param The class of the adapter that we use the model from. + * @param The class of the adapter, which is either a {@link ModelAdapter} or {@link ModelContainerAdapter} + */ + @SuppressWarnings("unchecked") + private static + void notifyModelChanged(TableClass model, AdapterClass adapter, ModelAdapter modelAdapter, Action action) { + if (FlowContentObserver.shouldNotify()) { + if (modelAdapter.hasCachingId()) { + notifyModelChanged(modelAdapter.getModelClass(), action, + modelAdapter.getCachingColumnName(), adapter.getCachingId(model)); + } else { + notifyModelChanged(modelAdapter.getModelClass(), action, null, null); + } + } + } + /** * Returns the uri for notifications from model changes * * @param modelClass * @return */ - public static Uri getNotificationUri(Class modelClass, BaseModel.Action action, String notifyKey, Object notifyValue) { + public static Uri getNotificationUri(Class modelClass, Action action, String notifyKey, Object notifyValue) { Uri.Builder uriBuilder = new Uri.Builder().scheme("dbflow") .authority(FlowManager.getTableName(modelClass)); if (action != null) { @@ -337,10 +386,10 @@ public static Uri getNotificationUri(Class modelClass, BaseMode /** * @param modelClass The model class to use. - * @param action The {@link BaseModel.Action} to use. + * @param action The {@link Action} to use. * @return The uri for updates to {@link Model}, meant for general changes. */ - public static Uri getNotificationUri(Class modelClass, BaseModel.Action action) { + public static Uri getNotificationUri(Class modelClass, Action action) { return getNotificationUri(modelClass, action, null, null); } @@ -350,7 +399,7 @@ public static Uri getNotificationUri(Class modelClass, BaseMode * * @param mOnTable The table that this trigger runs on * @param triggerName The name of the trigger - * @param The class that implements {@link com.raizlabs.android.dbflow.structure.Model} + * @param The class that implements {@link Model} */ public static void dropTrigger(Class mOnTable, String triggerName) { QueryBuilder queryBuilder = new QueryBuilder("DROP TRIGGER IF EXISTS ") @@ -363,7 +412,7 @@ public static void dropTrigger(Class mOnT * * @param mOnTable The table that this index runs on * @param indexName The name of the index. - * @param The class that implements {@link com.raizlabs.android.dbflow.structure.Model} + * @param The class that implements {@link Model} */ public static void dropIndex(Class mOnTable, String indexName) { QueryBuilder queryBuilder = new QueryBuilder("DROP INDEX IF EXISTS ") diff --git a/DBFlow/src/main/java/com/raizlabs/android/dbflow/structure/InternalAdapter.java b/DBFlow/src/main/java/com/raizlabs/android/dbflow/structure/InternalAdapter.java index 112b79540..2c8a9a53a 100644 --- a/DBFlow/src/main/java/com/raizlabs/android/dbflow/structure/InternalAdapter.java +++ b/DBFlow/src/main/java/com/raizlabs/android/dbflow/structure/InternalAdapter.java @@ -94,4 +94,9 @@ public interface InternalAdapter model) { return getAutoIncrementingId(model); } + @Override + public boolean hasCachingId() { + return false; + } + /** * Returns the type of the column for this model container. It's useful for when we do not know the exact class of the column * when in a {@link com.raizlabs.android.dbflow.structure.container.ModelContainer} diff --git a/README.md b/README.md index b668cfff3..1388f8a07 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,8 @@ with a "best practices" section. 8. Fixes bugs with the [Getting Started](https://github.com/Raizlabs/DBFlow/blob/master/usage/GettingStarted.md) section implementation. `OneToMany.Method.SAVE` now actually works on `insert`, `update`, and `save` methods. 9. Adds a `OnProgressProcessChangeListener` to listen for the total progress while looping through saving models in a `ProcessModelTransaction`. +10. Escalated `convertToCacheableList()` to `public` and now can query to know if +a `Model` has a valid caching id. Also some more public methods added to `SqlUtils`! #### 2.1.0