Skip to content

Commit

Permalink
Add ability to query just for the number of assets
Browse files Browse the repository at this point in the history
A HEAD request to /assets will include a "count" header which will be
set to the number of assets which would have been returned for a GET
request to the same URL.
  • Loading branch information
Azquelt committed Sep 11, 2015
1 parent 39d62ec commit 193de02
Show file tree
Hide file tree
Showing 10 changed files with 201 additions and 0 deletions.
21 changes: 21 additions & 0 deletions server/src/fat/java/com/ibm/ws/lars/rest/ApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,27 @@ public void testGetAllAssetsSorted() throws Exception {
assertThat(collatePages(page1, page2), contains(smallFoo, bigFoo, giantBar));
}

@SuppressWarnings("unused")
@Test
public void countAllAssets() throws Exception {
Asset bigFoo = addLittleAsset("name", "Big Foo", "category", "foo", "size", "20");
Asset smallFoo = addLittleAsset("name", "Small Foo", "category", "foo", "size", "10");
Asset giantBar = addLittleAsset("name", "Giant Bar", "category", "bar", "size", "40");
Asset smallBar = addLittleAsset("name", "Small Bar", "category", "bar", "size", "10");

int result = repository.getAssetCount("");
assertEquals(4, result);

result = repository.getAssetCount("category=foo");
assertEquals(2, result);

result = repository.getAssetCount("q=foo");
assertEquals(2, result);

result = repository.getAssetCount("q=foo&size=10");
assertEquals(1, result);
}

@SuppressWarnings("unchecked")
@Test
public void testGetAssetSummary() throws Exception {
Expand Down
16 changes: 16 additions & 0 deletions server/src/fat/java/com/ibm/ws/lars/rest/RepositoryContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.StatusLine;
Expand All @@ -47,6 +48,7 @@
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
Expand Down Expand Up @@ -273,6 +275,15 @@ public String doDelete(String url, int expectedStatusCode)
return doRequest(delete, expectedStatusCode);
}

public HttpResponse doHead(String url, int expectedStatusCode)
throws ClientProtocolException, IOException {
HttpHead head = new HttpHead(fullURL + url);
HttpResponse response = httpClient.execute(targetHost, head, context);

assertStatusCode(expectedStatusCode, response);
return response;
}

public String doRequest(HttpEntityEnclosingRequestBase request,
String content,
int expectedStatusCode)
Expand Down Expand Up @@ -444,6 +455,11 @@ void getBadAssetSummary(String parameters, int expectedRC) throws IOException {
doGet("/assets/summary?" + parameters, expectedRC);
}

int getAssetCount(String parameters) throws IOException {
HttpResponse response = doHead("/assets?" + parameters, HttpStatus.SC_NO_CONTENT);
return Integer.parseInt(response.getFirstHeader("count").getValue());
}

protected Attachment doPostAttachmentNoContent(String assetId, String name, Attachment attachment) throws ClientProtocolException, IOException, InvalidJsonAssetException {
List<NameValuePair> qparams = new ArrayList<>();
qparams.add(new BasicNameValuePair("name", name));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ public AssetList retrieveAllAssets(Map<String, List<Condition>> filters, String
return persistenceBean.retrieveAllAssets(filters, searchTerm, pagination, sortOptions);
}

/**
* @see Persistor#countAllAssets(Map, String)
*/
public int countAllAssets(Map<String, List<Condition>> filters, String searchTerm) {
return persistenceBean.countAllAssets(filters, searchTerm);
}

/**
* Summarizes a list of fields from the assets matched by the given filters and search term.
* <p>
Expand Down
22 changes: 22 additions & 0 deletions server/src/main/java/com/ibm/ws/lars/rest/PersistenceBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,13 @@ public AssetList retrieveAllAssets(Map<String, List<Condition>> filters, String
return AssetList.createAssetListFromMaps(assets);
}

/** {@inheritDoc} */
@Override
public int countAllAssets(Map<String, List<Condition>> filters, String searchTerm) {
BasicDBObject filterObject = createFilterObject(filters, searchTerm);
return queryCount(filterObject);
}

/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
Expand Down Expand Up @@ -278,6 +285,21 @@ private List<DBObject> query(DBObject filterObject, DBObject sortObject, DBObjec
return results;
}

private int queryCount(DBObject filterObject) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("queryCount: Querying database with query object " + filterObject);
}

DBCursor cursor = getAssetCollection().find(filterObject);
int count = cursor.count();

if (logger.isLoggable(Level.FINE)) {
logger.fine("queryCount: found " + count + " assets.");
}

return count;
}

