/* * 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.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.List; import bolts.Continuation; import bolts.Task; /** package */ class NetworkQueryController extends AbstractQueryController { private static final String TAG = "NetworkQueryController"; private final ParseHttpClient restClient; public NetworkQueryController(ParseHttpClient restClient) { this.restClient = restClient; } @Override public Task> findAsync( ParseQuery.State state, ParseUser user, Task cancellationToken) { String sessionToken = user != null ? user.getSessionToken() : null; return findAsync(state, sessionToken, cancellationToken); } @Override public Task countAsync( ParseQuery.State state, ParseUser user, Task cancellationToken) { String sessionToken = user != null ? user.getSessionToken() : null; return countAsync(state, sessionToken, cancellationToken); } /** * Retrieves a list of {@link ParseObject}s that satisfy this query from the source. * * @return A list of all {@link ParseObject}s obeying the conditions set in this query. */ /* package */ Task> findAsync( final ParseQuery.State state, String sessionToken, Task ct) { final long queryStart = System.nanoTime(); final ParseRESTCommand command = ParseRESTQueryCommand.findCommand(state, sessionToken); final long querySent = System.nanoTime(); return command.executeAsync(restClient, ct).onSuccess(new Continuation>() { @Override public List then(Task task) throws Exception { JSONObject json = task.getResult(); // Cache the results, unless we are ignoring the cache ParseQuery.CachePolicy policy = state.cachePolicy(); if (policy != null && (policy != ParseQuery.CachePolicy.IGNORE_CACHE)) { ParseKeyValueCache.saveToKeyValueCache(command.getCacheKey(), json.toString()); } long queryReceived = System.nanoTime(); List response = convertFindResponse(state, task.getResult()); long objectsParsed = System.nanoTime(); if (json.has("trace")) { Object serverTrace = json.get("trace"); PLog.d("ParseQuery", String.format("Query pre-processing took %f seconds\n" + "%s\n" + "Client side parsing took %f seconds\n", (querySent - queryStart) / (1000.0f * 1000.0f), serverTrace, (objectsParsed - queryReceived) / (1000.0f * 1000.0f))); } return response; } }, Task.BACKGROUND_EXECUTOR); } /* package */ Task countAsync( final ParseQuery.State state, String sessionToken, Task ct) { final ParseRESTCommand command = ParseRESTQueryCommand.countCommand(state, sessionToken); return command.executeAsync(restClient, ct).onSuccessTask(new Continuation>() { @Override public Task then(Task task) throws Exception { // Cache the results, unless we are ignoring the cache ParseQuery.CachePolicy policy = state.cachePolicy(); if (policy != null && policy != ParseQuery.CachePolicy.IGNORE_CACHE) { JSONObject result = task.getResult(); ParseKeyValueCache.saveToKeyValueCache(command.getCacheKey(), result.toString()); } return task; } }, Task.BACKGROUND_EXECUTOR).onSuccess(new Continuation() { @Override public Integer then(Task task) throws Exception { // Convert response return task.getResult().optInt("count"); } }); } // Converts the JSONArray that represents the results of a find command to an // ArrayList. /* package */ List convertFindResponse(ParseQuery.State state, JSONObject response) throws JSONException { ArrayList answer = new ArrayList<>(); JSONArray results = response.getJSONArray("results"); if (results == null) { PLog.d(TAG, "null results in find response"); } else { String resultClassName = response.optString("className", null); if (resultClassName == null) { resultClassName = state.className(); } for (int i = 0; i < results.length(); ++i) { JSONObject data = results.getJSONObject(i); T object = ParseObject.fromJSON(data, resultClassName, ParseDecoder.get(), state.selectedKeys()); answer.add(object); /* * If there was a $relatedTo constraint on the query, then add any results to the list of * known objects in the relation for offline caching */ ParseQuery.RelationConstraint relation = (ParseQuery.RelationConstraint) state.constraints().get("$relatedTo"); if (relation != null) { relation.getRelation().addKnownObject(object); } } } return answer; } }