package hdgl.db.query.visitor; import hdgl.db.query.expression.AsteriskQuantifier; import hdgl.db.query.expression.Concat; import hdgl.db.query.expression.Condition; import hdgl.db.query.expression.Edge; import hdgl.db.query.expression.Order; import hdgl.db.query.expression.Parallel; import hdgl.db.query.expression.PlusQuantifier; import hdgl.db.query.expression.Quantifier; import hdgl.db.query.expression.Query; import hdgl.db.query.expression.QuestionQuantifier; import hdgl.db.query.expression.Expression; import hdgl.db.query.expression.Vertex; public class CompleteQueryVisitor implements Visitor<CompleteQueryVisitor.ExpressionWithFrom, CompleteQueryVisitor.PathForm> { public static Expression complete(Expression expression){ CompleteQueryVisitor v = new CompleteQueryVisitor(); ExpressionWithFrom r = expression.accept(v, PathForm.Vertex, PathForm.Vertex); assert PathForm.Vertex.compatible(r.getHead()) && PathForm.Vertex.compatible(r.getTail()); return r.getExpression(); } public static class ExpressionWithFrom{ private PathForm head; private PathForm tail; private Expression expression; public ExpressionWithFrom(PathForm head, PathForm tail, Expression expression) { super(); this.head = head; this.tail = tail; this.expression = expression; } public PathForm getHead() { return head; } public void setHead(PathForm head) { this.head = head; } public PathForm getTail() { return tail; } public void setTail(PathForm tail) { this.tail = tail; } public Expression getExpression() { return expression; } public void setExpression(Expression expression) { this.expression = expression; } } public static enum PathForm{ Any, Vertex, Edge; public PathForm other(){ switch (this) { case Any: return Any; case Vertex: return Edge; case Edge: return Vertex; default: throw new RuntimeException("Never should this exception happen"); } } public boolean compatible(PathForm other){ switch (this) { case Any: return true; case Vertex: return other==Vertex; case Edge: return other==Edge; default: throw new RuntimeException("Never should this exception happen"); } } } @Override public ExpressionWithFrom visitQuery(Query query, PathForm... arguments) { ExpressionWithFrom inner = query.getExpression().accept(this, PathForm.Vertex, PathForm.Vertex); assert PathForm.Vertex.compatible(inner.getHead()) && PathForm.Vertex.compatible(inner.getTail()); return new ExpressionWithFrom(PathForm.Vertex, PathForm.Vertex, new Query(inner.getExpression())); } @Override public ExpressionWithFrom visitVertex(Vertex vertex, PathForm... arguments) { PathForm head = arguments[0]; if (head == PathForm.Any) head = PathForm.Vertex; PathForm tail = arguments[1]; if (tail == PathForm.Any) tail = PathForm.Vertex; Expression n = vertex.clone(Expression.class); if(head == PathForm.Edge){ n = new Concat(Edge.UNRESTRICTED.clone(Expression.class), n); } if(tail==PathForm.Edge){ n = new Concat(n, Edge.UNRESTRICTED.clone(Expression.class)); } return new ExpressionWithFrom(head, tail, n); } @Override public ExpressionWithFrom visitEdge(Edge edge, PathForm... arguments) { PathForm head = arguments[0]; if (head == PathForm.Any) head = PathForm.Edge; PathForm tail = arguments[1]; if (tail == PathForm.Any) tail = PathForm.Edge; Expression n = edge.clone(Expression.class); if(head == PathForm.Vertex){ n = new Concat(Vertex.UNRESTRICTED.clone(Expression.class), n); } if(tail==PathForm.Vertex){ n = new Concat(n, Vertex.UNRESTRICTED.clone(Expression.class)); } return new ExpressionWithFrom(head, tail, n); } private ExpressionWithFrom visitQuantifier(Quantifier quantifier, PathForm... arguments) { PathForm head = arguments[0]; PathForm tail = arguments[1]; ExpressionWithFrom subexpression = quantifier.getQuantified().accept(this, head, head.other()); assert head.compatible(subexpression.getHead()) && head.other().compatible(subexpression.getTail()); if(tail.compatible(subexpression.getTail())){ return new ExpressionWithFrom(subexpression.getHead(), subexpression.getTail(), new AsteriskQuantifier(subexpression.getExpression())); }else{ if(tail == PathForm.Edge){ return new ExpressionWithFrom(subexpression.getHead(), PathForm.Edge, new Concat( new AsteriskQuantifier(subexpression.getExpression()), Edge.UNRESTRICTED.clone(Expression.class)) ); }else if(tail == PathForm.Vertex){ return new ExpressionWithFrom(subexpression.getHead(), PathForm.Vertex, new Concat( new AsteriskQuantifier(subexpression.getExpression()), Vertex.UNRESTRICTED.clone(Expression.class)) ); }else{ throw new RuntimeException("Never should this exception happen."); } } } @Override public ExpressionWithFrom visitAsteriskQuantifier( AsteriskQuantifier quantifier, PathForm... arguments) { return visitQuantifier(quantifier, arguments); } @Override public ExpressionWithFrom visitQuestionQuantifier(QuestionQuantifier quantifier, PathForm... arguments) { return visitQuantifier(quantifier, arguments); } @Override public ExpressionWithFrom visitPlusQuantifier(PlusQuantifier quantifier, PathForm... arguments) { return visitQuantifier(quantifier, arguments); } @Override public ExpressionWithFrom visitConcat(Concat concat, PathForm... arguments) { PathForm head = arguments[0]; PathForm tail = arguments[1]; ExpressionWithFrom first = concat.getFirst().accept(this, head, PathForm.Any); assert head.compatible(first.getHead()); ExpressionWithFrom second = concat.getSecond().accept(this, first.getTail().other(), tail); assert first.getTail().other().compatible(second.getHead()) && tail.compatible(second.getTail()); return new ExpressionWithFrom(first.getHead(), second.getTail(), new Concat(first.getExpression(), second.getExpression())); } @Override public ExpressionWithFrom visitCondition(Condition cond, PathForm... arguments) { throw new RuntimeException("Never should this exception happen."); } @Override public ExpressionWithFrom visitOrder(Order order, PathForm... arguments) { throw new RuntimeException("Never should this exception happen."); } @Override public ExpressionWithFrom visitParallel(Parallel parallel, PathForm... arguments) { PathForm head = arguments[0]; PathForm tail = arguments[1]; ExpressionWithFrom first = parallel.getFirst().accept(this, head, tail); assert head.compatible(first.getHead()) && tail.compatible(first.getTail()); ExpressionWithFrom second = parallel.getSecond().accept(this, first.getHead(), first.getTail()); assert first.getHead().compatible(second.getHead()) && first.getTail().compatible(second.getTail()); return new ExpressionWithFrom(first.getHead(), first.getTail(), new Parallel(first.getExpression(), second.getExpression())); } }