private int getMongoSortOrder(SortOrder sortOrder) {
switch (sortOrder) {
case ASCENDING:
Expand Down
12 changes: 12 additions & 0 deletions server/src/main/java/com/ibm/ws/lars/rest/Persistor.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ public interface Persistor {
*/
public AssetList retrieveAllAssets(Map<String, List<Condition>> filters, String searchTerm, PaginationOptions pagination, SortOptions sortOptions);

/**
* Retrieve the number of assets which match the given set of filters.
* <p>
* <code>filters</code> and <code>searchTerm</code> have the same meaning as in
* {@link #retrieveAllAssets(Map, String, PaginationOptions, SortOptions)}
*
* @param filters filters to apply to the results, may be empty to not filter
* @param searchTerm search to match against the results, may be null to not search
* @return the number of assets which match the given filter and search term.
*/
public int countAllAssets(Map<String, List<Condition>> filters, String searchTerm);

/**
* Gets the list of distinct values of the given field in all assets which match the given
* filters and searchTerm.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
Expand Down Expand Up @@ -128,6 +129,20 @@ public Response getAssets(@Context UriInfo info) throws JsonProcessingException,
return Response.ok(json).build();
}

@HEAD
@Path("/assets")
public Response countAssets(@Context UriInfo info) throws InvalidParameterException {
if (logger.isLoggable(Level.FINE)) {
logger.fine("countAssets called with query parameters: " + info.getRequestUri().getRawQuery());
}

AssetQueryParameters params = AssetQueryParameters.create(info);

int count = assetService.countAllAssets(params.getFilterMap(), params.getSearchTerm());

return Response.noContent().header("count", count).build();
}

@POST
@Path("/assets")
@Produces(MediaType.APPLICATION_JSON)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ public List<Object> getDistinctValues(String field, Map<String, List<Condition>>
throw new UnsupportedOperationException("Filtering is not supported in this test facade");
}

/** {@inheritDoc} */
@Override
public int countAllAssets(Map<String, List<Condition>> filters, String searchTerm) {
throw new UnsupportedOperationException("Filtering is not supported in this test facade");
}

/*
* (non-Javadoc)
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*******************************************************************************/
package com.ibm.ws.lars.rest;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -201,4 +203,50 @@ public void testRetrieveAllAssetsWithSearchAndSort(final @Mocked DBCollection co
SortOptions sortOptions = new SortOptions("key2", SortOrder.DESCENDING);
createTestBean().retrieveAllAssets(filters, "foo", null, sortOptions);
}

@Test
public void testCountAllAssets(final @Mocked DBCollection collection, final @Injectable DBCursor cursor) {
BasicDBList list = new BasicDBList();
list.add(new BasicDBObject("key1", "value1"));
final BasicDBObject searchObject = new BasicDBObject("$and", list);

new Expectations() {
{
collection.find(searchObject);
result = cursor;

cursor.count();
result = 3;
}
};

HashMap<String, List<Condition>> filters = new HashMap<>();
filters.put("key1", Arrays.asList(new Condition[] { new Condition(Operation.EQUALS, "value1") }));
int count = createTestBean().countAllAssets(filters, null);
assertEquals(3, count);
}

@Test
public void testCountAllAssetsWithSearch(final @Mocked DBCollection collection, final @Injectable DBCursor cursor) {
BasicDBList list = new BasicDBList();
list.add(new BasicDBObject("key1", "value1"));
list.add(new BasicDBObject("$text", new BasicDBObject("$search", "foo")));
final BasicDBObject searchObject = new BasicDBObject("$and", list);

new Expectations() {
{
collection.find(searchObject);
result = cursor;

cursor.count();
result = 3;
}
};

HashMap<String, List<Condition>> filters = new HashMap<>();
filters.put("key1", Arrays.asList(new Condition[] { new Condition(Operation.EQUALS, "value1") }));
int count = createTestBean().countAllAssets(filters, "foo");
assertEquals(3, count);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.ibm.ws.lars.rest.model.Asset;
import com.ibm.ws.lars.rest.model.Attachment;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCursor;

public class PersistenceBeanLoggingTest {

Expand Down Expand Up @@ -144,4 +145,22 @@ public void testFindAttachmentsForAsset() {
createTestBean().findAttachmentsForAsset(NON_EXISTENT_ID);
}

@Test
public void testQueryCount(@Mocked final DBCursor cursor) {
final BasicDBObject filterObject = new BasicDBObject("key1", "value1");
new Expectations() {
{
logger.isLoggable(Level.FINE);
result = true;

logger.fine("queryCount: Querying database with query object " + filterObject);

cursor.count();
result = 3;

logger.fine("queryCount: found 3 assets.");
}
};
Deencapsulation.invoke(createTestBean(), "queryCount", filterObject);
}
}
35 changes: 35 additions & 0 deletions server/src/test/java/com/ibm/ws/lars/rest/PersistenceBeanTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,41 @@ public void testSortOptions() throws Exception {
assertThat(collatePages(page1, page2), contains(asset1, asset2, asset3, asset4));
}

@Test
public void testCountAllAssets() throws Exception {
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"hot\", \"ground\":\"flat\", \"name\":\"hot and flat\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"hot\", \"ground\":\"hilly\", \"name\":\"hot and hilly\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"hot\", \"ground\":\"mountainous\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"cold\", \"ground\":\"flat\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"cold\", \"ground\":\"hilly\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"cold\", \"ground\":\"mountainous\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"warm\", \"ground\":\"flat\", \"name\":\"warm and flat\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"warm\", \"ground\":\"hilly\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"warm\", \"ground\":\"mountainous\"}"));

Map<String, List<Condition>> emptyFilter = Collections.emptyMap();

// Test counting all assets
int result = persistenceBean.countAllAssets(emptyFilter, null);
assertEquals(9, result);

// Test counting assets with a filter
Map<String, List<Condition>> filter = new HashMap<>();
filter.put("weather", Arrays.asList(eq("hot")));
result = persistenceBean.countAllAssets(filter, null);
assertEquals(3, result);

// Test counting assets with a search
result = persistenceBean.countAllAssets(emptyFilter, "flat");
assertEquals(2, result);

// Test counting assets with a filter and a search
filter.clear();
filter.put("weather", Arrays.asList(eq("hot")));
result = persistenceBean.countAllAssets(filter, "flat");
assertEquals(1, result);
}

/**
* Collate the contents of several AssetLists into one List.
* <p>
Expand Down

0 comments on commit 193de02

Please sign in to comment.