org.modeshape.jcr.query.optimize.RewritePathAndNameCriteria Maven / Gradle / Ivy
/*
* ModeShape (http://www.modeshape.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.modeshape.jcr.query.optimize;
import java.util.LinkedList;
import org.modeshape.common.annotation.Immutable;
import org.modeshape.jcr.query.QueryContext;
import org.modeshape.jcr.query.model.And;
import org.modeshape.jcr.query.model.Between;
import org.modeshape.jcr.query.model.ChildNode;
import org.modeshape.jcr.query.model.Comparison;
import org.modeshape.jcr.query.model.Constraint;
import org.modeshape.jcr.query.model.DescendantNode;
import org.modeshape.jcr.query.model.DynamicOperand;
import org.modeshape.jcr.query.model.FullTextSearch;
import org.modeshape.jcr.query.model.NodeDepth;
import org.modeshape.jcr.query.model.NodeLocalName;
import org.modeshape.jcr.query.model.NodeName;
import org.modeshape.jcr.query.model.NodePath;
import org.modeshape.jcr.query.model.Not;
import org.modeshape.jcr.query.model.Or;
import org.modeshape.jcr.query.model.PropertyExistence;
import org.modeshape.jcr.query.model.SetCriteria;
import org.modeshape.jcr.query.model.Visitors;
import org.modeshape.jcr.query.plan.PlanNode;
import org.modeshape.jcr.query.plan.PlanNode.Property;
import org.modeshape.jcr.query.plan.PlanNode.Type;
/**
* An {@link OptimizerRule optimizer rule} that rewrites Constraint trees, moving path-, name-, or depth-oriented criteria to the
* left-most parts of the constraint tree.
*/
@Immutable
public class RewritePathAndNameCriteria implements OptimizerRule {
public static final RewritePathAndNameCriteria INSTANCE = new RewritePathAndNameCriteria();
@Override
public PlanNode execute( QueryContext context,
PlanNode plan,
LinkedList ruleStack ) {
// Remove the view from the selectors ...
for (PlanNode node : plan.findAllAtOrBelow(Type.SELECT)) {
Constraint constraint = node.getProperty(Property.SELECT_CRITERIA, Constraint.class);
Constraint newConstraint = rewriteCriteria(context, constraint);
if (constraint != newConstraint) {
node.getSelectors().clear();
node.addSelectors(Visitors.getSelectorsReferencedBy(newConstraint));
node.setProperty(Property.SELECT_CRITERIA, newConstraint);
}
}
return plan;
}
protected Constraint rewriteCriteria( QueryContext context,
Constraint constraint ) {
if (constraint instanceof And) {
And and = (And)constraint;
Constraint oldLeft = and.left();
Constraint oldRight = and.right();
Constraint newLeft = rewriteCriteria(context, oldLeft);
Constraint newRight = rewriteCriteria(context, oldRight);
if (newRight != oldRight) {
// The right side is path-oriented ...
if (newLeft != oldLeft) {
// The left is too, so create a new And constraint to signal that it's path oriented ...
return new And(newLeft, newRight);
}
// Only the right is, so swap the order ...
return new And(newRight, newLeft);
}
// Neither are path-oriented ...
return and;
}
if (constraint instanceof Or) {
Or or = (Or)constraint;
Constraint oldLeft = or.left();
Constraint oldRight = or.right();
Constraint newLeft = rewriteCriteria(context, oldLeft);
Constraint newRight = rewriteCriteria(context, oldRight);
if (newRight != oldRight) {
// The right side is path-oriented ...
if (newLeft != oldLeft) {
// The left is too, so create a new Or constraint to signal that it's path oriented ...
return new Or(newLeft, newRight);
}
// Only the right is, so swap the order ...
return new Or(newRight, newLeft);
}
// Neither are path-oriented ...
return or;
}
if (constraint instanceof Not) {
Not not = (Not)constraint;
Constraint oldWrapped = not.getConstraint();
Constraint newWrapped = rewriteCriteria(context, oldWrapped);
if (newWrapped != oldWrapped) {
// The wrapped constraint is path-oriented, so create a new Not to signal it ...
return new Not(newWrapped);
}
return not;
}
if (constraint instanceof ChildNode) {
ChildNode childNode = (ChildNode)constraint;
return new ChildNode(childNode.selectorName(), childNode.getParentPath());
}
if (constraint instanceof DescendantNode) {
DescendantNode descNode = (DescendantNode)constraint;
return new DescendantNode(descNode.selectorName(), descNode.getAncestorPath());
}
if (constraint instanceof PropertyExistence) {
return constraint;
}
if (constraint instanceof FullTextSearch) {
return constraint;
}
if (constraint instanceof Between) {
Between between = (Between)constraint;
DynamicOperand operand = between.getOperand();
if (isPathOriented(operand)) {
return new Between(operand, between.getLowerBound(), between.getUpperBound(), between.isLowerBoundIncluded(),
between.isUpperBoundIncluded());
}
return between;
}
if (constraint instanceof Comparison) {
Comparison comparison = (Comparison)constraint;
DynamicOperand operand = comparison.getOperand1();
if (isPathOriented(operand)) {
return new Comparison(operand, comparison.operator(), comparison.getOperand2());
}
return comparison;
}
if (constraint instanceof SetCriteria) {
SetCriteria criteria = (SetCriteria)constraint;
DynamicOperand operand = criteria.getOperand();
if (isPathOriented(operand)) {
return new SetCriteria(operand, criteria.rightOperands());
}
return criteria;
}
return constraint;
}
protected boolean isPathOriented( DynamicOperand op ) {
return op instanceof NodeDepth || op instanceof NodeLocalName || op instanceof NodeName || op instanceof NodePath;
}
@Override
public String toString() {
return getClass().getSimpleName();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy