Return-Path: X-Original-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Delivered-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 3FE1790F1 for ; Tue, 20 Mar 2012 16:15:50 +0000 (UTC) Received: (qmail 69782 invoked by uid 500); 20 Mar 2012 16:15:50 -0000 Delivered-To: apmail-jackrabbit-oak-commits-archive@jackrabbit.apache.org Received: (qmail 69760 invoked by uid 500); 20 Mar 2012 16:15:50 -0000 Mailing-List: contact oak-commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: oak-commits@jackrabbit.apache.org Delivered-To: mailing list oak-commits@jackrabbit.apache.org Received: (qmail 69751 invoked by uid 99); 20 Mar 2012 16:15:50 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 20 Mar 2012 16:15:50 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 20 Mar 2012 16:15:43 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 33FF12388860; Tue, 20 Mar 2012 16:15:21 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1302967 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/query/ main/java/org/apache/jackrabbit/oak/query/ast/ main/java/org/apache/jackrabbit/oak/query/index/ test/java/org/apache/jackrabbit/oak/query/index/ Date: Tue, 20 Mar 2012 16:15:20 -0000 To: oak-commits@jackrabbit.apache.org From: thomasm@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120320161521.33FF12388860@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: thomasm Date: Tue Mar 20 16:15:20 2012 New Revision: 1302967 URL: http://svn.apache.org/viewvc?rev=1302967&view=rev Log: OAK-28 Query implementation Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/FilterTest.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/LikePatternTest.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingCursorTest.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Value.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/Operator.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyExistenceImpl.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/Filter.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java?rev=1302967&r1=1302966&r2=1302967&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java Tue Mar 20 16:15:20 2012 @@ -278,17 +278,17 @@ public class SQL2Parser { private ConstraintImpl parseCondition(DynamicOperandImpl left) throws ParseException { ConstraintImpl c; if (readIf("=")) { - c = factory.comparison(left, Operator.EQ, parseStaticOperand()); + c = factory.comparison(left, Operator.EQUAL, parseStaticOperand()); } else if (readIf("<>")) { - c = factory.comparison(left, Operator.NE, parseStaticOperand()); + c = factory.comparison(left, Operator.NOT_EQUAL, parseStaticOperand()); } else if (readIf("<")) { - c = factory.comparison(left, Operator.LT, parseStaticOperand()); + c = factory.comparison(left, Operator.LESS_THAN, parseStaticOperand()); } else if (readIf(">")) { - c = factory.comparison(left, Operator.GT, parseStaticOperand()); + c = factory.comparison(left, Operator.GREATER_THAN, parseStaticOperand()); } else if (readIf("<=")) { - c = factory.comparison(left, Operator.LE, parseStaticOperand()); + c = factory.comparison(left, Operator.LESS_OR_EQUAL, parseStaticOperand()); } else if (readIf(">=")) { - c = factory.comparison(left, Operator.GE, parseStaticOperand()); + c = factory.comparison(left, Operator.GREATER_OR_EQUAL, parseStaticOperand()); } else if (readIf("LIKE")) { c = factory.comparison(left, Operator.LIKE, parseStaticOperand()); } else if (readIf("IS")) { Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Value.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Value.java?rev=1302967&r1=1302966&r2=1302967&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Value.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Value.java Tue Mar 20 16:15:20 2012 @@ -105,4 +105,9 @@ public class Value implements Comparable return value.toString().compareTo(o.toString()); } + @Override + public String toString() { + return getString(); + } + } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java?rev=1302967&r1=1302966&r2=1302967&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java Tue Mar 20 16:15:20 2012 @@ -110,24 +110,25 @@ public abstract class AstVisitorBase imp *
  • Orderings
  • *
  • Columns
  • * + * + * @param query the query to visit */ - public boolean visit(Query node) { - node.getSource().accept(this); - ConstraintImpl constraint = node.getConstraint(); + public void visit(Query query) { + query.getSource().accept(this); + ConstraintImpl constraint = query.getConstraint(); if (constraint != null) { constraint.accept(this); } - OrderingImpl[] orderings = node.getOrderings(); + OrderingImpl[] orderings = query.getOrderings(); if (orderings != null) { for (OrderingImpl ordering : orderings) { ordering.accept(this); } } - ColumnImpl[] columns = node.getColumns(); + ColumnImpl[] columns = query.getColumns(); for (ColumnImpl column : columns) { column.accept(this); } - return true; } /** Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java?rev=1302967&r1=1302966&r2=1302967&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java Tue Mar 20 16:15:20 2012 @@ -55,14 +55,14 @@ public class ComparisonImpl extends Cons return false; } switch (operator) { - case EQ: + case EQUAL: return v1.equals(v2); - case GE: - case GT: - case LE: - case LT: + case GREATER_OR_EQUAL: + case GREATER_THAN: + case LESS_OR_EQUAL: + case LESS_THAN: return operand1.currentValue() .equals(operand2.currentValue()); - case NE: + case NOT_EQUAL: return !operand1.currentValue().equals(operand2.currentValue()); case LIKE: return evaluateLike(v1, v2); @@ -268,10 +268,10 @@ public class ComparisonImpl extends Cons } else { ValueFactory vf = query.getValueFactory(); if (lowerBound != null) { - operand1.apply(f, Operator.GE, vf.createValue(lowerBound)); + operand1.apply(f, Operator.GREATER_OR_EQUAL, vf.createValue(lowerBound)); } if (upperBound != null) { - operand1.apply(f, Operator.LE, vf.createValue(upperBound)); + operand1.apply(f, Operator.LESS_OR_EQUAL, vf.createValue(upperBound)); } } } else { Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java?rev=1302967&r1=1302966&r2=1302967&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java Tue Mar 20 16:15:20 2012 @@ -93,10 +93,10 @@ public class EquiJoinConditionImpl exten Value v1 = selector1.currentProperty(property1Name); Value v2 = selector2.currentProperty(property2Name); if (f.getSelector() == selector1 && v2 != null) { - f.restrictProperty(property1Name, Operator.EQ, v2); + f.restrictProperty(property1Name, Operator.EQUAL, v2); } if (f.getSelector() == selector2 && v1 != null) { - f.restrictProperty(property2Name, Operator.EQ, v1); + f.restrictProperty(property2Name, Operator.EQUAL, v1); } } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/Operator.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/Operator.java?rev=1302967&r1=1302966&r2=1302967&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/Operator.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/Operator.java Tue Mar 20 16:15:20 2012 @@ -21,17 +21,17 @@ package org.apache.jackrabbit.oak.query. */ public enum Operator { - EQ("="), + EQUAL("="), - NE("<>"), + NOT_EQUAL("<>"), - GT(">"), + GREATER_THAN(">"), - GE(">="), + GREATER_OR_EQUAL(">="), - LT("<"), + LESS_THAN("<"), - LE("<="), + LESS_OR_EQUAL("<="), LIKE("like"); Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyExistenceImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyExistenceImpl.java?rev=1302967&r1=1302966&r2=1302967&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyExistenceImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyExistenceImpl.java Tue Mar 20 16:15:20 2012 @@ -67,7 +67,7 @@ public class PropertyExistenceImpl exten @Override public void apply(Filter f) { if (f.getSelector() == selector) { - f.restrictProperty(propertyName, Operator.NE, (Value) null); + f.restrictProperty(propertyName, Operator.NOT_EQUAL, (Value) null); } } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/Filter.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/Filter.java?rev=1302967&r1=1302966&r2=1302967&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/Filter.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/Filter.java Tue Mar 20 16:15:20 2012 @@ -94,9 +94,9 @@ public class Filter { */ private String valuePrefix; - private HashMap propertyRanges = new HashMap(); + private HashMap propertyRestrictions = new HashMap(); - static class PropertyValueCondition { + static class PropertyRestriction { /** * The name of the property. @@ -106,22 +106,28 @@ public class Filter { /** * The first value to read, or null to read from the beginning. */ - public String first; + public Value first; /** - * Whether only values bigger than the first value should be returned. + * Whether values that match the first should be returned. */ - public boolean firstExcluding; + public boolean firstIncluding; /** * The last value to read, or null to read until the end. */ - public String last; + public Value last; /** - * Whether only values smaller than the last value should be returned. + * Whether values that match the last should be returned. */ - public boolean lastExcluding; + public boolean lastIncluding; + + @Override + public String toString() { + return (first == null ? "" : ((firstIncluding ? "[" : "(") + first)) + ".." + + (last == null ? "" : last + (lastIncluding ? "]" : ")")); + } } @@ -138,6 +144,8 @@ public class Filter { /** * Get the path. + * + * @return the path */ public String getPath() { return path; @@ -176,7 +184,7 @@ public class Filter { } public void setAlwaysFalse() { - propertyRanges.clear(); + propertyRestrictions.clear(); valuePrefix = "none"; nodeType = "none"; path = "none"; @@ -192,8 +200,14 @@ public class Filter { return selector; } - public void restrictProperty(String propertyName, Operator op, Value value) { - restrictProperty(propertyName, op, value == null ? null : value.getString()); + /** + * Get the restriction for the given property, if any. + * + * @param propertyName the property name + * @return the restriction or null + */ + public PropertyRestriction getPropertyRestriction(String propertyName) { + return propertyRestrictions.get(propertyName); } public boolean testPath(String path) { @@ -214,53 +228,62 @@ public class Filter { } } - public void restrictProperty(String propertyName, Operator op, String value) { - PropertyValueCondition x = propertyRanges.get(propertyName); + public void restrictProperty(String propertyName, Operator op, Value value) { + PropertyRestriction x = propertyRestrictions.get(propertyName); if (x == null) { - x = new PropertyValueCondition(); + x = new PropertyRestriction(); x.propertyName = propertyName; - propertyRanges.put(propertyName, x); + propertyRestrictions.put(propertyName, x); } - String oldFirst = x.first, oldLast = x.last; + Value oldFirst = x.first, oldLast = x.last; switch (op) { - case EQ: + case EQUAL: x.first = maxValue(oldFirst, value); - x.firstExcluding = false; + x.firstIncluding = x.first == oldFirst ? x.firstIncluding : true; x.last = minValue(oldLast, value); - x.lastExcluding = false; + x.lastIncluding = x.last == oldLast ? x.lastIncluding : true; break; - case NE: - // not null + case NOT_EQUAL: + if (value != null) { + throw new IllegalArgumentException("NOT_EQUAL only supported for NOT_EQUAL NULL"); + } break; - case GT: + case GREATER_THAN: x.first = maxValue(oldFirst, value); - x.firstExcluding = true; + x.firstIncluding = false; break; - case GE: + case GREATER_OR_EQUAL: x.first = maxValue(oldFirst, value); - x.firstExcluding = x.first == oldFirst ? x.firstExcluding : false; + x.firstIncluding = x.first == oldFirst ? x.firstIncluding : true; break; - case LT: + case LESS_THAN: x.last = minValue(oldLast, value); - x.lastExcluding = true; + x.lastIncluding = false; break; - case LE: + case LESS_OR_EQUAL: x.last = minValue(oldLast, value); - x.lastExcluding = x.last == oldLast ? x.lastExcluding : false; + x.lastIncluding = x.last == oldLast ? x.lastIncluding : true; break; case LIKE: - throw new RuntimeException("LIKE is not supported"); + throw new IllegalArgumentException("LIKE is not supported"); + } + if (x.first != null && x.last != null) { + if (x.first.compareTo(x.last) > 0) { + setAlwaysFalse(); + } else if (x.first.compareTo(x.last) == 0 && (!x.firstIncluding || !x.lastIncluding)) { + setAlwaysFalse(); + } } } - static String maxValue(String a, String b) { + static Value maxValue(Value a, Value b) { if (a == null) { return b; } return a.compareTo(b) < 0 ? b : a; } - static String minValue(String a, String b) { + static Value minValue(Value a, Value b) { if (a == null) { return b; } Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/FilterTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/FilterTest.java?rev=1302967&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/FilterTest.java (added) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/FilterTest.java Tue Mar 20 16:15:20 2012 @@ -0,0 +1,259 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.jackrabbit.oak.query.index; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import java.util.ArrayList; +import java.util.Random; +import org.apache.jackrabbit.oak.query.Value; +import org.apache.jackrabbit.oak.query.ValueFactory; +import org.apache.jackrabbit.oak.query.ast.Operator; +import org.apache.jackrabbit.oak.query.index.Filter.PathRestriction; +import org.junit.Test; + +/** + * Tests the Filter class. + */ +public class FilterTest { + + @Test + public void propertyRestriction() { + Value one = new ValueFactory().createValue("1"); + Value two = new ValueFactory().createValue("2"); + + Filter f = new Filter(null); + assertTrue(null == f.getPropertyRestriction("x")); + f.restrictProperty("x", Operator.LESS_OR_EQUAL, two); + assertEquals("..2]", f.getPropertyRestriction("x").toString()); + f.restrictProperty("x", Operator.GREATER_OR_EQUAL, one); + assertEquals("[1..2]", f.getPropertyRestriction("x").toString()); + f.restrictProperty("x", Operator.GREATER_THAN, one); + assertEquals("(1..2]", f.getPropertyRestriction("x").toString()); + f.restrictProperty("x", Operator.LESS_THAN, two); + assertEquals("(1..2)", f.getPropertyRestriction("x").toString()); + f.restrictProperty("x", Operator.EQUAL, two); + assertTrue(f.isAlwaysFalse()); + + f = new Filter(null); + f.restrictProperty("x", Operator.EQUAL, one); + assertEquals("[1..1]", f.getPropertyRestriction("x").toString()); + f.restrictProperty("x", Operator.EQUAL, one); + assertEquals("[1..1]", f.getPropertyRestriction("x").toString()); + f.restrictProperty("x", Operator.GREATER_OR_EQUAL, one); + assertEquals("[1..1]", f.getPropertyRestriction("x").toString()); + f.restrictProperty("x", Operator.LESS_OR_EQUAL, one); + assertEquals("[1..1]", f.getPropertyRestriction("x").toString()); + f.restrictProperty("x", Operator.GREATER_THAN, one); + assertTrue(f.isAlwaysFalse()); + + f = new Filter(null); + f.restrictProperty("x", Operator.EQUAL, one); + assertEquals("[1..1]", f.getPropertyRestriction("x").toString()); + f.restrictProperty("x", Operator.LESS_THAN, one); + assertTrue(f.isAlwaysFalse()); + + f = new Filter(null); + f.restrictProperty("x", Operator.NOT_EQUAL, null); + assertEquals("..", f.getPropertyRestriction("x").toString()); + f.restrictProperty("x", Operator.LESS_THAN, one); + assertEquals("..1)", f.getPropertyRestriction("x").toString()); + f.restrictProperty("x", Operator.EQUAL, two); + assertTrue(f.isAlwaysFalse()); + + } + + @Test + public void pathRestrictionsRandomized() throws Exception { + ArrayList paths = new ArrayList(); + // create paths /a, /b, /c, /a/a, /a/b, ... /c/c/c + paths.add("/"); + for (int i = 'a'; i <= 'c'; i++) { + String p1 = "/" + (char) i; + paths.add(p1); + for (int j = 'a'; j <= 'c'; j++) { + String p2 = "/" + (char) j; + paths.add(p1 + p2); + for (int k = 'a'; k <= 'c'; k++) { + String p3 = "/" + (char) k; + paths.add(p1 + p2 + p3); + } + } + } + Random r = new Random(1); + for (int i = 0; i < 10000; i++) { + String p1 = paths.get(r.nextInt(paths.size())); + String p2 = paths.get(r.nextInt(paths.size())); + PathRestriction r1 = PathRestriction.values()[r.nextInt(PathRestriction.values().length)]; + PathRestriction r2 = PathRestriction.values()[r.nextInt(PathRestriction.values().length)]; + Filter f1 = new Filter(null); + f1.restrictPath(p1, r1); + Filter f2 = new Filter(null); + f2.restrictPath(p2, r2); + Filter fc = new Filter(null); + fc.restrictPath(p1, r1); + fc.restrictPath(p2, r2); + int tooMany = 0; + for (String p : paths) { + boolean expected = f1.testPath(p) && f2.testPath(p); + boolean got = fc.testPath(p); + if (expected == got) { + // good + } else if (expected && !got) { + fc = new Filter(null); + fc.restrictPath(p1, r1); + fc.restrictPath(p2, r2); + fail("not matched: " + p1 + "/" + r1.name() + " && " + p2 + "/" + r2.name()); + } else { + // not great, but not a problem + tooMany++; + } + } + if (tooMany > 3) { + fail("too many matches: " + p1 + "/" + r1.name() + " && " + p2 + "/" + r2.name() + " superfluous: " + tooMany); + } + } + } + + @Test + public void pathRestrictions() throws Exception { + Filter f = new Filter(null); + assertEquals("/", f.getPath()); + assertEquals(PathRestriction.ALL_CHILDREN, f.getPathRestriction()); + + f.restrictPath("/test", PathRestriction.ALL_CHILDREN); + f.restrictPath("/test2", PathRestriction.ALL_CHILDREN); + assertTrue(f.isAlwaysFalse()); + + f = new Filter(null); + f.restrictPath("/test", PathRestriction.ALL_CHILDREN); + assertEquals("/test", f.getPath()); + assertEquals(PathRestriction.ALL_CHILDREN, f.getPathRestriction()); + f.restrictPath("/test/x", PathRestriction.DIRECT_CHILDREN); + assertEquals("/test/x", f.getPath()); + assertEquals(PathRestriction.DIRECT_CHILDREN, f.getPathRestriction()); + f.restrictPath("/test/x/y", PathRestriction.PARENT); + assertEquals("/test/x/y", f.getPath()); + assertEquals(PathRestriction.PARENT, f.getPathRestriction()); + + f = new Filter(null); + f.restrictPath("/test", PathRestriction.DIRECT_CHILDREN); + f.restrictPath("/test/x/y", PathRestriction.PARENT); + assertEquals("/test/x/y", f.getPath()); + assertEquals(PathRestriction.PARENT, f.getPathRestriction()); + f.restrictPath("/test/y", PathRestriction.DIRECT_CHILDREN); + assertTrue(f.isAlwaysFalse()); + + f = new Filter(null); + f.restrictPath("/test/x/y", PathRestriction.PARENT); + f.restrictPath("/test/x", PathRestriction.EXACT); + assertEquals("/test/x", f.getPath()); + assertEquals(PathRestriction.EXACT, f.getPathRestriction()); + f.restrictPath("/test/y", PathRestriction.EXACT); + assertTrue(f.isAlwaysFalse()); + + f = new Filter(null); + f.restrictPath("/test", PathRestriction.ALL_CHILDREN); + f.restrictPath("/test", PathRestriction.PARENT); + assertTrue(f.isAlwaysFalse()); + + f = new Filter(null); + f.restrictPath("/test/x", PathRestriction.PARENT); + f.restrictPath("/test", PathRestriction.ALL_CHILDREN); + assertEquals("/test/x", f.getPath()); + assertEquals(PathRestriction.PARENT, f.getPathRestriction()); + f.restrictPath("/test/x", PathRestriction.ALL_CHILDREN); + assertTrue(f.isAlwaysFalse()); + + f = new Filter(null); + f.restrictPath("/test", PathRestriction.ALL_CHILDREN); + f.restrictPath("/test", PathRestriction.EXACT); + assertTrue(f.isAlwaysFalse()); + + f = new Filter(null); + f.restrictPath("/test", PathRestriction.DIRECT_CHILDREN); + f.restrictPath("/test/x", PathRestriction.EXACT); + assertEquals("/test/x", f.getPath()); + assertEquals(PathRestriction.EXACT, f.getPathRestriction()); + + f = new Filter(null); + f.restrictPath("/test", PathRestriction.DIRECT_CHILDREN); + f.restrictPath("/test/x/y", PathRestriction.EXACT); + assertTrue(f.isAlwaysFalse()); + + f = new Filter(null); + f.restrictPath("/test/x", PathRestriction.PARENT); + f.restrictPath("/", PathRestriction.ALL_CHILDREN); + assertEquals("/test/x", f.getPath()); + assertEquals(PathRestriction.PARENT, f.getPathRestriction()); + f.restrictPath("/test/y", PathRestriction.EXACT); + assertTrue(f.isAlwaysFalse()); + + f = new Filter(null); + f.restrictPath("/test", PathRestriction.DIRECT_CHILDREN); + assertEquals("/test", f.getPath()); + assertEquals(PathRestriction.DIRECT_CHILDREN, f.getPathRestriction()); + f.restrictPath("/", PathRestriction.ALL_CHILDREN); + assertEquals("/test", f.getPath()); + assertEquals(PathRestriction.DIRECT_CHILDREN, f.getPathRestriction()); + f.restrictPath("/test", PathRestriction.ALL_CHILDREN); + assertEquals("/test", f.getPath()); + assertEquals(PathRestriction.DIRECT_CHILDREN, f.getPathRestriction()); + f.restrictPath("/test/x/y", PathRestriction.PARENT); + assertEquals("/test/x/y", f.getPath()); + assertEquals(PathRestriction.PARENT, f.getPathRestriction()); + f.restrictPath("/test2", PathRestriction.ALL_CHILDREN); + assertTrue(f.isAlwaysFalse()); + + f = new Filter(null); + f.restrictPath("/test/x", PathRestriction.EXACT); + assertEquals("/test/x", f.getPath()); + assertEquals(PathRestriction.EXACT, f.getPathRestriction()); + f.restrictPath("/test", PathRestriction.ALL_CHILDREN); + f.restrictPath("/test", PathRestriction.DIRECT_CHILDREN); + f.restrictPath("/test/x/y", PathRestriction.PARENT); + f.restrictPath("/test/y", PathRestriction.DIRECT_CHILDREN); + assertTrue(f.isAlwaysFalse()); + + f = new Filter(null); + f.restrictPath("/test/x/y", PathRestriction.PARENT); + assertEquals("/test/x/y", f.getPath()); + assertEquals(PathRestriction.PARENT, f.getPathRestriction()); + f.restrictPath("/test/x", PathRestriction.PARENT); + assertEquals("/test/x", f.getPath()); + assertEquals(PathRestriction.PARENT, f.getPathRestriction()); + f.restrictPath("/test", PathRestriction.ALL_CHILDREN); + assertEquals("/test/x", f.getPath()); + assertEquals(PathRestriction.PARENT, f.getPathRestriction()); + f.restrictPath("/test", PathRestriction.DIRECT_CHILDREN); + assertEquals("/test/x", f.getPath()); + assertEquals(PathRestriction.PARENT, f.getPathRestriction()); + f.restrictPath("/test/x", PathRestriction.PARENT); + assertEquals("/test/x", f.getPath()); + assertEquals(PathRestriction.PARENT, f.getPathRestriction()); + f.restrictPath("/test", PathRestriction.PARENT); + assertEquals("/test", f.getPath()); + assertEquals(PathRestriction.PARENT, f.getPathRestriction()); + f.restrictPath("/test2", PathRestriction.EXACT); + assertTrue(f.isAlwaysFalse()); + + } + +} Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/LikePatternTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/LikePatternTest.java?rev=1302967&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/LikePatternTest.java (added) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/LikePatternTest.java Tue Mar 20 16:15:20 2012 @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.jackrabbit.oak.query.index; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; +import org.apache.jackrabbit.oak.query.ast.ComparisonImpl; +import org.junit.Test; + +public class LikePatternTest { + + @Test + public void pattern() { + pattern("%_", "X", "", null, null); + pattern("A%", "A", "X", "A", "B"); + pattern("A%%", "A", "X", "A", "B"); + pattern("%\\_%", "A_A", "AAA", null, null); + } + + private void pattern(String pattern, String match, String noMatch, String lower, String upper) { + ComparisonImpl.LikePattern p = new ComparisonImpl.LikePattern(pattern); + if (match != null) { + assertTrue(p.matches(match)); + } + if (noMatch != null) { + assertFalse(p.matches(noMatch)); + } + assertEquals(lower, p.getLowerBound()); + assertEquals(upper, p.getUpperBound()); + } + +} Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingCursorTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingCursorTest.java?rev=1302967&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingCursorTest.java (added) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingCursorTest.java Tue Mar 20 16:15:20 2012 @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.jackrabbit.oak.query.index; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import org.apache.jackrabbit.mk.MicroKernelFactory; +import org.apache.jackrabbit.mk.api.MicroKernel; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests the TraversingCursor. + */ +public class TraversingCursorTest { + + MicroKernel mk; + String head; + + @Before + public void setUp() { + mk = MicroKernelFactory.getInstance("simple:/target/temp;clear"); + head = mk.getHeadRevision(); + } + + @After + public void tearDown() { + mk.dispose(); + } + + @Test + public void traverse() throws Exception { + TraversingReader r = new TraversingReader(mk); + traverse(r); + } + + @Test + public void traverseBlockwise() throws Exception { + TraversingReader r = new TraversingReader(mk); + r.setChildBlockSize(2); + traverse(r); + } + + private void traverse(TraversingReader r) { + head = mk.commit("/", "+ \"parents\": { \"p0\": {\"id\": \"0\"}, \"p1\": {\"id\": \"1\"}, \"p2\": {\"id\": \"2\"}}", head, ""); + head = mk.commit("/", "+ \"children\": { \"c1\": {\"p\": \"1\"}, \"c2\": {\"p\": \"1\"}, \"c3\": {\"p\": \"2\"}, \"c4\": {\"p\": \"3\"}}", head, ""); + Filter f = new Filter(null); + Cursor c; + f.setPath("/"); + c = r.query(f, head); + String[] list = {"/", "/parents", "/parents/p0", "/parents/p1", "/parents/p2", + "/children", "/children/c1", "/children/c2", "/children/c3", "/children/c4"}; + for (String s : list) { + assertTrue(c.next()); + assertEquals(s, c.currentPath()); + } + assertFalse(c.next()); + assertFalse(c.next()); + f.setPath("/nowhere"); + c = r.query(f, head); + assertFalse(c.next()); + assertFalse(c.next()); + } + +}