/*
* Copyright (c) 2015-present, Parse, LLC.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.parse;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CancellationException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
import bolts.Continuation;
import bolts.Task;
import bolts.TaskCompletionSource;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class ParseQueryTest {
@Before
public void setUp() {
ParseTestUtils.setTestParseUser();
ParseObject.registerSubclass(ParseUser.class);
}
@After
public void tearDown() {
ParseObject.unregisterSubclass(ParseUser.class);
ParseCorePlugins.getInstance().reset();
Parse.disableLocalDatastore();
}
@Test
public void testConstructors() {
assertEquals("_User", ParseQuery.getQuery(ParseUser.class).getClassName());
assertEquals("TestObject", ParseQuery.getQuery("TestObject").getClassName());
assertEquals("_User", new ParseQuery<>(ParseUser.class).getClassName());
assertEquals("TestObject", new ParseQuery<>("TestObject").getClassName());
ParseQuery.State.Builder<ParseObject> builder = new ParseQuery.State.Builder<>("TestObject");
ParseQuery<ParseObject> query = new ParseQuery<>(builder);
assertEquals("TestObject", query.getClassName());
assertSame(builder, query.getBuilder());
}
@Test
public void testCopy() throws InterruptedException {
ParseQuery<ParseObject> query = new ParseQuery<>("TestObject");
query.setUser(new ParseUser());
query.whereEqualTo("foo", "bar");
ParseQuery.State.Builder<ParseObject> builder = query.getBuilder();
ParseQuery.State<ParseObject> state = query.getBuilder().build();
ParseQuery<ParseObject> queryCopy = new ParseQuery<>(query);
ParseQuery.State.Builder<ParseObject> builderCopy = queryCopy.getBuilder();
ParseQuery.State<ParseObject> stateCopy = queryCopy.getBuilder().build();
assertNotSame(query, queryCopy);
assertSame(query.getUserAsync(state).getResult(), queryCopy.getUserAsync(stateCopy).getResult());
assertNotSame(builder, builderCopy);
assertSame(state.constraints().get("foo"), stateCopy.constraints().get("foo"));
}
// ParseUser#setUser is for tests only
@Test
public void testSetUser() throws ParseException {
ParseQuery<ParseObject> query = ParseQuery.getQuery("TestObject");
ParseUser user = new ParseUser();
query.setUser(user);
assertSame(user, ParseTaskUtils.wait(query.getUserAsync(query.getBuilder().build())));
// TODO(grantland): Test that it gets the current user
Parse.enableLocalDatastore(null);
query.fromLocalDatastore()
.ignoreACLs();
assertNull(ParseTaskUtils.wait(query.getUserAsync(query.getBuilder().build())));
}
@Test
public void testQueriesOnlyRunOneNetworkConnection() throws ParseException {
TestQueryController controller = new TestQueryController();
ParseCorePlugins.getInstance().registerQueryController(controller);
TaskCompletionSource<Void> tcs = new TaskCompletionSource();
controller.await(tcs.getTask());
ParseQuery<ParseObject> query = ParseQuery.getQuery("TestObject");
query.setUser(new ParseUser());
Task<Void> task = query.findInBackground().makeVoid();
try {
query.find();
fail("Should've thrown an exception.");
} catch (RuntimeException e) {
// do nothing
}
try {
query.findInBackground(new FindCallback<ParseObject>() {
@Override
public void done(List<ParseObject> objects, ParseException e) {
}
});
fail("Should've thrown an exception.");
} catch (RuntimeException e) {
// do nothing
}
try {
query.count();
fail("Should've thrown an exception.");
} catch (RuntimeException e) {
// do nothing
}
try {
query.countInBackground(new CountCallback() {
@Override
public void done(int count, ParseException e) {
}
});
fail("Should've thrown an exception.");
} catch (RuntimeException e) {
// do nothing
}
try {
query.get("abc");
fail("Should've thrown an exception.");
} catch (RuntimeException e) {
// do nothing
}
try {
query.getInBackground("abc", new GetCallback<ParseObject>() {
@Override
public void done(ParseObject object, ParseException e) {
}
});
fail("Should've thrown an exception.");
} catch (RuntimeException e) {
// do nothing
}
tcs.setResult(null);
ParseTaskUtils.wait(task);
}
@Test
public void testCountLimitReset() throws ParseException {
// Mock CacheQueryController
ParseQueryController controller = mock(CacheQueryController.class);
ParseCorePlugins.getInstance().registerQueryController(controller);
when(controller.countAsync(
any(ParseQuery.State.class),
any(ParseUser.class),
any(Task.class))).thenReturn(Task.forResult(0));
final ParseQuery<ParseObject> query = ParseQuery.getQuery("TestObject");
query.countInBackground();
assertEquals(-1, query.getLimit());
}
@Test
public void testCountWithCallbackLimitReset() throws ParseException {
// Mock CacheQueryController
CacheQueryController controller = mock(CacheQueryController.class);
ParseCorePlugins.getInstance().registerQueryController(controller);
when(controller.countAsync(
any(ParseQuery.State.class),
any(ParseUser.class),
any(Task.class))).thenReturn(Task.forResult(0));
final ParseQuery<ParseObject> query = ParseQuery.getQuery("TestObject");
query.countInBackground(null);
assertEquals(-1, query.getLimit());
}
@Test
public void testCountLimit() throws ParseException {
CacheQueryController controller = mock(CacheQueryController.class);
ParseCorePlugins.getInstance().registerQueryController(controller);
when(controller.countAsync(
any(ParseQuery.State.class),
any(ParseUser.class),
any(Task.class))).thenReturn(Task.forResult(0));
ArgumentCaptor<ParseQuery.State> state = ArgumentCaptor.forClass(ParseQuery.State.class);
final ParseQuery<ParseObject> query = ParseQuery.getQuery("TestObject");
query.countInBackground();
verify(controller, times(1)).countAsync(state.capture(), any(ParseUser.class), any(Task.class));
assertEquals(0, state.getValue().limit());
}
@Test
public void testCountWithCallbackLimit() throws ParseException {
CacheQueryController controller = mock(CacheQueryController.class);
ParseCorePlugins.getInstance().registerQueryController(controller);
when(controller.countAsync(
any(ParseQuery.State.class),
any(ParseUser.class),
any(Task.class))).thenReturn(Task.forResult(0));
ArgumentCaptor<ParseQuery.State> state = ArgumentCaptor.forClass(ParseQuery.State.class);
final ParseQuery<ParseObject> query = ParseQuery.getQuery("TestObject");
query.countInBackground(null);
verify(controller, times(1)).countAsync(state.capture(), any(ParseUser.class), any(Task.class));
assertEquals(0, state.getValue().limit());
}
@Test
public void testQueriesFreezeDuringExecution() throws ParseException {
ParseObject.registerSubclass(ParseUser.class);
TestQueryController controller = new TestQueryController();
ParseCorePlugins.getInstance().registerQueryController(controller);
TaskCompletionSource<Void> tcs = new TaskCompletionSource();
controller.await(tcs.getTask());
ParseQuery<ParseObject> query = ParseQuery.getQuery("TestObject");
query.setUser(new ParseUser());
Task<Void> task = query.findInBackground().cast();
try {
query.whereEqualTo("foo", "bar");
fail("Should've thrown an exception.");
} catch (RuntimeException e) {
// do nothing
}
try {
query.include("foo");
fail("Should've thrown an exception.");
} catch (RuntimeException e) {
// do nothing
}
try {
query.orderByAscending("foo");
fail("Should've thrown an exception.");
} catch (RuntimeException e) {
// do nothing
}
try {
query.orderByDescending("bar");
fail("Should've thrown an exception.");
} catch (RuntimeException e) {
// do nothing
}
tcs.setResult(null);
ParseTaskUtils.wait(task);
}
@Test
public void testQueryCancellation() throws ParseException {
TestQueryController controller = new TestQueryController();
ParseCorePlugins.getInstance().registerQueryController(controller);
TaskCompletionSource<Void> tcs = new TaskCompletionSource();
controller.await(tcs.getTask());
ParseQuery<ParseObject> query = ParseQuery.getQuery("TestObject");
query.setUser(new ParseUser());
Task<Void> task = query.findInBackground().makeVoid();
query.cancel();
tcs.setResult(null);
try {
ParseTaskUtils.wait(task);
} catch (RuntimeException e) {
assertThat(e.getCause(), instanceOf(CancellationException.class));
}
// Should succeed
task = query.findInBackground().makeVoid();
ParseTaskUtils.wait(task);
}
// TODO(grantland): Add CACHE_THEN_NETWORK tests (find, count, getFirst, get)
// TODO(grantland): Add cache tests (hasCachedResult, clearCachedResult, clearAllCachedResults)
// TODO(grantland): Add ParseQuery -> ParseQuery.State.Builder calls
//region testConditions
@Test
public void testCachePolicy() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.setCachePolicy(ParseQuery.CachePolicy.CACHE_ELSE_NETWORK);
assertEquals(ParseQuery.CachePolicy.CACHE_ELSE_NETWORK, query.getCachePolicy());
}
@Test
public void testFromNetwork() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
Parse.enableLocalDatastore(null);
query.fromNetwork();
assertTrue(query.isFromNetwork());
}
@Test
public void testFromPin() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
Parse.enableLocalDatastore(null);
query.fromPin();
// We generate a state to verify the content of the builder
ParseQuery.State state = query.getBuilder().build();
assertTrue(state.isFromLocalDatastore());
assertEquals(ParseObject.DEFAULT_PIN, state.pinName());
}
@Test
public void testMaxCacheAge() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.setMaxCacheAge(10);
assertEquals(10, query.getMaxCacheAge());
}
@Test
public void testWhereNotEqualTo() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.whereNotEqualTo("key", "value");
verifyCondition(query, "key", "$ne", "value");
}
@Test
public void testWhereGreaterThan() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.whereGreaterThan("key", "value");
verifyCondition(query, "key", "$gt", "value");
}
@Test
public void testWhereLessThanOrEqualTo() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.whereLessThanOrEqualTo("key", "value");
verifyCondition(query, "key", "$lte", "value");
}
@Test
public void testWhereGreaterThanOrEqualTo() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.whereGreaterThanOrEqualTo("key", "value");
verifyCondition(query, "key", "$gte", "value");
}
@Test
public void testWhereContainedIn() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
List<String> values = Arrays.asList("value", "valueAgain");
query.whereContainedIn("key", values);
verifyCondition(query, "key", "$in", values);
}
@Test
public void testWhereContainsAll() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
List<String> values = Arrays.asList("value", "valueAgain");
query.whereContainsAll("key", values);
verifyCondition(query, "key", "$all", values);
}
@Test
public void testWhereNotContainedIn() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
List<String> values = Arrays.asList("value", "valueAgain");
query.whereNotContainedIn("key", values);
verifyCondition(query, "key", "$nin", values);
}
@Test
public void testWhereMatches() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.whereMatches("key", "regex");
verifyCondition(query, "key", "$regex", "regex");
}
@Test
public void testWhereMatchesWithModifiers() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.whereMatches("key", "regex", "modifiers");
verifyCondition(query, "key", "$regex", "regex");
verifyCondition(query, "key", "$options", "modifiers");
}
@Test
public void testWhereStartsWith() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
String value = "prefix";
query.whereStartsWith("key", value);
verifyCondition(query, "key", "$regex", "^" + Pattern.quote(value));
}
@Test
public void testWhereEndsWith() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
String value = "suffix";
query.whereEndsWith("key", value);
verifyCondition(query, "key", "$regex", Pattern.quote(value) + "$");
}
@Test
public void testWhereExists() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.whereExists("key");
verifyCondition(query, "key", "$exists", true);
}
@Test
public void testWhereDoesNotExist() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.whereDoesNotExist("key");
verifyCondition(query, "key", "$exists", false);
}
@Test
public void testWhereContains() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
String value = "value";
query.whereContains("key", value);
verifyCondition(query, "key", "$regex", Pattern.quote(value));
}
@Test
public void testWhereMatchesQuery() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
ParseQuery<ParseObject> conditionQuery = new ParseQuery<>("Test");
conditionQuery.whereExists("keyAgain");
query.whereMatchesQuery("key", conditionQuery);
verifyCondition(query, "key", "$inQuery", conditionQuery.getBuilder());
}
@Test
public void testWhereDoesNotMatchQuery() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
ParseQuery<ParseObject> conditionQuery = new ParseQuery<>("Test");
conditionQuery.whereExists("keyAgain");
query.whereDoesNotMatchQuery("key", conditionQuery);
verifyCondition(query, "key", "$notInQuery", conditionQuery.getBuilder());
}
@Test
public void testWhereMatchesKeyInQuery() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
ParseQuery<ParseObject> conditionQuery = new ParseQuery<>("Test");
conditionQuery.whereExists("keyAgain");
query.whereMatchesKeyInQuery("key", "keyAgain", conditionQuery);
Map<String, Object> conditions = new HashMap<>();
conditions.put("key", "keyAgain");
conditions.put("query", conditionQuery.getBuilder());
verifyCondition(query, "key", "$select", conditions);
}
@Test
public void testWhereDoesNotMatchKeyInQuery() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
ParseQuery<ParseObject> conditionQuery = new ParseQuery<>("Test");
conditionQuery.whereExists("keyAgain");
query.whereDoesNotMatchKeyInQuery("key", "keyAgain", conditionQuery);
Map<String, Object> conditions = new HashMap<>();
conditions.put("key", "keyAgain");
conditions.put("query", conditionQuery.getBuilder());
verifyCondition(query, "key", "$dontSelect", conditions);
}
@Test
public void testWhereNear() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
ParseGeoPoint point = new ParseGeoPoint(10, 10);
query.whereNear("key", point);
verifyCondition(query, "key", "$nearSphere", point);
}
@Test
public void testWhereWithinGeoBox() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
ParseGeoPoint point = new ParseGeoPoint(10, 10);
ParseGeoPoint pointAgain = new ParseGeoPoint(20, 20);
query.whereWithinGeoBox("key", point, pointAgain);
// We generate a state to verify the content of the builder
ParseQuery.State state = query.getBuilder().build();
ParseQuery.QueryConstraints queryConstraints = state.constraints();
ParseQuery.KeyConstraints keyConstraints =
(ParseQuery.KeyConstraints) queryConstraints.get("key");
Map map = (Map) keyConstraints.get("$within");
List<Object> list = (List<Object>) map.get("$box");
assertEquals(2, list.size());
assertTrue(list.contains(point));
assertTrue(list.contains(pointAgain));
}
@Test
public void testWhereWithinRadians() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
ParseGeoPoint point = new ParseGeoPoint(10, 10);
query.whereWithinRadians("key", point, 100.0);
verifyCondition(query, "key", "$nearSphere", point);
verifyCondition(query, "key", "$maxDistance", 100.0);
}
@Test
public void testWhereWithinMiles() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
ParseGeoPoint point = new ParseGeoPoint(10, 10);
query.whereWithinMiles("key", point, 100.0);
verifyCondition(query, "key", "$nearSphere", point);
verifyCondition(query, "key", "$maxDistance", 100.0 / ParseGeoPoint.EARTH_MEAN_RADIUS_MILE);
}
@Test
public void testWhereWithinKilometers() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
ParseGeoPoint point = new ParseGeoPoint(10, 10);
query.whereWithinKilometers("key", point, 100.0);
verifyCondition(query, "key", "$nearSphere", point);
verifyCondition(query, "key", "$maxDistance", 100.0 / ParseGeoPoint.EARTH_MEAN_RADIUS_KM);
}
@Test
public void testOr() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.whereEqualTo("key", "value");
ParseQuery<ParseObject> queryAgain = new ParseQuery<>("Test");
queryAgain.whereEqualTo("keyAgain", "valueAgain");
List<ParseQuery<ParseObject>> queries = Arrays.asList(query, queryAgain);
ParseQuery<ParseObject> combinedQuery = ParseQuery.or(queries);
// We generate a state to verify the content of the builder
ParseQuery.State state = combinedQuery.getBuilder().build();
ParseQuery.QueryConstraints combinedQueryConstraints = state.constraints();
List list = (List) combinedQueryConstraints.get("$or");
assertEquals(2, list.size());
// Verify query constraint
ParseQuery.QueryConstraints queryConstraintsFromCombinedQuery =
(ParseQuery.QueryConstraints) list.get(0);
assertEquals(1, queryConstraintsFromCombinedQuery.size());
assertEquals("value", queryConstraintsFromCombinedQuery.get("key"));
// Verify queryAgain constraint
ParseQuery.QueryConstraints queryAgainConstraintsFromCombinedQuery =
(ParseQuery.QueryConstraints) list.get(1);
assertEquals(1, queryAgainConstraintsFromCombinedQuery.size());
assertEquals("valueAgain", queryAgainConstraintsFromCombinedQuery.get("keyAgain"));
}
// TODO(mengyan): Add testOr illegal cases unit test
@Test
public void testInclude() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.include("key");
// We generate a state to verify the content of the builder
ParseQuery.State state = query.getBuilder().build();
assertEquals(1, state.includes().size());
assertTrue(state.includes().contains("key"));
}
@Test
public void testSelectKeys() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.selectKeys(Arrays.asList("key", "keyAgain"));
// We generate a state to verify the content of the builder
ParseQuery.State state = query.getBuilder().build();
assertEquals(2, state.selectedKeys().size());
assertTrue(state.selectedKeys().contains("key"));
assertTrue(state.selectedKeys().contains("keyAgain"));
}
@Test
public void testAddAscendingOrder() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.addAscendingOrder("key");
// We generate a state to verify the content of the builder
ParseQuery.State state = query.getBuilder().build();
assertEquals(1, state.order().size());
assertTrue(state.order().contains("key"));
}
@Test
public void testAddDescendingOrder() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.addDescendingOrder("key");
// We generate a state to verify the content of the builder
ParseQuery.State state = query.getBuilder().build();
assertEquals(1, state.order().size());
assertTrue(state.order().contains(String.format("-%s", "key")));
}
@Test
public void testOrderByAscending() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.orderByAscending("key");
query.orderByAscending("keyAgain");
// We generate a state to verify the content of the builder
ParseQuery.State state = query.getBuilder().build();
assertEquals(1, state.order().size());
assertTrue(state.order().contains("keyAgain"));
}
@Test
public void testOrderByDescending() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.orderByDescending("key");
query.orderByDescending("keyAgain");
// We generate a state to verify the content of the builder
ParseQuery.State state = query.getBuilder().build();
assertEquals(1, state.order().size());
assertTrue(state.order().contains(String.format("-%s", "keyAgain")));
}
@Test
public void testLimit() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.setLimit(5);
assertEquals(5, query.getLimit());
}
@Test
public void testSkip() throws Exception {
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
query.setSkip(5);
assertEquals(5, query.getSkip());
}
private static void verifyCondition(
ParseQuery query, String key, String conditionKey, Object value) {
// We generate a state to verify the content of the builder
ParseQuery.State state = query.getBuilder().build();
ParseQuery.QueryConstraints queryConstraints = state.constraints();
ParseQuery.KeyConstraints keyConstraints =
(ParseQuery.KeyConstraints) queryConstraints.get(key);
assertEquals(value, keyConstraints.get(conditionKey));
}
private static void verifyCondition(
ParseQuery query, String key, String conditionKey, List values) {
// We generate a state to verify the content of the builder
ParseQuery.State state = query.getBuilder().build();
ParseQuery.QueryConstraints queryConstraints = state.constraints();
ParseQuery.KeyConstraints keyConstraints =
(ParseQuery.KeyConstraints) queryConstraints.get(key);
Collection<String> list = (Collection<String>) keyConstraints.get(conditionKey);
assertEquals(values.size(), list.size());
for (Object value : values) {
assertTrue(list.contains(value));
}
}
private static void verifyCondition(
ParseQuery query, String key, String conditionKey, Map values) {
// We generate a state to verify the content of the builder
ParseQuery.State state = query.getBuilder().build();
ParseQuery.QueryConstraints queryConstraints = state.constraints();
ParseQuery.KeyConstraints keyConstraints =
(ParseQuery.KeyConstraints) queryConstraints.get(key);
Map map = (Map) keyConstraints.get(conditionKey);
assertEquals(values.size(), map.size());
for (Object constraintKey : map.keySet()) {
assertTrue(values.containsKey(constraintKey));
assertEquals(map.get(constraintKey), values.get(constraintKey));
}
}
//endregion
/**
* A {@link ParseQueryController} used for testing.
*/
private static class TestQueryController implements ParseQueryController {
private Task<Void> toAwait = Task.forResult(null);
public Task<Void> await(final Task<Void> task) {
toAwait = toAwait.continueWithTask(new Continuation<Void, Task<Void>>() {
@Override
public Task<Void> then(Task<Void> ignored) throws Exception {
return task;
}
});
return toAwait;
}
@Override
public <T extends ParseObject> Task<List<T>> findAsync(ParseQuery.State<T> state,
ParseUser user, Task<Void> cancellationToken) {
final AtomicBoolean cancelled = new AtomicBoolean(false);
cancellationToken.continueWith(new Continuation<Void, Void>() {
@Override
public Void then(Task<Void> task) throws Exception {
cancelled.set(true);
return null;
}
});
return await(Task.<Void>forResult(null).continueWithTask(new Continuation<Void, Task<Void>>() {
@Override
public Task<Void> then(Task<Void> task) throws Exception {
if (cancelled.get()) {
return Task.cancelled();
}
return task;
}
})).cast();
}
@Override
public <T extends ParseObject> Task<Integer> countAsync(ParseQuery.State<T> state,
ParseUser user, Task<Void> cancellationToken) {
final AtomicBoolean cancelled = new AtomicBoolean(false);
cancellationToken.continueWith(new Continuation<Void, Void>() {
@Override
public Void then(Task<Void> task) throws Exception {
cancelled.set(true);
return null;
}
});
return await(Task.<Void>forResult(null).continueWithTask(new Continuation<Void, Task<Void>>() {
@Override
public Task<Void> then(Task<Void> task) throws Exception {
if (cancelled.get()) {
return Task.cancelled();
}
return task;
}
})).cast();
}
@Override
public <T extends ParseObject> Task<T> getFirstAsync(ParseQuery.State<T> state,
ParseUser user, Task<Void> cancellationToken) {
final AtomicBoolean cancelled = new AtomicBoolean(false);
cancellationToken.continueWith(new Continuation<Void, Void>() {
@Override
public Void then(Task<Void> task) throws Exception {
cancelled.set(true);
return null;
}
});
return await(Task.<Void>forResult(null).continueWithTask(new Continuation<Void, Task<Void>>() {
@Override
public Task<Void> then(Task<Void> task) throws Exception {
if (cancelled.get()) {
return Task.cancelled();
}
return task;
}
})).cast();
}
}
}