/*
* Copyright 2015, The Querydsl Team (http://www.querydsl.com/team)
*
* Licensed 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 com.querydsl.collections;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.mysema.commons.lang.CloseableIterator;
import com.mysema.commons.lang.IteratorAdapter;
import com.querydsl.core.*;
import com.querydsl.core.support.FetchableQueryBase;
import com.querydsl.core.types.*;
/**
* {@code AbstractCollQuery} provides a base class for {@link Collection} query implementations.
*
* @param <T> result type
* @param <Q> concrete subtype
*
* @see CollQuery
* @author tiwe
*/
public abstract class AbstractCollQuery<T, Q extends AbstractCollQuery<T, Q>> extends FetchableQueryBase<T, Q>
implements FetchableQuery<T, Q> {
private final Map<Expression<?>, Iterable<?>> iterables = new HashMap<Expression<?>, Iterable<?>>();
private final QueryEngine queryEngine;
public AbstractCollQuery(QueryMetadata metadata, QueryEngine queryEngine) {
super(new CollQueryMixin<Q>(metadata));
@SuppressWarnings("unchecked") // Q is this + subtype
Q self = (Q) this;
this.queryMixin.setSelf(self);
this.queryEngine = queryEngine;
}
@Override
public long fetchCount() {
return queryEngine.count(queryMixin.getMetadata(), iterables);
}
protected QueryMetadata getMetadata() {
return queryMixin.getMetadata();
}
private <D> Expression<D> createAlias(Path<? extends Collection<D>> target, Path<D> alias) {
return ExpressionUtils.operation(alias.getType(), Ops.ALIAS, target, alias);
}
private <D> Expression<D> createAlias(MapExpression<?,D> target, Path<D> alias) {
return ExpressionUtils.operation(alias.getType(), Ops.ALIAS, target, alias);
}
/**
* Add a query source
*
* @param <A> type of expression
* @param entity Path for the source
* @param col content of the source
* @return current object
*/
public <A> Q from(Path<A> entity, Iterable<? extends A> col) {
iterables.put(entity, col);
getMetadata().addJoin(JoinType.DEFAULT, entity);
return queryMixin.getSelf();
}
/**
* Bind the given collection to an already existing query source
*
* @param <A> type of expression
* @param entity Path for the source
* @param col content of the source
* @return current object
*/
public <A> Q bind(Path<A> entity, Iterable<? extends A> col) {
iterables.put(entity, col);
return queryMixin.getSelf();
}
@Override
public Q groupBy(Expression<?> e) {
throw new UnsupportedOperationException();
}
@Override
public Q groupBy(Expression<?>... o) {
throw new UnsupportedOperationException();
}
@Override
public Q having(Predicate e) {
throw new UnsupportedOperationException();
}
@Override
public Q having(Predicate... e) {
throw new UnsupportedOperationException();
}
protected QueryEngine getQueryEngine() {
return queryEngine;
}
/**
* Define an inner join from the Collection typed path to the alias
*
* @param <P> type of expression
* @param target target of the join
* @param alias alias for the join target
* @return current object
*/
public <P> Q innerJoin(Path<? extends Collection<P>> target, Path<P> alias) {
getMetadata().addJoin(JoinType.INNERJOIN, createAlias(target, alias));
return queryMixin.getSelf();
}
/**
* Define an inner join from the Map typed path to the alias
*
* @param <P> type of expression
* @param target target of the join
* @param alias alias for the join target
* @return current object
*/
public <P> Q innerJoin(MapExpression<?,P> target, Path<P> alias) {
getMetadata().addJoin(JoinType.INNERJOIN, createAlias(target, alias));
return queryMixin.getSelf();
}
/**
* Define a left join from the Collection typed path to the alias
*
* @param <P> type of expression
* @param target target of the join
* @param alias alias for the join target
* @return current object
*/
public <P> Q leftJoin(Path<? extends Collection<P>> target, Path<P> alias) {
getMetadata().addJoin(JoinType.LEFTJOIN, createAlias(target, alias));
return queryMixin.getSelf();
}
/**
* Define a left join from the Map typed path to the alias
*
* @param <P> type of expression
* @param target target of the join
* @param alias alias for the joint target
* @return current object
*/
public <P> Q leftJoin(MapExpression<?,P> target, Path<P> alias) {
getMetadata().addJoin(JoinType.LEFTJOIN, createAlias(target, alias));
return queryMixin.getSelf();
}
@Override
public CloseableIterator<T> iterate() {
@SuppressWarnings("unchecked") // This is the built type
Expression<T> projection = (Expression<T>) queryMixin.getMetadata().getProjection();
return new IteratorAdapter<T>(queryEngine.list(getMetadata(), iterables, projection).iterator());
}
@Override
public List<T> fetch() {
@SuppressWarnings("unchecked") // This is the built type
Expression<T> projection = (Expression<T>) queryMixin.getMetadata().getProjection();
return queryEngine.list(getMetadata(), iterables, projection);
}
@Override
public QueryResults<T> fetchResults() {
@SuppressWarnings("unchecked") // This is the built type
Expression<T> projection = (Expression<T>) queryMixin.getMetadata().getProjection();
long count = queryEngine.count(getMetadata(), iterables);
if (count > 0L) {
List<T> list = queryEngine.list(getMetadata(), iterables, projection);
return new QueryResults<T>(list, getMetadata().getModifiers(), count);
} else {
return QueryResults.<T>emptyResults();
}
}
@Override
public T fetchOne() {
queryMixin.setUnique(true);
if (queryMixin.getMetadata().getModifiers().getLimit() == null) {
limit(2L);
}
return uniqueResult(iterate());
}
}