@Override public Task<T> call(ParseSQLiteDatabase db) { return fetchLocallyAsync(object, db); } });
@Override public <T extends ParseObject> Task<List<T>> findAsync( ParseQuery.State<T> state, ParseUser user, Task<Void> cancellationToken) { if (state.isFromLocalDatastore()) { return offlineStore.findFromPinAsync(state.pinName(), state, user); } else { return networkController.findAsync(state, user, cancellationToken); } }
/** * Removes the objects and every object they point to in the local datastore, recursively. * * @param name the name * @return A {@link bolts.Task} that is resolved when unpinning all completes. * @see #pinAll(String, java.util.List) */ public static Task<Void> unpinAllInBackground(String name) { if (!Parse.isLocalDatastoreEnabled()) { throw new IllegalStateException("Method requires Local Datastore. " + "Please refer to `Parse#enableLocalDatastore(Context)`."); } if (name == null) { name = DEFAULT_PIN; } return Parse.getLocalDatastore().unpinAllObjectsAsync(name); }
@Override public Task<Void> then(Task<Void> task) { synchronized (mutex) { if (isDeleted) { store.unregisterObject(ParseObject.this); return store.deleteDataForObjectAsync(ParseObject.this); } else { return store.updateDataForObjectAsync(ParseObject.this); } } } });
@Test public void testSetAsync() throws Exception { OfflineStore lds = mock(OfflineStore.class); when(lds.unpinAllObjectsAsync(anyString())).thenReturn(Task.<Void>forResult(null)); when(lds.pinAllObjectsAsync(anyString(), anyList(), anyBoolean())) .thenReturn(Task.forResult(null)); Parse.setLocalDatastore(lds); OfflineObjectStore<ParseUser> store = new OfflineObjectStore<>(ParseUser.class, PIN_NAME, null); ParseUser user = mock(ParseUser.class); ParseTaskUtils.wait(store.setAsync(user)); verify(lds, times(1)).unpinAllObjectsAsync(PIN_NAME); verify(user, times(1)).pinInBackground(PIN_NAME, false); }
object = store.getObject(className, objectId);
offlineStore = new OfflineStore(configuration.context); } else { ParseKeyValueCache.initialize(configuration.context);
/** * Runs a ParseQuery against the store's contents. * * @return The objects that match the query's constraints. */ /* package for OfflineQueryLogic */ <T extends ParseObject> Task<List<T>> findAsync( ParseQuery.State<T> query, ParseUser user, ParsePin pin, ParseSQLiteDatabase db) { return findAsync(query, user, pin, false, db); }
private Task<Void> deleteObjects(final List<String> uuids, final ParseSQLiteDatabase db) { if (uuids.size() <= 0) { return Task.forResult(null); } // SQLite has a max 999 SQL variables in a statement, so we need to split it up into manageable // chunks. We can do this because we're already in a transaction. if (uuids.size() > MAX_SQL_VARIABLES) { return deleteObjects(uuids.subList(0, MAX_SQL_VARIABLES), db).onSuccessTask(new Continuation<Void, Task<Void>>() { @Override public Task<Void> then(Task<Void> task) { return deleteObjects(uuids.subList(MAX_SQL_VARIABLES, uuids.size()), db); } }); } String[] placeholders = new String[uuids.size()]; for (int i = 0; i < placeholders.length; i++) { placeholders[i] = "?"; } String where = OfflineSQLiteOpenHelper.KEY_UUID + " IN (" + TextUtils.join(",", placeholders) + ")"; // dynamic args String[] args = uuids.toArray(new String[uuids.size()]); return db.deleteAsync(OfflineSQLiteOpenHelper.TABLE_OBJECTS, where, args); }
@Override public <T extends ParseObject> Task<Integer> countAsync( ParseQuery.State<T> state, ParseUser user, Task<Void> cancellationToken) { if (state.isFromLocalDatastore()) { return offlineStore.countFromPinAsync(state.pinName(), state, user); } else { return networkController.countAsync(state, user, cancellationToken); } } }
return getOrCreateUUIDAsync(object, db).onSuccessTask(new Continuation<String, Task<Void>>() { @Override public Task<Void> then(Task<String> task) {
ParseCorePlugins.getInstance().registerQueryController(queryController); OfflineStore lds = mock(OfflineStore.class); when(lds.pinAllObjectsAsync(anyString(), anyList(), anyBoolean())) .thenReturn(Task.forResult(null)); when(lds.unpinAllObjectsAsync(anyString())).thenReturn(Task.<Void>forResult(null)); when(lds.pinAllObjectsAsync(anyString(), anyList(), anyBoolean())) .thenReturn(Task.<Void>forResult(null)); Parse.setLocalDatastore(lds); verify(legacy, times(1)).getAsync(); verify(legacy, times(1)).deleteAsync(); verify(lds, times(1)).unpinAllObjectsAsync(PIN_NAME); verify(user, times(1)).pinInBackground(PIN_NAME, false); assertNotNull(userAgain);
@Test public void testParcelWhileDeletingWithLDSEnabled() throws Exception { mockCurrentUserController(); TaskCompletionSource<Void> tcs = mockObjectControllerForDelete(); ParseObject object = new ParseObject("TestObject"); object.setObjectId("id"); OfflineStore lds = mock(OfflineStore.class); when(lds.getObject("TestObject", "id")).thenReturn(object); Parse.setLocalDatastore(lds); Task<Void> deleteTask = object.deleteInBackground(); assertTrue(object.isDeleting); Parcel parcel = Parcel.obtain(); object.writeToParcel(parcel, 0); parcel.setDataPosition(0); ParseObject other = ParseObject.CREATOR.createFromParcel(parcel); assertSame(object, other); assertTrue(other.isDeleting); // Still deleting tcs.setResult(null); deleteTask.waitForCompletion(); // complete deletion on original object. assertFalse(other.isDeleting); assertTrue(other.isDeleted); Parse.setLocalDatastore(null); }
@Test public void testObjectNotFoundWhenSaveAsync() throws Exception { OfflineStore lds = new OfflineStore(RuntimeEnvironment.application); Parse.setLocalDatastore(lds);
@Override public Task<Boolean> matchesAsync(final T object, ParseSQLiteDatabase db) { /* * As an optimization, we do this lazily. Then we may not have to do it at all, if this part * of the query gets short-circuited. */ if (subQueryResults == null) { //TODO (grantland): We need to pass through the original pin we were limiting the parent // query on. subQueryResults = store.findAsync(subQuery, user, null, db); } return subQueryResults.onSuccess(new Continuation<List<T>, Boolean>() { @Override public Boolean then(Task<List<T>> task) throws ParseException { return matches(object, task.getResult()); } }); }
@Override public Task<Void> then(Task<Void> task) { return store.fetchLocallyAsync(ParseObject.this).makeVoid(); } });
/** * Removes the objects and every object they point to in the local datastore, recursively. * * @param name the name * @param objects the objects * @return A {@link bolts.Task} that is resolved when unpinning all completes. * @see #pinAllInBackground(String, java.util.List) */ public static <T extends ParseObject> Task<Void> unpinAllInBackground(String name, List<T> objects) { if (!Parse.isLocalDatastoreEnabled()) { throw new IllegalStateException("Method requires Local Datastore. " + "Please refer to `Parse#enableLocalDatastore(Context)`."); } if (name == null) { name = DEFAULT_PIN; } return Parse.getLocalDatastore().unpinAllObjectsAsync(name, objects); }
@Test public void testParcelWhileSavingWithLDSEnabled() throws Exception { mockCurrentUserController(); TaskCompletionSource<ParseObject.State> tcs = mockObjectControllerForSave(); ParseObject object = new ParseObject("TestObject"); object.setObjectId("id"); OfflineStore lds = mock(OfflineStore.class); when(lds.getObject("TestObject", "id")).thenReturn(object); Parse.setLocalDatastore(lds); object.put("key", "value"); object.increment("number", 3); Task<Void> saveTask = object.saveInBackground(); assertTrue(object.hasOutstandingOperations()); // Saving assertFalse(object.isDirty()); // Not dirty because it's saving Parcel parcel = Parcel.obtain(); object.writeToParcel(parcel, 0); parcel.setDataPosition(0); ParseObject other = ParseObject.CREATOR.createFromParcel(parcel); assertSame(object, other); assertTrue(other.hasOutstandingOperations()); // Still saving assertFalse(other.isDirty()); // Still not dirty assertEquals(other.getNumber("number"), 3); tcs.setResult(null); saveTask.waitForCompletion(); Parse.setLocalDatastore(null); }
@Test public void testFailingFindAllPinned() throws Exception { OfflineStore offlineStore = mock(OfflineStore.class); Parse.setLocalDatastore(offlineStore); when(offlineStore.findFromPinAsync(eq(EventuallyPin.PIN_NAME), any(ParseQuery.State.class), any(ParseUser.class))) .thenReturn(Task.forError(new SQLiteException())); ParsePlugins plugins = mock(ParsePlugins.class); ParsePlugins.set(plugins); when(plugins.restClient()).thenReturn(ParseHttpClient.createClient(null)); thrown.expect(SQLiteException.class); ParseTaskUtils.wait(EventuallyPin.findAllPinned()); } }
private Task<ParsePin> getParsePin(final String name, ParseSQLiteDatabase db) { ParseQuery.State<ParsePin> query = new ParseQuery.State.Builder<>(ParsePin.class) .whereEqualTo(ParsePin.KEY_NAME, name) .build(); /* We need to call directly to the OfflineStore since we don't want/need a user to query for * ParsePins */ return findAsync(query, null, null, db).onSuccess(new Continuation<List<ParsePin>, ParsePin>() { @Override public ParsePin then(Task<List<ParsePin>> task) { ParsePin pin = null; if (task.getResult() != null && task.getResult().size() > 0) { pin = task.getResult().get(0); } //TODO (grantland): What do we do if there are more than 1 result? if (pin == null) { pin = ParseObject.create(ParsePin.class); pin.setName(name); } return pin; } }); }