[Major] simplified API for fluent API in StrolchSearch

No matter how hard you try, you can't have an API be good the first round
This commit is contained in:
Robert von Burg 2018-03-27 14:58:54 +02:00
parent 5befc47268
commit 825f8de64d
17 changed files with 390 additions and 237 deletions

View File

@ -409,13 +409,13 @@ public abstract class AbstractTransaction implements StrolchTransaction {
String id = elements.get(2);
switch (objectClassType) {
case Tags.RESOURCE:
groupedParameterizedElement = getResourceMap().getBy(this, type, id);
groupedParameterizedElement = getResourceBy(type, id);
break;
case Tags.ORDER:
groupedParameterizedElement = getOrderMap().getBy(this, type, id);
groupedParameterizedElement = getOrderBy(type, id);
break;
case Tags.ACTIVITY:
groupedParameterizedElement = getActivityMap().getBy(this, type, id);
groupedParameterizedElement = getActivityBy(type, id);
break;
default:
throw new StrolchException(MessageFormat.format("Unknown object class {0}", objectClassType)); //$NON-NLS-1$

View File

@ -0,0 +1,19 @@
package li.strolch.search;
import li.strolch.model.activity.Activity;
public class ActivitySearch extends StrolchSearch<Activity> {
private SearchNavigator<Activity> navigator;
@Override
protected SearchNavigator<Activity> getNavigator() {
return this.navigator;
}
@Override
public ActivitySearch types(String... types) {
this.navigator = tx -> tx.streamActivities(types);
return this;
}
}

View File

@ -3,51 +3,51 @@ package li.strolch.search;
import li.strolch.model.StrolchRootElement;
import li.strolch.utils.collections.DateRange;
public interface ExpressionBuilder {
public interface ExpressionBuilder<T extends StrolchRootElement> {
Object extract(StrolchRootElement element);
default SearchExpression isEqualTo(Object right) {
default SearchExpression<T> isEqualTo(Object right) {
return element -> PredicatesSupport.isEqualTo(right).matches(extract(element));
}
default SearchExpression isNotEqualTo(Object right) {
default SearchExpression<T> isNotEqualTo(Object right) {
return element -> PredicatesSupport.isNotEqualTo(right).matches(extract(element));
}
default SearchExpression isEqualToIgnoreCase(Object right) {
default SearchExpression<T> isEqualToIgnoreCase(Object right) {
return element -> PredicatesSupport.isEqualToIgnoreCase(right).matches(extract(element));
}
default SearchExpression isNotEqualToIgnoreCase(Object right) {
default SearchExpression<T> isNotEqualToIgnoreCase(Object right) {
return element -> PredicatesSupport.isNotEqualToIgnoreCase(right).matches(extract(element));
}
default SearchExpression startsWith(Object right) {
default SearchExpression<T> startsWith(Object right) {
return element -> PredicatesSupport.startsWith(right).matches(extract(element));
}
default SearchExpression startsWithIgnoreCase(Object right) {
default SearchExpression<T> startsWithIgnoreCase(Object right) {
return element -> PredicatesSupport.startsWithIgnoreCase(right).matches(extract(element));
}
default SearchExpression endsWith(Object right) {
default SearchExpression<T> endsWith(Object right) {
return element -> PredicatesSupport.endsWith(right).matches(extract(element));
}
default SearchExpression endsWithIgnoreCase(Object right) {
default SearchExpression<T> endsWithIgnoreCase(Object right) {
return element -> PredicatesSupport.endsWithIgnoreCase(right).matches(extract(element));
}
default SearchExpression contains(Object right) {
default SearchExpression<T> contains(Object right) {
return element -> PredicatesSupport.contains(right).matches(extract(element));
}
default SearchExpression containsIgnoreCase(Object right) {
default SearchExpression<T> containsIgnoreCase(Object right) {
return element -> PredicatesSupport.containsIgnoreCase(right).matches(extract(element));
}
default SearchExpression inRange(DateRange range) {
default SearchExpression<T> inRange(DateRange range) {
return element -> PredicatesSupport.inRange(range).matches(extract(element));
}
}

View File

@ -1,42 +1,40 @@
package li.strolch.search;
import li.strolch.model.Order;
import li.strolch.model.ParameterBag;
import li.strolch.model.StrolchElement;
import li.strolch.model.*;
import li.strolch.model.activity.Activity;
import li.strolch.model.parameter.Parameter;
public class ExpressionsSupport {
public static SearchExpression not(SearchExpression expression) {
public static <T extends StrolchRootElement> SearchExpression<T> not(SearchExpression<T> expression) {
return element -> !expression.matches(element);
}
public static ExpressionBuilder id() {
public static <T extends StrolchRootElement> ExpressionBuilder<T> id() {
return StrolchElement::getId;
}
public static SearchExpression id(SearchPredicate predicate) {
public static <T extends StrolchRootElement> SearchExpression<T> id(SearchPredicate predicate) {
return element -> predicate.matches(element.getId());
}
public static ExpressionBuilder name() {
public static <T extends StrolchRootElement> ExpressionBuilder<T> name() {
return StrolchElement::getName;
}
public static SearchExpression name(SearchPredicate predicate) {
public static <T extends StrolchRootElement> SearchExpression<T> name(SearchPredicate predicate) {
return element -> predicate.matches(element.getName());
}
public static ExpressionBuilder date() {
public static <T extends StrolchRootElement> ExpressionBuilder<T> date() {
return element -> ((Order) element).getDate();
}
public static SearchExpression date(SearchPredicate predicate) {
public static <T extends StrolchRootElement> SearchExpression<T> date(SearchPredicate predicate) {
return element -> predicate.matches(((Order) element).getDate());
}
public static ExpressionBuilder state() {
public static <T extends StrolchRootElement> ExpressionBuilder<T> state() {
return element -> {
if (element instanceof Order)
return ((Order) element).getState();
@ -46,11 +44,11 @@ public class ExpressionsSupport {
};
}
public static SearchExpression state(SearchPredicate predicate) {
public static <T extends StrolchRootElement> SearchExpression<T> state(SearchPredicate predicate) {
return element -> predicate.matches(state().extract(element));
}
public static ExpressionBuilder param(String bagId, String paramId) {
public static <T extends StrolchRootElement> ExpressionBuilder<T> param(String bagId, String paramId) {
return element -> {
ParameterBag bag = element.getParameterBag(bagId);
if (bag == null)
@ -61,11 +59,12 @@ public class ExpressionsSupport {
};
}
public static SearchExpression param(String bagId, String paramId, SearchPredicate predicate) {
public static <T extends StrolchRootElement> SearchExpression<T> param(String bagId, String paramId,
SearchPredicate predicate) {
return element -> predicate.matches(param(bagId, paramId).extract(element));
}
public static SearchExpression paramNull(String bagId, String paramId) {
public static <T extends StrolchRootElement> SearchExpression<T> paramNull(String bagId, String paramId) {
return element -> {
ParameterBag bag = element.getParameterBag(bagId);
if (bag == null)

View File

@ -1,34 +0,0 @@
package li.strolch.search;
import li.strolch.model.StrolchRootElement;
public class GenericSearch<T extends StrolchRootElement> extends StrolchSearch<T> {
@Override
protected void define() {
// ignored
}
@SuppressWarnings("unchecked")
public GenericSearch<T> resources(String... types) {
super.resources(types);
return this;
}
@SuppressWarnings("unchecked")
public GenericSearch<T> orders(String... types) {
super.orders(types);
return this;
}
@SuppressWarnings("unchecked")
public GenericSearch<T> activities(String... types) {
super.activities(types);
return this;
}
public GenericSearch<T> where(SearchExpression expression) {
super.where(expression);
return this;
}
}

View File

@ -0,0 +1,19 @@
package li.strolch.search;
import li.strolch.model.Order;
public class OrderSearch extends StrolchSearch<Order> {
private SearchNavigator<Order> navigator;
@Override
protected SearchNavigator<Order> getNavigator() {
return this.navigator;
}
@Override
public OrderSearch types(String... types) {
this.navigator = tx -> tx.streamOrders(types);
return this;
}
}

View File

@ -0,0 +1,19 @@
package li.strolch.search;
import li.strolch.model.Resource;
public class ResourceSearch extends StrolchSearch<Resource> {
private SearchNavigator<Resource> navigator;
@Override
protected SearchNavigator<Resource> getNavigator() {
return this.navigator;
}
@Override
public ResourceSearch types(String... types) {
this.navigator = tx -> tx.streamResources(types);
return this;
}
}

View File

@ -0,0 +1,32 @@
package li.strolch.search;
import java.util.stream.Stream;
import li.strolch.model.Order;
import li.strolch.model.Resource;
import li.strolch.model.StrolchRootElement;
import li.strolch.model.activity.Activity;
public class RootElementSearch extends StrolchSearch<StrolchRootElement> {
private SearchNavigator<StrolchRootElement> navigator;
@Override
protected SearchNavigator<StrolchRootElement> getNavigator() {
return this.navigator;
}
@Override
public RootElementSearch types(String... types) {
this.navigator = tx -> {
Stream<Resource> resources = tx.streamResources(types);
Stream<Activity> activities = tx.streamActivities(types);
Stream<Order> orders = tx.streamOrders(types);
return Stream.concat(resources, Stream.concat(activities, orders));
};
return this;
}
}

View File

@ -6,6 +6,7 @@ import java.util.stream.Stream;
import li.strolch.model.StrolchElement;
import li.strolch.model.StrolchRootElement;
import li.strolch.model.parameter.Parameter;
import li.strolch.model.visitor.StrolchRootElementVisitor;
public class RootElementSearchResult<T extends StrolchRootElement> extends SearchResult<T> {
@ -46,4 +47,8 @@ public class RootElementSearchResult<T extends StrolchRootElement> extends Searc
this.stream = this.stream.sorted(comparator);
return this;
}
public <U> SearchResult<U> visitor(StrolchRootElementVisitor<U> visitor) {
return new SearchResult<U>(this.stream.map(e -> e.accept(visitor)));
}
}

View File

@ -4,11 +4,8 @@ import static li.strolch.search.ExpressionsSupport.*;
import static li.strolch.search.PredicatesSupport.containsIgnoreCase;
import static li.strolch.utils.helper.StringHelper.trimOrEmpty;
import li.strolch.model.Order;
import li.strolch.model.Resource;
import li.strolch.model.StrolchRootElement;
import li.strolch.model.Tags;
import li.strolch.model.activity.Activity;
import li.strolch.utils.helper.StringHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -17,25 +14,26 @@ public class SearchBuilder {
private static final Logger logger = LoggerFactory.getLogger(SearchBuilder.class);
public static GenericSearch<Order> buildOrderSearch(String query, String... types) {
return buildSearch(new GenericSearch<Order>().orders(types), query);
public static OrderSearch buildOrderSearch(String query, String... types) {
return buildSearch(new OrderSearch().types(types), query);
}
public static GenericSearch<Resource> buildResourceSearch(String query, String... types) {
return buildSearch(new GenericSearch<Resource>().resources(types), query);
public static ResourceSearch buildResourceSearch(String query, String... types) {
return buildSearch(new ResourceSearch().types(types), query);
}
public static GenericSearch<Activity> buildActivitySearch(String query, String... types) {
return buildSearch(new GenericSearch<Activity>().activities(types), query);
public static ActivitySearch buildActivitySearch(String query, String... types) {
return buildSearch(new ActivitySearch().types(types), query);
}
private static <T extends StrolchRootElement> GenericSearch<T> buildSearch(GenericSearch<T> search, String query) {
@SuppressWarnings("unchecked")
private static <T extends StrolchRootElement, U extends StrolchSearch<T>> U buildSearch(U search, String query) {
query = trimOrEmpty(query);
if (query.isEmpty())
return search;
SearchExpression se = null;
SearchExpression<T> se = null;
String[] parts = query.split(" ");
for (String part : parts) {
@ -43,7 +41,7 @@ public class SearchBuilder {
if (!part.startsWith("param:")) {
if (se == null)
se = id(containsIgnoreCase(part)).or(name(containsIgnoreCase(part)));
se = (SearchExpression<T>) id(containsIgnoreCase(part)).or(name(containsIgnoreCase(part)));
else
se = se.or(id(containsIgnoreCase(part))).or(name(containsIgnoreCase(part)));
@ -52,7 +50,7 @@ public class SearchBuilder {
if (paramParts.length != 4) {
if (se == null)
se = id(containsIgnoreCase(part)).or(name(containsIgnoreCase(part)));
se = (SearchExpression<T>) id(containsIgnoreCase(part)).or(name(containsIgnoreCase(part)));
else
se = se.or(id(containsIgnoreCase(part))).or(name(containsIgnoreCase(part)));
@ -73,7 +71,8 @@ public class SearchBuilder {
if (se == null)
throw new IllegalArgumentException("search expression not evaluated for string " + query);
return search.where(se);
search = (U) search.where(se);
return search;
}
public static <T extends StrolchRootElement> RootElementSearchResult<T> orderBy(

View File

@ -1,20 +1,41 @@
package li.strolch.search;
import li.strolch.model.Order;
import li.strolch.model.Resource;
import li.strolch.model.StrolchRootElement;
import li.strolch.model.activity.Activity;
public interface SearchExpression {
public interface SearchExpression<T extends StrolchRootElement> {
boolean matches(StrolchRootElement element);
boolean matches(T element);
default SearchExpression or(SearchExpression right) {
default SearchExpression<T> or(SearchExpression<T> right) {
return element -> this.matches(element) || right.matches(element);
}
default SearchExpression and(SearchExpression right) {
default SearchExpression<T> and(SearchExpression<T> right) {
return element -> this.matches(element) && right.matches(element);
}
default SearchExpression not() {
default SearchExpression<T> not() {
return element -> !this.matches(element);
}
default SearchExpression<Resource> asResourceExp() {
@SuppressWarnings("unchecked")
SearchExpression<Resource> exp = element -> this.matches((T) element);
return exp;
}
default SearchExpression<Order> asOrderExp() {
@SuppressWarnings("unchecked")
SearchExpression<Order> exp = element -> this.matches((T) element);
return exp;
}
default SearchExpression<Activity> asActivityExp() {
@SuppressWarnings("unchecked")
SearchExpression<Activity> exp = element -> this.matches((T) element);
return exp;
}
}

View File

@ -1,52 +1,54 @@
package li.strolch.search;
public interface SearchExpressions {
import li.strolch.model.StrolchRootElement;
default SearchExpression not(SearchExpression expression) {
public interface SearchExpressions<T extends StrolchRootElement> {
default SearchExpression<T> not(SearchExpression<T> expression) {
return element -> !expression.matches(element);
}
default ExpressionBuilder id() {
default ExpressionBuilder<T> id() {
return ExpressionsSupport.id();
}
default SearchExpression id(SearchPredicate predicate) {
default SearchExpression<T> id(SearchPredicate predicate) {
return ExpressionsSupport.id(predicate);
}
default ExpressionBuilder name() {
default ExpressionBuilder<T> name() {
return ExpressionsSupport.name();
}
default SearchExpression name(SearchPredicate predicate) {
default SearchExpression<T> name(SearchPredicate predicate) {
return ExpressionsSupport.name(predicate);
}
default ExpressionBuilder date() {
default ExpressionBuilder<T> date() {
return ExpressionsSupport.date();
}
default SearchExpression date(SearchPredicate predicate) {
default SearchExpression<T> date(SearchPredicate predicate) {
return ExpressionsSupport.date(predicate);
}
default ExpressionBuilder state() {
default ExpressionBuilder<T> state() {
return ExpressionsSupport.state();
}
default SearchExpression state(SearchPredicate predicate) {
default SearchExpression<T> state(SearchPredicate predicate) {
return ExpressionsSupport.state(predicate);
}
default ExpressionBuilder param(String bagId, String paramId) {
default ExpressionBuilder<T> param(String bagId, String paramId) {
return ExpressionsSupport.param(bagId, paramId);
}
default SearchExpression param(String bagId, String paramId, SearchPredicate predicate) {
default SearchExpression<T> param(String bagId, String paramId, SearchPredicate predicate) {
return ExpressionsSupport.param(bagId, paramId, predicate);
}
default SearchExpression paramNull(String bagId, String paramId) {
default SearchExpression<T> paramNull(String bagId, String paramId) {
return ExpressionsSupport.paramNull(bagId, paramId);
}
}

View File

@ -6,6 +6,7 @@ import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -27,6 +28,10 @@ public class SearchResult<T> {
return new SearchResult<>(this.stream.map(mapper));
}
public SearchResult<T> filter(Predicate<T> predicate) {
return new SearchResult<>(this.stream.filter(predicate));
}
public SearchResult<T> orderBy(Comparator<? super T> comparator) {
this.stream = this.stream.sorted(comparator);
return this;

View File

@ -13,21 +13,34 @@ import li.strolch.utils.dbc.DBC;
import li.strolch.utils.helper.ExceptionHelper;
public abstract class StrolchSearch<T extends StrolchRootElement>
implements SearchExpressions, SearchPredicates, Restrictable {
implements SearchExpressions<T>, SearchPredicates, Restrictable {
private String privilegeValue;
private SearchNavigator<T> navigator;
private SearchExpression expression;
private SearchExpression<T> expression;
public StrolchSearch() {
this.privilegeValue = getClass().getName();
}
protected abstract SearchNavigator<T> getNavigator();
/**
* Used to configure the navigator
*
* @param types
* the types of elements to search
*
* @return this for chaining
*/
public abstract StrolchSearch<T> types(String... types);
/**
* Allows to implement the search expression in one method, or to prepare a project specific search expression
*/
protected abstract void define();
protected void define() {
// default is no-op
}
/**
* Adds the given {@link SearchExpression} to the current search
@ -37,7 +50,7 @@ public abstract class StrolchSearch<T extends StrolchRootElement>
*
* @return this for chaining
*/
public StrolchSearch<T> where(SearchExpression expression) {
public StrolchSearch<T> where(SearchExpression<T> expression) {
if (this.expression == null)
this.expression = expression;
else
@ -68,33 +81,15 @@ public abstract class StrolchSearch<T extends StrolchRootElement>
// first prepare
define();
// then validate status
DBC.PRE.assertNotNull("navigation not set! Call one of resources(), orders() or activities()", this.navigator);
// then validate navigator
DBC.PRE.assertNotNull("navigation not set! Call types()", getNavigator());
Stream<T> stream = this.navigator.navigate(tx);
Stream<T> stream = getNavigator().navigate(tx);
if (this.expression != null)
stream = stream.filter(e -> this.expression.matches(e));
return new RootElementSearchResult<T>(stream);
}
@SuppressWarnings("unchecked")
protected StrolchSearch<T> resources(String... types) {
this.navigator = tx -> (Stream<T>) tx.streamResources(types);
return this;
}
@SuppressWarnings("unchecked")
protected StrolchSearch<T> orders(String... types) {
this.navigator = tx -> (Stream<T>) tx.streamOrders(types);
return this;
}
@SuppressWarnings("unchecked")
protected StrolchSearch<T> activities(String... types) {
this.navigator = tx -> (Stream<T>) tx.streamActivities(types);
return this;
return new RootElementSearchResult<>(stream);
}
/**

View File

@ -130,10 +130,24 @@ public class StrolchSearchTest {
try (StrolchTransaction tx = realm.openTx(cert, ParallelTests.class)) {
List<JsonObject> result = new NewBallSearch() //
.id("the-id") //
.status("bla") //
.color("yellow") //
List<JsonObject> result = new BallSearch("the-id", "STATUS", "yellow")
.where(element -> element.hasTimedState(STATE_FLOAT_ID)).search(tx)
.map(a -> a.accept(toJsonVisitor)).toList();
assertEquals(2, result.size());
}
}
@Test
public void shouldSearchResources2() {
StrolchRootElementToJsonVisitor toJsonVisitor = new StrolchRootElementToJsonVisitor();
StrolchRealm realm = runtimeMock.getAgent().getContainer().getRealm(cert);
try (StrolchTransaction tx = realm.openTx(cert, ParallelTests.class)) {
List<JsonObject> result = new NewBallSearch().id("the-id").status("bla").color("yellow")
// do search, returns SearchResult
.search(tx)
@ -146,28 +160,58 @@ public class StrolchSearchTest {
}
}
@Test
public void shouldSearchResources3() {
StrolchRealm realm = runtimeMock.getAgent().getContainer().getRealm(cert);
try (StrolchTransaction tx = realm.openTx(cert, ParallelTests.class)) {
assertEquals(4,
new ResourceSearch().types().where(param(BAG_ID, PARAM_STRING_ID, contains("rol"))).search(tx)
.toList().size());
assertEquals(4,
new ResourceSearch().types().where(param(BAG_ID, PARAM_STRING_ID, startsWithIgnoreCase("STR")))
.search(tx).toList().size());
}
}
@Test
public void shouldSearchResources4() {
StrolchRealm realm = runtimeMock.getAgent().getContainer().getRealm(cert);
try (StrolchTransaction tx = realm.openTx(cert, ParallelTests.class)) {
assertEquals(7, new ResourceSearch().types().search(tx).toList().size());
}
}
@Test
public void shouldSearchResources5() {
StrolchRealm realm = runtimeMock.getAgent().getContainer().getRealm(cert);
try (StrolchTransaction tx = realm.openTx(cert, ParallelTests.class)) {
assertEquals(2, new ResourceSearch().types("sdf", "Ball").search(tx).toList().size());
assertEquals(2, new ResourceSearch().types("Ball", "sdf").search(tx).toList().size());
assertEquals(2, new ResourceSearch().types("4gdf", "Ball", "sdf").search(tx).toList().size());
}
}
@Test
public void shouldSearchOrders() {
StrolchRealm realm = runtimeMock.getAgent().getContainer().getRealm(cert);
try (StrolchTransaction tx = realm.openTx(cert, ParallelTests.class)) {
List<Order> result = new StrolchSearch<Order>() {
List<Order> result = new OrderSearch() {
@Override
public void define() {
DateRange dateRange = new DateRange() //
DateRange dateRange = new DateRange()
.from(ISO8601FormatFactory.getInstance().parseDate("2012-01-01T00:00:00.000+01:00"), true)
.to(ISO8601FormatFactory.getInstance().parseDate("2013-01-01T00:00:00.000+01:00"), true);
orders() //
.where(date(isEqualTo(new Date(1384929777699L))) //
.or(state(isEqualTo(State.CREATED)) //
.and(param(BAG_ID, PARAM_STRING_ID, isEqualTo("Strolch"))) //
.and(param(BAG_ID, PARAM_DATE_ID, inRange(dateRange)))));
types().where(date(isEqualTo(new Date(1384929777699L))).or(state(isEqualTo(State.CREATED))
.and(param(BAG_ID, PARAM_STRING_ID, isEqualTo("Strolch")))
.and(param(BAG_ID, PARAM_DATE_ID, inRange(dateRange)))));
}
} //
.search(tx) //
.toList();
}.search(tx).toList();
assertEquals(7, result.size());
}
@ -178,105 +222,107 @@ public class StrolchSearchTest {
StrolchRealm realm = runtimeMock.getAgent().getContainer().getRealm(cert);
try (StrolchTransaction tx = realm.openTx(cert, ParallelTests.class)) {
StrolchSearch<Order> search = new StrolchSearch<Order>() {
StrolchSearch<Order> search = new OrderSearch() {
@Override
public void define() {
orders("SortingType").where(state(isEqualTo(State.CREATED)));
types("SortingType").where(state(isEqualTo(State.CREATED)));
}
};
List<Order> result;
result = search //
.search(tx) //
.orderById(true) //
.toList();
result = search.search(tx).orderById(true).toList();
assertEquals(5, result.size());
assertEquals("ggg", result.get(0).getId());
result = search //
.search(tx) //
.orderByName(false) //
.toList();
result = search.search(tx).orderByName(false).toList();
assertEquals(5, result.size());
assertEquals("aaa", result.get(0).getId());
}
}
@Test
public void shouldSearchOrders2() {
StrolchRealm realm = runtimeMock.getAgent().getContainer().getRealm(cert);
try (StrolchTransaction tx = realm.openTx(cert, ParallelTests.class)) {
assertEquals(5, new OrderSearch().types("sdf", "SortingType").search(tx).toList().size());
assertEquals(5, new OrderSearch().types("SortingType", "sdf").search(tx).toList().size());
assertEquals(5, new OrderSearch().types("4gdf", "SortingType", "sdf").search(tx).toList().size());
assertEquals(7, new OrderSearch().types().search(tx).toList().size());
}
}
@Test
public void shouldSearchActivities() {
StrolchRealm realm = runtimeMock.getAgent().getContainer().getRealm(cert);
try (StrolchTransaction tx = realm.openTx(cert, ParallelTests.class)) {
Map<String, State> states = new StrolchSearch<Activity>() {
Map<String, State> states = new ActivitySearch() {
@Override
public void define() {
activities() //
.where(state().isEqualTo(State.PLANNING) //
.and(name(isEqualTo("Activity"))) //
);
types().where(state().isEqualTo(State.PLANNING).and(name(isEqualTo("Activity"))));
}
} //
.search(tx) //
.toMap(Activity::getId, Activity::getState);
}.search(tx).toMap(Activity::getId, Activity::getState);
assertEquals(1, states.size());
}
}
@Test
public void shouldSearchGeneric() {
public void shouldSearchActivities1() {
StrolchRealm realm = runtimeMock.getAgent().getContainer().getRealm(cert);
try (StrolchTransaction tx = realm.openTx(cert, ParallelTests.class)) {
Map<String, State> states = new GenericSearch<Activity>() //
Map<String, State> states = new ActivitySearch()
.activities() //
.where(state().isEqualTo(State.PLANNING) //
.and(name(isEqualTo("Activity")))) //
.types().where(state().isEqualTo(State.PLANNING).and(name(isEqualTo("Activity"))).asActivityExp())
.search(tx) //
.toMap(Activity::getId, Activity::getState);
.search(tx).toMap(Activity::getId, Activity::getState);
assertEquals(1, states.size());
}
}
@Test
public void shouldSearchGeneric1() {
public void shouldSearchActivities2() {
StrolchRealm realm = runtimeMock.getAgent().getContainer().getRealm(cert);
try (StrolchTransaction tx = realm.openTx(cert, ParallelTests.class)) {
assertEquals(4, new GenericSearch<Resource>() //
.resources() //
.where(param(BAG_ID, PARAM_STRING_ID, contains("rol"))) //
.search(tx) //
.toList().size());
assertEquals(4, new GenericSearch<Resource>() //
.resources() //
.where(param(BAG_ID, PARAM_STRING_ID, startsWithIgnoreCase("STR"))) //
.search(tx) //
.toList().size());
assertEquals(2, new ActivitySearch().types("sdf", "ActivityType").search(tx).toList().size());
assertEquals(2, new ActivitySearch().types("ActivityType", "sdf").search(tx).toList().size());
assertEquals(2, new ActivitySearch().types("4gdf", "ActivityType", "sdf").search(tx).toList().size());
assertEquals(2, new ActivitySearch().types().search(tx).toList().size());
}
}
@Test
public void shouldSearchGeneric2() {
public void shouldSearchActivities3() {
StrolchRealm realm = runtimeMock.getAgent().getContainer().getRealm(cert);
try (StrolchTransaction tx = realm.openTx(cert, ParallelTests.class)) {
assertEquals(7, new GenericSearch<Resource>() //
.resources() //
.search(tx) //
.toList().size());
assertEquals(1, new ActivitySearch().types("sdf", "ActivityType")
.where(element -> element.getActionsByType("Use").size() == 4).search(tx).toList().size());
}
}
public class NewBallSearch extends StrolchSearch<Resource> {
@Test
public void shouldSearchRootElements() {
StrolchRealm realm = runtimeMock.getAgent().getContainer().getRealm(cert);
try (StrolchTransaction tx = realm.openTx(cert, ParallelTests.class)) {
assertEquals(9,
new RootElementSearch().types("SortingType", "Ball", "ActivityType").search(tx).toList().size());
assertEquals(16, new RootElementSearch().types().search(tx).toList().size());
assertEquals(2, new RootElementSearch().types("ActivityType").search(tx).toList().size());
}
}
public class NewBallSearch extends ResourceSearch {
@Override
protected void define() {
resources("Ball");
types("Ball");
}
public NewBallSearch id(String id) {
@ -295,7 +341,7 @@ public class StrolchSearchTest {
}
}
public class BallSearch extends StrolchSearch<Resource> {
public class BallSearch extends ResourceSearch {
private String id;
private String status;
@ -309,37 +355,36 @@ public class StrolchSearchTest {
@Override
public void define() {
resources("Ball") //
.where(id(isEqualTo(this.id)) //
.or(param("parameters", "status", isEqualTo(this.status)) //
.and(not(param("parameters", "color", isEqualTo(this.color)))) //
types("Ball").where(id(isEqualTo(this.id)).or(param("parameters", "status", isEqualTo(this.status))
.and(not(param("parameters", "color", isEqualTo(this.color))))
.and(param(BAG_ID, PARAM_FLOAT_ID, isEqualTo(44.3D))) //
.and(param(BAG_ID, PARAM_FLOAT_ID, isEqualTo(44.3D)))
.and(param(BAG_ID, PARAM_STRING_ID, isEqualTo("Strolch"))) //
.and(param(BAG_ID, PARAM_STRING_ID, isEqualToIgnoreCase("strolch"))) //
.and(param(BAG_ID, PARAM_STRING_ID, isNotEqualTo("dfgdfg"))) //
.and(param(BAG_ID, PARAM_STRING_ID, isNotEqualToIgnoreCase("dfgdfg"))) //
.and(param(BAG_ID, PARAM_STRING_ID, contains("rol"))) //
.and(param(BAG_ID, PARAM_STRING_ID, containsIgnoreCase("ROL"))) //
.and(param(BAG_ID, PARAM_STRING_ID, startsWith("Str"))) //
.and(param(BAG_ID, PARAM_STRING_ID, startsWithIgnoreCase("str"))) //
.and(param(BAG_ID, PARAM_STRING_ID, endsWith("lch"))) //
.and(param(BAG_ID, PARAM_STRING_ID, endsWithIgnoreCase("LCH"))) //
.and(param(BAG_ID, PARAM_STRING_ID, isEqualTo("Strolch")))
.and(param(BAG_ID, PARAM_STRING_ID, isEqualToIgnoreCase("strolch")))
.and(param(BAG_ID, PARAM_STRING_ID, isNotEqualTo("dfgdfg")))
.and(param(BAG_ID, PARAM_STRING_ID, isNotEqualToIgnoreCase("dfgdfg")))
.and(param(BAG_ID, PARAM_STRING_ID, contains("rol")))
.and(param(BAG_ID, PARAM_STRING_ID, containsIgnoreCase("ROL")))
.and(param(BAG_ID, PARAM_STRING_ID, startsWith("Str")))
.and(param(BAG_ID, PARAM_STRING_ID, startsWithIgnoreCase("str")))
.and(param(BAG_ID, PARAM_STRING_ID, endsWith("lch")))
.and(param(BAG_ID, PARAM_STRING_ID, endsWithIgnoreCase("LCH")))
.and(param(BAG_ID, PARAM_BOOLEAN_ID, isEqualTo(true))) //
.and(param(BAG_ID, PARAM_DATE_ID, isEqualTo(new Date(1354295525628L)))) //
.and(param(BAG_ID, PARAM_INTEGER_ID, isEqualTo(77))) //
.and(param(BAG_ID, PARAM_BOOLEAN_ID, isEqualTo(true)))
.and(param(BAG_ID, PARAM_DATE_ID, isEqualTo(new Date(1354295525628L))))
.and(param(BAG_ID, PARAM_INTEGER_ID, isEqualTo(77)))
.and(param(BAG_ID, PARAM_LIST_FLOAT_ID, isEqualTo(asList(6.0D, 11.0D, 16.0D)))) //
.and(param(BAG_ID, PARAM_LIST_FLOAT_ID, contains(singletonList(6.0D)))) //
.and(param(BAG_ID, PARAM_LIST_FLOAT_ID, isEqualTo(asList(6.0D, 11.0D, 16.0D))))
.and(param(BAG_ID, PARAM_LIST_FLOAT_ID, contains(singletonList(6.0D))))
.and(param(BAG_ID, PARAM_LIST_INTEGER_ID, isEqualTo(asList(5, 10, 15)))) //
.and(param(BAG_ID, PARAM_LIST_LONG_ID, isEqualTo(asList(7L, 12L, 17L)))) //
.and(param(BAG_ID, PARAM_LIST_STRING_ID, isEqualTo(asList("Hello", "World")))) //
.and(param(BAG_ID, PARAM_LIST_INTEGER_ID, isEqualTo(asList(5, 10, 15))))
.and(param(BAG_ID, PARAM_LIST_LONG_ID, isEqualTo(asList(7L, 12L, 17L))))
.and(param(BAG_ID, PARAM_LIST_STRING_ID, isEqualTo(asList("Hello", "World"))))
.and(paramNull(BAG_ID, "non-existant")) //
));
.and(paramNull(BAG_ID, "non-existant"))
//
));
}
}
}

View File

@ -1,26 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<StrolchModel>
<Activity Id="activity_1" Name="Activity" Type="ActivityType" TimeOrdering="Series">
<Policies>
<Policy Type="PlanningPolicy" Value="key:SimplePlanning" />
<Policy Type="ConfirmationPolicy" Value="key:NoConfirmation" />
</Policies>
<Action Id="action_1" Name="Action 1" ResourceId="dummyId" ResourceType="dummyType" State="Created" Type="Use">
<Policies>
<Policy Type="PlanningPolicy" Value="key:SimplePlanning" />
<Policy Type="ConfirmationPolicy" Value="key:NoConfirmation" />
</Policies>
<ValueChange StateId="dummyId" Time="2012-11-30T18:12:05.628+01:00" Value="5" Type="Integer" />
</Action>
<Activity Id="child_activity" Name="Child Activity" Type="childType" TimeOrdering="Series">
<Policies>
<Policy Type="PlanningPolicy" Value="key:SimplePlanning" />
<Policy Type="ConfirmationPolicy" Value="key:NoConfirmation" />
</Policies>
<Action Id="action_2" Name="Action 2" ResourceId="dummyId" ResourceType="dummyType" State="Planned" Type="Use" />
<Action Id="action_3" Name="Action 3" ResourceId="dummyId" ResourceType="dummyType" State="Created" Type="Use" />
</Activity>
</Activity>
<Activity Id="activity_1" Name="Activity" Type="ActivityType" TimeOrdering="Series">
<Policies>
<Policy Type="PlanningPolicy" Value="key:SimplePlanning"/>
<Policy Type="ConfirmationPolicy" Value="key:NoConfirmation"/>
</Policies>
<Action Id="action_1" Name="Action 1" ResourceId="dummyId" ResourceType="dummyType" State="Created" Type="Use">
<Policies>
<Policy Type="PlanningPolicy" Value="key:SimplePlanning"/>
<Policy Type="ConfirmationPolicy" Value="key:NoConfirmation"/>
</Policies>
<ValueChange StateId="dummyId" Time="2012-11-30T18:12:05.628+01:00" Value="5" Type="Integer"/>
</Action>
<Activity Id="child_activity" Name="Child Activity" Type="childType" TimeOrdering="Series">
<Policies>
<Policy Type="PlanningPolicy" Value="key:SimplePlanning"/>
<Policy Type="ConfirmationPolicy" Value="key:NoConfirmation"/>
</Policies>
<Action Id="action_2" Name="Action 2" ResourceId="dummyId" ResourceType="dummyType" State="Planned" Type="Use"/>
<Action Id="action_3" Name="Action 3" ResourceId="dummyId" ResourceType="dummyType" State="Created" Type="Use"/>
</Activity>
</Activity>
<Activity Id="activity_2" Name="Activity" Type="ActivityType" TimeOrdering="Series">
<Policies>
<Policy Type="PlanningPolicy" Value="key:SimplePlanning"/>
<Policy Type="ConfirmationPolicy" Value="key:NoConfirmation"/>
</Policies>
<Action Id="action_1" Name="Action 1" ResourceId="dummyId" ResourceType="dummyType" Type="Use">
<Policies>
<Policy Type="PlanningPolicy" Value="key:SimplePlanning"/>
<Policy Type="ConfirmationPolicy" Value="key:NoConfirmation"/>
</Policies>
<ValueChange StateId="dummyId" Time="2012-11-30T18:12:05.628+01:00" Value="5" Type="Integer"/>
</Action>
<Action Id="action_2" Name="Action 2" ResourceId="dummyId" ResourceType="dummyType" Type="Use">
<Policies>
<Policy Type="PlanningPolicy" Value="key:SimplePlanning"/>
<Policy Type="ConfirmationPolicy" Value="key:NoConfirmation"/>
</Policies>
<ValueChange StateId="dummyId" Time="2012-11-30T18:12:05.628+01:00" Value="5" Type="Integer"/>
</Action>
<Activity Id="child_activity" Name="Child Activity" Type="childType" TimeOrdering="Series">
<Policies>
<Policy Type="PlanningPolicy" Value="key:SimplePlanning"/>
<Policy Type="ConfirmationPolicy" Value="key:NoConfirmation"/>
</Policies>
<Action Id="action_2" Name="Action 2" ResourceId="dummyId" ResourceType="dummyType" Type="Use"/>
<Action Id="action_3" Name="Action 3" ResourceId="dummyId" ResourceType="dummyType" Type="Use"/>
</Activity>
</Activity>
</StrolchModel>

View File

@ -60,9 +60,7 @@ import li.strolch.rest.StrolchRestfulConstants;
import li.strolch.rest.helper.ResponseUtil;
import li.strolch.rest.helper.RestfulHelper;
import li.strolch.rest.model.QueryData;
import li.strolch.search.GenericSearch;
import li.strolch.search.RootElementSearchResult;
import li.strolch.search.SearchBuilder;
import li.strolch.search.*;
import li.strolch.service.*;
import li.strolch.service.AddActivityService.AddActivityArg;
import li.strolch.service.AddOrderService.AddOrderArg;
@ -401,7 +399,7 @@ public class Inspector {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
// parse the query string
GenericSearch<Resource> search = SearchBuilder.buildResourceSearch(queryData.getQuery(), type);
ResourceSearch search = SearchBuilder.buildResourceSearch(queryData.getQuery(), type);
// query the data
RootElementSearchResult<Resource> result;
@ -445,7 +443,7 @@ public class Inspector {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
// parse the query string
GenericSearch<Order> search = SearchBuilder.buildOrderSearch(queryData.getQuery(), type);
OrderSearch search = SearchBuilder.buildOrderSearch(queryData.getQuery(), type);
// query the data
RootElementSearchResult<Order> result;
@ -491,7 +489,7 @@ public class Inspector {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
// parse the query string
GenericSearch<Activity> search = SearchBuilder.buildActivitySearch(queryData.getQuery(), type);
ActivitySearch search = SearchBuilder.buildActivitySearch(queryData.getQuery(), type);
// query the data
RootElementSearchResult<Activity> result;
@ -536,7 +534,7 @@ public class Inspector {
queryData.initializeUnsetFields();
GenericSearch<Resource> search = SearchBuilder.buildResourceSearch(queryData.getQuery(), type);
ResourceSearch search = SearchBuilder.buildResourceSearch(queryData.getQuery(), type);
StreamingOutput streamingOutput = stream -> {
try (StrolchTransaction tx = openTx(cert, realm)) {
@ -569,7 +567,7 @@ public class Inspector {
queryData.initializeUnsetFields();
GenericSearch<Order> search = SearchBuilder.buildOrderSearch(queryData.getQuery(), type);
OrderSearch search = SearchBuilder.buildOrderSearch(queryData.getQuery(), type);
StreamingOutput streamingOutput = stream -> {
try (StrolchTransaction tx = openTx(cert, realm)) {
@ -602,7 +600,7 @@ public class Inspector {
queryData.initializeUnsetFields();
GenericSearch<Activity> search = SearchBuilder.buildActivitySearch(queryData.getQuery(), type);
ActivitySearch search = SearchBuilder.buildActivitySearch(queryData.getQuery(), type);
StreamingOutput streamingOutput = stream -> {
try (StrolchTransaction tx = openTx(cert, realm)) {
@ -700,7 +698,7 @@ public class Inspector {
Order order;
try (StrolchTransaction tx = openTx(cert, realm)) {
order = tx.getOrderBy( type, id);
order = tx.getOrderBy(type, id);
}
if (order == null) {
throw new StrolchException(MessageFormat.format("No Order exists for {0}/{1}", type, id)); //$NON-NLS-1$