Skip to content

Commit

Permalink
[s1ck#49] implemented shorterThan
Browse files Browse the repository at this point in the history
  • Loading branch information
lc0197 committed Jun 15, 2020
1 parent ece859b commit a9cb27d
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 30 deletions.
5 changes: 5 additions & 0 deletions src/main/antlr4/org/s1ck/gdl/GDL.g4
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ intervalFunc
| immediatelySucceedsOperator
| equalsOperator
| longerThanOperator
| shorterThanOperator
;
overlapsIntervallOperator
: 'overlaps(' interval ')'
Expand Down Expand Up @@ -259,6 +260,10 @@ longerThanOperator
: 'longerThan(' (interval | timeConstant) ')'
;

shorterThanOperator
: 'shorterThan(' (interval | timeConstant) ')'
;

timeConstant
: 'Millis(' IntegerLiteral ')'
| 'Seconds(' IntegerLiteral ')'
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/s1ck/gdl/GDLHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
86 changes: 84 additions & 2 deletions src/main/java/org/s1ck/gdl/GDLLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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
Expand All @@ -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];
Expand All @@ -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());
Expand Down Expand Up @@ -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];
Expand All @@ -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) {
Expand All @@ -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(")){
Expand Down Expand Up @@ -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);
Expand All @@ -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 ?
Expand All @@ -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<GDLParser.ComplexTimePointArgumentContext> argumentContexts =
Expand Down Expand Up @@ -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<String> vars = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
}

Expand Down
68 changes: 51 additions & 17 deletions src/test/java/org/s1ck/gdl/GDLLoaderTemporalTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -717,66 +717,91 @@ 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);
TimeSelector bValFrom = new TimeSelector("b", VAL_FROM);
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);
Expand All @@ -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);
}

Expand Down

0 comments on commit a9cb27d

Please sign in to comment.