From a9cb27da84236d3c69204b18cf0b9ca3312f62dc Mon Sep 17 00:00:00 2001 From: lc0197 Date: Fri, 8 May 2020 09:55:36 +0200 Subject: [PATCH] [#49] implemented shorterThan --- src/main/antlr4/org/s1ck/gdl/GDL.g4 | 5 ++ src/main/java/org/s1ck/gdl/GDLHandler.java | 2 +- src/main/java/org/s1ck/gdl/GDLLoader.java | 86 ++++++++++++++++++- .../model/comparables/time/TimeConstant.java | 16 ++-- .../org/s1ck/gdl/GDLLoaderTemporalTest.java | 68 +++++++++++---- 5 files changed, 147 insertions(+), 30 deletions(-) diff --git a/src/main/antlr4/org/s1ck/gdl/GDL.g4 b/src/main/antlr4/org/s1ck/gdl/GDL.g4 index 33e7079..b09fbd1 100644 --- a/src/main/antlr4/org/s1ck/gdl/GDL.g4 +++ b/src/main/antlr4/org/s1ck/gdl/GDL.g4 @@ -216,6 +216,7 @@ intervalFunc | immediatelySucceedsOperator | equalsOperator | longerThanOperator + | shorterThanOperator ; overlapsIntervallOperator : 'overlaps(' interval ')' @@ -259,6 +260,10 @@ longerThanOperator : 'longerThan(' (interval | timeConstant) ')' ; +shorterThanOperator + : 'shorterThan(' (interval | timeConstant) ')' + ; + timeConstant : 'Millis(' IntegerLiteral ')' | 'Seconds(' IntegerLiteral ')' diff --git a/src/main/java/org/s1ck/gdl/GDLHandler.java b/src/main/java/org/s1ck/gdl/GDLHandler.java index 087b950..22e3064 100644 --- a/src/main/java/org/s1ck/gdl/GDLHandler.java +++ b/src/main/java/org/s1ck/gdl/GDLHandler.java @@ -202,7 +202,7 @@ public static class Builder { /** * Flag to indicate if the query should be postprocessed, i.e. reduced to simple comparisons. */ - private boolean processQuery = true; + private boolean processQuery = false; /** * Strategy for handling parser errors. diff --git a/src/main/java/org/s1ck/gdl/GDLLoader.java b/src/main/java/org/s1ck/gdl/GDLLoader.java index 509fc90..0d8004b 100644 --- a/src/main/java/org/s1ck/gdl/GDLLoader.java +++ b/src/main/java/org/s1ck/gdl/GDLLoader.java @@ -553,6 +553,9 @@ else if(intervalFunc.equalsOperator()!=null){ else if(intervalFunc.longerThanOperator()!=null){ return createLongerThanPredicates(from, to, intervalFunc.longerThanOperator()); } + else if(intervalFunc.shorterThanOperator()!=null){ + return createShorterThanPredicates(from, to, intervalFunc.shorterThanOperator()); + } return null; } @@ -606,7 +609,7 @@ private Predicate createBetweenPredicates(TimePoint from, TimePoint to, GDLParse } /** - * Creates a predicate a.precedes(b) = a <= b. + * Creates a predicate a.precedes(b) = a.to <= b.from. * Function is used for interval and timestamp function {@code precedes}, as they both * only compare two time stamps * @param to the time stamp of the caller to compare @@ -619,6 +622,12 @@ private Predicate createPrecedesPredicates(TimePoint to, GDLParser.PrecedesOpera return new Comparison(to, LTE, arg_from); } + /** + * Creates a predicate a.immediatelyPrecedes(b) = (a.to == b.from). + * @param to the time stamp of the caller to compare + * @param ctx the context containing the from value to be compared + * @return immediatelyPrecedes predicate + */ private Predicate createImmediatelyPrecedesPredicates(TimePoint to, GDLParser.ImmediatelyPrecedesOperatorContext ctx){ TimePoint[] arg = buildIntervall(ctx.interval()); TimePoint arg_from = arg[0]; @@ -639,6 +648,14 @@ private Predicate createSucceedsPredicates(TimePoint point, GDLParser.SucceedsOp return new Comparison(point, GTE, arg_to); } + /** + * Creates a predicate a.immediatelySucceeds(b) = (a.from == b.to). + * Function is used for interval and timestamp function {@code precedes}, as they both + * only compare two time stamps + * @param from the from value of the caller interval + * @param ctx the context containing the to value of the interval to be compared + * @return immediatelySucceeds predicate + */ private Predicate createImmediatelySucceedsPredicates(TimePoint from, GDLParser.ImmediatelySucceedsOperatorContext ctx){ TimePoint[] arg = buildIntervall(ctx.interval()); @@ -672,6 +689,13 @@ private Predicate createContainsPredicates(TimePoint from, TimePoint to, GDLPars } } + /** + * Creates a predicate a.equals(b) = (a.from = b.from AND a.to = b.to). + * @param from from value of the calling interval + * @param to to value of the calling interval + * @param ctx context containing the callee interval + * @return equals predicate + */ private Predicate createEqualsPredicates(TimePoint from, TimePoint to, GDLParser.EqualsOperatorContext ctx){ TimePoint[] arg = buildIntervall(ctx.interval()); TimePoint arg_from = arg[0]; @@ -682,6 +706,13 @@ private Predicate createEqualsPredicates(TimePoint from, TimePoint to, GDLParser ); } + /** + * Creates a predicate a.longerThan(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 longerThan predicate + */ private Predicate createLongerThanPredicates(TimePoint from, TimePoint to, GDLParser.LongerThanOperatorContext ctx){ Duration rhs = new Duration(from, to); if(ctx.timeConstant()!=null) { @@ -696,6 +727,34 @@ else if(ctx.interval()!=null){ return null; } + /** + * Creates a predicate a.shorterThan(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 shorterThan predicate + */ + private Predicate createShorterThanPredicates(TimePoint from, TimePoint to, GDLParser.ShorterThanOperatorContext ctx){ + Duration rhs = new Duration(from, to); + if(ctx.timeConstant()!=null) { + TimeConstant constant = buildTimeConstant(ctx.timeConstant()); + return new Comparison(rhs, LT, constant); + } + else if(ctx.interval()!=null){ + TimePoint[] interval = buildIntervall(ctx.interval()); + Duration lhs = new Duration(interval[0], interval[1]); + return new Comparison(rhs, LT, 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)}), + * seconds ({@code Seconds(n)}) or milliseconds ({@code Millis(n)}). + * @param ctx the context containing the constant. + * @return time constant + */ private TimeConstant buildTimeConstant(GDLParser.TimeConstantContext ctx){ int value = Integer.parseInt(ctx.IntegerLiteral().getText()); if(ctx.getText().startsWith("Days(")){ @@ -878,6 +937,13 @@ private Predicate createBeforePredicates(TimePoint from, GDLParser.BeforePointOp return new Comparison(from, Comparator.LT, x); } + /** + * Creates a after {@code Predicate} given the caller (a timestamp) and its context + * + * @param from the caller + * @param ctx context including the argument + * @return a {@code Predicate} encoding the after function: from>x + */ private Predicate createAfterPredicates(TimePoint from, GDLParser.AfterPointOperatorContext ctx){ TimePoint x = buildTimePoint(ctx.timePoint()); return new Comparison(from, Comparator.GT, x); @@ -902,10 +968,20 @@ else if (ctx.complexTimePoint()!=null){ return null; } + /** + * Builds a TimeLiteral given a context. + * @param ctx context containing the literal + * @return TimeLiteral + */ private TimeLiteral buildTimeLiteral(GDLParser.TimeLiteralContext ctx){ return new TimeLiteral(ctx.getText().trim()); } + /** + * Builds a TimeSelector (variable.field, where field in {TX_FROM, TX_TO, VAL_FROM, VAL_TO}) + * @param ctx context containing the selector + * @return TimeSelector + */ private TimeSelector buildTimeSelector(GDLParser.TimeSelectorContext ctx){ // checks whether ID is even there (is a vertex or edge) and returns its variable String var = ctx.Identifier()!=null ? @@ -914,6 +990,12 @@ private TimeSelector buildTimeSelector(GDLParser.TimeSelectorContext ctx){ return new TimeSelector(var, field); } + /** + * Builds a "complex" time point, i.e. a time point described by a {@code MAX(...)} or + * {@code MIN(...)} expression. + * @param ctx context containing the time point + * @return complex time point + */ private TimePoint buildComplexTimePoint(GDLParser.ComplexTimePointContext ctx){ List argumentContexts = @@ -960,7 +1042,7 @@ public void enterAsOf(GDLParser.AsOfContext ctx){ * Creates the default asOf conditions, that ensure that every element's transaction time is * as of now. This is only done if no other constraints on transaction times' ends * are specified in the query. - * @return + * @return default asOf predicates */ private Predicate createDefaultAsOf(){ Set vars = new HashSet<>(); diff --git a/src/main/java/org/s1ck/gdl/model/comparables/time/TimeConstant.java b/src/main/java/org/s1ck/gdl/model/comparables/time/TimeConstant.java index 8fd6053..a4cf8a1 100644 --- a/src/main/java/org/s1ck/gdl/model/comparables/time/TimeConstant.java +++ b/src/main/java/org/s1ck/gdl/model/comparables/time/TimeConstant.java @@ -18,8 +18,7 @@ public class TimeConstant extends TimePoint { /** * The number of milliseconds wrapped by this class */ - private long millis; - + private Long millis; /** * Create a constant of size days+hours+minutes+seconds+millis (in millis) @@ -30,14 +29,11 @@ public class TimeConstant extends TimePoint { * @param millis number of millis [0-999] */ public TimeConstant(int days, int hours, int minutes, int seconds, int millis){ - if( (hours<0 || hours>23) || (minutes<0 || minutes>59) || (seconds<0||seconds>59) || (millis <0 || millis >999)){ - throw new IllegalArgumentException("not a valid timestamp"); - } - long sum = millis; - sum +=1000*seconds; - sum +=1000*60*minutes; - sum +=1000*60*60*hours; - sum +=1000*60*60*24*days; + long sum = (long)millis; + sum +=1000L*(long)seconds; + sum +=1000L*60L*(long)minutes; + sum +=1000L*60L*60L*(long)hours; + sum +=1000*60L*60L*24L*(long)days; this.millis = sum; } diff --git a/src/test/java/org/s1ck/gdl/GDLLoaderTemporalTest.java b/src/test/java/org/s1ck/gdl/GDLLoaderTemporalTest.java index 5a39e97..53f5b2d 100644 --- a/src/test/java/org/s1ck/gdl/GDLLoaderTemporalTest.java +++ b/src/test/java/org/s1ck/gdl/GDLLoaderTemporalTest.java @@ -717,8 +717,17 @@ public void minMaxTest(){ @Test public void longerThanTest(){ + lengthComparisonTest("longerThan", GT); + } + + @Test + public void shorterThanTest(){ + lengthComparisonTest("shorterThan", LT); + } + + private void lengthComparisonTest(String operator, Comparator comparator){ GDLLoader loader = getLoaderFromGDLString("MATCH (a)-[e]->(b) " + - "WHERE a.val.longerThan(Days(10))", false); + "WHERE a.val."+operator+"(Days(80))", false); TimeSelector aValFrom = new TimeSelector("a", VAL_FROM); TimeSelector aValTo = new TimeSelector("a", VAL_TO); @@ -726,57 +735,73 @@ public void longerThanTest(){ TimeSelector bValTo = new TimeSelector("b", VAL_TO); TimeSelector eValFrom = new TimeSelector("e", VAL_FROM); TimeSelector eValTo = new TimeSelector("e", VAL_TO); - TimeConstant tenDays = new TimeConstant(10,0,0,0,0); + TimeConstant eightyDays = new TimeConstant(80,0,0,0,0); Duration valDuration = new Duration(aValFrom, aValTo); - Predicate expected = new Comparison(valDuration, GT, tenDays); + Predicate expected = new Comparison(valDuration, comparator, eightyDays); assertPredicateEquals(loader.getPredicates().get(), expected); loader = getLoaderFromGDLString("MATCH (a)-[e]->(b) " + - "WHERE a.val.longerThan(Hours(12))", false); + "WHERE a.val."+operator+"(Hours(12))", false); TimeConstant twelveHours = new TimeConstant(0,12,0,0,0); - expected = new Comparison(valDuration, GT, twelveHours); + expected = new Comparison(valDuration, comparator, twelveHours); assertPredicateEquals(loader.getPredicates().get(), expected); - System.out.println(loader.getPredicates()); loader = getLoaderFromGDLString("MATCH (a)-[e]->(b) " + - "WHERE val.longerThan(Minutes(5))", false); + "WHERE val."+operator+"(Minutes(5))", false); TimeConstant fiveMinutes = new TimeConstant(0,0,5,0,0); MaxTimePoint globalValFrom = new MaxTimePoint(eValFrom, aValFrom, bValFrom); MinTimePoint globalValTo = new MinTimePoint(eValTo, aValTo, bValTo); Duration globalValDuration = new Duration(globalValFrom, globalValTo); - expected = new Comparison(globalValDuration, GT, fiveMinutes); + expected = new Comparison(globalValDuration, comparator, fiveMinutes); assertPredicateEquals(loader.getPredicates().get(), expected); loader = getLoaderFromGDLString("MATCH (a)-[e]->(b) " + - "WHERE a.val.merge(b.val).longerThan(Hours(20))", false); + "WHERE a.val.merge(b.val)."+operator+"(Hours(20))", false); TimeConstant twentyHours = new TimeConstant(0,20,0,0,0); MaxTimePoint mergeFrom = new MaxTimePoint(aValFrom, bValFrom); MinTimePoint mergeTo = new MinTimePoint(aValTo, bValTo); Duration mergeDuration = new Duration(mergeFrom, mergeTo); expected = new And( - new Comparison(mergeDuration, GT, twentyHours), + new Comparison(mergeDuration, comparator, twentyHours), new Comparison(mergeFrom, LTE, mergeTo) - ); + ); assertPredicateEquals(loader.getPredicates().get(), expected); loader = getLoaderFromGDLString("MATCH (a)-[e]->(b) " + - "WHERE Interval(a.val_from, b.val_to).longerThan(Days(4))", false); + "WHERE a.val.merge(b.val)."+operator+"(e.val.join(b.val))", false); + MinTimePoint joinFrom = new MinTimePoint(eValFrom, bValFrom); + MaxTimePoint joinTo = new MaxTimePoint(eValTo, bValTo); + Duration joinDuration = new Duration(joinFrom, joinTo); + Comparison ebOverlap = new Comparison(new MaxTimePoint(eValFrom, bValFrom), LTE, + new MinTimePoint(eValTo, bValTo)); + expected = new And( + new And( + new Comparison(mergeDuration, comparator, joinDuration), + ebOverlap), + new Comparison(mergeFrom, LTE, mergeTo) + ); + System.out.println(loader.getPredicates().get()); + System.out.println(expected); + assertPredicateEquals(loader.getPredicates().get(), expected); + + loader = getLoaderFromGDLString("MATCH (a)-[e]->(b) " + + "WHERE Interval(a.val_from, b.val_to)."+operator+"(Days(4))", false); TimeConstant fourDays = new TimeConstant(4,0,0,0,0); Duration intervalDuration = new Duration(aValFrom, bValTo); - expected = new Comparison(intervalDuration, GT, fourDays); + expected = new Comparison(intervalDuration, comparator, fourDays); assertPredicateEquals(loader.getPredicates().get(), expected); loader = getLoaderFromGDLString("MATCH (a)-[e]->(b) " + - "WHERE a.val.longerThan(b.val)", false); + "WHERE a.val."+operator+"(b.val)", false); Duration aVal = new Duration(aValFrom, aValTo); Duration bVal = new Duration(bValFrom, bValTo); - expected = new Comparison(aVal, GT, bVal); + expected = new Comparison(aVal, comparator, bVal); assertPredicateEquals(loader.getPredicates().get(), expected); loader = getLoaderFromGDLString("MATCH (a)-[e]->(b) " + - "WHERE val.longerThan(tx)", false); + "WHERE val."+operator+"(tx)", false); TimeSelector eTxFrom = new TimeSelector("e", TX_FROM); TimeSelector aTxFrom = new TimeSelector("a", TX_FROM); TimeSelector bTxFrom = new TimeSelector("b", TX_FROM); @@ -786,7 +811,16 @@ public void longerThanTest(){ MaxTimePoint globalTxFrom = new MaxTimePoint(eTxFrom, aTxFrom, bTxFrom); MinTimePoint globalTxTo = new MinTimePoint(eTxTo, aTxTo, bTxTo); Duration globalTxDuration = new Duration(globalTxFrom, globalTxTo); - expected = new Comparison(globalValDuration, GT, globalTxDuration); + expected = new Comparison(globalValDuration, comparator, globalTxDuration); + assertPredicateEquals(loader.getPredicates().get(), expected); + + loader = getLoaderFromGDLString("MATCH (a)-[e]->(b) " + + "WHERE val."+operator+"(Interval(2020-05-01, 2020-05-05))", false); + TimeLiteral l1 = new TimeLiteral("2020-05-01"); + TimeLiteral l2 = new TimeLiteral("2020-05-05"); + Duration constantInterval = new Duration(l1, l2); + expected = new Comparison(globalValDuration, comparator, constantInterval); + System.out.println(loader.getPredicates().get()); assertPredicateEquals(loader.getPredicates().get(), expected); }