diff --git a/src/main/antlr4/org/s1ck/gdl/GDL.g4 b/src/main/antlr4/org/s1ck/gdl/GDL.g4 index 6451c8d..c9bc82a 100644 --- a/src/main/antlr4/org/s1ck/gdl/GDL.g4 +++ b/src/main/antlr4/org/s1ck/gdl/GDL.g4 @@ -213,6 +213,8 @@ intervalFunc | equalsOperator | longerThanOperator | shorterThanOperator + | lengthAtLeastOperator + | lengthAtMostOperator ; overlapsIntervallOperator : 'overlaps(' interval ')' @@ -260,6 +262,14 @@ shorterThanOperator : 'shorterThan(' (interval | timeConstant) ')' ; +lengthAtLeastOperator + : 'lengthAtLeast(' (interval | timeConstant) ')' + ; + +lengthAtMostOperator + : 'lengthAtMost(' (interval | timeConstant) ')' + ; + timeConstant : 'Millis(' IntegerLiteral ')' | 'Seconds(' IntegerLiteral ')' diff --git a/src/main/java/org/s1ck/gdl/GDLLoader.java b/src/main/java/org/s1ck/gdl/GDLLoader.java index 0d8004b..b42efec 100644 --- a/src/main/java/org/s1ck/gdl/GDLLoader.java +++ b/src/main/java/org/s1ck/gdl/GDLLoader.java @@ -556,6 +556,12 @@ else if(intervalFunc.longerThanOperator()!=null){ else if(intervalFunc.shorterThanOperator()!=null){ return createShorterThanPredicates(from, to, intervalFunc.shorterThanOperator()); } + else if(intervalFunc.lengthAtLeastOperator()!=null){ + return createLengthAtLeastPredicates(from, to, intervalFunc.lengthAtLeastOperator()); + } + else if(intervalFunc.lengthAtMostOperator()!=null){ + return createLengthAtMostPredicates(from, to, intervalFunc.lengthAtMostOperator()); + } return null; } @@ -748,6 +754,50 @@ else if(ctx.interval()!=null){ return null; } + /** + * Creates a predicate a.lengthAtLeast(b) = (length(a) >= length(b)) + * @param from from value of the calling interval + * @param to to value of the calling interval + * @param ctx context containing the callee interval + * @return lengthAtLeast predicate + */ + private Predicate createLengthAtLeastPredicates(TimePoint from, TimePoint to, + GDLParser.LengthAtLeastOperatorContext ctx){ + Duration rhs = new Duration(from, to); + if(ctx.timeConstant()!=null) { + TimeConstant constant = buildTimeConstant(ctx.timeConstant()); + return new Comparison(rhs, GTE, constant); + } + else if(ctx.interval()!=null){ + TimePoint[] interval = buildIntervall(ctx.interval()); + Duration lhs = new Duration(interval[0], interval[1]); + return new Comparison(rhs, GTE, lhs); + } + return null; + } + + /** + * Creates a predicate a.lengthAtMost(b) = (length(a) <= length(b)) + * @param from from value of the calling interval + * @param to to value of the calling interval + * @param ctx context containing the callee interval + * @return lengthAtMost predicate + */ + private Predicate createLengthAtMostPredicates(TimePoint from, TimePoint to, + GDLParser.LengthAtMostOperatorContext ctx){ + Duration rhs = new Duration(from, to); + if(ctx.timeConstant()!=null) { + TimeConstant constant = buildTimeConstant(ctx.timeConstant()); + return new Comparison(rhs, LTE, constant); + } + else if(ctx.interval()!=null){ + TimePoint[] interval = buildIntervall(ctx.interval()); + Duration lhs = new Duration(interval[0], interval[1]); + return new Comparison(rhs, LTE, lhs); + } + return null; + } + /** * Creates a TimeConstant given a suitable context. Constants can be a constant number * of days ({@code Days(n)}), hours ({@code Hours(n)}), minutes ({@code Minutes(n)}), diff --git a/src/test/java/org/s1ck/gdl/GDLLoaderTemporalTest.java b/src/test/java/org/s1ck/gdl/GDLLoaderTemporalTest.java index 53f5b2d..f418767 100644 --- a/src/test/java/org/s1ck/gdl/GDLLoaderTemporalTest.java +++ b/src/test/java/org/s1ck/gdl/GDLLoaderTemporalTest.java @@ -725,6 +725,16 @@ public void shorterThanTest(){ lengthComparisonTest("shorterThan", LT); } + @Test + public void lengthAtLeastTest(){ + lengthComparisonTest("lengthAtLeast", GTE); + } + + @Test + public void lengthAtMostTest(){ + lengthComparisonTest("lengthAtMost", LTE); + } + private void lengthComparisonTest(String operator, Comparator comparator){ GDLLoader loader = getLoaderFromGDLString("MATCH (a)-[e]->(b) " + "WHERE a.val."+operator+"(Days(80))", false);