mirror of
https://github.com/querydsl/querydsl.git
synced 2026-06-13 21:01:01 +08:00
277 lines
8.0 KiB
Java
277 lines
8.0 KiB
Java
/*
|
|
* Copyright (c) 2009 Mysema Ltd.
|
|
* All rights reserved.
|
|
*
|
|
*/
|
|
package com.mysema.query.jdo;
|
|
|
|
import java.io.Closeable;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
|
|
import javax.annotation.Nullable;
|
|
import javax.jdo.PersistenceManager;
|
|
import javax.jdo.Query;
|
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import com.mysema.commons.lang.CloseableIterator;
|
|
import com.mysema.commons.lang.IteratorAdapter;
|
|
import com.mysema.query.DefaultQueryMetadata;
|
|
import com.mysema.query.QueryException;
|
|
import com.mysema.query.QueryMetadata;
|
|
import com.mysema.query.QueryModifiers;
|
|
import com.mysema.query.SearchResults;
|
|
import com.mysema.query.support.ProjectableQuery;
|
|
import com.mysema.query.types.EntityPath;
|
|
import com.mysema.query.types.Expression;
|
|
import com.mysema.query.types.FactoryExpression;
|
|
import com.mysema.query.types.QTuple;
|
|
|
|
/**
|
|
* Abstract base class for custom implementations of the JDOQLQuery interface.
|
|
*
|
|
* @author tiwe
|
|
*
|
|
* @param <Q>
|
|
*/
|
|
public abstract class AbstractJDOQLQuery<Q extends AbstractJDOQLQuery<Q>> extends ProjectableQuery<Q>{
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(JDOQLQueryImpl.class);
|
|
|
|
private final Closeable closeable = new Closeable(){
|
|
@Override
|
|
public void close() throws IOException {
|
|
AbstractJDOQLQuery.this.close();
|
|
}
|
|
};
|
|
|
|
private final boolean detach;
|
|
|
|
private List<Object> orderedConstants = new ArrayList<Object>();
|
|
|
|
@Nullable
|
|
private final PersistenceManager persistenceManager;
|
|
|
|
private final List<Query> queries = new ArrayList<Query>(2);
|
|
|
|
private final JDOQLTemplates templates;
|
|
|
|
private final Set<String> fetchGroups = new HashSet<String>();
|
|
|
|
@Nullable
|
|
private Integer maxFetchDepth;
|
|
|
|
public AbstractJDOQLQuery(@Nullable PersistenceManager persistenceManager) {
|
|
this(persistenceManager, JDOQLTemplates.DEFAULT, new DefaultQueryMetadata(), false);
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public AbstractJDOQLQuery(
|
|
@Nullable PersistenceManager persistenceManager,
|
|
JDOQLTemplates templates,
|
|
QueryMetadata metadata, boolean detach) {
|
|
super(new JDOQLQueryMixin<Q>(metadata));
|
|
this.queryMixin.setSelf((Q) this);
|
|
this.templates = templates;
|
|
this.persistenceManager = persistenceManager;
|
|
this.detach = detach;
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public Q addFetchGroup(String fetchGroupName) {
|
|
fetchGroups.add(fetchGroupName);
|
|
return (Q)this;
|
|
}
|
|
|
|
public void close() {
|
|
for (Query query : queries){
|
|
query.closeAll();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public long count() {
|
|
Query query = createQuery(true);
|
|
query.setUnique(true);
|
|
reset();
|
|
Long rv = (Long) execute(query);
|
|
if (rv != null){
|
|
return rv.longValue();
|
|
}else{
|
|
throw new QueryException("Query returned null");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean exists(){
|
|
boolean rv = limit(1).uniqueResult(getSource()) != null;
|
|
close();
|
|
return rv;
|
|
}
|
|
|
|
private Expression<?> getSource(){
|
|
return queryMixin.getMetadata().getJoins().get(0).getTarget();
|
|
}
|
|
|
|
private Query createQuery(boolean forCount) {
|
|
Expression<?> source = getSource();
|
|
|
|
// serialize
|
|
JDOQLSerializer serializer = new JDOQLSerializer(getTemplates(), source);
|
|
serializer.serialize(queryMixin.getMetadata(), forCount, false);
|
|
|
|
logQuery(serializer.toString());
|
|
|
|
// create Query
|
|
Query query = persistenceManager.newQuery(serializer.toString());
|
|
orderedConstants = serializer.getConstants();
|
|
queries.add(query);
|
|
|
|
if (!forCount){
|
|
List<? extends Expression<?>> projection = queryMixin.getMetadata().getProjection();
|
|
Class<?> exprType = projection.get(0).getClass();
|
|
if (exprType.equals(QTuple.class)){
|
|
query.setResultClass(JDOTuple.class);
|
|
} else if (FactoryExpression.class.isAssignableFrom(exprType)){
|
|
query.setResultClass(projection.get(0).getType());
|
|
}
|
|
|
|
if (!fetchGroups.isEmpty()){
|
|
query.getFetchPlan().setGroups(fetchGroups);
|
|
}
|
|
if (maxFetchDepth != null){
|
|
query.getFetchPlan().setMaxFetchDepth(maxFetchDepth);
|
|
}
|
|
}
|
|
|
|
return query;
|
|
}
|
|
|
|
protected void logQuery(String queryString){
|
|
if (logger.isDebugEnabled()){
|
|
logger.debug(queryString.replace('\n', ' '));
|
|
}
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
private <T> T detach(T results){
|
|
if (results instanceof Collection){
|
|
return (T) persistenceManager.detachCopyAll(results);
|
|
}else{
|
|
return persistenceManager.detachCopy(results);
|
|
}
|
|
}
|
|
|
|
private Object execute(Query query) {
|
|
Object rv;
|
|
if (!orderedConstants.isEmpty()) {
|
|
rv = query.executeWithArray(orderedConstants.toArray());
|
|
} else {
|
|
rv = query.execute();
|
|
}
|
|
if (isDetach()){
|
|
rv = detach(rv);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
public Q from(EntityPath<?>... args) {
|
|
return queryMixin.from(args);
|
|
}
|
|
|
|
public QueryMetadata getMetadata(){
|
|
return queryMixin.getMetadata();
|
|
}
|
|
|
|
public JDOQLTemplates getTemplates() {
|
|
return templates;
|
|
}
|
|
|
|
public boolean isDetach() {
|
|
return detach;
|
|
}
|
|
|
|
public CloseableIterator<Object[]> iterate(Expression<?>[] args) {
|
|
return new IteratorAdapter<Object[]>(list(args).iterator(), closeable);
|
|
}
|
|
|
|
public <RT> CloseableIterator<RT> iterate(Expression<RT> projection) {
|
|
return new IteratorAdapter<RT>(list(projection).iterator(), closeable);
|
|
}
|
|
|
|
@Override
|
|
@SuppressWarnings("unchecked")
|
|
public List<Object[]> list(Expression<?>[] args) {
|
|
queryMixin.addToProjection(args);
|
|
Object rv = execute(createQuery(false));
|
|
reset();
|
|
return (rv instanceof List) ? ((List<Object[]>)rv) : Collections.singletonList((Object[])rv);
|
|
}
|
|
|
|
@Override
|
|
@SuppressWarnings("unchecked")
|
|
public <RT> List<RT> list(Expression<RT> expr) {
|
|
queryMixin.addToProjection(expr);
|
|
Object rv = execute(createQuery(false));
|
|
reset();
|
|
return rv instanceof List ? (List<RT>)rv : Collections.singletonList((RT)rv);
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public <RT> SearchResults<RT> listResults(Expression<RT> expr) {
|
|
queryMixin.addToProjection(expr);
|
|
Query countQuery = createQuery(true);
|
|
countQuery.setUnique(true);
|
|
countQuery.setResult("count(this)");
|
|
long total = (Long) execute(countQuery);
|
|
if (total > 0) {
|
|
QueryModifiers modifiers = queryMixin.getMetadata().getModifiers();
|
|
Query query = createQuery(false);
|
|
reset();
|
|
return new SearchResults<RT>((List<RT>) execute(query), modifiers, total);
|
|
} else {
|
|
reset();
|
|
return SearchResults.emptyResults();
|
|
}
|
|
}
|
|
|
|
private void reset(){
|
|
queryMixin.getMetadata().reset();
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public Q setMaxFetchDepth(int depth) {
|
|
maxFetchDepth = depth;
|
|
return (Q)this;
|
|
}
|
|
|
|
@Override
|
|
public String toString(){
|
|
if (!queryMixin.getMetadata().getJoins().isEmpty()){
|
|
Expression<?> source = getSource();
|
|
JDOQLSerializer serializer = new JDOQLSerializer(getTemplates(), source);
|
|
serializer.serialize(queryMixin.getMetadata(), false, false);
|
|
return serializer.toString().trim();
|
|
}else{
|
|
return super.toString();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
@SuppressWarnings("unchecked")
|
|
public <RT> RT uniqueResult(Expression<RT> expr) {
|
|
queryMixin.addToProjection(expr);
|
|
Query query = createQuery(false);
|
|
query.setUnique(true);
|
|
reset();
|
|
return (RT) execute(query);
|
|
}
|
|
}
|