Permalink
Browse files

MODE-1680 The xpath query is not well-formed

  • Loading branch information...
1 parent ea3b90e commit 2cd2c190337336da833b9ccf04107b7521a610a2 @okulikov okulikov committed with rhauch Mar 5, 2013
@@ -1114,6 +1114,7 @@ public String toString() {
private final Order order;
private final FunctionCall scoreFunction;
private final NameTest attributeName;
+ private final PathExpression path;
public OrderBySpec( Order order,
FunctionCall scoreFunction ) {
@@ -1122,6 +1123,7 @@ public OrderBySpec( Order order,
this.order = order;
this.scoreFunction = scoreFunction;
this.attributeName = null;
+ this.path = null;
}
public OrderBySpec( Order order,
@@ -1131,6 +1133,23 @@ public OrderBySpec( Order order,
this.order = order;
this.scoreFunction = null;
this.attributeName = attributeName;
+ this.path = null;
+ }
+
+ public OrderBySpec(Order order, PathExpression path) {
+ this.order = order;
+ this.scoreFunction = null;
+ this.attributeName = null;
+ this.path = path;
+ }
+
+ /**
+ * Gets child axis for this order specification.
+ *
+ * @return child axis node or null if order is defined by an attribute or score function.
+ */
+ public PathExpression getPath() {
+ return path;
}
/**
@@ -466,8 +466,8 @@ protected FunctionCall parseFunctionCall( TokenStream tokens ) {
do {
args.add(collapse(parseExprSingle(tokens)));
} while (tokens.canConsume(","));
- tokens.consume(")");
}
+ tokens.consume(")");
return new FunctionCall(name, args);
}
@@ -696,8 +696,17 @@ protected OrderBySpec parseOrderBySpec( TokenStream tokens ) {
else if (tokens.canConsume("descending")) order = Order.DESCENDING;
return new OrderBySpec(order, scoreFunction);
}
- throw new ParsingException(tokens.nextPosition(),
- "Expected either 'jcr:score(tableName)' or '@<propertyName>' but found " + tokens.consume());
+
+ PathExpression path = this.parsePathExpr(tokens);
+ Order order = Order.ASCENDING;
+ if (tokens.canConsume("ascending")) {
+ order = Order.ASCENDING;
+ } else if (tokens.canConsume("descending")) {
+ order = Order.DESCENDING;
+ }
+ return new OrderBySpec(order, path);
+// throw new ParsingException(tokens.nextPosition(),
+// "Expected either 'jcr:score(tableName)' or '@<propertyName>' but found " + tokens.consume());
}
/**
@@ -273,7 +273,7 @@ protected void translate( PathExpression pathExpression ) {
operandBuilder.propertyValue(tableName, attribute.toString());
builder.select(tableName + "." + attribute.toString());
}
- } else {
+ } else if (spec.getScoreFunction() != null) {
// This order-by is defined by a "jcr:score" function ...
FunctionCall scoreFunction = spec.getScoreFunction();
assert scoreFunction != null;
@@ -287,6 +287,22 @@ protected void translate( PathExpression pathExpression ) {
}
}
operandBuilder.fullTextSearchScore(nameOfTableToScore);
+ } else {
+ PathExpression axes = spec.getPath();
+ List<StepExpression> axesSteps = axes.getSteps();
+
+ if (axesSteps.size() != 2) {
+ throw new InvalidQueryException("Only child axis supported in ORDER BY clause");
+ }
+
+ NameTest childNode = (NameTest) ((AxisStep)axesSteps.get(0)).getNodeTest();
+ String alias = childNode.getLocalTest();
+
+ NameTest attribute = ((AttributeNameTest) ((AxisStep)axesSteps.get(1)).getNodeTest()).getNameTest();
+
+ builder.select(tableName + "." + attribute.toString());
+ builder.join("nt:base as " + alias).onChildNode(tableName, alias);
+ operandBuilder.propertyValue(alias, attribute.toString());
}
}
orderByBuilder.end();
@@ -575,6 +591,8 @@ protected String translatePredicate( Component predicate,
}
where.fullTextSearchScore(scoreTableName).is(operator, value);
+ } else if (functionName.matches("fn", "name")) {
+ where.nodeName(tableName);
} else {
throw new InvalidQueryException(query,
"Only the 'jcr:score' function is allowed in a comparison predicate; therefore '"
@@ -600,18 +618,23 @@ protected String translatePredicate( Component predicate,
throw new InvalidQueryException(query, "The 'jcr:like' function requires two parameters; therefore '"
+ predicate + "' is not valid");
}
- if (!(param1 instanceof AttributeNameTest)) {
- throw new InvalidQueryException(query,
- "The first parameter of 'jcr:like' must be an property reference with the '@' symbol; therefore '"
- + predicate + "' is not valid");
- }
+// if (!(param1 instanceof AttributeNameTest)) {
+// throw new InvalidQueryException(query,
+// "The first parameter of 'jcr:like' must be an property reference with the '@' symbol; therefore '"
+// + predicate + "' is not valid");
+// }
if (!(param2 instanceof Literal)) {
throw new InvalidQueryException(query, "The second parameter of 'jcr:like' must be a literal; therefore '"
+ predicate + "' is not valid");
}
- NameTest attributeName = ((AttributeNameTest)param1).getNameTest();
String value = ((Literal)param2).getValue();
- where.propertyValue(tableName, nameFrom(attributeName)).isLike(value);
+
+ if (param1 instanceof FunctionCall) {
+ where.nodeName(tableName).isLike(value);
+ } else if (param1 instanceof AttributeNameTest) {
+ NameTest attributeName = ((AttributeNameTest)param1).getNameTest();
+ where.propertyValue(tableName, nameFrom(attributeName)).isLike(value);
+ }
} else if (functionName.matches("jcr", "contains")) {
if (parameters.size() != 2) {
throw new InvalidQueryException(query, "The 'jcr:contains' function requires two parameters; therefore '"
@@ -35,6 +35,7 @@
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
+import org.modeshape.common.FixFor;
import org.modeshape.common.text.ParsingException;
import org.modeshape.common.text.TokenStream;
import org.modeshape.common.text.TokenStream.Tokenizer;
@@ -88,6 +89,12 @@ public void afterEach() {
parser = null;
}
+ @FixFor("MODE-1680")
+ @Test
+ public void shoudlParse() {
+ assertParsable("/jcr:root//element(*,nt:file)[(@jcr:mixinTypes = 'mix:simpleVersionable') and jcr:like(fn:name(), 'a%')]order by @jcr:created ascending");
+ }
+
@Test
public void shouldParseXPathExpressions() {
assertParsable("/jcr:root/a/b/c");
@@ -398,6 +398,13 @@ public void shouldTranslateFromXPathContainingContainsCriteria() {
isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE (nodeSet1.[jcr:primaryType] = 'mgnl:content' AND CONTAINS(nodeSet1.*,'paragraph'))"));
}
+ @FixFor("MODE-1680")
+ @Test
+ public void shouldTranslateOrderByClauseWithChildAxis() {
+ assertThat(xpath("/jcr:root//element(*,nt:file)[(@jcr:mixinTypes = 'mix:simpleVersionable') and jcr:like(fn:name(), 'a%')]order by jcr:content/@jcr:created ascending"),
+ isSql("SELECT [nt:file].[jcr:created] FROM [nt:file] INNER JOIN [nt:base] AS content ON ISCHILDNODE(content,[nt:file]) WHERE ([nt:file].[jcr:mixinTypes] = 'mix:simpleVersionable' AND NAME([nt:file]) LIKE 'a%') ORDER BY content.[jcr:created] ASC"));
+ }
+
// ----------------------------------------------------------------------------------------------------------------
// utility methods
// ----------------------------------------------------------------------------------------------------------------

0 comments on commit 2cd2c19

Please sign in to comment.