[New] QueryParser can now handle parameters incl. without prefixes

This commit is contained in:
Robert von Burg 2016-08-30 11:44:55 +02:00
parent c5cd74b168
commit d25e7577f7
3 changed files with 270 additions and 64 deletions

View File

@ -1,9 +1,14 @@
package li.strolch.model.query.parser;
import static org.petitparser.parser.primitive.CharacterParser.digit;
import static org.petitparser.parser.primitive.CharacterParser.letter;
import static org.petitparser.parser.primitive.CharacterParser.of;
import static org.petitparser.parser.primitive.CharacterParser.whitespace;
import static org.petitparser.parser.primitive.CharacterParser.word;
import static org.petitparser.parser.primitive.StringParser.ofIgnoringCase;
import java.util.Set;
import org.petitparser.context.Result;
import org.petitparser.parser.Parser;
import org.petitparser.tools.CompositeParser;
@ -16,6 +21,7 @@ import li.strolch.model.query.IdSelection;
import li.strolch.model.query.NameSelection;
import li.strolch.model.query.OrSelection;
import li.strolch.model.query.OrderQuery;
import li.strolch.model.query.ParameterSelection;
import li.strolch.model.query.ResourceQuery;
import li.strolch.model.query.StrolchElementQuery;
import li.strolch.model.query.StrolchTypeNavigation;
@ -23,81 +29,170 @@ import li.strolch.model.visitor.NoStrategyActivityVisitor;
import li.strolch.model.visitor.NoStrategyOrderVisitor;
import li.strolch.model.visitor.NoStrategyResourceVisitor;
import li.strolch.utils.StringMatchMode;
import li.strolch.utils.collections.MapOfSets;
public class QueryParser extends CompositeParser {
public abstract class QueryParser extends CompositeParser {
private StrolchElementQuery<?> query;
private OrSelection or;
private IdSelection idSelection;
/**
* Use static helper methods instead of constructors
*
* @param resourceQuery
*/
private QueryParser(StrolchElementQuery<?> query) {
// don't allow public construction
public QueryParser(StrolchElementQuery<?> query) {
this.query = query;
}
private OrSelection or() {
protected OrSelection or() {
if (this.or == null)
this.or = query.or();
return or;
}
@Override
protected void initialize() {
private Parser[] charParsers() {
return new Parser[] { of('@'), of('.'), of('-'), of('_'), of('+'), of(':') };
}
protected Parser key(String key) {
return ofIgnoringCase(key + ":").seq(word().or(charParsers()).star().flatten()).pick(1);
}
public abstract MapOfSets<String, String> getBagParamSet();
public abstract boolean withPrefix();
protected void defs() {
// [id:<value>] [name:<value>] [type:<value>] [param:<bagId>:<paramId>] [value]
Parser id = ofIgnoringCase("id:").seq(word().star().flatten()).pick(1);
Parser name = ofIgnoringCase("name:").seq(word().star().flatten()).pick(1);
Parser type = ofIgnoringCase("type:").seq(word().star().flatten()).pick(1);
Parser parsers = null;
def("id", id);
def("name", name);
def("type", type);
if (withPrefix()) {
def("id", key("id"));
def("name", key("name"));
def("type", key("type"));
Parser query = whitespace().optional().seq(ref("type").or(ref("id")).or(ref("name")).or(whitespace())).star();
for (String bagId : getBagParamSet().keySet()) {
Set<String> set = getBagParamSet().getSet(bagId);
for (String paramId : set) {
def(paramId, key(paramId));
if (parsers == null) {
parsers = ref(paramId);
} else {
parsers = parsers.or(ref(paramId));
}
}
}
if (parsers == null)
parsers = ref("id").or(ref("name")).or(ref("type"));
else
parsers = parsers.or(ref("id")).or(ref("name")).or(ref("type"));
} else {
def("other", letter().or(digit()).seq(word().or(charParsers()).star().flatten()).flatten());
parsers = ref("other");
}
parsers = parsers.or(whitespace());
Parser query = whitespace().optional().seq(parsers).star();
def("query", query);
def("start", ref("query"));
}
action("id", (String s) -> {
String trimmed = s.trim();
if (trimmed.isEmpty())
return null;
protected void actions() {
if (this.idSelection == null) {
this.idSelection = new IdSelection(trimmed, StringMatchMode.ci());
or().with(this.idSelection);
} else {
this.idSelection.with(trimmed);
if (withPrefix()) {
for (String bagId : getBagParamSet().keySet()) {
Set<String> set = getBagParamSet().getSet(bagId);
for (String paramId : set) {
action(paramId, (String s) -> {
String trimmed = s.trim();
if (!trimmed.isEmpty())
or().with(
ParameterSelection.anyTypeSelection(bagId, paramId, trimmed, StringMatchMode.ci()));
return null;
});
}
}
return null;
});
action("name", (String s) -> {
String trimmed = s.trim();
if (!trimmed.isEmpty())
or().with(new NameSelection(trimmed, StringMatchMode.ci()));
return null;
});
action("type", (String s) -> {
String trimmed = s.trim();
if (!trimmed.isEmpty())
this.query.setNavigation(new StrolchTypeNavigation(trimmed));
return null;
});
action("id", (String s) -> {
String trimmed = s.trim();
if (trimmed.isEmpty())
return null;
if (this.idSelection == null) {
this.idSelection = new IdSelection(trimmed, StringMatchMode.ci());
or().with(this.idSelection);
} else {
this.idSelection.with(trimmed);
}
return null;
});
action("name", (String s) -> {
String trimmed = s.trim();
if (!trimmed.isEmpty())
or().with(new NameSelection(trimmed, StringMatchMode.ci()));
return null;
});
action("type", (String s) -> {
String trimmed = s.trim();
if (!trimmed.isEmpty())
this.query.setNavigation(new StrolchTypeNavigation(trimmed));
return null;
});
} else {
action("other", (String s) -> {
for (String bagId : getBagParamSet().keySet()) {
Set<String> set = getBagParamSet().getSet(bagId);
for (String paramId : set) {
String trimmed = s.trim();
if (!trimmed.isEmpty())
or().with(
ParameterSelection.anyTypeSelection(bagId, paramId, trimmed, StringMatchMode.ci()));
}
}
return null;
});
}
action("start", o -> this.query);
}
public static ResourceQuery<Resource> parseToResourceQuery(String queryString, boolean withAny) {
QueryParser parser = new QueryParser(new ResourceQuery<>());
@Override
protected void initialize() {
defs();
actions();
}
public static ResourceQuery<Resource> parseToResourceQuery(String queryString, boolean withPrefix,
boolean withAny) {
return parseToResourceQuery(new MapOfSets<>(), withPrefix, queryString, withAny);
}
public static ResourceQuery<Resource> parseToResourceQuery(MapOfSets<String, String> bagParamSet,
boolean withPrefix, String queryString, boolean withAny) {
QueryParser parser = new QueryParser(new ResourceQuery<>()) {
@Override
public MapOfSets<String, String> getBagParamSet() {
return bagParamSet;
}
@Override
public boolean withPrefix() {
return withPrefix;
}
};
Result result = parser.parse(queryString);
ResourceQuery<Resource> query = result.get();
query.setResourceVisitor(new NoStrategyResourceVisitor());
@ -109,8 +204,23 @@ public class QueryParser extends CompositeParser {
return query;
}
public static OrderQuery<Order> parseToOrderQuery(String queryString, boolean withAny) {
QueryParser parser = new QueryParser(new OrderQuery<>());
public static OrderQuery<Order> parseToOrderQuery(String queryString, boolean withPrefix, boolean withAny) {
return parseToOrderQuery(new MapOfSets<>(), withPrefix, queryString, withAny);
}
public static OrderQuery<Order> parseToOrderQuery(MapOfSets<String, String> bagParamSet, boolean withPrefix,
String queryString, boolean withAny) {
QueryParser parser = new QueryParser(new OrderQuery<>()) {
@Override
public MapOfSets<String, String> getBagParamSet() {
return bagParamSet;
}
@Override
public boolean withPrefix() {
return withPrefix;
}
};
Result result = parser.parse(queryString);
OrderQuery<Order> query = result.get();
query.setOrderVisitor(new NoStrategyOrderVisitor());
@ -122,8 +232,24 @@ public class QueryParser extends CompositeParser {
return query;
}
public static ActivityQuery<Activity> parseToActivityQuery(String queryString, boolean withAny) {
QueryParser parser = new QueryParser(new ActivityQuery<>());
public static ActivityQuery<Activity> parseToActivityQuery(String queryString, boolean withPrefix,
boolean withAny) {
return parseToActivityQuery(new MapOfSets<>(), withPrefix, queryString, withAny);
}
public static ActivityQuery<Activity> parseToActivityQuery(MapOfSets<String, String> bagParamSet,
boolean withPrefix, String queryString, boolean withAny) {
QueryParser parser = new QueryParser(new ActivityQuery<>()) {
@Override
public MapOfSets<String, String> getBagParamSet() {
return bagParamSet;
}
@Override
public boolean withPrefix() {
return withPrefix;
}
};
Result result = parser.parse(queryString);
ActivityQuery<Activity> query = result.get();
query.setActivityVisitor(new NoStrategyActivityVisitor());

View File

@ -74,7 +74,7 @@ public class ModelQuery {
List<Resource> resources = new ArrayList<>();
// parse the query string
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery(queryData.getQuery(), true);
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery(queryData.getQuery(), true, true);
// query the data
long dataSetSize = 0L;
@ -132,7 +132,7 @@ public class ModelQuery {
List<Order> orders = new ArrayList<>();
// parse the query string
OrderQuery<Order> query = QueryParser.parseToOrderQuery(queryData.getQuery(), true);
OrderQuery<Order> query = QueryParser.parseToOrderQuery(queryData.getQuery(), true, true);
// query the data
long dataSetSize = 0L;
@ -191,7 +191,7 @@ public class ModelQuery {
List<Activity> activities = new ArrayList<>();
// parse the query string
ActivityQuery<Activity> query = QueryParser.parseToActivityQuery(queryData.getQuery(), true);
ActivityQuery<Activity> query = QueryParser.parseToActivityQuery(queryData.getQuery(), true, true);
// query the data
long dataSetSize = 0L;

View File

@ -12,57 +12,59 @@ import li.strolch.model.Resource;
import li.strolch.model.query.IdSelection;
import li.strolch.model.query.NameSelection;
import li.strolch.model.query.OrSelection;
import li.strolch.model.query.ParameterSelection.AnyTypeParameterSelection;
import li.strolch.model.query.ResourceQuery;
import li.strolch.model.query.Selection;
import li.strolch.model.query.StrolchTypeNavigation;
import li.strolch.utils.collections.MapOfSets;
public class QueryParserTest {
@Test
public void shouldIgnoreGibberish() {
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("sdf dfg3 !sdf", false);
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("sdf dfg3 !sdf", true, false);
assertFalse(query.hasNavigation());
assertFalse(query.hasSelection());
}
@Test
public void shouldParseEmpty() {
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("", false);
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("", true, false);
assertFalse(query.hasNavigation());
assertFalse(query.hasSelection());
}
@Test
public void shouldParseEmptyId() {
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("id:", false);
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("id:", true, false);
assertFalse(query.hasNavigation());
assertFalse(query.hasSelection());
}
@Test
public void shouldParseEmptyName() {
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("name:", false);
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("name:", true, false);
assertFalse(query.hasNavigation());
assertFalse(query.hasSelection());
}
@Test
public void shouldParseEmptyType() {
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("type:", false);
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("type:", true, false);
assertFalse(query.hasNavigation());
assertFalse(query.hasSelection());
}
@Test
public void shouldParseEmptyIdNameType() {
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("id: name: type:", false);
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("id: name: type:", true, false);
assertFalse(query.hasNavigation());
assertFalse(query.hasSelection());
}
@Test
public void shouldParseId() {
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("id:asd", false);
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("id:asd", true, false);
OrSelection or = (OrSelection) query.getSelection();
List<Selection> selections = or.getSelections();
assertEquals(1, selections.size());
@ -76,7 +78,7 @@ public class QueryParserTest {
@Test
public void shouldParseIds() {
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("id:asd id:bbb", false);
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("id:asd id:bbb", true, false);
OrSelection or = (OrSelection) query.getSelection();
List<Selection> selections = or.getSelections();
assertEquals(1, selections.size());
@ -91,7 +93,7 @@ public class QueryParserTest {
@Test
public void shouldParseName() {
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("name:asd", false);
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("name:asd", true, false);
OrSelection or = (OrSelection) query.getSelection();
List<Selection> selections = or.getSelections();
assertEquals(1, selections.size());
@ -102,7 +104,7 @@ public class QueryParserTest {
@Test
public void shouldParseNames() {
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("name:asd name:bbb", false);
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("name:asd name:bbb", true, false);
OrSelection or = (OrSelection) query.getSelection();
List<Selection> selections = or.getSelections();
assertEquals(2, selections.size());
@ -116,7 +118,7 @@ public class QueryParserTest {
@Test
public void shouldParseType() {
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("type:asd", false);
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("type:asd", true, false);
assertFalse(query.hasSelection());
assertTrue(query.hasNavigation());
StrolchTypeNavigation navigation = (StrolchTypeNavigation) query.getNavigation();
@ -125,7 +127,7 @@ public class QueryParserTest {
@Test
public void shouldReplaceMultipleType() {
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("type:asd type:fff", false);
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("type:asd type:fff", true, false);
assertFalse(query.hasSelection());
assertTrue(query.hasNavigation());
StrolchTypeNavigation navigation = (StrolchTypeNavigation) query.getNavigation();
@ -134,7 +136,8 @@ public class QueryParserTest {
@Test
public void shouldParseIdNameType() {
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("id:foo name:bar type:asd", false);
ResourceQuery<Resource> query = QueryParser
.parseToResourceQuery("id:foo name:bar type:asd date:1970-01-01T01:00:00.000+01:00", true, false);
OrSelection or = (OrSelection) query.getSelection();
List<Selection> selections = or.getSelections();
assertEquals(2, selections.size());
@ -145,7 +148,8 @@ public class QueryParserTest {
@Test
public void shouldParseWithWhitespace() {
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery(" id:foo name:bar type:asd \t ", false);
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery(" id:foo name:bar type:asd \t ", true,
false);
OrSelection or = (OrSelection) query.getSelection();
List<Selection> selections = or.getSelections();
assertEquals(2, selections.size());
@ -153,4 +157,80 @@ public class QueryParserTest {
assertEquals(NameSelection.class, selections.get(1).getClass());
assertTrue(query.hasNavigation());
}
@Test
public void shouldParserWithParameters() {
MapOfSets<String, String> maps = new MapOfSets<>();
maps.addElement("parameters", "email");
maps.addElement("parameters", "date");
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery(maps, true,
"type:asd id:asd email:bla@dsfdfg.ch date:1970-01-01T01:00:00.000+01:00", false);
assertTrue(query.hasNavigation());
OrSelection or = (OrSelection) query.getSelection();
List<Selection> selections = or.getSelections();
assertEquals(3, selections.size());
assertEquals(IdSelection.class, selections.get(0).getClass());
assertEquals(AnyTypeParameterSelection.class, selections.get(1).getClass());
assertEquals(AnyTypeParameterSelection.class, selections.get(2).getClass());
AnyTypeParameterSelection sel = (AnyTypeParameterSelection) selections.get(1);
assertEquals("parameters", sel.getBagKey());
assertEquals("email", sel.getParamKey());
assertEquals("bla@dsfdfg.ch", sel.getValue());
sel = (AnyTypeParameterSelection) selections.get(2);
assertEquals("parameters", sel.getBagKey());
assertEquals("date", sel.getParamKey());
assertEquals("1970-01-01T01:00:00.000+01:00", sel.getValue());
}
@Test
public void shouldParserWithParametersAndNoPrefix() {
MapOfSets<String, String> maps = new MapOfSets<>();
maps.addElement("parameters", "email");
maps.addElement("parameters", "date");
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery(maps, false,
"asd bla@dsfdfg.ch 1970-01-01T01:00:00.000+01:00", false);
assertFalse(query.hasNavigation());
OrSelection or = (OrSelection) query.getSelection();
List<Selection> selections = or.getSelections();
assertEquals(6, selections.size());
for (Selection selection : selections) {
assertEquals(AnyTypeParameterSelection.class, selection.getClass());
}
AnyTypeParameterSelection sel;
sel = (AnyTypeParameterSelection) selections.get(0);
assertEquals("parameters", sel.getBagKey());
assertEquals("date", sel.getParamKey());
assertEquals("asd", sel.getValue());
sel = (AnyTypeParameterSelection) selections.get(1);
assertEquals("parameters", sel.getBagKey());
assertEquals("email", sel.getParamKey());
assertEquals("asd", sel.getValue());
sel = (AnyTypeParameterSelection) selections.get(2);
assertEquals("parameters", sel.getBagKey());
assertEquals("date", sel.getParamKey());
assertEquals("bla@dsfdfg.ch", sel.getValue());
sel = (AnyTypeParameterSelection) selections.get(3);
assertEquals("parameters", sel.getBagKey());
assertEquals("email", sel.getParamKey());
assertEquals("bla@dsfdfg.ch", sel.getValue());
sel = (AnyTypeParameterSelection) selections.get(4);
assertEquals("parameters", sel.getBagKey());
assertEquals("date", sel.getParamKey());
assertEquals("1970-01-01T01:00:00.000+01:00", sel.getValue());
sel = (AnyTypeParameterSelection) selections.get(5);
assertEquals("parameters", sel.getBagKey());
assertEquals("email", sel.getParamKey());
assertEquals("1970-01-01T01:00:00.000+01:00", sel.getValue());
}
}