You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2007/04/22 11:09:20 UTC
svn commit: r531159 - in /jackrabbit/trunk/jackrabbit-core/src:
main/java/org/apache/jackrabbit/core/query/lucene/
main/java/org/apache/jackrabbit/core/query/xpath/
test/java/org/apache/jackrabbit/core/query/
Author: mreutegg
Date: Sun Apr 22 02:09:19 2007
New Revision: 531159
URL: http://svn.apache.org/viewvc?view=rev&rev=531159
Log:
JCR-857: Basic support for fn:name()
Added:
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/FnNameQueryTest.java (with props)
Modified:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/XPathQueryBuilder.java
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/TestAll.java
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java?view=diff&rev=531159&r1=531158&r2=531159
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java Sun Apr 22 02:09:19 2007
@@ -17,6 +17,7 @@
package org.apache.jackrabbit.core.query.lucene;
import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.SearchManager;
import org.apache.jackrabbit.core.query.AndQueryNode;
import org.apache.jackrabbit.core.query.DerefQueryNode;
import org.apache.jackrabbit.core.query.ExactQueryNode;
@@ -38,7 +39,6 @@
import org.apache.jackrabbit.core.query.lucene.fulltext.QueryParser;
import org.apache.jackrabbit.core.query.lucene.fulltext.ParseException;
import org.apache.jackrabbit.core.state.ItemStateManager;
-import org.apache.jackrabbit.name.MalformedPathException;
import org.apache.jackrabbit.name.NameException;
import org.apache.jackrabbit.name.NoPrefixDeclaredException;
import org.apache.jackrabbit.name.Path;
@@ -47,6 +47,7 @@
import org.apache.jackrabbit.name.PathFormat;
import org.apache.jackrabbit.util.ISO8601;
import org.apache.jackrabbit.util.XMLChar;
+import org.apache.jackrabbit.util.ISO9075;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.lucene.analysis.Analyzer;
@@ -639,149 +640,183 @@
exceptions.add(e);
}
- switch (node.getOperation()) {
- case QueryConstants.OPERATION_EQ_VALUE: // =
- case QueryConstants.OPERATION_EQ_GENERAL:
- BooleanQuery or = new BooleanQuery();
- for (int i = 0; i < stringValues.length; i++) {
- Term t = new Term(FieldNames.PROPERTIES,
- FieldNames.createNamedValue(field, stringValues[i]));
- Query q;
- if (transform[0] == TransformConstants.TRANSFORM_UPPER_CASE) {
- q = new CaseTermQuery.Upper(t);
- } else if (transform[0] == TransformConstants.TRANSFORM_LOWER_CASE) {
- q = new CaseTermQuery.Lower(t);
- } else {
- q = new TermQuery(t);
- }
- or.add(q, Occur.SHOULD);
- }
- query = or;
- if (node.getOperation() == QueryConstants.OPERATION_EQ_VALUE) {
- query = createSingleValueConstraint(or, field);
- }
- break;
- case QueryConstants.OPERATION_GE_VALUE: // >=
- case QueryConstants.OPERATION_GE_GENERAL:
- or = new BooleanQuery();
- for (int i = 0; i < stringValues.length; i++) {
- Term lower = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
- Term upper = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, "\uFFFF"));
- or.add(new RangeQuery(lower, upper, true, transform[0]), Occur.SHOULD);
- }
- query = or;
- if (node.getOperation() == QueryConstants.OPERATION_GE_VALUE) {
- query = createSingleValueConstraint(or, field);
- }
- break;
- case QueryConstants.OPERATION_GT_VALUE: // >
- case QueryConstants.OPERATION_GT_GENERAL:
- or = new BooleanQuery();
- for (int i = 0; i < stringValues.length; i++) {
- Term lower = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
- Term upper = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, "\uFFFF"));
- or.add(new RangeQuery(lower, upper, false, transform[0]), Occur.SHOULD);
- }
- query = or;
- if (node.getOperation() == QueryConstants.OPERATION_GT_VALUE) {
- query = createSingleValueConstraint(or, field);
- }
- break;
- case QueryConstants.OPERATION_LE_VALUE: // <=
- case QueryConstants.OPERATION_LE_GENERAL: // <=
- or = new BooleanQuery();
- for (int i = 0; i < stringValues.length; i++) {
- Term lower = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, ""));
- Term upper = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
- or.add(new RangeQuery(lower, upper, true, transform[0]), Occur.SHOULD);
- }
- query = or;
- if (node.getOperation() == QueryConstants.OPERATION_LE_VALUE) {
- query = createSingleValueConstraint(query, field);
- }
- break;
- case QueryConstants.OPERATION_LIKE: // LIKE
- // the like operation always has one string value.
- // no coercing, see above
- if (stringValues[0].equals("%")) {
- query = new MatchAllQuery(field);
- } else {
- query = new WildcardQuery(FieldNames.PROPERTIES, field, stringValues[0], transform[0]);
- }
- break;
- case QueryConstants.OPERATION_LT_VALUE: // <
- case QueryConstants.OPERATION_LT_GENERAL:
- or = new BooleanQuery();
- for (int i = 0; i < stringValues.length; i++) {
- Term lower = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, ""));
- Term upper = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
- or.add(new RangeQuery(lower, upper, false, transform[0]), Occur.SHOULD);
- }
- query = or;
- if (node.getOperation() == QueryConstants.OPERATION_LT_VALUE) {
- query = createSingleValueConstraint(or, field);
+ // support for fn:name()
+ QName propName = relPath.getNameElement().getName();
+ if (propName.getNamespaceURI().equals(SearchManager.NS_FN_URI) &&
+ propName.getLocalName().equals("name()")) {
+ if (node.getValueType() != QueryConstants.TYPE_STRING) {
+ exceptions.add(new InvalidQueryException("Name function can " +
+ "only be used in conjunction with a string literal"));
+ return data;
+ }
+ if (node.getOperation() != QueryConstants.OPERATION_EQ_VALUE &&
+ node.getOperation() != QueryConstants.OPERATION_EQ_GENERAL) {
+ exceptions.add(new InvalidQueryException("Name function can " +
+ "only be used in conjunction with an equals operator"));
+ return data;
+ }
+ // check if string literal is a valid XML QName
+ if (XMLChar.isValidName(node.getStringValue())) {
+ // parse string literal as JCR QName
+ try {
+ String translatedQName = nsMappings.translatePropertyName(
+ ISO9075.decode(node.getStringValue()),
+ session.getNamespaceResolver());
+ Term t = new Term(FieldNames.LABEL, translatedQName);
+ query = new TermQuery(t);
+ } catch (NameException e) {
+ exceptions.add(e);
+ return data;
}
- break;
- case QueryConstants.OPERATION_NE_VALUE: // !=
- // match nodes with property 'field' that includes svp and mvp
- BooleanQuery notQuery = new BooleanQuery();
- notQuery.add(new MatchAllQuery(field), Occur.SHOULD);
- // exclude all nodes where 'field' has the term in question
- for (int i = 0; i < stringValues.length; i++) {
- Term t = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
- Query q;
- if (transform[0] == TransformConstants.TRANSFORM_UPPER_CASE) {
- q = new CaseTermQuery.Upper(t);
- } else if (transform[0] == TransformConstants.TRANSFORM_LOWER_CASE) {
- q = new CaseTermQuery.Lower(t);
+ } else {
+ // will never match -> create dummy query
+ query = new TermQuery(new Term(FieldNames.UUID, ""));
+ }
+ } else {
+ switch (node.getOperation()) {
+ case QueryConstants.OPERATION_EQ_VALUE: // =
+ case QueryConstants.OPERATION_EQ_GENERAL:
+ BooleanQuery or = new BooleanQuery();
+ for (int i = 0; i < stringValues.length; i++) {
+ Term t = new Term(FieldNames.PROPERTIES,
+ FieldNames.createNamedValue(field, stringValues[i]));
+ Query q;
+ if (transform[0] == TransformConstants.TRANSFORM_UPPER_CASE) {
+ q = new CaseTermQuery.Upper(t);
+ } else if (transform[0] == TransformConstants.TRANSFORM_LOWER_CASE) {
+ q = new CaseTermQuery.Lower(t);
+ } else {
+ q = new TermQuery(t);
+ }
+ or.add(q, Occur.SHOULD);
+ }
+ query = or;
+ if (node.getOperation() == QueryConstants.OPERATION_EQ_VALUE) {
+ query = createSingleValueConstraint(or, field);
+ }
+ break;
+ case QueryConstants.OPERATION_GE_VALUE: // >=
+ case QueryConstants.OPERATION_GE_GENERAL:
+ or = new BooleanQuery();
+ for (int i = 0; i < stringValues.length; i++) {
+ Term lower = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
+ Term upper = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, "\uFFFF"));
+ or.add(new RangeQuery(lower, upper, true, transform[0]), Occur.SHOULD);
+ }
+ query = or;
+ if (node.getOperation() == QueryConstants.OPERATION_GE_VALUE) {
+ query = createSingleValueConstraint(or, field);
+ }
+ break;
+ case QueryConstants.OPERATION_GT_VALUE: // >
+ case QueryConstants.OPERATION_GT_GENERAL:
+ or = new BooleanQuery();
+ for (int i = 0; i < stringValues.length; i++) {
+ Term lower = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
+ Term upper = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, "\uFFFF"));
+ or.add(new RangeQuery(lower, upper, false, transform[0]), Occur.SHOULD);
+ }
+ query = or;
+ if (node.getOperation() == QueryConstants.OPERATION_GT_VALUE) {
+ query = createSingleValueConstraint(or, field);
+ }
+ break;
+ case QueryConstants.OPERATION_LE_VALUE: // <=
+ case QueryConstants.OPERATION_LE_GENERAL: // <=
+ or = new BooleanQuery();
+ for (int i = 0; i < stringValues.length; i++) {
+ Term lower = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, ""));
+ Term upper = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
+ or.add(new RangeQuery(lower, upper, true, transform[0]), Occur.SHOULD);
+ }
+ query = or;
+ if (node.getOperation() == QueryConstants.OPERATION_LE_VALUE) {
+ query = createSingleValueConstraint(query, field);
+ }
+ break;
+ case QueryConstants.OPERATION_LIKE: // LIKE
+ // the like operation always has one string value.
+ // no coercing, see above
+ if (stringValues[0].equals("%")) {
+ query = new MatchAllQuery(field);
} else {
- q = new TermQuery(t);
+ query = new WildcardQuery(FieldNames.PROPERTIES, field, stringValues[0], transform[0]);
}
- notQuery.add(q, Occur.MUST_NOT);
- }
- // and exclude all nodes where 'field' is multi valued
- notQuery.add(new TermQuery(new Term(FieldNames.MVP, field)), Occur.MUST_NOT);
- query = notQuery;
- break;
- case QueryConstants.OPERATION_NE_GENERAL: // !=
- // that's:
- // all nodes with property 'field'
- // minus the nodes that have a single property 'field' that is
- // not equal to term in question
- // minus the nodes that have a multi-valued property 'field' and
- // all values are equal to term in question
- notQuery = new BooleanQuery();
- notQuery.add(new MatchAllQuery(field), Occur.SHOULD);
- for (int i = 0; i < stringValues.length; i++) {
- // exclude the nodes that have the term and are single valued
- Term t = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
- Query svp = new NotQuery(new TermQuery(new Term(FieldNames.MVP, field)));
- BooleanQuery and = new BooleanQuery();
- Query q;
- if (transform[0] == TransformConstants.TRANSFORM_UPPER_CASE) {
- q = new CaseTermQuery.Upper(t);
- } else if (transform[0] == TransformConstants.TRANSFORM_LOWER_CASE) {
- q = new CaseTermQuery.Lower(t);
- } else {
- q = new TermQuery(t);
+ break;
+ case QueryConstants.OPERATION_LT_VALUE: // <
+ case QueryConstants.OPERATION_LT_GENERAL:
+ or = new BooleanQuery();
+ for (int i = 0; i < stringValues.length; i++) {
+ Term lower = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, ""));
+ Term upper = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
+ or.add(new RangeQuery(lower, upper, false, transform[0]), Occur.SHOULD);
+ }
+ query = or;
+ if (node.getOperation() == QueryConstants.OPERATION_LT_VALUE) {
+ query = createSingleValueConstraint(or, field);
+ }
+ break;
+ case QueryConstants.OPERATION_NE_VALUE: // !=
+ // match nodes with property 'field' that includes svp and mvp
+ BooleanQuery notQuery = new BooleanQuery();
+ notQuery.add(new MatchAllQuery(field), Occur.SHOULD);
+ // exclude all nodes where 'field' has the term in question
+ for (int i = 0; i < stringValues.length; i++) {
+ Term t = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
+ Query q;
+ if (transform[0] == TransformConstants.TRANSFORM_UPPER_CASE) {
+ q = new CaseTermQuery.Upper(t);
+ } else if (transform[0] == TransformConstants.TRANSFORM_LOWER_CASE) {
+ q = new CaseTermQuery.Lower(t);
+ } else {
+ q = new TermQuery(t);
+ }
+ notQuery.add(q, Occur.MUST_NOT);
+ }
+ // and exclude all nodes where 'field' is multi valued
+ notQuery.add(new TermQuery(new Term(FieldNames.MVP, field)), Occur.MUST_NOT);
+ query = notQuery;
+ break;
+ case QueryConstants.OPERATION_NE_GENERAL: // !=
+ // that's:
+ // all nodes with property 'field'
+ // minus the nodes that have a single property 'field' that is
+ // not equal to term in question
+ // minus the nodes that have a multi-valued property 'field' and
+ // all values are equal to term in question
+ notQuery = new BooleanQuery();
+ notQuery.add(new MatchAllQuery(field), Occur.SHOULD);
+ for (int i = 0; i < stringValues.length; i++) {
+ // exclude the nodes that have the term and are single valued
+ Term t = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
+ Query svp = new NotQuery(new TermQuery(new Term(FieldNames.MVP, field)));
+ BooleanQuery and = new BooleanQuery();
+ Query q;
+ if (transform[0] == TransformConstants.TRANSFORM_UPPER_CASE) {
+ q = new CaseTermQuery.Upper(t);
+ } else if (transform[0] == TransformConstants.TRANSFORM_LOWER_CASE) {
+ q = new CaseTermQuery.Lower(t);
+ } else {
+ q = new TermQuery(t);
+ }
+ and.add(q, Occur.MUST);
+ and.add(svp, Occur.MUST);
+ notQuery.add(and, Occur.MUST_NOT);
}
- and.add(q, Occur.MUST);
- and.add(svp, Occur.MUST);
- notQuery.add(and, Occur.MUST_NOT);
- }
- // todo above also excludes multi-valued properties that contain
- // multiple instances of only stringValues. e.g. text={foo, foo}
- query = notQuery;
- break;
- case QueryConstants.OPERATION_NULL:
- query = new NotQuery(new MatchAllQuery(field));
- break;
- case QueryConstants.OPERATION_NOT_NULL:
- query = new MatchAllQuery(field);
- break;
- default:
- throw new IllegalArgumentException("Unknown relation operation: "
- + node.getOperation());
+ // todo above also excludes multi-valued properties that contain
+ // multiple instances of only stringValues. e.g. text={foo, foo}
+ query = notQuery;
+ break;
+ case QueryConstants.OPERATION_NULL:
+ query = new NotQuery(new MatchAllQuery(field));
+ break;
+ case QueryConstants.OPERATION_NOT_NULL:
+ query = new MatchAllQuery(field);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown relation operation: "
+ + node.getOperation());
+ }
}
if (relPath.getLength() > 1) {
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/XPathQueryBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/XPathQueryBuilder.java?view=diff&rev=531159&r1=531158&r2=531159
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/XPathQueryBuilder.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/XPathQueryBuilder.java Sun Apr 22 02:09:19 2007
@@ -923,8 +923,9 @@
// use function name as name of a pseudo property in a relation
try {
QName name = NameFormat.parse(fName + "()", resolver);
+ Path.PathElement element = Path.PathElement.create(name);
RelationQueryNode relNode = (RelationQueryNode) queryNode;
- relNode.setRelativePath(Path.create(name, 0));
+ relNode.addPathElement(element);
} catch (NameException e) {
exceptions.add(e);
}
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/FnNameQueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/FnNameQueryTest.java?view=auto&rev=531159
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/FnNameQueryTest.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/FnNameQueryTest.java Sun Apr 22 02:09:19 2007
@@ -0,0 +1,62 @@
+/*
+ * 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.core.query;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Node;
+
+/**
+ * <code>FnNameQueryTest</code> tests queries with fn:name() functions.
+ */
+public class FnNameQueryTest extends AbstractQueryTest {
+
+ public void testFnName() throws RepositoryException {
+ Node n1 = testRootNode.addNode(nodeName1);
+ n1.setProperty(propertyName1, 1);
+ Node n2 = testRootNode.addNode(nodeName2);
+ n2.setProperty(propertyName1, 2);
+ Node n3 = testRootNode.addNode(nodeName3);
+ n3.setProperty(propertyName1, 3);
+
+ testRootNode.save();
+
+ String base = testPath + "/*[@" + propertyName1;
+ executeXPathQuery(base + " = 1 and fn:name() = '" + nodeName1 + "']",
+ new Node[]{n1});
+ executeXPathQuery(base + " = 1 and fn:name() = '" + nodeName2 + "']",
+ new Node[]{});
+ executeXPathQuery(base + " > 0 and fn:name() = '" + nodeName2 + "']",
+ new Node[]{n2});
+ executeXPathQuery(base + " > 0 and (fn:name() = '" + nodeName1 +
+ "' or fn:name() = '" + nodeName2 + "')]", new Node[]{n1, n2});
+ executeXPathQuery(base + " > 0 and not(fn:name() = '" + nodeName1 + "')]",
+ new Node[]{n2, n3});
+ }
+
+ public void testFnNameWithSpace() throws RepositoryException {
+ Node n1 = testRootNode.addNode("My Documents");
+ n1.setProperty(propertyName1, 1);
+
+ testRootNode.save();
+
+ String base = testPath + "/*[@" + propertyName1;
+ executeXPathQuery(base + " = 1 and fn:name() = 'My Documents']",
+ new Node[]{});
+ executeXPathQuery(base + " = 1 and fn:name() = 'My_x0020_Documents']",
+ new Node[]{n1});
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/FnNameQueryTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/TestAll.java?view=diff&rev=531159&r1=531158&r2=531159
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/TestAll.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/TestAll.java Sun Apr 22 02:09:19 2007
@@ -48,6 +48,7 @@
suite.addTestSuite(UpperLowerCaseQueryTest.class);
suite.addTestSuite(ChildAxisQueryTest.class);
suite.addTestSuite(QueryResultTest.class);
+ suite.addTestSuite(FnNameQueryTest.class);
// exclude long running tests per default
//suite.addTestSuite(MassiveRangeTest.class);