[OLINGO-568] improved search in technical service
Signed-off-by: Christian Amend <christian.amend@sap.com>
This commit is contained in:
parent
69ef9f5194
commit
8674a1f299
|
@ -19,10 +19,11 @@
|
|||
package org.apache.olingo.fit.tecsvc.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.client.api.communication.ODataClientErrorException;
|
||||
import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest;
|
||||
|
@ -83,7 +84,7 @@ public class SystemQueryOptionITCase extends AbstractParamTecSvcITCase {
|
|||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
ClientEntity entity = response.getBody().getEntities().get(i);
|
||||
assertEquals(new Integer(i + 1).toString(), entity.getProperty(PROPERTY_INT16).getValue().toString());
|
||||
assertShortOrInt(i + 1, entity.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +103,7 @@ public class SystemQueryOptionITCase extends AbstractParamTecSvcITCase {
|
|||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ClientEntity entity = response.getBody().getEntities().get(i);
|
||||
assertEquals(new Integer(i + 6).toString(), entity.getProperty(PROPERTY_INT16).getValue().toString());
|
||||
assertShortOrInt(i + 6, entity.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,7 +119,7 @@ public class SystemQueryOptionITCase extends AbstractParamTecSvcITCase {
|
|||
ODataRetrieveResponse<ClientEntitySet> response = request.execute();
|
||||
saveCookieHeader(response);
|
||||
|
||||
assertEquals(0, response.getBody().getEntities().size());
|
||||
assertTrue(response.getBody().getEntities().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -132,15 +133,16 @@ public class SystemQueryOptionITCase extends AbstractParamTecSvcITCase {
|
|||
ODataRetrieveResponse<ClientEntitySet> response = request.execute();
|
||||
saveCookieHeader(response);
|
||||
|
||||
assertEquals(0, response.getBody().getEntities().size());
|
||||
assertTrue(response.getBody().getEntities().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterWithTopSkipOrderByAndServerSidePaging() {
|
||||
public void searchAndFilterWithTopSkipOrderByAndServerSidePaging() {
|
||||
ODataEntitySetRequest<ClientEntitySet> request = getClient().getRetrieveRequestFactory()
|
||||
.getEntitySetRequest(getClient().newURIBuilder(SERVICE_URI)
|
||||
.appendEntitySetSegment(ES_SERVER_SIDE_PAGING)
|
||||
.filter("PropertyInt16 le 105") // 1, 2, ... , 105
|
||||
.search("\"Number:\" AND NOT \"106\"") // 1, 2, ..., 105, 107, ...
|
||||
.filter("PropertyInt16 le 106") // 1, 2, ..., 105
|
||||
.orderBy("PropertyInt16 desc") // 105, 104, ..., 2, 1
|
||||
.count(true) // 105
|
||||
.skip(3) // 102, 101, ..., 2, 1
|
||||
|
@ -155,14 +157,14 @@ public class SystemQueryOptionITCase extends AbstractParamTecSvcITCase {
|
|||
|
||||
int id = 102;
|
||||
|
||||
// Check first 10 entities
|
||||
// Check first 10 entities.
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ClientEntity entity = response.getBody().getEntities().get(i);
|
||||
assertEquals(new Integer(id).toString(), entity.getProperty(PROPERTY_INT16).getValue().toString());
|
||||
assertShortOrInt(id, entity.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue());
|
||||
id--;
|
||||
}
|
||||
|
||||
// Get 3 * 10 = 30 Entities and check the key
|
||||
// Get 3 * 10 = 30 Entities and check the key.
|
||||
for (int j = 0; j < 3; j++) {
|
||||
request = getClient().getRetrieveRequestFactory().getEntitySetRequest(response.getBody().getNext());
|
||||
setCookieHeader(request);
|
||||
|
@ -172,12 +174,12 @@ public class SystemQueryOptionITCase extends AbstractParamTecSvcITCase {
|
|||
assertEquals(10, response.getBody().getEntities().size());
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ClientEntity entity = response.getBody().getEntities().get(i);
|
||||
assertEquals(new Integer(id).toString(), entity.getProperty(PROPERTY_INT16).getValue().toString());
|
||||
assertShortOrInt(id, entity.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue());
|
||||
id--;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the last 3 items
|
||||
// Get the last 3 items.
|
||||
request = getClient().getRetrieveRequestFactory().getEntitySetRequest(response.getBody().getNext());
|
||||
setCookieHeader(request);
|
||||
response = request.execute();
|
||||
|
@ -186,12 +188,12 @@ public class SystemQueryOptionITCase extends AbstractParamTecSvcITCase {
|
|||
assertEquals(3, response.getBody().getEntities().size());
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ClientEntity entity = response.getBody().getEntities().get(i);
|
||||
assertEquals(new Integer(id).toString(), entity.getProperty(PROPERTY_INT16).getValue().toString());
|
||||
assertShortOrInt(id, entity.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue());
|
||||
id--;
|
||||
}
|
||||
|
||||
// Make sure that the body no not contain a next link
|
||||
assertEquals(null, response.getBody().getNext());
|
||||
assertNull(response.getBody().getNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -299,7 +301,7 @@ public class SystemQueryOptionITCase extends AbstractParamTecSvcITCase {
|
|||
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), e.getStatusLine().getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void basicSearch() {
|
||||
ODataEntitySetRequest<ClientEntitySet> request = getClient().getRetrieveRequestFactory()
|
||||
|
@ -308,9 +310,9 @@ public class SystemQueryOptionITCase extends AbstractParamTecSvcITCase {
|
|||
.search("Second")
|
||||
.build());
|
||||
setCookieHeader(request);
|
||||
ODataRetrieveResponse<ClientEntitySet> response = request.execute();
|
||||
List<ClientEntity> entities = response.getBody().getEntities();
|
||||
assertEquals(1, entities.size());
|
||||
final ODataRetrieveResponse<ClientEntitySet> response = request.execute();
|
||||
saveCookieHeader(response);
|
||||
assertEquals(1, response.getBody().getEntities().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -321,9 +323,9 @@ public class SystemQueryOptionITCase extends AbstractParamTecSvcITCase {
|
|||
.search("Second AND positive")
|
||||
.build());
|
||||
setCookieHeader(request);
|
||||
ODataRetrieveResponse<ClientEntitySet> response = request.execute();
|
||||
List<ClientEntity> entities = response.getBody().getEntities();
|
||||
assertEquals(0, entities.size());
|
||||
final ODataRetrieveResponse<ClientEntitySet> response = request.execute();
|
||||
saveCookieHeader(response);
|
||||
assertTrue(response.getBody().getEntities().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -335,7 +337,7 @@ public class SystemQueryOptionITCase extends AbstractParamTecSvcITCase {
|
|||
.build());
|
||||
setCookieHeader(request);
|
||||
ODataRetrieveResponse<ClientEntitySet> response = request.execute();
|
||||
List<ClientEntity> entities = response.getBody().getEntities();
|
||||
assertEquals(2, entities.size());
|
||||
saveCookieHeader(response);
|
||||
assertEquals(2, response.getBody().getEntities().size());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -471,23 +471,22 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
edmEntitySet.getEntityType();
|
||||
|
||||
EntityCollection entitySetInitial = readEntityCollection(uriInfo);
|
||||
|
||||
if (entitySetInitial == null) {
|
||||
entitySetInitial = new EntityCollection();
|
||||
}
|
||||
|
||||
// Modifying the original entitySet means modifying the "database", so we have to make a shallow
|
||||
// copy of the entity set (new EntitySet, but exactly the same data)
|
||||
// copy of the entity set (new EntitySet, but exactly the same data).
|
||||
EntityCollection entitySet = new EntityCollection();
|
||||
entitySet.getEntities().addAll(entitySetInitial.getEntities());
|
||||
|
||||
// Apply system query options
|
||||
// Apply system query options.
|
||||
SearchHandler.applySearchSystemQueryOption(uriInfo.getSearchOption(), entitySet);
|
||||
FilterHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), entitySet, uriInfo, serviceMetadata.getEdm());
|
||||
CountHandler.applyCountSystemQueryOption(uriInfo.getCountOption(), entitySet);
|
||||
OrderByHandler.applyOrderByOption(uriInfo.getOrderByOption(), entitySet, uriInfo, serviceMetadata.getEdm());
|
||||
SkipHandler.applySkipSystemQueryHandler(uriInfo.getSkipOption(), entitySet);
|
||||
TopHandler.applyTopSystemQueryOption(uriInfo.getTopOption(), entitySet);
|
||||
SearchHandler.applySearchSystemQueryOption(uriInfo.getSearchOption(), entitySet);
|
||||
|
||||
final Integer pageSize = odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).getMaxPageSize();
|
||||
final Integer serverPageSize = ServerSidePagingHandler.applyServerSidePaging(uriInfo.getSkipTokenOption(),
|
||||
|
|
|
@ -47,8 +47,8 @@ import org.apache.olingo.server.api.ODataRequest;
|
|||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.deserializer.FixedFormatDeserializer;
|
||||
import org.apache.olingo.server.api.prefer.PreferencesApplied;
|
||||
import org.apache.olingo.server.api.prefer.Preferences.Return;
|
||||
import org.apache.olingo.server.api.prefer.PreferencesApplied;
|
||||
import org.apache.olingo.server.api.processor.ComplexCollectionProcessor;
|
||||
import org.apache.olingo.server.api.processor.ComplexProcessor;
|
||||
import org.apache.olingo.server.api.processor.CountComplexCollectionProcessor;
|
||||
|
@ -226,6 +226,9 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
|
|||
((UriResourceFunction) resourceParts.get(0)).getParameters(), resource), path) :
|
||||
getPropertyData(entity, path);
|
||||
|
||||
// TODO: implement filter on collection properties (on a shallow copy of the values)
|
||||
// FilterHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), property, uriInfo, serviceMetadata.getEdm());
|
||||
|
||||
if (property == null && representationType != RepresentationType.COUNT) {
|
||||
if (representationType == RepresentationType.VALUE) {
|
||||
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
|
||||
|
|
|
@ -18,6 +18,13 @@
|
|||
*/
|
||||
package org.apache.olingo.server.tecsvc.processor.queryoptions.options;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Iterator;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.EntityCollection;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
|
@ -29,64 +36,83 @@ import org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorK
|
|||
import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
|
||||
import org.apache.olingo.server.api.uri.queryoption.search.SearchTerm;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Locale;
|
||||
|
||||
public class SearchHandler {
|
||||
private static SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
|
||||
|
||||
public static void applySearchSystemQueryOption(final SearchOption searchOption, final EntityCollection entitySet)
|
||||
public static void applySearchSystemQueryOption(final SearchOption searchOption, EntityCollection entitySet)
|
||||
throws ODataApplicationException {
|
||||
|
||||
if (searchOption != null) {
|
||||
SearchExpression se = searchOption.getSearchExpression();
|
||||
Iterator<Entity> it = entitySet.getEntities().iterator();
|
||||
while(it.hasNext()) {
|
||||
while (it.hasNext()) {
|
||||
boolean keep = false;
|
||||
Entity entity = it.next();
|
||||
ListIterator<Property> properties = entity.getProperties().listIterator();
|
||||
while(properties.hasNext() && !keep) {
|
||||
while (properties.hasNext() && !keep) {
|
||||
keep = isTrue(se, properties.next());
|
||||
}
|
||||
if(!keep) {
|
||||
if (!keep) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isTrue(SearchTerm term, Property property) {
|
||||
if(property.isPrimitive() && !property.isNull()) {
|
||||
String propertyString = asString(property);
|
||||
return propertyString != null && propertyString.contains(term.getSearchTerm());
|
||||
private static boolean isTrue(final SearchTerm term, final Property property) {
|
||||
if (property.isNull()) {
|
||||
return false;
|
||||
} else if (property.isPrimitive()) {
|
||||
if (property.isCollection()) {
|
||||
for (final Object primitive : property.asCollection()) {
|
||||
final String propertyString = asString(primitive);
|
||||
if (propertyString != null && propertyString.contains(term.getSearchTerm())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
final String propertyString = asString(property.asPrimitive());
|
||||
return propertyString != null && propertyString.contains(term.getSearchTerm());
|
||||
}
|
||||
} else if (property.isComplex()) {
|
||||
if (property.isCollection()) {
|
||||
for (final Object member : property.asCollection()) {
|
||||
if (isTrue(term, (Property) member)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
for (final Property innerProperty : property.asComplex().getValue()) {
|
||||
if (isTrue(term, innerProperty)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String asString(Property property) {
|
||||
// TODO: mibo(151117): improve 'string' conversion
|
||||
Object primitive = property.asPrimitive();
|
||||
if(primitive instanceof Calendar) {
|
||||
return SIMPLE_DATE_FORMAT.format(((Calendar) primitive).getTime());
|
||||
} else if(primitive instanceof Date) {
|
||||
return SIMPLE_DATE_FORMAT.format((Date) primitive);
|
||||
} else if(primitive instanceof byte[]) {
|
||||
private static String asString(final Object primitive) {
|
||||
// TODO: improve 'string' conversion; maybe consider only String properties
|
||||
if (primitive instanceof String) {
|
||||
return (String) primitive;
|
||||
} else if (primitive instanceof Calendar) {
|
||||
return DatatypeConverter.printDateTime((Calendar) primitive);
|
||||
} else if (primitive instanceof byte[]) {
|
||||
return DatatypeConverter.printBase64Binary((byte[]) primitive);
|
||||
} else {
|
||||
return primitive.toString();
|
||||
}
|
||||
return primitive.toString();
|
||||
}
|
||||
|
||||
private static boolean isTrue(SearchBinary binary, Property property) throws ODataApplicationException {
|
||||
private static boolean isTrue(final SearchBinary binary, final Property property) throws ODataApplicationException {
|
||||
SearchExpression left = binary.getLeftOperand();
|
||||
SearchExpression right = binary.getRightOperand();
|
||||
if(binary.getOperator() == SearchBinaryOperatorKind.AND) {
|
||||
if (binary.getOperator() == SearchBinaryOperatorKind.AND) {
|
||||
return isTrue(left, property) && isTrue(right, property);
|
||||
} else if(binary.getOperator() == SearchBinaryOperatorKind.OR) {
|
||||
} else if (binary.getOperator() == SearchBinaryOperatorKind.OR) {
|
||||
return isTrue(left, property) || isTrue(right, property);
|
||||
} else {
|
||||
throw new ODataApplicationException("Found unknown SearchBinaryOperatorKind: " + binary.getOperator(),
|
||||
|
@ -94,12 +120,13 @@ public class SearchHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean isTrue(SearchExpression searchExpression, Property property) throws ODataApplicationException {
|
||||
if(searchExpression.isSearchBinary()) {
|
||||
private static boolean isTrue(final SearchExpression searchExpression, final Property property)
|
||||
throws ODataApplicationException {
|
||||
if (searchExpression.isSearchBinary()) {
|
||||
return isTrue(searchExpression.asSearchBinary(), property);
|
||||
} else if(searchExpression.isSearchTerm()) {
|
||||
} else if (searchExpression.isSearchTerm()) {
|
||||
return isTrue(searchExpression.asSearchTerm(), property);
|
||||
} else if(searchExpression.isSearchUnary()) {
|
||||
} else if (searchExpression.isSearchUnary()) {
|
||||
return !isTrue(searchExpression.asSearchUnary().getOperand(), property);
|
||||
}
|
||||
throw new ODataApplicationException("Found unknown SearchExpression: " + searchExpression,
|
||||
|
|
Loading…
Reference in New Issue