mirror of https://github.com/apache/openjpa.git
OPENJPA-806: Interface changes (merge Selectable to Visitable) + String Functions (Concat etc) + Detect recursion
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@724402 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
7a6ac4afc7
commit
74c5f3078f
|
@ -19,12 +19,15 @@
|
|||
|
||||
package org.apache.openjpa.persistence.criteria;
|
||||
|
||||
import javax.persistence.CaseExpression;
|
||||
import javax.persistence.DomainObject;
|
||||
import javax.persistence.Expression;
|
||||
import javax.persistence.QueryBuilder;
|
||||
import javax.persistence.QueryDefinition;
|
||||
import javax.persistence.SelectItem;
|
||||
|
||||
import org.apache.openjpa.persistence.query.AbstractDomainObject;
|
||||
import org.apache.openjpa.persistence.query.QueryBuilderImpl;
|
||||
import org.apache.openjpa.persistence.query.QueryDefinitionImpl;
|
||||
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||
|
||||
|
@ -45,7 +48,7 @@ import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
|||
*
|
||||
*/
|
||||
public class TestCriteria extends SingleEMFTestCase {
|
||||
protected QueryBuilder qb;
|
||||
protected QueryBuilderImpl qb;
|
||||
protected StringComparison comparator = new StringComparison();
|
||||
|
||||
public void setUp() {
|
||||
|
@ -53,7 +56,7 @@ public class TestCriteria extends SingleEMFTestCase {
|
|||
Department.class, Employee.class, Exempt.class, Item.class,
|
||||
Manager.class, Person.class, VideoStore.class, Order.class,
|
||||
Customer.class);
|
||||
qb = emf.getQueryBuilder();
|
||||
qb = (QueryBuilderImpl)emf.getQueryBuilder();
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
|
@ -61,14 +64,7 @@ public class TestCriteria extends SingleEMFTestCase {
|
|||
}
|
||||
|
||||
void compare(String s, QueryDefinition q) {
|
||||
String actual = ((QueryDefinitionImpl)q).toJPQL();
|
||||
if (!comparator.compare(s,actual)) {
|
||||
fail("\r\nExpected: [" + s + "]\r\nActual : [" + actual + "]");
|
||||
}
|
||||
}
|
||||
|
||||
void compare(String s, DomainObject q) {
|
||||
String actual = ((AbstractDomainObject)q).getOwner().toJPQL();
|
||||
String actual = qb.toJPQL(q);
|
||||
if (!comparator.compare(s,actual)) {
|
||||
fail("\r\nExpected: [" + s + "]\r\nActual : [" + actual + "]");
|
||||
}
|
||||
|
@ -353,11 +349,11 @@ public class TestCriteria extends SingleEMFTestCase {
|
|||
DomainObject address = customer.join("address");
|
||||
q.where(address.get("state").equal("CA"))
|
||||
.select(order.get("quantity"), address.get("zipcode"))
|
||||
.orderBy(order.get("quantity"), address.get("zipcode"));
|
||||
.orderBy(order.get("quantity").desc(), address.get("zipcode"));
|
||||
String jpql = "SELECT o.quantity, a.zipcode"
|
||||
+ " FROM Customer c JOIN c.orders o JOIN c.address a"
|
||||
+ " WHERE a.state = 'CA'"
|
||||
+ " ORDER BY o.quantity, a.zipcode";
|
||||
+ " ORDER BY o.quantity DESC, a.zipcode";
|
||||
compare(jpql, q);
|
||||
}
|
||||
|
||||
|
@ -370,10 +366,10 @@ public class TestCriteria extends SingleEMFTestCase {
|
|||
.and(a.get("county").equal("Santa Clara")))
|
||||
.orderBy(o.get("quantity"), taxedCost, a.get("zipcode"));
|
||||
|
||||
String jpql = "SELECT o.quantity, o.cost*1.08, a.zipcode"
|
||||
String jpql = "SELECT o.quantity, o.cost*1.08 as o2, a.zipcode"
|
||||
+ " FROM Order o JOIN o.customer c JOIN c.address a"
|
||||
+ " WHERE a.state = 'CA' AND a.county = 'Santa Clara'"
|
||||
+ " ORDER BY o.quantity, o.cost*1.08, a.zipcode";
|
||||
+ " ORDER BY o.quantity, o2, a.zipcode";
|
||||
|
||||
compare(jpql, o);
|
||||
}
|
||||
|
@ -410,4 +406,54 @@ public class TestCriteria extends SingleEMFTestCase {
|
|||
compare(jpql, customer);
|
||||
}
|
||||
|
||||
public void testTypeList() {
|
||||
DomainObject q = qb.createQueryDefinition(Employee.class);
|
||||
q.where(q.type().in(Exempt.class, Contractor.class));
|
||||
|
||||
String jpql = "SELECT e "
|
||||
+ " FROM Employee e"
|
||||
+ " WHERE TYPE(e) IN (Exempt, Contractor)";
|
||||
compare(jpql, q);
|
||||
}
|
||||
|
||||
public void testStringList() {
|
||||
DomainObject q = qb.createQueryDefinition(Employee.class);
|
||||
q.where(q.get("country").in("USA", "UK", "France"));
|
||||
|
||||
String jpql = "SELECT e "
|
||||
+ " FROM Employee e"
|
||||
+ " WHERE e.country IN ('USA', 'UK', 'France')";
|
||||
compare(jpql, q);
|
||||
}
|
||||
|
||||
public void testConcat() {
|
||||
DomainObject e = qb.createQueryDefinition(Employee.class);
|
||||
DomainObject f = e.join("frequentFlierPlan");
|
||||
Expression c =
|
||||
e.generalCase().when(f.get("annualMiles").greaterThan(50000)).then("Platinum")
|
||||
.when(f.get("annualMiles").greaterThan(25000)).then("Gold")
|
||||
.elseCase("");
|
||||
e.select(e.get("name"), f.get("name"), e.concat(c,e.literal("Frequent Flyer")));
|
||||
|
||||
String jpql = "SELECT e.name, f.name, CONCAT("
|
||||
+ " CASE WHEN f.annualMiles > 50000 THEN 'Platinum'"
|
||||
+ " WHEN f.annualMiles > 25000 THEN 'Gold'"
|
||||
+ " ELSE '' END, 'Frequent Flyer')"
|
||||
+ "FROM Employee e JOIN e.frequentFlierPlan f";
|
||||
|
||||
compare(jpql, e);
|
||||
}
|
||||
|
||||
public void testRecursiveDefinitionIsNotAllowed() {
|
||||
DomainObject q = qb.createQueryDefinition(Customer.class);
|
||||
q.where(q.exists().and(q.get("name").equal("wrong")));
|
||||
|
||||
try {
|
||||
compare("?", q);
|
||||
fail();
|
||||
} catch (RuntimeException e) {
|
||||
// good
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -343,7 +343,7 @@ public class EntityManagerFactoryImpl
|
|||
}
|
||||
|
||||
public QueryBuilder getQueryBuilder() {
|
||||
return new QueryBuilderImpl();
|
||||
return new QueryBuilderImpl(this);
|
||||
}
|
||||
|
||||
public Set<String> getSupportedProperties() {
|
||||
|
|
|
@ -66,6 +66,7 @@ import org.apache.openjpa.meta.ClassMetaData;
|
|||
import org.apache.openjpa.meta.FieldMetaData;
|
||||
import org.apache.openjpa.meta.QueryMetaData;
|
||||
import org.apache.openjpa.meta.SequenceMetaData;
|
||||
import org.apache.openjpa.persistence.query.QueryBuilderImpl;
|
||||
import org.apache.openjpa.util.Exceptions;
|
||||
import org.apache.openjpa.util.ImplHelper;
|
||||
import org.apache.openjpa.util.RuntimeExceptionTranslator;
|
||||
|
@ -1395,12 +1396,14 @@ public class EntityManagerImpl
|
|||
"JPA 2.0 - Method not yet implemented");
|
||||
}
|
||||
|
||||
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) {
|
||||
public <T> T find(Class<T> entityClass, Object primaryKey,
|
||||
LockModeType lockMode) {
|
||||
throw new UnsupportedOperationException(
|
||||
"JPA 2.0 - Method not yet implemented");
|
||||
}
|
||||
|
||||
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties) {
|
||||
public <T> T find(Class<T> entityClass, Object primaryKey,
|
||||
LockModeType lockMode, Map<String, Object> properties) {
|
||||
throw new UnsupportedOperationException(
|
||||
"JPA 2.0 - Method not yet implemented");
|
||||
}
|
||||
|
@ -1411,8 +1414,7 @@ public class EntityManagerImpl
|
|||
}
|
||||
|
||||
public QueryBuilder getQueryBuilder() {
|
||||
throw new UnsupportedOperationException(
|
||||
"JPA 2.0 - Method not yet implemented");
|
||||
return new QueryBuilderImpl(_emf);
|
||||
}
|
||||
|
||||
public Set<String> getSupportedProperties() {
|
||||
|
@ -1420,7 +1422,8 @@ public class EntityManagerImpl
|
|||
"JPA 2.0 - Method not yet implemented");
|
||||
}
|
||||
|
||||
public void lock(Object entity, LockModeType lockMode, Map<String, Object> properties) {
|
||||
public void lock(Object entity, LockModeType lockMode, Map<String,
|
||||
Object> properties) {
|
||||
throw new UnsupportedOperationException(
|
||||
"JPA 2.0 - Method not yet implemented");
|
||||
}
|
||||
|
@ -1430,7 +1433,8 @@ public class EntityManagerImpl
|
|||
"JPA 2.0 - Method not yet implemented");
|
||||
}
|
||||
|
||||
public void refresh(Object entity, LockModeType lockMode, Map<String, Object> properties) {
|
||||
public void refresh(Object entity, LockModeType lockMode, Map<String,
|
||||
Object> properties) {
|
||||
throw new UnsupportedOperationException(
|
||||
"JPA 2.0 - Method not yet implemented");
|
||||
}
|
||||
|
|
|
@ -390,6 +390,5 @@ public abstract class AbstractDomainObject extends AbstractPath
|
|||
join.setAlias(ctx);
|
||||
}
|
||||
|
||||
abstract public String asJoinable(AliasContext ctx);
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ package org.apache.openjpa.persistence.query;
|
|||
|
||||
import javax.persistence.Aggregate;
|
||||
import javax.persistence.Expression;
|
||||
import javax.persistence.OrderByItem;
|
||||
import javax.persistence.PathExpression;
|
||||
import javax.persistence.Predicate;
|
||||
|
||||
|
@ -113,12 +112,4 @@ abstract class AbstractPath extends ExpressionImpl implements
|
|||
public Expression type() {
|
||||
return new TypeExpression(this);
|
||||
}
|
||||
|
||||
public OrderByItem asc() {
|
||||
return new OrderableItem(this, Boolean.TRUE);
|
||||
}
|
||||
|
||||
public OrderByItem desc() {
|
||||
return new OrderableItem(this, Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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.openjpa.persistence.query;
|
||||
|
||||
/**
|
||||
* An abstract implementation that throws UnsupportedOperationException on
|
||||
* every method.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
abstract class AbstractVisitable implements Visitable {
|
||||
|
||||
public String asExpression(AliasContext ctx) {
|
||||
throw new UnsupportedOperationException(this.getClass().getName());
|
||||
}
|
||||
|
||||
public String asProjection(AliasContext ctx) {
|
||||
throw new UnsupportedOperationException(this.getClass().getName());
|
||||
}
|
||||
|
||||
public String getAliasHint(AliasContext ctx) {
|
||||
throw new UnsupportedOperationException(this.getClass().getName());
|
||||
}
|
||||
|
||||
public void setAlias(AliasContext ctx) {
|
||||
throw new UnsupportedOperationException(this.getClass().getName());
|
||||
}
|
||||
|
||||
public String asJoinable(AliasContext ctx) {
|
||||
throw new UnsupportedOperationException(this.getClass().getName());
|
||||
}
|
||||
|
||||
}
|
|
@ -20,12 +20,21 @@ package org.apache.openjpa.persistence.query;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
import javax.persistence.Expression;
|
||||
|
||||
import org.apache.openjpa.meta.MetaDataRepository;
|
||||
|
||||
class AliasContext {
|
||||
private Stack<Object> _operating = new Stack<Object>();
|
||||
private Map<ExpressionImpl, String> _aliases =
|
||||
new HashMap<ExpressionImpl, String>();
|
||||
private final MetaDataRepository _repos;
|
||||
|
||||
public AliasContext(MetaDataRepository repos) {
|
||||
_repos = repos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets alias for the given Expression or gets the alias if the given
|
||||
|
@ -40,10 +49,10 @@ class AliasContext {
|
|||
String alias = _aliases.get(path);
|
||||
if (alias != null)
|
||||
return alias;
|
||||
alias = path.getAliasHint().substring(0,1).toLowerCase();
|
||||
alias = path.getAliasHint(this).substring(0,1).toLowerCase();
|
||||
int i = 2;
|
||||
while (_aliases.containsValue(alias)) {
|
||||
alias = alias + i;
|
||||
alias = alias.substring(0,1) + i;
|
||||
i++;
|
||||
}
|
||||
_aliases.put(path, alias);
|
||||
|
@ -57,4 +66,16 @@ class AliasContext {
|
|||
public boolean hasAlias(Expression path) {
|
||||
return _aliases.containsKey(path);
|
||||
}
|
||||
|
||||
public AliasContext push(Object e) {
|
||||
if (_operating.contains(e))
|
||||
throw new RuntimeException(e + " is already in this ctx");
|
||||
_operating.add(e);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getEntityName(Class cls) {
|
||||
return cls.getSimpleName();
|
||||
// return _repos.getMetaData(cls, null, true).getTypeAlias();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package org.apache.openjpa.persistence.query;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ArrayExpression extends ExpressionImpl {
|
||||
private final Object[] _values;
|
||||
|
||||
public ArrayExpression(Object[] values) {
|
||||
_values = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asExpression(AliasContext ctx) {
|
||||
StringBuffer tmp = new StringBuffer("(");
|
||||
for (int i = 0; i < _values.length; i++) {
|
||||
tmp.append(JPQLHelper.toJPQL(ctx, _values[i]))
|
||||
.append(i == _values.length-1 ? "" : ", ");
|
||||
}
|
||||
tmp.append(")");
|
||||
return tmp.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asProjection(AliasContext ctx) {
|
||||
return asExpression(ctx);
|
||||
}
|
||||
|
||||
}
|
|
@ -27,7 +27,8 @@ import javax.persistence.Predicate;
|
|||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
class BinaryExpressionPredicate implements Predicate, Visitable {
|
||||
class BinaryExpressionPredicate extends AbstractVisitable
|
||||
implements Predicate, Visitable {
|
||||
protected final Expression _e1;
|
||||
protected final Expression _e2;
|
||||
protected final BinaryConditionalOperator _op;
|
||||
|
|
|
@ -34,9 +34,7 @@ public enum BinaryFunctionalOperator {
|
|||
MOD("MOD"),
|
||||
PLUS("+"),
|
||||
RANGE(","),
|
||||
SUBSTR("SUBSTR"),
|
||||
TIMES("*"),
|
||||
TRIM("TRIM");
|
||||
TIMES("*");
|
||||
|
||||
private final String _symbol;
|
||||
|
||||
|
|
|
@ -56,7 +56,9 @@ public class BinaryOperatorExpression extends ExpressionImpl {
|
|||
}
|
||||
|
||||
public String asProjection(AliasContext ctx) {
|
||||
return ((Selectable)_e1).asProjection(ctx) + _op
|
||||
+ ((Selectable)_e2).asProjection(ctx);
|
||||
return ((Visitable)_e1).asProjection(ctx) + _op
|
||||
+ ((Visitable)_e2).asProjection(ctx)
|
||||
+ (ctx.hasAlias(this) ? " as " + ctx.getAlias(this) : "");
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,15 +18,15 @@
|
|||
*/
|
||||
package org.apache.openjpa.persistence.query;
|
||||
|
||||
import javax.persistence.SelectItem;
|
||||
|
||||
/**
|
||||
* An item that can be selected in a query.
|
||||
* Denotes CONCAT(e1,e2,..) Expression.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public interface Selectable extends SelectItem {
|
||||
String asProjection(AliasContext ctx);
|
||||
void setAlias(AliasContext ctx);
|
||||
public class ConcatExpression extends UnaryOperatorExpression {
|
||||
public ConcatExpression(ArrayExpression op) {
|
||||
super(op, UnaryFunctionalOperator.CONCAT);
|
||||
}
|
||||
}
|
|
@ -33,28 +33,13 @@ class ConstantExpression extends ExpressionImpl {
|
|||
_value = value;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return _value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asExpression(AliasContext ctx) {
|
||||
if (_value.getClass().isArray()) {
|
||||
return Arrays.asList((Object[])_value).toString();
|
||||
}
|
||||
return quoted(_value);
|
||||
return JPQLHelper.toJPQL(ctx, _value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asProjection(AliasContext ctx) {
|
||||
return asExpression(ctx);
|
||||
}
|
||||
|
||||
String quoted(Object o) {
|
||||
if (o instanceof String)
|
||||
return "'" + o + "'";
|
||||
if (o instanceof Class)
|
||||
return ((Class)o).getSimpleName();
|
||||
return o.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,28 +36,14 @@ public class ElseExpression extends ExpressionImpl {
|
|||
@Override
|
||||
public String asExpression(AliasContext ctx) {
|
||||
return _caseClause.toJPQL(ctx)
|
||||
+ " ELSE " + toJPQL(ctx, _elseClause)
|
||||
+ " ELSE " + JPQLHelper.toJPQL(ctx, _elseClause)
|
||||
+ " END ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asProjection(AliasContext ctx) {
|
||||
return _caseClause.toJPQL(ctx)
|
||||
+ " ELSE " + toJPQL(ctx, _elseClause)
|
||||
+ " ELSE " + JPQLHelper.toJPQL(ctx, _elseClause)
|
||||
+ " END ";
|
||||
}
|
||||
|
||||
String toJPQL(AliasContext ctx, Object o) {
|
||||
if (o instanceof Visitable) {
|
||||
return ((Visitable)o).asExpression(ctx);
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
String asProjection(AliasContext ctx, Object o) {
|
||||
if (o instanceof Selectable) {
|
||||
return ((Selectable)o).asProjection(ctx);
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@ package org.apache.openjpa.persistence.query;
|
|||
*/
|
||||
public class ExistsExpression extends UnaryExpressionPredicate {
|
||||
public ExistsExpression(QueryDefinitionImpl op) {
|
||||
super(op, UnaryConditionalOperator.EXISTS, UnaryConditionalOperator.EXISTS_NOT);
|
||||
super(op, UnaryConditionalOperator.EXISTS,
|
||||
UnaryConditionalOperator.EXISTS_NOT);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
package org.apache.openjpa.persistence.query;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
|
@ -36,18 +37,19 @@ import javax.persistence.TrimSpec;
|
|||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
abstract class ExpressionImpl implements Expression, Selectable, Visitable {
|
||||
abstract class ExpressionImpl extends AbstractVisitable
|
||||
implements Expression, Visitable {
|
||||
|
||||
public Expression abs() {
|
||||
return new AbsExpression(this);
|
||||
}
|
||||
|
||||
public Expression concat(String... str) {
|
||||
throw new UnsupportedOperationException();
|
||||
return new ConcatExpression(new ArrayExpression(str));
|
||||
}
|
||||
|
||||
public Expression concat(Expression... str) {
|
||||
throw new UnsupportedOperationException();
|
||||
return new ConcatExpression(new ArrayExpression(str));
|
||||
}
|
||||
|
||||
public Expression dividedBy(Number num) {
|
||||
|
@ -59,27 +61,23 @@ abstract class ExpressionImpl implements Expression, Selectable, Visitable {
|
|||
}
|
||||
|
||||
public Predicate in(String... strings) {
|
||||
return new InExpression(this, new ConstantExpression(strings));
|
||||
return new InExpression(this, new ArrayExpression(strings));
|
||||
}
|
||||
|
||||
public Predicate in(Number... nums) {
|
||||
return new InExpression(this,
|
||||
new ConstantExpression(nums));
|
||||
return new InExpression(this, new ArrayExpression(nums));
|
||||
}
|
||||
|
||||
public Predicate in(Enum<?>... enums) {
|
||||
return new InExpression(this,
|
||||
new ConstantExpression(enums));
|
||||
return new InExpression(this, new ArrayExpression(enums));
|
||||
}
|
||||
|
||||
public Predicate in(Class... classes) {
|
||||
return new InExpression(this,
|
||||
new ConstantExpression(classes));
|
||||
return new InExpression(this, new ArrayExpression(classes));
|
||||
}
|
||||
|
||||
public Predicate in(Expression... params) {
|
||||
return new InExpression(this,
|
||||
new ConstantExpression(params));
|
||||
return new InExpression(this, new ArrayExpression(params));
|
||||
}
|
||||
|
||||
public Predicate in(Subquery subquery) {
|
||||
|
@ -95,7 +93,7 @@ abstract class ExpressionImpl implements Expression, Selectable, Visitable {
|
|||
}
|
||||
|
||||
public Expression locate(String str) {
|
||||
return locate(str, 0);
|
||||
return new LocateExpression(this, str, 0);
|
||||
}
|
||||
|
||||
public Expression locate(Expression expr) {
|
||||
|
@ -103,11 +101,11 @@ abstract class ExpressionImpl implements Expression, Selectable, Visitable {
|
|||
}
|
||||
|
||||
public Expression locate(String str, int position) {
|
||||
return new LocateExpression(this, new ConstantExpression(str), position);
|
||||
return new LocateExpression(this, str, position);
|
||||
}
|
||||
|
||||
public Expression locate(String str, Expression position) {
|
||||
return new LocateExpression(this, new ConstantExpression(str), position);
|
||||
return new LocateExpression(this, str, position);
|
||||
}
|
||||
|
||||
public Expression locate(Expression str, int position) {
|
||||
|
@ -215,15 +213,15 @@ abstract class ExpressionImpl implements Expression, Selectable, Visitable {
|
|||
}
|
||||
|
||||
public Expression upper() {
|
||||
return new ToUpperExpression(this);
|
||||
return new UpperExpression(this);
|
||||
}
|
||||
|
||||
public OrderByItem asc() {
|
||||
throw new UnsupportedOperationException(this.toString());
|
||||
return new OrderableItem(this, true);
|
||||
}
|
||||
|
||||
public OrderByItem desc() {
|
||||
throw new UnsupportedOperationException(this.toString());
|
||||
return new OrderableItem(this, false);
|
||||
}
|
||||
|
||||
public Predicate between(PredicateOperand arg1, PredicateOperand arg2) {
|
||||
|
@ -404,7 +402,7 @@ abstract class ExpressionImpl implements Expression, Selectable, Visitable {
|
|||
}
|
||||
|
||||
public Predicate like(PredicateOperand pattern) {
|
||||
return new LikeExpression(this, (Expression)pattern, null);
|
||||
return new LikeExpression(this, (Expression)pattern);
|
||||
}
|
||||
|
||||
public Predicate like(PredicateOperand pattern, PredicateOperand escChar) {
|
||||
|
@ -416,7 +414,7 @@ abstract class ExpressionImpl implements Expression, Selectable, Visitable {
|
|||
}
|
||||
|
||||
public Predicate like(String pattern) {
|
||||
return new LikeExpression(this, new ConstantExpression(pattern), null);
|
||||
return new LikeExpression(this, new ConstantExpression(pattern));
|
||||
}
|
||||
|
||||
public Predicate like(String pattern, PredicateOperand escapeChar) {
|
||||
|
@ -468,7 +466,7 @@ abstract class ExpressionImpl implements Expression, Selectable, Visitable {
|
|||
ctx.getAlias(this);
|
||||
}
|
||||
|
||||
public String getAliasHint() {
|
||||
public String getAliasHint(AliasContext ctx) {
|
||||
return "o";
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@ import javax.persistence.FetchJoinObject;
|
|||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class FetchPath implements FetchJoinObject, Visitable {
|
||||
public class FetchPath extends AbstractVisitable
|
||||
implements FetchJoinObject, Visitable {
|
||||
private NavigationPath _path;
|
||||
private PathOperator _joinType;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.apache.openjpa.persistence.query;
|
||||
|
||||
import javax.persistence.Expression;
|
||||
import javax.persistence.Subquery;
|
||||
|
||||
/**
|
||||
* Denotes e1 IN (e2) Expression.
|
||||
|
@ -9,7 +10,13 @@ import javax.persistence.Expression;
|
|||
*
|
||||
*/
|
||||
public class InExpression extends BinaryExpressionPredicate {
|
||||
public InExpression(Expression op, Expression op2) {
|
||||
super(op, BinaryConditionalOperator.IN, BinaryConditionalOperator.IN_NOT, op2);
|
||||
public InExpression(Expression op, ArrayExpression op2) {
|
||||
super(op, BinaryConditionalOperator.IN,
|
||||
BinaryConditionalOperator.IN_NOT, op2);
|
||||
}
|
||||
|
||||
public InExpression(Expression op, Expression subquery) {
|
||||
super(op, BinaryConditionalOperator.IN,
|
||||
BinaryConditionalOperator.IN_NOT, subquery);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,9 +25,17 @@ package org.apache.openjpa.persistence.query;
|
|||
*
|
||||
*/
|
||||
public class JPQLHelper {
|
||||
private static final String SINGLE_QUOTE = "'";
|
||||
|
||||
static String toJPQL(AliasContext ctx, Object o) {
|
||||
if (o == null)
|
||||
return "NULL";
|
||||
if (o instanceof Visitable)
|
||||
return ((Visitable)o).asExpression(ctx);
|
||||
if (o instanceof Class)
|
||||
return ctx.getEntityName((Class)o);
|
||||
if (o instanceof String)
|
||||
return SINGLE_QUOTE + (String)o + SINGLE_QUOTE;
|
||||
return o.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ public class JoinPath extends AbstractDomainObject implements DomainObject {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getAliasHint() {
|
||||
public String getAliasHint(AliasContext ctx) {
|
||||
return getLastSegment();
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ public class JoinPath extends AbstractDomainObject implements DomainObject {
|
|||
return (AbstractDomainObject)super.getParent();
|
||||
}
|
||||
|
||||
// @Override
|
||||
@Override
|
||||
public String asJoinable(AliasContext ctx) {
|
||||
StringBuffer tmp = new StringBuffer(getOperator().toString());
|
||||
tmp.append(getParent().asProjection(ctx))
|
||||
|
|
|
@ -27,18 +27,28 @@ import javax.persistence.Expression;
|
|||
*
|
||||
*/
|
||||
public class LikeExpression extends BinaryExpressionPredicate {
|
||||
public LikeExpression(Expression op1, Expression op2, Object echar) {
|
||||
super(escape(op1, echar), BinaryConditionalOperator.LIKE,
|
||||
BinaryConditionalOperator.LIKE_NOT, escape(op2, echar));
|
||||
private final Object _echar;
|
||||
private final boolean _escaped;
|
||||
|
||||
public LikeExpression(Expression e, Expression pattern, Object echar) {
|
||||
super(e, BinaryConditionalOperator.LIKE,
|
||||
BinaryConditionalOperator.LIKE_NOT, pattern);
|
||||
_echar = echar;
|
||||
_escaped = true;
|
||||
}
|
||||
|
||||
static Expression escape(Expression o, Object echar) {
|
||||
if (echar != null && o instanceof ConstantExpression
|
||||
&& ((ConstantExpression)o).getValue() instanceof String) {
|
||||
String escapeChar = echar.toString();
|
||||
return new ConstantExpression(escapeChar + o.toString() + escapeChar);
|
||||
}
|
||||
return o;
|
||||
public LikeExpression(Expression e, Expression pattern) {
|
||||
super(e, BinaryConditionalOperator.LIKE,
|
||||
BinaryConditionalOperator.LIKE_NOT, pattern);
|
||||
|
||||
_echar = null;
|
||||
_escaped = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asExpression(AliasContext ctx) {
|
||||
return super.asExpression(ctx)
|
||||
+ (_escaped ? "ESCAPE " + JPQLHelper.toJPQL(ctx, _echar) : "");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,13 +21,42 @@ package org.apache.openjpa.persistence.query;
|
|||
import javax.persistence.Expression;
|
||||
|
||||
/**
|
||||
* Denotes LOCATE(e)
|
||||
* Denotes LOCATE(e1, e2, n) Expression.
|
||||
* e1 : string to be located
|
||||
* e2 : string to be searched
|
||||
* n : starting poistion in e2, default is 1
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class LocateExpression extends BinaryOperatorExpression {
|
||||
public LocateExpression(Expression op, Expression op2, Object pos) {
|
||||
super(op, BinaryFunctionalOperator.LOCATE, op2);
|
||||
private final Expression _start;
|
||||
|
||||
public LocateExpression(Expression key, String str, int start) {
|
||||
super(key, BinaryFunctionalOperator.LOCATE, new ConstantExpression(str));
|
||||
_start = new ConstantExpression(start);
|
||||
}
|
||||
|
||||
public LocateExpression(Expression key, Expression str, int start) {
|
||||
super(key, BinaryFunctionalOperator.LOCATE, str);
|
||||
_start = new ConstantExpression(start);
|
||||
}
|
||||
|
||||
public LocateExpression(Expression key, String str, Expression start) {
|
||||
super(key, BinaryFunctionalOperator.LOCATE, new ConstantExpression(str));
|
||||
_start = start;
|
||||
}
|
||||
|
||||
public LocateExpression(Expression key, Expression str, Expression start) {
|
||||
super(key, BinaryFunctionalOperator.LOCATE, str);
|
||||
_start = start;
|
||||
}
|
||||
|
||||
public String asExpression(AliasContext ctx) {
|
||||
return _op + "(" + ((Visitable)_e1).asExpression(ctx) + ","
|
||||
+ ((Visitable)_e2).asExpression(ctx)
|
||||
+ (_start == null ? "" : "," + ((Visitable)_start).asExpression(ctx))
|
||||
+ ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@ import javax.persistence.Predicate;
|
|||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class LogicalPredicate implements Predicate, Visitable {
|
||||
public class LogicalPredicate extends AbstractVisitable
|
||||
implements Predicate, Visitable {
|
||||
private final Predicate _p1;
|
||||
private final Predicate _p2;
|
||||
private final ConditionalOperator _op;
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
package org.apache.openjpa.persistence.query;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -31,7 +30,8 @@ import javax.persistence.SelectItem;
|
|||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class NewInstance implements Selectable {
|
||||
public class NewInstance extends AbstractVisitable
|
||||
implements SelectItem, Visitable {
|
||||
private final Class _cls;
|
||||
private List<SelectItem> _args;
|
||||
NewInstance(Class cls, SelectItem...args) {
|
||||
|
@ -59,12 +59,9 @@ public class NewInstance implements Selectable {
|
|||
int N = _args.size();
|
||||
for (SelectItem arg : _args) {
|
||||
i++;
|
||||
tmp.append(((Selectable)arg).asProjection(ctx))
|
||||
tmp.append(((Visitable)arg).asProjection(ctx))
|
||||
.append(i == N ? ")" : ",");
|
||||
}
|
||||
return tmp.toString();
|
||||
}
|
||||
|
||||
public void setAlias(AliasContext ctx) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@ public class OperatorPath extends AbstractDomainObject {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getAliasHint() {
|
||||
return getParent().getAliasHint();
|
||||
public String getAliasHint(AliasContext ctx) {
|
||||
return getParent().getAliasHint(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -26,22 +26,27 @@ import javax.persistence.OrderByItem;
|
|||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class OrderableItem implements OrderByItem {
|
||||
public class OrderableItem extends AbstractVisitable
|
||||
implements OrderByItem, Visitable {
|
||||
private final Boolean _asc;
|
||||
private final ExpressionImpl path;
|
||||
private final ExpressionImpl _e;
|
||||
|
||||
OrderableItem(ExpressionImpl path) {
|
||||
this(path, null);
|
||||
}
|
||||
|
||||
public ExpressionImpl getExpression() {
|
||||
return _e;
|
||||
}
|
||||
|
||||
OrderableItem(ExpressionImpl path, Boolean asc) {
|
||||
super();
|
||||
this._asc = asc;
|
||||
this.path = path;
|
||||
this._e = path;
|
||||
}
|
||||
|
||||
public String toJPQL(AliasContext ctx) {
|
||||
return path.asExpression(ctx) + " "
|
||||
+ (_asc == null ? "" : (_asc ? " ASC " : "DESC"));
|
||||
public String asExpression(AliasContext ctx) {
|
||||
return (ctx.hasAlias(_e) ? ctx.getAlias(_e) : _e.asExpression(ctx))
|
||||
+ (_asc == null ? "" : (_asc ? " ASC " : " DESC"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,13 +24,19 @@ package org.apache.openjpa.persistence.query;
|
|||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class ParameterExpression extends ConstantExpression {
|
||||
public class ParameterExpression extends ExpressionImpl {
|
||||
private final String _name;
|
||||
public ParameterExpression(String name) {
|
||||
super(name);
|
||||
_name = ":" + name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asExpression(AliasContext ctx) {
|
||||
return ":" + getValue();
|
||||
return _name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asProjection(AliasContext ctx) {
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,11 +18,19 @@
|
|||
*/
|
||||
package org.apache.openjpa.persistence.query;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.DomainObject;
|
||||
import javax.persistence.PathExpression;
|
||||
import javax.persistence.QueryBuilder;
|
||||
import javax.persistence.QueryDefinition;
|
||||
|
||||
import org.apache.openjpa.meta.ClassMetaData;
|
||||
import org.apache.openjpa.meta.MetaDataRepository;
|
||||
import org.apache.openjpa.persistence.EntityManagerFactoryImpl;
|
||||
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory;
|
||||
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
|
||||
|
||||
/**
|
||||
* The factory for QueryDefinition.
|
||||
*
|
||||
|
@ -31,25 +39,39 @@ import javax.persistence.QueryDefinition;
|
|||
*
|
||||
*/
|
||||
public class QueryBuilderImpl implements QueryBuilder {
|
||||
private final OpenJPAEntityManagerFactorySPI _emf;
|
||||
|
||||
public QueryBuilderImpl(OpenJPAEntityManagerFactorySPI emf) {
|
||||
_emf = emf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a QueryDefinition without a domain root.
|
||||
* Creates a QueryDefinition without a domain.
|
||||
*/
|
||||
public QueryDefinition createQueryDefinition() {
|
||||
return new QueryDefinitionImpl(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a QueryDefinition with given class as domain root.
|
||||
* Creates a QueryDefinition with given class as domain.
|
||||
*/
|
||||
public DomainObject createQueryDefinition(Class root) {
|
||||
return new QueryDefinitionImpl(this).addRoot(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a QueryDefinition that can be used as a subquery to some
|
||||
* other query.
|
||||
* Creates a QueryDefinition that can be used a correlated subquery
|
||||
* with the given path as domain.
|
||||
*/
|
||||
public DomainObject createSubqueryDefinition(PathExpression path) {
|
||||
return new QueryDefinitionImpl(this).addSubqueryRoot(path);
|
||||
}
|
||||
|
||||
public String toJPQL(QueryDefinition query) {
|
||||
MetaDataRepository repos = null;//_emf.getConfiguration().getMetaDataRepositoryInstance()
|
||||
AliasContext ctx = new AliasContext(repos);
|
||||
if (query instanceof AbstractDomainObject)
|
||||
return ((AbstractDomainObject)query).getOwner().asExpression(ctx);
|
||||
return ((QueryDefinitionImpl)query).asExpression(ctx);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,16 +49,21 @@ public class QueryDefinitionImpl extends ExpressionImpl
|
|||
private final QueryBuilderImpl _builder;
|
||||
private List<AbstractDomainObject> _domains;
|
||||
private List<PathExpression> _groupBys;
|
||||
private List<Subquery> _subqueries;
|
||||
private List<OrderableItem> _orderBys;
|
||||
private List<Selectable> _projections;
|
||||
private List<SelectItem> _projections;
|
||||
private boolean _distinct;
|
||||
private Predicate _where;
|
||||
private Predicate _having;
|
||||
|
||||
private static enum Visit {PROJECTION, EXPRESSION, JOINABLE};
|
||||
|
||||
protected static Localizer _loc =
|
||||
Localizer.forPackage(QueryDefinitionImpl.class);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param builder
|
||||
*/
|
||||
protected QueryDefinitionImpl(QueryBuilderImpl builder) {
|
||||
_builder = builder;
|
||||
}
|
||||
|
@ -73,14 +78,9 @@ public class QueryDefinitionImpl extends ExpressionImpl
|
|||
}
|
||||
|
||||
public DomainObject addSubqueryRoot(PathExpression path) {
|
||||
if (_domains != null && _domains.contains(path))
|
||||
throw new IllegalArgumentException(_loc.get("query-subroot-clash",
|
||||
path).toString());
|
||||
AbstractPath impl = (AbstractPath)path;
|
||||
if (_subqueries == null)
|
||||
_subqueries = new ArrayList<Subquery>();
|
||||
AbstractDomainObject newRoot = new NavigationPath(this, impl.getParent(),
|
||||
impl.getLastSegment().toString());
|
||||
AbstractDomainObject newRoot = new NavigationPath(this,
|
||||
impl.getParent(), impl.getLastSegment().toString());
|
||||
addDomain(newRoot);
|
||||
return newRoot;
|
||||
}
|
||||
|
@ -229,11 +229,13 @@ public class QueryDefinitionImpl extends ExpressionImpl
|
|||
public QueryDefinition orderBy(OrderByItem... orderByItems) {
|
||||
if (_orderBys == null)
|
||||
_orderBys = new ArrayList<OrderableItem>();
|
||||
else
|
||||
_orderBys.clear();
|
||||
for (OrderByItem i : orderByItems) {
|
||||
if (i instanceof OrderableItem)
|
||||
_orderBys.add((OrderableItem)i);
|
||||
else
|
||||
_orderBys.add(new OrderableItem((ExpressionImpl)i, null));
|
||||
_orderBys.add(new OrderableItem((ExpressionImpl)i));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -241,6 +243,8 @@ public class QueryDefinitionImpl extends ExpressionImpl
|
|||
public QueryDefinition orderBy(List<OrderByItem> orderByItemList) {
|
||||
if (_orderBys == null)
|
||||
_orderBys = new ArrayList<OrderableItem>();
|
||||
else
|
||||
_orderBys.clear();
|
||||
for (OrderByItem i : orderByItemList) {
|
||||
if (i instanceof OrderableItem)
|
||||
_orderBys.add((OrderableItem)i);
|
||||
|
@ -276,13 +280,13 @@ public class QueryDefinitionImpl extends ExpressionImpl
|
|||
|
||||
private QueryDefinition select(List<SelectItem> items, boolean isDistinct) {
|
||||
if (_projections == null) {
|
||||
_projections = new ArrayList<Selectable>();
|
||||
_projections = new ArrayList<SelectItem>();
|
||||
} else {
|
||||
_projections.clear();
|
||||
}
|
||||
_distinct = isDistinct;
|
||||
for (SelectItem item : items)
|
||||
_projections.add((Selectable)item);
|
||||
_projections.add(item);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -323,78 +327,48 @@ public class QueryDefinitionImpl extends ExpressionImpl
|
|||
return this;
|
||||
}
|
||||
|
||||
private List<Selectable> getProjections() {
|
||||
private List<SelectItem> getProjections() {
|
||||
if (_projections == null) {
|
||||
List<Selectable> defaultProjection = new ArrayList<Selectable>();
|
||||
List<SelectItem> defaultProjection = new ArrayList<SelectItem>();
|
||||
defaultProjection.add(_domains.get(0));
|
||||
return defaultProjection;
|
||||
}
|
||||
return _projections;
|
||||
}
|
||||
|
||||
public String toJPQL() {
|
||||
return asExpression(new AliasContext());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public String asExpression(AliasContext ctx) {
|
||||
ctx.push(this);
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
registerDomains(ctx);
|
||||
buffer.append("SELECT ");
|
||||
if (_distinct)
|
||||
buffer.append("DISTINCT ");
|
||||
List<Selectable> projs = getProjections();
|
||||
for (int i=0; i < projs.size(); i++) {
|
||||
projs.get(i).setAlias(ctx);
|
||||
buffer.append(projs.get(i).asProjection(ctx));
|
||||
if (i != projs.size()-1)
|
||||
buffer.append(",");
|
||||
}
|
||||
|
||||
fillBuffer(_distinct ? "SELECT DISTINCT " : "SELECT ", buffer, ctx,
|
||||
getProjections(), Visit.PROJECTION);
|
||||
buffer.append(" FROM ");
|
||||
for (int i=0; _domains != null && i < _domains.size(); i++) {
|
||||
buffer.append(_domains.get(i).asJoinable(ctx));
|
||||
List<JoinPath> joins = _domains.get(i).getJoins();
|
||||
if (joins != null) {
|
||||
for (int j = 0; j < joins.size(); j++) {
|
||||
buffer.append(joins.get(j).asJoinable(ctx));
|
||||
}
|
||||
}
|
||||
List<FetchPath> fetchJoins = _domains.get(i).getFetchJoins();
|
||||
if (fetchJoins != null) {
|
||||
for (int j = 0; j < fetchJoins.size(); j++) {
|
||||
buffer.append(fetchJoins.get(j).asExpression(ctx));
|
||||
}
|
||||
}
|
||||
|
||||
fillBuffer(" ", buffer, ctx, _domains.get(i).getJoins(),
|
||||
Visit.JOINABLE);
|
||||
fillBuffer(" ", buffer, ctx, _domains.get(i).getFetchJoins(),
|
||||
Visit.EXPRESSION);
|
||||
if (i != _domains.size()-1)
|
||||
buffer.append(",");
|
||||
}
|
||||
if (_where != null) {
|
||||
buffer.append(" WHERE ").append(((Visitable)_where).asExpression(ctx));
|
||||
buffer.append(" WHERE ")
|
||||
.append(((Visitable)_where).asExpression(ctx));
|
||||
}
|
||||
|
||||
if (_groupBys != null) {
|
||||
buffer.append(" GROUP BY ");
|
||||
for (int i = 0; i<_groupBys.size(); i++) {
|
||||
buffer.append(((ExpressionImpl)_groupBys.get(i)).asExpression(ctx));
|
||||
if (i != _groupBys.size()-1)
|
||||
buffer.append(",");
|
||||
}
|
||||
}
|
||||
fillBuffer(" GROUP BY ", buffer, ctx, _groupBys, Visit.EXPRESSION);
|
||||
|
||||
if (_having != null) {
|
||||
buffer.append(" HAVING ").append(((Visitable)_having).asExpression(ctx));
|
||||
}
|
||||
if (_orderBys != null) {
|
||||
buffer.append(" ORDER BY ");
|
||||
for (int i = 0; i<_orderBys.size(); i++) {
|
||||
buffer.append(((OrderableItem)_orderBys.get(i)).toJPQL(ctx));
|
||||
if (i != _orderBys.size()-1)
|
||||
buffer.append(",");
|
||||
}
|
||||
buffer.append(" HAVING ")
|
||||
.append(((Visitable)_having).asExpression(ctx));
|
||||
}
|
||||
fillBuffer(" ORDER BY ", buffer, ctx, _orderBys, Visit.EXPRESSION);
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
@ -403,6 +377,26 @@ public class QueryDefinitionImpl extends ExpressionImpl
|
|||
return asExpression(ctx);
|
||||
}
|
||||
|
||||
public void fillBuffer(String header, StringBuffer buffer, AliasContext ctx,
|
||||
List list, Visit visit) {
|
||||
if (list == null || list.isEmpty())
|
||||
return;
|
||||
buffer.append(header);
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
Visitable v = (Visitable)list.get(i);
|
||||
switch(visit) {
|
||||
case PROJECTION : buffer.append(v.asProjection(ctx))
|
||||
.append(i != list.size()-1 ? ", " : " ");
|
||||
break;
|
||||
case EXPRESSION : buffer.append(v.asExpression(ctx))
|
||||
.append(i != list.size()-1 ? ", " : " ");
|
||||
break;
|
||||
case JOINABLE : buffer.append(v.asJoinable(ctx));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers each domain with an alias.
|
||||
* @param ctx
|
||||
|
@ -413,12 +407,11 @@ public class QueryDefinitionImpl extends ExpressionImpl
|
|||
domain.setAlias(ctx);
|
||||
}
|
||||
}
|
||||
if (_subqueries != null) {
|
||||
for (Subquery sub : _subqueries) {
|
||||
if (sub instanceof QueryDefinitionImpl)
|
||||
((QueryDefinitionImpl)sub).registerDomains(ctx);
|
||||
else
|
||||
((AbstractDomainObject)sub).setAlias(ctx);
|
||||
if (_orderBys != null) {
|
||||
for (OrderableItem o : _orderBys) {
|
||||
ExpressionImpl e = o.getExpression();
|
||||
if (_projections != null && _projections.contains(e))
|
||||
e.setAlias(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@ public class RootPath extends AbstractDomainObject implements DomainObject {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getAliasHint() {
|
||||
return getLastSegment().getSimpleName();
|
||||
public String getAliasHint(AliasContext ctx) {
|
||||
return ctx.getEntityName(getLastSegment());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -31,7 +31,7 @@ public class RootPath extends AbstractDomainObject implements DomainObject {
|
|||
|
||||
@Override
|
||||
public String asJoinable(AliasContext ctx) {
|
||||
return getLastSegment().getSimpleName() + " " + ctx.getAlias(this);
|
||||
return ctx.getEntityName(getLastSegment()) + " " + ctx.getAlias(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -26,20 +26,37 @@ import javax.persistence.Expression;
|
|||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class SubStringExpression extends BinaryOperatorExpression {
|
||||
public SubStringExpression(Expression op, Expression op2) {
|
||||
this(op, op2, new ConstantExpression(0));
|
||||
public class SubStringExpression extends UnaryOperatorExpression {
|
||||
private final Expression _start;
|
||||
private final Expression _length;
|
||||
public SubStringExpression(Expression op, Expression start) {
|
||||
super(op, UnaryFunctionalOperator.SUBSTR);
|
||||
_start = start;
|
||||
_length = null;
|
||||
}
|
||||
|
||||
public SubStringExpression(Expression op, int start) {
|
||||
this(op, start, 0);
|
||||
super(op, UnaryFunctionalOperator.SUBSTR);
|
||||
_start = new ConstantExpression(start);
|
||||
_length = null;
|
||||
}
|
||||
|
||||
public SubStringExpression(Expression op, int start, int len) {
|
||||
this(op, new ConstantExpression(start), new ConstantExpression(len));
|
||||
super(op, UnaryFunctionalOperator.SUBSTR);
|
||||
_start = new ConstantExpression(start);
|
||||
_length = new ConstantExpression(len);
|
||||
}
|
||||
|
||||
public SubStringExpression(Expression op, Expression op2, Expression pos) {
|
||||
super(op, BinaryFunctionalOperator.SUBSTR, op2);
|
||||
public SubStringExpression(Expression op, Expression start, Expression l) {
|
||||
super(op, UnaryFunctionalOperator.SUBSTR);
|
||||
_start = start;
|
||||
_length = new ConstantExpression(l);
|
||||
}
|
||||
|
||||
public String asExpression(AliasContext ctx) {
|
||||
return _op + "(" + ((Visitable)_e).asExpression(ctx)
|
||||
+ "," + ((Visitable)_start).asExpression(ctx)
|
||||
+ (_length == null ? "" : "," + ((Visitable)_length).asExpression(ctx))
|
||||
+ ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,15 +27,29 @@ import javax.persistence.TrimSpec;
|
|||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class TrimExpression extends BinaryOperatorExpression {
|
||||
TrimSpec _spec;
|
||||
public TrimExpression(Expression op1, char ch, TrimSpec spec) {
|
||||
super(op1, BinaryFunctionalOperator.TRIM, new ConstantExpression(ch));
|
||||
public class TrimExpression extends UnaryOperatorExpression {
|
||||
private final Expression _trimChar;
|
||||
private final TrimSpec _spec;
|
||||
private static final String BLANK = "' '";
|
||||
|
||||
public TrimExpression(Expression op, char ch, TrimSpec spec) {
|
||||
super(op, UnaryFunctionalOperator.TRIM);
|
||||
_trimChar = new ConstantExpression(ch);
|
||||
_spec = spec;
|
||||
}
|
||||
|
||||
public TrimExpression(Expression op, Expression ch, TrimSpec spec) {
|
||||
super(op, UnaryFunctionalOperator.TRIM);
|
||||
_trimChar = ch;
|
||||
_spec = spec;
|
||||
}
|
||||
|
||||
public TrimExpression(Expression op, Expression op1, TrimSpec spec) {
|
||||
super(op, BinaryFunctionalOperator.TRIM, op1);
|
||||
_spec = spec;
|
||||
public String asExpression(AliasContext ctx) {
|
||||
String trim = _trimChar == null ? BLANK
|
||||
: ((Visitable)_trimChar).asExpression(ctx);
|
||||
String spec = _spec == null ? "" : _spec.toString();
|
||||
return _op + "(" + spec + " " + trim + " FROM "
|
||||
+ ((Visitable)_e).asExpression(ctx) + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,7 +27,8 @@ import javax.persistence.Predicate;
|
|||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
class UnaryExpressionPredicate implements Predicate, Visitable {
|
||||
class UnaryExpressionPredicate extends AbstractVisitable
|
||||
implements Predicate, Visitable {
|
||||
protected final Expression _e;
|
||||
protected final UnaryConditionalOperator _op;
|
||||
private final UnaryConditionalOperator _nop;
|
||||
|
|
|
@ -32,22 +32,25 @@ public enum UnaryFunctionalOperator {
|
|||
ALL("ALL"),
|
||||
ANY("ANY"),
|
||||
AVG("AVG"),
|
||||
CONCAT("CONCAT"),
|
||||
COUNT("COUNT"),
|
||||
DISTINCT("DISTINCT"),
|
||||
EXISTS("EXISTS"),
|
||||
INDEX("INDEX"),
|
||||
LENGTH("LENGTH"),
|
||||
LOCATE("LOCATE"),
|
||||
LOWER("TOLOWER"),
|
||||
LOWER("LOWER"),
|
||||
MAX("MAX"),
|
||||
MIN("MIN"),
|
||||
MINUS("-"),
|
||||
SIZE("SIZE"),
|
||||
SOME("SOME"),
|
||||
SQRT("SQRT"),
|
||||
SUBSTR("SUBSTRING"),
|
||||
SUM("SUM"),
|
||||
TRIM("TRIM"),
|
||||
TYPE("TYPE"),
|
||||
UPPER("TOUPPER");
|
||||
UPPER("UPPER");
|
||||
|
||||
private final String _symbol;
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ class UnaryOperatorExpression extends ExpressionImpl implements Aggregate {
|
|||
}
|
||||
|
||||
public String asProjection(AliasContext ctx) {
|
||||
return _op + "(" + ((Selectable)_e).asProjection(ctx) + ")";
|
||||
return _op + "(" + ((Visitable)_e).asProjection(ctx) + ")" +
|
||||
(ctx.hasAlias(this) ? " " + ctx.getAlias(this) : "");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ import javax.persistence.Expression;
|
|||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class ToUpperExpression extends UnaryOperatorExpression {
|
||||
public ToUpperExpression(Expression op) {
|
||||
public class UpperExpression extends UnaryOperatorExpression {
|
||||
public UpperExpression(Expression op) {
|
||||
super(op, UnaryFunctionalOperator.UPPER);
|
||||
}
|
||||
}
|
|
@ -18,6 +18,8 @@
|
|||
*/
|
||||
package org.apache.openjpa.persistence.query;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* An element of query that is convertible to a JPQL String given a aliasing
|
||||
* scheme. QueryDefinition visits each of its element and translates them.
|
||||
|
@ -25,9 +27,26 @@ package org.apache.openjpa.persistence.query;
|
|||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public interface Visitable {
|
||||
public interface Visitable extends Serializable {
|
||||
/**
|
||||
* Get a JPQL fragment as used in a WHERE clause.
|
||||
*/
|
||||
String asExpression(AliasContext ctx);
|
||||
|
||||
/**
|
||||
* Gets the string representation in a SELECT projection.
|
||||
*/
|
||||
String asProjection(AliasContext ctx);
|
||||
|
||||
/**
|
||||
* Sets alias.
|
||||
*/
|
||||
void setAlias(AliasContext ctx);
|
||||
|
||||
String getAliasHint(AliasContext ctx);
|
||||
|
||||
String asJoinable(AliasContext ctx);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue