Skip to content
This repository was archived by the owner on Jan 31, 2022. It is now read-only.

Commit 015ca84

Browse files
author
Clément Le Provost
committed
[offline] Add support for getObjects in MirroredIndex
- Same offline fallback policy as search. - Purely online and purely offline variants. NOTE: Had to rewire the online overloads to target the same implementation, so that it can be easily overloaded on the offline side.
1 parent 333deda commit 015ca84

File tree

4 files changed

+219
-12
lines changed

4 files changed

+219
-12
lines changed

algoliasearch/src/main/java/com/algolia/search/saas/Index.java

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -399,12 +399,7 @@ public Request partialUpdateObjectsAsync(final @NonNull JSONArray partialObjects
399399
* @return A cancellable request.
400400
*/
401401
public Request getObjectAsync(final @NonNull String objectID, @NonNull CompletionHandler completionHandler) {
402-
return getClient().new AsyncTaskRequest(completionHandler) {
403-
@NonNull
404-
@Override protected JSONObject run() throws AlgoliaException {
405-
return getObject(objectID);
406-
}
407-
}.start();
402+
return getObjectAsync(objectID, null, completionHandler);
408403
}
409404

410405
/**
@@ -432,12 +427,7 @@ public Request getObjectAsync(final @NonNull String objectID, final List<String>
432427
* @return A cancellable request.
433428
*/
434429
public Request getObjectsAsync(final @NonNull List<String> objectIDs, @NonNull CompletionHandler completionHandler) {
435-
return getClient().new AsyncTaskRequest(completionHandler) {
436-
@NonNull
437-
@Override protected JSONObject run() throws AlgoliaException {
438-
return getObjects(objectIDs);
439-
}
440-
}.start();
430+
return getObjectsAsync(objectIDs, null, completionHandler);
441431
}
442432

443433
/**

algoliasearch/src/offline/java/com/algolia/search/saas/MirroredIndex.java

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,149 @@ private JSONObject _browseMirror(@NonNull Query query) throws AlgoliaException
12451245
}
12461246
}
12471247

1248+
// ----------------------------------------------------------------------
1249+
// Getting individual objects
1250+
// ----------------------------------------------------------------------
1251+
1252+
/**
1253+
* Get individual objects from the online API, falling back to the local mirror in case of error (when enabled).
1254+
*
1255+
* @param objectIDs Identifiers of objects to retrieve.
1256+
* @param attributesToRetrieve Attributes to retrieve. If `null` or if at least one item is `*`, all retrievable
1257+
* attributes will be retrieved.
1258+
* @param completionHandler The listener that will be notified of the request's outcome.
1259+
* @return A cancellable request.
1260+
*/
1261+
@Override
1262+
public Request getObjectsAsync(final @NonNull List<String> objectIDs, final @Nullable List<String> attributesToRetrieve, @NonNull CompletionHandler completionHandler) {
1263+
if (!mirrored) {
1264+
return super.getObjectsAsync(objectIDs, attributesToRetrieve, completionHandler);
1265+
} else {
1266+
return new OnlineOfflineGetObjectsRequest(objectIDs, attributesToRetrieve, completionHandler).start();
1267+
}
1268+
}
1269+
1270+
private class OnlineOfflineGetObjectsRequest extends OnlineOfflineRequest {
1271+
private final List<String> objectIDs;
1272+
private final List<String> attributesToRetrieve;
1273+
1274+
public OnlineOfflineGetObjectsRequest(@NonNull List<String> objectIDs, final @Nullable List<String> attributesToRetrieve, @NonNull CompletionHandler completionHandler) {
1275+
super(completionHandler);
1276+
this.objectIDs = objectIDs;
1277+
this.attributesToRetrieve = attributesToRetrieve;
1278+
}
1279+
1280+
@Override
1281+
protected Request startOnlineRequest(CompletionHandler completionHandler) {
1282+
return getObjectsOnlineAsync(objectIDs, attributesToRetrieve, completionHandler);
1283+
}
1284+
1285+
@Override
1286+
protected Request startOfflineRequest(CompletionHandler completionHandler) {
1287+
return getObjectsOfflineAsync(objectIDs, attributesToRetrieve, completionHandler);
1288+
}
1289+
}
1290+
1291+
/**
1292+
* Get individual objects, explicitly targeting the online API, not the offline mirror.
1293+
*
1294+
* @param objectIDs Identifiers of objects to retrieve.
1295+
* @param attributesToRetrieve Attributes to retrieve. If `null` or if at least one item is `*`, all retrievable
1296+
* attributes will be retrieved.
1297+
* @param completionHandler The listener that will be notified of the request's outcome.
1298+
* @return A cancellable request.
1299+
*/
1300+
public Request getObjectsOnlineAsync(@NonNull final List<String> objectIDs, final @Nullable List<String> attributesToRetrieve, @NonNull final CompletionHandler completionHandler) {
1301+
return getClient().new AsyncTaskRequest(completionHandler) {
1302+
@NonNull
1303+
@Override
1304+
protected JSONObject run() throws AlgoliaException {
1305+
return getObjectsOnline(objectIDs, attributesToRetrieve);
1306+
}
1307+
}.start();
1308+
}
1309+
1310+
/**
1311+
* Get individual objects, explicitly targeting the online API, not the offline mirror.
1312+
*
1313+
* @param objectIDs Identifiers of objects to retrieve.
1314+
* @param completionHandler The listener that will be notified of the request's outcome.
1315+
* @return A cancellable request.
1316+
*/
1317+
public Request getObjectsOnlineAsync(@NonNull final List<String> objectIDs, @NonNull final CompletionHandler completionHandler) {
1318+
return getObjectsOnlineAsync(objectIDs, null, completionHandler);
1319+
}
1320+
1321+
private JSONObject getObjectsOnline(@NonNull final List<String> objectIDs, final @Nullable List<String> attributesToRetrieve) throws AlgoliaException {
1322+
try {
1323+
JSONObject content = super.getObjects(objectIDs, attributesToRetrieve);
1324+
// TODO: Factorize origin tagging
1325+
content.put(JSON_KEY_ORIGIN, JSON_VALUE_ORIGIN_REMOTE);
1326+
return content;
1327+
}
1328+
catch (JSONException e) {
1329+
throw new AlgoliaException("Failed to patch JSON result");
1330+
}
1331+
}
1332+
1333+
/**
1334+
* Get individual objects, explicitly targeting the offline mirror, not the online API.
1335+
*
1336+
* @param objectIDs Identifiers of objects to retrieve.
1337+
* @param attributesToRetrieve Attributes to retrieve. If `null` or if at least one item is `*`, all retrievable
1338+
* attributes will be retrieved.
1339+
* @param completionHandler The listener that will be notified of the request's outcome.
1340+
* @return A cancellable request.
1341+
* @throws IllegalStateException if mirroring is not activated on this index.
1342+
*/
1343+
public Request getObjectsOfflineAsync(@NonNull final List<String> objectIDs, final @Nullable List<String> attributesToRetrieve, @NonNull CompletionHandler completionHandler) {
1344+
if (!mirrored) {
1345+
throw new IllegalStateException("Mirroring not activated on this index");
1346+
}
1347+
return getClient().new AsyncTaskRequest(completionHandler, getClient().localSearchExecutorService) {
1348+
@NonNull
1349+
@Override
1350+
protected JSONObject run() throws AlgoliaException {
1351+
return _getObjectsOffline(objectIDs, attributesToRetrieve);
1352+
}
1353+
}.start();
1354+
}
1355+
1356+
/**
1357+
* Get individual objects, explicitly targeting the offline mirror, not the online API.
1358+
*
1359+
* @param objectIDs Identifiers of objects to retrieve.
1360+
* @param completionHandler The listener that will be notified of the request's outcome.
1361+
* @return A cancellable request.
1362+
* @throws IllegalStateException if mirroring is not activated on this index.
1363+
*/
1364+
public Request getObjectsOfflineAsync(@NonNull final List<String> objectIDs, @NonNull final CompletionHandler completionHandler) {
1365+
return getObjectsOfflineAsync(objectIDs, null, completionHandler);
1366+
}
1367+
1368+
private JSONObject _getObjectsOffline(@NonNull final List<String> objectIDs, final @Nullable List<String> attributesToRetrieve) throws AlgoliaException
1369+
{
1370+
try {
1371+
Query query = new Query();
1372+
if (attributesToRetrieve != null) {
1373+
query.setAttributesToRetrieve(attributesToRetrieve.toArray(new String[attributesToRetrieve.size()]));
1374+
}
1375+
Response searchResults = getLocalIndex().getObjects(objectIDs.toArray(new String[objectIDs.size()]), query.build());
1376+
if (searchResults.getStatusCode() == 200) {
1377+
String jsonString = new String(searchResults.getData(), "UTF-8");
1378+
JSONObject json = new JSONObject(jsonString);
1379+
json.put(JSON_KEY_ORIGIN, JSON_VALUE_ORIGIN_LOCAL);
1380+
return json;
1381+
}
1382+
else {
1383+
throw new AlgoliaException(searchResults.getErrorMessage(), searchResults.getStatusCode());
1384+
}
1385+
}
1386+
catch (JSONException | UnsupportedEncodingException e) {
1387+
throw new AlgoliaException("Get objects failed", e);
1388+
}
1389+
}
1390+
12481391
// ----------------------------------------------------------------------
12491392
// Listeners
12501393
// ----------------------------------------------------------------------

algoliasearch/src/test/java/com/algolia/search/saas/IndexTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,24 @@ public void getObjectsAsync() throws Exception {
429429
});
430430
}
431431

432+
@Test
433+
public void getObjectsWithAttributesToRetrieveAsync() throws Exception {
434+
List<String> attributesToRetrieve = new ArrayList<>();
435+
attributesToRetrieve.add("objectID");
436+
index.getObjectsAsync(ids, attributesToRetrieve, new AssertCompletionHandler() {
437+
@Override public void doRequestCompleted(JSONObject content, AlgoliaException error) {
438+
if (error == null) {
439+
JSONArray res = content.optJSONArray("results");
440+
assertNotNull(res);
441+
assertTrue("Object has unexpected objectId", res.optJSONObject(0).optString("objectID").equals(ids.get(0)));
442+
assertFalse("Object has unexpected 'city' attribute", res.optJSONObject(1).has("city"));
443+
} else {
444+
fail(error.getMessage());
445+
}
446+
}
447+
});
448+
}
449+
432450
@Test
433451
public void waitTaskAsync() throws Exception {
434452
index.addObjectAsync(new JSONObject("{\"city\": \"New York\"}"), new AssertCompletionHandler() {

algoliasearch/src/testOffline/java/com/algolia/search/saas/MirroredIndexTest.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.json.JSONObject;
3333
import org.junit.Test;
3434

35+
import java.util.Arrays;
3536
import java.util.HashMap;
3637
import java.util.Map;
3738
import java.util.concurrent.CountDownLatch;
@@ -40,6 +41,7 @@
4041
import static org.junit.Assert.assertEquals;
4142
import static org.junit.Assert.assertFalse;
4243
import static org.junit.Assert.assertNotEquals;
44+
import static org.junit.Assert.assertNotNull;
4345
import static org.junit.Assert.assertNull;
4446
import static org.junit.Assert.fail;
4547

@@ -311,4 +313,58 @@ public void doRequestCompleted(JSONObject content, AlgoliaException error) {
311313
}
312314
});
313315
}
316+
317+
@Test
318+
public void testGetObjects() {
319+
final CountDownLatch signal = new CountDownLatch(4);
320+
321+
// Populate the online index & sync the offline mirror.
322+
final MirroredIndex index = client.getIndex(Helpers.safeIndexName(Helpers.getMethodName()));
323+
sync(index, new SyncCompletionHandler() {
324+
@Override
325+
public void syncCompleted(@Nullable Throwable error) {
326+
assertNull(error);
327+
328+
// Query the online index explicitly.
329+
index.getObjectsOnlineAsync(Arrays.asList("1"), new AssertCompletionHandler() {
330+
@Override
331+
public void doRequestCompleted(JSONObject content, AlgoliaException error) {
332+
assertNull(error);
333+
assertNotNull(content.optJSONArray("results"));
334+
assertEquals(1, content.optJSONArray("results").length());
335+
assertEquals("remote", content.optString("origin"));
336+
337+
// Test offline fallback.
338+
client.setReadHosts("unknown.algolia.com");
339+
index.setRequestStrategy(MirroredIndex.Strategy.FALLBACK_ON_FAILURE);
340+
index.getObjectsAsync(Arrays.asList("1", "2", "3"), new AssertCompletionHandler() {
341+
@Override
342+
public void doRequestCompleted(JSONObject content, AlgoliaException error) {
343+
assertNull(error);
344+
assertNotNull(content.optJSONArray("results"));
345+
assertEquals(3, content.optJSONArray("results").length());
346+
assertEquals("local", content.optString("origin"));
347+
signal.countDown();
348+
}
349+
});
350+
signal.countDown();
351+
}
352+
});
353+
354+
// Query the offline index explicitly.
355+
index.getObjectsOfflineAsync(Arrays.asList("1", "2"), new AssertCompletionHandler() {
356+
@Override
357+
public void doRequestCompleted(JSONObject content, AlgoliaException error) {
358+
assertNull(error);
359+
assertNotNull(content.optJSONArray("results"));
360+
assertEquals(2, content.optJSONArray("results").length());
361+
assertEquals("local", content.optString("origin"));
362+
signal.countDown();
363+
}
364+
});
365+
366+
signal.countDown();
367+
}
368+
});
369+
}
314370
}

0 commit comments

Comments
 (0)