// result columns
// builder.select(tableName + "." + propertyName);
where.hasProperty(tableName, propertyName);
} else if (predicate instanceof NameTest) {
// This adds the criteria that the child node exists ...
NameTest childName = (NameTest)predicate;
String alias = newAlias();
builder.joinAllNodesAs(alias).onChildNode(tableName, alias);
if (!childName.isWildcard()) where.nodeName(alias).isEqualTo(nameFrom(childName));
tableName = alias;
} else if (predicate instanceof Comparison) {
Comparison comparison = (Comparison)predicate;
Component left = comparison.getLeft();
Component right = comparison.getRight();
Operator operator = comparison.getOperator();
if (left instanceof Literal) {
Component temp = left;
left = right;
right = temp;
operator = operator.getReverse();
}
if (left instanceof AttributeNameTest) {
AttributeNameTest attribute = (AttributeNameTest)left;
String propertyName = nameFrom(attribute.getNameTest());
if (right instanceof Literal) {
String value = ((Literal)right).getValue();
where.propertyValue(tableName, propertyName).is(operator, value);
} else if (right instanceof FunctionCall) {
FunctionCall call = (FunctionCall)right;
NameTest functionName = call.getName();
List<Component> parameters = call.getParameters();
// Is this a cast ...
String castType = CAST_FUNCTION_NAME_TO_TYPE.get(functionName);
if (castType != null) {
if (parameters.size() == 1 && parameters.get(0).collapse() instanceof Literal) {
// The first parameter can be the type name (or table name) ...
Literal value = (Literal)parameters.get(0).collapse();
where.propertyValue(tableName, propertyName).is(operator).cast(value.getValue()).as(castType);
} else {
throw new InvalidQueryException(query, "A cast function requires one literal parameter; therefore '"
+ comparison + "' is not valid");
}
} else {
throw new InvalidQueryException(query,
"Only the 'jcr:score' function is allowed in a comparison predicate; therefore '"
+ comparison + "' is not valid");
}
}
} else if (left instanceof FunctionCall && right instanceof Literal) {
FunctionCall call = (FunctionCall)left;
NameTest functionName = call.getName();
List<Component> parameters = call.getParameters();
String value = ((Literal)right).getValue();
if (functionName.matches("jcr", "score")) {
String scoreTableName = tableName;
if (parameters.isEmpty()) {
scoreTableName = tableName;
} else if (parameters.size() == 1 && parameters.get(0) instanceof NameTest) {
// The first parameter can be the type name (or table name) ...
NameTest name = (NameTest)parameters.get(0);
if (!name.isWildcard()) scoreTableName = nameFrom(name);
} else {
throw new InvalidQueryException(query,
"The 'jcr:score' function may have no parameters or the type name as the only parameter.");
}
where.fullTextSearchScore(scoreTableName).is(operator, value);
} else {
throw new InvalidQueryException(query,
"Only the 'jcr:score' function is allowed in a comparison predicate; therefore '"
+ comparison + "' is not valid");
}
}
} else if (predicate instanceof FunctionCall) {
FunctionCall call = (FunctionCall)predicate;
NameTest functionName = call.getName();
List<Component> parameters = call.getParameters();
Component param1 = parameters.size() > 0 ? parameters.get(0) : null;
Component param2 = parameters.size() > 1 ? parameters.get(1) : null;
if (functionName.matches(null, "not")) {
if (parameters.size() != 1) {
throw new InvalidQueryException(query, "The 'not' function requires one parameter; therefore '" + predicate
+ "' is not valid");
}
where = where.not().openParen();
translatePredicate(param1, tableName, where);
where.closeParen();
} else if (functionName.matches("jcr", "like")) {
if (parameters.size() != 2) {
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 (!(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);
} else if (functionName.matches("jcr", "contains")) {
if (parameters.size() != 2) {
throw new InvalidQueryException(query, "The 'jcr:contains' function requires two parameters; therefore '"
+ predicate + "' is not valid");
}
if (!(param2 instanceof Literal)) {
throw new InvalidQueryException(query,
"The second parameter of 'jcr:contains' must be a literal; therefore '"
+ predicate + "' is not valid");
}
String value = ((Literal)param2).getValue();
if (param1 instanceof ContextItem) {
// refers to the current node (or table) ...
where.search(tableName, value);
} else if (param1 instanceof AttributeNameTest) {
// refers to an attribute on the current node (or table) ...
NameTest attributeName = ((AttributeNameTest)param1).getNameTest();
where.search(tableName, nameFrom(attributeName), value);
} else if (param1 instanceof NameTest) {
// refers to child node, so we need to add a join ...
String alias = newAlias();
builder.joinAllNodesAs(alias).onChildNode(tableName, alias);
// Now add the criteria ...
where.search(alias, value);
tableName = alias;
} else if (param1 instanceof PathExpression) {
// refers to a descendant node ...
PathExpression pathExpr = (PathExpression)param1;
if (pathExpr.getLastStep().collapse() instanceof AttributeNameTest) {
AttributeNameTest attributeName = (AttributeNameTest)pathExpr.getLastStep().collapse();
pathExpr = pathExpr.withoutLast();
String searchTable = translatePredicate(pathExpr, tableName, where);
if (attributeName.getNameTest().isWildcard()) {
where.search(searchTable, value);
} else {
where.search(searchTable, nameFrom(attributeName.getNameTest()), value);
}
} else {
String searchTable = translatePredicate(param1, tableName, where);
where.search(searchTable, value);
}
} else {
throw new InvalidQueryException(query,
"The first parameter of 'jcr:contains' must be a relative path (e.g., '.', an attribute name, a child name, etc.); therefore '"
+ predicate + "' is not valid");
}
} else if (functionName.matches("jcr", "deref")) {
throw new InvalidQueryException(query,
"The 'jcr:deref' function is not required by JCR and is not currently supported; therefore '"
+ predicate + "' is not valid");
} else {
throw new InvalidQueryException(query,
"Only the 'jcr:like' and 'jcr:contains' functions are allowed in a predicate; therefore '"
+ predicate + "' is not valid");
}
} else if (predicate instanceof PathExpression) {
// Requires that the descendant node with the relative path does exist ...
PathExpression pathExpr = (PathExpression)predicate;
List<StepExpression> steps = pathExpr.getSteps();
OrderBy orderBy = pathExpr.getOrderBy();
assert steps.size() > 1; // 1 or 0 would have been collapsed ...
Component firstStep = steps.get(0).collapse();
if (firstStep instanceof ContextItem) {
// Remove the context and retry ...
return translatePredicate(new PathExpression(true, steps.subList(1, steps.size()), orderBy), tableName, where);
}
if (firstStep instanceof NameTest) {
// Special case where this is similar to '[a/@id]'
NameTest childName = (NameTest)firstStep;
String alias = newAlias();
builder.joinAllNodesAs(alias).onChildNode(tableName, alias);
if (!childName.isWildcard()) {
where.nodeName(alias).isEqualTo(nameFrom(childName));
}
return translatePredicate(new PathExpression(true, steps.subList(1, steps.size()), orderBy), alias, where);
}
if (firstStep instanceof DescendantOrSelf) {