diff --git a/svalbard/odata/src/main/antlr4/org/n52/svalbard/odata/grammar/STAQueryOptionsGrammar.g4 b/svalbard/odata/src/main/antlr4/org/n52/svalbard/odata/grammar/STAQueryOptionsGrammar.g4 index dd145e94a..b3515f0b9 100644 --- a/svalbard/odata/src/main/antlr4/org/n52/svalbard/odata/grammar/STAQueryOptionsGrammar.g4 +++ b/svalbard/odata/src/main/antlr4/org/n52/svalbard/odata/grammar/STAQueryOptionsGrammar.g4 @@ -138,7 +138,7 @@ geoExpr ; memberExpr - : ALPHAPLUS (SLASH ALPHAPLUS)* + : (ALPHAPLUS SLASH)* (ALPHAPLUS | Time_LLC) ; textMethodCallExpr @@ -189,6 +189,7 @@ boolMethodCallExpr | st_intersectsMethodCallExpr | st_containsMethodCallExpr | st_relateMethodCallExpr + | containsMethodCallExpr ; textOrMember @@ -244,6 +245,10 @@ endsWithMethodCallExpr : EndsWith_LLC OP (SP)* textOrMember (SP)* COMMA (SP)* textOrMember (SP)* CP ; +containsMethodCallExpr + : Contains_LLC OP (SP)* memberExpr (SP)* COMMA (SP)* boolExpr (SP)* COMMA (SP)* boolExpr (SP)* CP + ; + intersectsMethodCallExpr : GeoDotIntersects_LLC OP (SP)* geoOrMember (SP)* COMMA (SP)* geoOrMember (SP)* CP ; diff --git a/svalbard/odata/src/main/antlr4/org/n52/svalbard/odata/grammar/STAQueryOptionsLexer.g4 b/svalbard/odata/src/main/antlr4/org/n52/svalbard/odata/grammar/STAQueryOptionsLexer.g4 index 07f657ca6..e235c55b7 100644 --- a/svalbard/odata/src/main/antlr4/org/n52/svalbard/odata/grammar/STAQueryOptionsLexer.g4 +++ b/svalbard/odata/src/main/antlr4/org/n52/svalbard/odata/grammar/STAQueryOptionsLexer.g4 @@ -293,7 +293,7 @@ FILTER_SP ; FILTER_SEMI - : SEMI -> type (SEMI) , popMode + : SEMI -> popMode, popMode, type (SEMI) ; FILTER_COMMA @@ -359,6 +359,10 @@ Trim_LLC Concat_LLC : 'concat' ; + +Contains_LLC + : 'contains' + ; // Date Functions Year_LLC diff --git a/svalbard/odata/src/main/java/org/n52/svalbard/odata/core/QueryOptionsFactory.java b/svalbard/odata/src/main/java/org/n52/svalbard/odata/core/QueryOptionsFactory.java index ab8b1fad2..cfcf6db95 100644 --- a/svalbard/odata/src/main/java/org/n52/svalbard/odata/core/QueryOptionsFactory.java +++ b/svalbard/odata/src/main/java/org/n52/svalbard/odata/core/QueryOptionsFactory.java @@ -14,6 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.n52.svalbard.odata.core; import org.antlr.v4.runtime.BaseErrorListener; @@ -34,8 +35,12 @@ */ @SuppressWarnings("unchecked") public class QueryOptionsFactory { + public STAQueryOptionsLexer createLexer(String query) { - return new STAQueryOptionsLexer(CharStreams.fromString(query.trim())); + STAQueryOptionsLexer staQueryOptionsLexer = new STAQueryOptionsLexer(CharStreams.fromString(query.trim())); + staQueryOptionsLexer.removeErrorListeners(); + staQueryOptionsLexer.addErrorListener(new CustomErrorListener(staQueryOptionsLexer.getVocabulary())); + return staQueryOptionsLexer; } public STAQueryOptionsGrammar createGrammar(String query) { @@ -44,11 +49,11 @@ public STAQueryOptionsGrammar createGrammar(String query) { private STAQueryOptionsGrammar createGrammar(STAQueryOptionsLexer lexer) { STAQueryOptionsGrammar parser = new STAQueryOptionsGrammar(new CommonTokenStream(lexer)); + parser.removeErrorListeners(); parser.addErrorListener(new CustomErrorListener(lexer.getVocabulary())); return parser; } - //TODO: make nicer public QueryOptions createQueryOptions(String query) { return createGrammar(query).queryOptions().accept(new STAQueryOptionVisitor()); } @@ -71,9 +76,13 @@ private CustomErrorListener(Vocabulary vocabulary) { @Override public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { - - String message = String.format("failed to parse due to %s with offending token: %s", msg, - vocabulary.getDisplayName(e.getOffendingToken().getType())); + String message; + if (e.getOffendingToken() != null) { + message = String.format("Failed to parse QueryOptions due to %s with offending token: %s", msg, + vocabulary.getDisplayName(e.getOffendingToken().getType())); + } else { + message = String.format("Failed to parse QueryOptions due to error: %s", msg); + } throw new IllegalStateException(message, e); } } diff --git a/svalbard/odata/src/main/java/org/n52/svalbard/odata/core/STAQueryOptionVisitor.java b/svalbard/odata/src/main/java/org/n52/svalbard/odata/core/STAQueryOptionVisitor.java index f6b7ca2dd..51c2e1271 100644 --- a/svalbard/odata/src/main/java/org/n52/svalbard/odata/core/STAQueryOptionVisitor.java +++ b/svalbard/odata/src/main/java/org/n52/svalbard/odata/core/STAQueryOptionVisitor.java @@ -715,6 +715,14 @@ public Object visitSt_containsMethodCallExpr(STAQueryOptionsGrammar.St_containsM new StringValueExpr(ctx.escapedString().getText())); } + @Override public Object visitContainsMethodCallExpr(STAQueryOptionsGrammar.ContainsMethodCallExprContext ctx) { + return new MethodCallExpr(ctx.Contains_LLC().getText(), + visitMemberExpr(ctx.memberExpr()), + new BooleanBinaryExpr(FilterConstants.BinaryLogicOperator.And, + visitBoolExpr(ctx.boolExpr(0)), + visitBoolExpr(ctx.boolExpr(1)))); + } + @Override public TextExpr visitTextMethodCallExpr(STAQueryOptionsGrammar.TextMethodCallExprContext ctx) { // textMethodCallExpr // : diff --git a/svalbard/odata/src/test/java/org/n52/svalbard/odata/core/OrderByQueryOptionTest.java b/svalbard/odata/src/test/java/org/n52/svalbard/odata/core/OrderByQueryOptionTest.java index ab62ed033..bb73935c8 100644 --- a/svalbard/odata/src/test/java/org/n52/svalbard/odata/core/OrderByQueryOptionTest.java +++ b/svalbard/odata/src/test/java/org/n52/svalbard/odata/core/OrderByQueryOptionTest.java @@ -34,7 +34,7 @@ public void testInvalidOrderByFilter() { // May no be empty init(ODataConstants.QueryOptions.ORDERBY + EQ + ""); Assertions.assertThrows( - NullPointerException.class, + Exception.class, () -> parser.queryOptions().accept(new STAQueryOptionVisitor()) ); diff --git a/svalbard/odata/src/test/java/org/n52/svalbard/odata/core/TestConstants.java b/svalbard/odata/src/test/java/org/n52/svalbard/odata/core/TestConstants.java index 7815835db..2ee1d4641 100644 --- a/svalbard/odata/src/test/java/org/n52/svalbard/odata/core/TestConstants.java +++ b/svalbard/odata/src/test/java/org/n52/svalbard/odata/core/TestConstants.java @@ -79,6 +79,8 @@ public interface TestConstants { "$filter=result mod 2 eq 0", "$filter=(result sub 5) gt 10", "$filter=geo.distance(Locations/location, geography'POINT(-122 43)') gt 1", + "$filter=time gt 2000-11-27T10:44:51.331Z and time lt 2020-08-27T15:45:31.021Z&$expand=Things" + + "($select=name)&$select=time&$top=1000", "$select=result,resultTime", "$select=id,Observations&$expand=Observations/FeatureOfInterest", @@ -106,12 +108,17 @@ public interface TestConstants { "$expand=Observations($orderby=result asc)", "$expand=Datastream&$orderby=Datastreams/id desc, phenomenonTime", "$orderby=phenomenonTime&$filter=phenomenonTime ge 2018-05-04T00:22:54.738+02:00 and " + - "2018-05-05T09:58:53.338+02:00 le 2018-05-05T09:58:53.338+02:00&$top=200", + "2018-05-05T09:58:53.338+02:00 le 2018-05-05T09:58:53.338+02:00&$top=200", "$orderby=phenomenonTime&$filter=(phenomenonTime ge 2018-05-04T00:22:54.738+02:00) and " + - "(2018-05-05T09:58:53.338+02:00 le 2018-05-05T09:58:53.338+02:00)&$top=200", + "(2018-05-05T09:58:53.338+02:00 le 2018-05-05T09:58:53.338+02:00)&$top=200", "$orderby=phenomenonTime&$filter=((phenomenonTime ge 2018-05-04T00:22:54.738+02:00) and " + - "(2018-05-05T09:58:53.338+02:00 le 2018-05-05T09:58:53.338+02:00))&$top=200" + "(2018-05-05T09:58:53.338+02:00 le 2018-05-05T09:58:53.338+02:00))&$top=200", + + // 52N-STA specific functions. used for filtering on nested parameters + "$filter=contains(parameters, name eq 'photo_url_3', value ne '')", + "$filter=contains(parameters, name eq 'photo_url_3', startswith(value, 'test'))" + }; }