/*
* Copyright (C) 2010 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xcmis.search;
import org.xcmis.search.model.Limit;
import org.xcmis.search.model.Query;
import org.xcmis.search.model.QueryElement;
import org.xcmis.search.model.column.Column;
import org.xcmis.search.model.constraint.And;
import org.xcmis.search.model.constraint.ChildNode;
import org.xcmis.search.model.constraint.Comparison;
import org.xcmis.search.model.constraint.DescendantNode;
import org.xcmis.search.model.constraint.FullTextSearch;
import org.xcmis.search.model.constraint.Not;
import org.xcmis.search.model.constraint.Or;
import org.xcmis.search.model.constraint.PropertyExistence;
import org.xcmis.search.model.constraint.SameNode;
import org.xcmis.search.model.operand.BindVariableName;
import org.xcmis.search.model.operand.FullTextSearchScore;
import org.xcmis.search.model.operand.Length;
import org.xcmis.search.model.operand.Literal;
import org.xcmis.search.model.operand.LowerCase;
import org.xcmis.search.model.operand.NodeDepth;
import org.xcmis.search.model.operand.NodeLocalName;
import org.xcmis.search.model.operand.NodeName;
import org.xcmis.search.model.operand.PropertyValue;
import org.xcmis.search.model.operand.UpperCase;
import org.xcmis.search.model.ordering.Ordering;
import org.xcmis.search.model.source.Join;
import org.xcmis.search.model.source.Selector;
import org.xcmis.search.model.source.SelectorName;
import org.xcmis.search.model.source.join.ChildNodeJoinCondition;
import org.xcmis.search.model.source.join.DescendantNodeJoinCondition;
import org.xcmis.search.model.source.join.EquiJoinCondition;
import org.xcmis.search.model.source.join.SameNodeJoinCondition;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
/**
* @author <a href="mailto:Sergey.Kabashnyuk@exoplatform.org">Sergey Kabashnyuk</a>
* @version $Id: Visitors.java 34360 2009-07-22 23:58:59Z ksm $
*
*/
public class Visitors
{
/**
* Visit all objects in the supplied {@link QueryElement object} using a {@link NavigationVisitor} (specifically a
* {@link WalkAllVisitor}), and with each of these visited objects calling the appropriate {@code visit(...)} method on the
* supplied {@link QueryObjectModelVisitor}.
*
* @param <StrategyVisitor> the type of strategy visitor
* @param visitable the top-level object to be visited
* @param strategyVisitor the visitor that is to be called for each visited objects, but that does <i>not</i> call
* {@link Visitable#accept(Visitor)}
* @return the strategy visitor, allowing the caller to easily invoke operations on the visitor after visitation has completed
* @throws VisitException if exception occurs
*/
public static <StrategyVisitor extends QueryObjectModelVisitor> StrategyVisitor visitAll(QueryElement visitable,
StrategyVisitor strategyVisitor) throws VisitException
{
if (visitable != null)
{
visitable.accept(new WalkAllVisitor(strategyVisitor));
}
return strategyVisitor;
}
/**
* Visit the supplied {@link QueryElement object} using the supplied {@link QueryObjectModelVisitor}, which must be responsible for navigation as
* well as any business logic.
*
* @param visitable the top-level object to be visited
* @param visitor the visitor that is to be used
* @return the visitor, allowing the caller to easily invoke operations on the visitor after visitation has completed
* @throws VisitException if exception occurs
*/
public static <GeneralVisitor extends QueryObjectModelVisitor> GeneralVisitor visit(QueryElement visitable,
GeneralVisitor visitor) throws VisitException
{
if (visitable != null)
{
visitable.accept(visitor);
}
return visitor;
}
/**
* Using a visitor, obtain the readable string representation of the supplied {@link Visitable object}
*
* @param visitable the visitable
* @return the string representation
*/
public static String readable(QueryElement visitable)
{
try
{
return visit(visitable, new ReadableVisitor()).getString();
}
catch (VisitException e)
{
return "";
}
}
/**
* Get the names of the selectors referenced by the QueryElement object.
*
* @param visitable the object to be visited
* @return the set of selector names referenced in some way by the visitable; never null
*/
public static Set<SelectorName> getSelectorsReferencedBy(QueryElement visitable)
{
final Set<SelectorName> symbols = new HashSet<SelectorName>();
// Walk the entire structure, so only supply a StrategyVisitor (that does no navigation) ...
try
{
visit(visitable, new WalkAllVisitor(new AbstractModelVisitor()
{
@Override
public void visit(ChildNode childNode)
{
symbols.add(childNode.getSelectorName());
}
@Override
public void visit(ChildNodeJoinCondition joinCondition)
{
symbols.add(joinCondition.getChildSelectorName());
symbols.add(joinCondition.getParentSelectorName());
}
@Override
public void visit(Column column)
{
if (!column.isFunction())
{
symbols.add(column.getSelectorName());
}
}
@Override
public void visit(DescendantNode descendant)
{
symbols.add(descendant.getSelectorName());
}
@Override
public void visit(DescendantNodeJoinCondition joinCondition)
{
symbols.add(joinCondition.getAncestorSelectorName());
symbols.add(joinCondition.getDescendantSelectorName());
}
@Override
public void visit(EquiJoinCondition joinCondition)
{
symbols.add(joinCondition.getSelector1Name());
symbols.add(joinCondition.getSelector2Name());
}
@Override
public void visit(FullTextSearch fullTextSearch)
{
symbols.add(fullTextSearch.getSelectorName());
}
@Override
public void visit(FullTextSearchScore fullTextSearchScore)
{
symbols.add(fullTextSearchScore.getSelectorName());
}
@Override
public void visit(Length length)
{
symbols.add(length.getSelectorName());
}
@Override
public void visit(NodeDepth depth)
{
symbols.add(depth.getSelectorName());
}
@Override
public void visit(NodeLocalName node)
{
symbols.add(node.getSelectorName());
}
@Override
public void visit(NodeName node)
{
symbols.add(node.getSelectorName());
}
@Override
public void visit(Selector node)
{
if (node.hasAlias())
{
symbols.add(node.getAlias());
}
else
{
symbols.add(node.getName());
}
}
@Override
public void visit(PropertyExistence prop)
{
symbols.add(prop.getSelectorName());
}
@Override
public void visit(PropertyValue prop)
{
symbols.add(prop.getSelectorName());
}
@Override
public void visit(SameNode node)
{
symbols.add(node.getSelectorName());
}
@Override
public void visit(SameNodeJoinCondition joinCondition)
{
symbols.add(joinCondition.getSelector1Name());
symbols.add(joinCondition.getSelector2Name());
}
}));
}
catch (VisitException e)
{
//never happen
}
return symbols;
}
/**
* A common base class for all visitors, which provides no-op implementations for all {@code visit(...)} methods. Visitor
* implementations can subclass and implement only those methods that they need to implement.
* <p>
* This is often an excellent base class for <i> visitors</i>, which simply are {@link QueryObjectModelVisitor} implementations that
* are responsible only for visiting the supplied object but that never call {@link QueryElement#accept(QueryObjectModelVisitor)}.
* </p>
*/
public static class AbstractModelVisitor implements QueryObjectModelVisitor
{
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.constraint.And)
*/
public void visit(And node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.operand.BindVariableName)
*/
public void visit(BindVariableName node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.constraint.ChildNode)
*/
public void visit(ChildNode node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.source.join.ChildNodeJoinCondition)
*/
public void visit(ChildNodeJoinCondition node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.column.Column)
*/
public void visit(Column node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.constraint.Comparison)
*/
public void visit(Comparison node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.constraint.DescendantNode)
*/
public void visit(DescendantNode node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.source.join.DescendantNodeJoinCondition)
*/
public void visit(DescendantNodeJoinCondition node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.source.join.EquiJoinCondition)
*/
public void visit(EquiJoinCondition node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.constraint.FullTextSearch)
*/
public void visit(FullTextSearch node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.operand.FullTextSearchScore)
*/
public void visit(FullTextSearchScore node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.source.Join)
*/
public void visit(Join node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.operand.Length)
*/
public void visit(Length node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.Limit)
*/
public void visit(Limit limit) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.operand.Literal)
*/
public void visit(Literal node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.operand.LowerCase)
*/
public void visit(LowerCase node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.operand.NodeDepth)
*/
public void visit(NodeDepth depth) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.operand.NodeLocalName)
*/
public void visit(NodeLocalName node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.operand.NodeName)
*/
public void visit(NodeName node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.constraint.Not)
*/
public void visit(Not node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.constraint.Or)
*/
public void visit(Or node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.ordering.Ordering)
*/
public void visit(Ordering node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.constraint.PropertyExistence)
*/
public void visit(PropertyExistence node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.operand.PropertyValue)
*/
public void visit(PropertyValue node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.Query)
*/
public void visit(Query node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.constraint.SameNode)
*/
public void visit(SameNode node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.source.join.SameNodeJoinCondition)
*/
public void visit(SameNodeJoinCondition node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.operand.UpperCase)
*/
public void visit(UpperCase node) throws VisitException
{
}
/**
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.source.Selector)
*/
public void visit(Selector selector)
{
}
}
/**
* An abstract visitor implementation that performs navigation of the query object.
* <p>
* Subclasses should always implement the {@code visit(T object)} methods by performing the following actions:
* <ol>
* <li>Call <code>strategy.visit(object);</code></li>
* <li>Add any children of {@code object} that are to be visited using {@link #enqueue(QueryElement)}</li>
* <li>Call {@link #visitNext()}</code></li>
* </ol>
* </p>
*/
public static abstract class NavigationVisitor implements QueryObjectModelVisitor
{
protected final QueryObjectModelVisitor strategy;
private final LinkedList<? super QueryElement> itemQueue = new LinkedList<QueryElement>();
/**
* Create a visitor that walks all query objects.
*
* @param strategy the visitor that should be called at every node.
*/
protected NavigationVisitor(QueryObjectModelVisitor strategy)
{
assert strategy != null;
this.strategy = strategy;
}
protected final void enqueue(Iterable<? extends QueryElement> objectsToBeVisited)
{
for (QueryElement objectToBeVisited : objectsToBeVisited)
{
if (objectToBeVisited != null)
{
itemQueue.add(objectToBeVisited);
}
}
}
protected final void enqueue(QueryElement objectToBeVisited)
{
if (objectToBeVisited != null)
{
itemQueue.add(objectToBeVisited);
}
}
protected final void visitNext() throws VisitException
{
if (!itemQueue.isEmpty())
{
QueryElement first = (QueryElement)itemQueue.removeFirst();
assert first != null;
first.accept(this);
}
}
}
/**
* A visitor implementation that walks the entire query object tree and delegates to another supplied visitor to do the actual
* work.
*/
public static class WalkAllVisitor extends NavigationVisitor
{
/**
* Create a visitor that walks all query objects.
*
* @param strategy the visitor that should be called at every node.
*/
protected WalkAllVisitor(QueryObjectModelVisitor strategy)
{
super(strategy);
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(And)
*/
public void visit(And and) throws VisitException
{
strategy.visit(and);
enqueue(and.getLeft());
enqueue(and.getRight());
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(BindVariableName)
*/
public void visit(BindVariableName variableName) throws VisitException
{
strategy.visit(variableName);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(ChildNode)
*/
public void visit(ChildNode child) throws VisitException
{
strategy.visit(child);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(ChildNodeJoinCondition)
*/
public void visit(ChildNodeJoinCondition joinCondition) throws VisitException
{
strategy.visit(joinCondition);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(Column)
*/
public void visit(Column column) throws VisitException
{
strategy.visit(column);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(Comparison)
*/
public void visit(Comparison comparison) throws VisitException
{
strategy.visit(comparison);
enqueue(comparison.getOperand1());
enqueue(comparison.getOperand2());
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(DescendantNode)
*/
public void visit(DescendantNode descendant) throws VisitException
{
strategy.visit(descendant);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(DescendantNodeJoinCondition)
*/
public void visit(DescendantNodeJoinCondition condition) throws VisitException
{
strategy.visit(condition);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(EquiJoinCondition)
*/
public void visit(EquiJoinCondition condition) throws VisitException
{
strategy.visit(condition);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(FullTextSearch)
*/
public void visit(FullTextSearch fullTextSearch) throws VisitException
{
strategy.visit(fullTextSearch);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(FullTextSearchScore)
*/
public void visit(FullTextSearchScore score) throws VisitException
{
strategy.visit(score);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(Join)
*/
public void visit(Join join) throws VisitException
{
strategy.visit(join);
enqueue(join.getLeft());
enqueue(join.getJoinCondition());
enqueue(join.getRight());
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(Length)
*/
public void visit(Length length) throws VisitException
{
strategy.visit(length);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(Limit)
*/
public void visit(Limit limit) throws VisitException
{
strategy.visit(limit);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(Literal)
*/
public void visit(Literal literal) throws VisitException
{
strategy.visit(literal);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(LowerCase)
*/
public void visit(LowerCase lowerCase) throws VisitException
{
strategy.visit(lowerCase);
enqueue(lowerCase.getOperand());
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(NodeDepth)
*/
public void visit(NodeDepth depth) throws VisitException
{
strategy.visit(depth);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(NodeLocalName)
*/
public void visit(NodeLocalName nodeLocalName) throws VisitException
{
strategy.visit(nodeLocalName);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException
*
* @see QueryObjectModelVisitor#visit(NodeName)
*/
public void visit(NodeName nodeName) throws VisitException
{
strategy.visit(nodeName);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see {@link QueryObjectModelVisitor#visit(Not)}Not)
*/
public void visit(Not not) throws VisitException
{
strategy.visit(not);
enqueue(not.getConstraint());
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(Or)
*/
public void visit(Or or) throws VisitException
{
strategy.visit(or);
enqueue(or.getLeft());
enqueue(or.getRight());
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(Ordering)
*/
public void visit(Ordering ordering) throws VisitException
{
strategy.visit(ordering);
enqueue(ordering.getOperand());
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(PropertyExistence)
*/
public void visit(PropertyExistence existence) throws VisitException
{
strategy.visit(existence);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(PropertyValue)
*/
public void visit(PropertyValue propertyValue) throws VisitException
{
strategy.visit(propertyValue);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(Query)
*/
public void visit(Query query) throws VisitException
{
strategy.visit(query);
enqueue(query.getSource());
enqueue(query.getColumns());
enqueue(query.getConstraint());
enqueue(query.getOrderings());
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(SameNode)
*/
public void visit(SameNode sameNode) throws VisitException
{
strategy.visit(sameNode);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(SameNodeJoinCondition)
*/
public void visit(SameNodeJoinCondition condition) throws VisitException
{
strategy.visit(condition);
visitNext();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(UpperCase)
*/
public void visit(UpperCase upperCase) throws VisitException
{
strategy.visit(upperCase);
enqueue(upperCase.getOperand());
visitNext();
}
/**
* @throws VisitException if exception occurs
* @see org.xcmis.search.QueryObjectModelVisitor#visit(org.xcmis.search.model.source.Selector)
*/
public void visit(Selector selector) throws VisitException
{
strategy.visit(selector);
visitNext();
}
}
public static class ReadableVisitor implements QueryObjectModelVisitor
{
private final StringBuilder sb = new StringBuilder();
public ReadableVisitor()
{
}
protected final ReadableVisitor append(String string)
{
sb.append(string);
return this;
}
protected final ReadableVisitor append(char character)
{
sb.append(character);
return this;
}
protected final ReadableVisitor append(int value)
{
sb.append(value);
return this;
}
protected final ReadableVisitor append(SelectorName name)
{
sb.append(name.getName());
return this;
}
/**
* Get the string representation of the visited objects.
*
* @return the string representation
*/
public final String getString()
{
return sb.toString();
}
/**
* {@inheritDoc}
*
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
return sb.toString();
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(And)
*/
public void visit(And and) throws VisitException
{
append('(');
and.getLeft().accept(this);
append(" AND ");
and.getRight().accept(this);
append(')');
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(BindVariableName)
*/
public void visit(BindVariableName variable)
{
append('$').append(variable.getVariableName());
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(ChildNode)
*/
public void visit(ChildNode child)
{
append("ISCHILDNODE(");
append(child.getSelectorName());
append(',');
append(child.getParentPath());
append(')');
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(ChildNodeJoinCondition)
*/
public void visit(ChildNodeJoinCondition condition)
{
append("ISCHILDNODE(");
append(condition.getChildSelectorName());
append(',');
append(condition.getParentSelectorName());
append(')');
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(Column)
*/
public void visit(Column column)
{
if (column.isFunction())
{
append(column.getColumnFunction().toString());
append(" AS ").append(column.getColumnName());
}
else
{
append(column.getSelectorName());
if (column.getPropertyName() == null)
{
append(".*");
}
else
{
String propertyName = column.getPropertyName();
append('.').append(propertyName);
if (!propertyName.equals(column.getColumnName()) && !propertyName.equals(column.getColumnName()))
{
append(" AS ").append(column.getColumnName());
}
}
}
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(Comparison)
*/
public void visit(Comparison comparison) throws VisitException
{
comparison.getOperand1().accept(this);
append(' ').append(comparison.getOperator().getSymbol()).append(' ');
comparison.getOperand2().accept(this);
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(DescendantNode)
*/
public void visit(DescendantNode descendant)
{
append("ISDESCENDANTNODE(");
append(descendant.getSelectorName());
append(',');
append(descendant.getAncestorPath());
append(')');
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(DescendantNodeJoinCondition)
*/
public void visit(DescendantNodeJoinCondition condition)
{
append("ISDESCENDANTNODE(");
append(condition.getDescendantSelectorName());
append(',');
append(condition.getAncestorSelectorName());
append(')');
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(EquiJoinCondition)
*/
public void visit(EquiJoinCondition condition)
{
append(condition.getSelector1Name()).append('.').append(condition.getProperty1Name());
append(" = ");
append(condition.getSelector2Name()).append('.').append(condition.getProperty2Name());
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(FullTextSearch)
*/
public void visit(FullTextSearch fullText)
{
append("CONTAINS(").append(fullText.getSelectorName());
if (fullText.getPropertyName() != null)
{
append('.').append(fullText.getPropertyName());
}
sb.append(",'").append(fullText.getFullTextSearchExpression()).append("')");
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(FullTextSearchScore)
*/
public void visit(FullTextSearchScore score)
{
append("SCORE(").append(score.getSelectorName()).append(')');
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(Join)
*/
public void visit(Join join) throws VisitException
{
join.getLeft().accept(this);
// if (join.getType() != JoinType.INNER) {
sb.append(' ').append(join.getType().getSymbol());
// } else {
// sb.append(',');
// }
append(' ');
join.getRight().accept(this);
append(" ON ");
join.getJoinCondition().accept(this);
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(Length)
*/
public void visit(Length length) throws VisitException
{
append("LENGTH(");
length.getPropertyValue().accept(this);
append(')');
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(Limit)
*/
public void visit(Limit limit)
{
append("LIMIT ").append(limit.getRowLimit());
if (limit.getOffset() != 0)
{
append(" OFFSET ").append(limit.getOffset());
}
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(Literal)
*/
public void visit(Literal literal)
{
Object value = literal.getValue();
boolean quote = value instanceof String;
if (quote)
{
append('\'');
}
append(literal.getValue().toString());
if (quote)
{
append('\'');
}
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(LowerCase)
*/
public void visit(LowerCase lowerCase) throws VisitException
{
append("LOWER(");
lowerCase.getOperand().accept(this);
append(')');
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(NodeDepth)
*/
public void visit(NodeDepth depth)
{
append("DEPTH(").append(depth.getSelectorName()).append(')');
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(NodeLocalName)
*/
public void visit(NodeLocalName name)
{
append("LOCALNAME(").append(name.getSelectorName()).append(')');
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(NodeName)
*/
public void visit(NodeName name)
{
append("NAME(").append(name.getSelectorName()).append(')');
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(NamedSelector)
*/
public void visit(Selector selector)
{
append(selector.getName());
if (selector.hasAlias())
{
append(" AS ").append(selector.getAlias());
}
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(Not)
*/
public void visit(Not not) throws VisitException
{
append('(');
append("NOT ");
not.getConstraint().accept(this);
append(')');
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(Or)
*/
public void visit(Or or) throws VisitException
{
append('(');
or.getLeft().accept(this);
append(" OR ");
or.getRight().accept(this);
append(')');
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(Ordering)
*/
public void visit(Ordering ordering) throws VisitException
{
ordering.getOperand().accept(this);
append(' ').append(ordering.getOrder().getSymbol());
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(PropertyExistence)
*/
public void visit(PropertyExistence existence)
{
append(existence.getSelectorName()).append('.').append(existence.getPropertyName()).append(" IS NOT NULL");
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(PropertyValue)
*/
public void visit(PropertyValue value)
{
append(value.getSelectorName()).append('.').append(value.getPropertyName());
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(Query)
*/
public void visit(Query query) throws VisitException
{
append("SELECT ");
if (query.getColumns().isEmpty())
{
append('*');
}
else
{
boolean isFirst = true;
for (Column column : query.getColumns())
{
if (isFirst)
{
isFirst = false;
}
else
{
append(',');
}
column.accept(this);
}
}
append(" FROM ");
query.getSource().accept(this);
if (query.getConstraint() != null)
{
append(" WHERE ");
query.getConstraint().accept(this);
}
if (!query.getOrderings().isEmpty())
{
append(" ORDER BY ");
boolean isFirst = true;
for (Ordering ordering : query.getOrderings())
{
if (isFirst)
{
isFirst = false;
}
else
{
append(',');
}
ordering.accept(this);
}
}
if (!query.getLimits().isUnlimited())
{
append(' ');
query.getLimits().accept(this);
}
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(SameNode)
*/
public void visit(SameNode sameNode)
{
append("ISSAMENODE(").append(sameNode.getSelectorName()).append(',').append(sameNode.getPath()).append(')');
}
/**
* {@inheritDoc}
*
* @see QueryObjectModelVisitor#visit(SameNodeJoinCondition)
*/
public void visit(SameNodeJoinCondition condition)
{
append("ISSAMENODE(").append(condition.getSelector1Name()).append(',').append(condition.getSelector2Name());
if (condition.getSelector2Path() != null)
{
append(',').append(condition.getSelector2Path());
}
append(')');
}
/**
* {@inheritDoc}
* @throws VisitException if exception occurs
*
* @see QueryObjectModelVisitor#visit(UpperCase)
*/
public void visit(UpperCase upperCase) throws VisitException
{
append("UPPER(");
upperCase.getOperand().accept(this);
append(')');
}
}
}