/* * 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(')'); } } }