org.dellroad.querystream.jpa.SearchStream Maven / Gradle / Ivy
/*
* Copyright (C) 2018 Archie L. Cobbs. All rights reserved.
*/
package org.dellroad.querystream.jpa;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.AbstractQuery;
import javax.persistence.criteria.CollectionJoin;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.From;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.ListJoin;
import javax.persistence.criteria.MapJoin;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Selection;
import javax.persistence.criteria.SetJoin;
import javax.persistence.metamodel.CollectionAttribute;
import javax.persistence.metamodel.ListAttribute;
import javax.persistence.metamodel.MapAttribute;
import javax.persistence.metamodel.PluralAttribute;
import javax.persistence.metamodel.SetAttribute;
import javax.persistence.metamodel.SingularAttribute;
import org.dellroad.querystream.jpa.querytype.SearchType;
/**
* Builder for JPA criteria search queries, based on configuration through a {@link java.util.stream.Stream}-like API.
*
* @param stream item type
* @param criteria type for stream item
*/
public interface SearchStream>
extends QueryStream, CriteriaQuery, TypedQuery> {
/**
* Build and evaluate a JPA query based on this instance and return the result list.
*
*
* Delegates to {@link TypedQuery#getResultList} and can throw any exception thrown by that method.
*
* @return result of executed query
* @see TypedQuery#getResultList
*/
default List getResultList() {
return this.toQuery().getResultList();
}
/**
* Build and evaluate a JPA query based on this instance and return the result stream.
*
*
* Delegates to {@link TypedQuery#getResultStream} and can throw any exception thrown by that method.
*
* @return result of executed query
* @see TypedQuery#getResultStream
*/
default Stream getResultStream() {
return this.toQuery().getResultStream();
}
// CriteriaQuery stuff
/**
* Suppress duplicates.
*
* @return a new stream with duplicates removed
*/
SearchStream distinct();
/**
* Order results using the specified property.
*
*
* Replaces any existing sort ordering.
*
* @param attribute associated property
* @param asc true for ascending, false for descending
* @return a new stream with specified ordering
* @throws IllegalArgumentException if {@code attribute} is null
*/
SearchStream orderBy(SingularAttribute super X, ?> attribute, boolean asc);
/**
* Order results using the specified properties.
*
*
* Replaces any existing sort ordering.
*
* @param attribute1 associated property
* @param asc1 true for {@code attribute1} ascending, false for {@code attribute1} descending
* @param attribute2 associated property
* @param asc2 true for {@code attribute2} ascending, false for {@code attribute2} descending
* @return a new stream with specified ordering
* @throws IllegalArgumentException if {@code attribute1} or {@code attribute2} is null
*/
SearchStream orderBy(SingularAttribute super X, ?> attribute1, boolean asc1,
SingularAttribute super X, ?> attribute2, boolean asc2);
/**
* Order results using the specified properties.
*
*
* Replaces any existing sort ordering.
*
* @param attribute1 associated property
* @param asc1 true for {@code attribute1} ascending, false for {@code attribute1} descending
* @param attribute2 associated property
* @param asc2 true for {@code attribute2} ascending, false for {@code attribute2} descending
* @param attribute3 associated property
* @param asc3 true for {@code attribute3} ascending, false for {@code attribute3} descending
* @return a new stream with specified ordering
* @throws IllegalArgumentException if {@code attribute1}, {@code attribute2}, or {@code attribute3} is null
*/
SearchStream orderBy(SingularAttribute super X, ?> attribute1, boolean asc1,
SingularAttribute super X, ?> attribute2, boolean asc2, SingularAttribute super X, ?> attribute3, boolean asc3);
/**
* Order results using the specified expression reference.
*
*
* Replaces any existing sort ordering.
*
* @param ref previously bound expression reference
* @param asc true for ascending, false for descending
* @return a new stream with specified ordering
* @throws IllegalArgumentException if {@code ref} is null
*/
SearchStream orderBy(Ref, ? extends Expression>> ref, boolean asc);
/**
* Order results using the specified {@link Order}s.
*
*
* Replaces any existing sort ordering.
*
* @param orders ordering(s), with higher precedence orderings first
* @return a new stream with specified ordering(s)
* @throws IllegalArgumentException if {@code orders} is null
*/
SearchStream orderBy(Order... orders);
/**
* Order results using the {@link Expression} produced by the given {@link Function}.
*
*
* Replaces any existing sort ordering.
*
* @param orderExprFunction {@link Function} that produces an {@link Expression} to order on given an item expression
* @param asc true for ascending, false for descending
* @return a new stream with specified ordering
* @throws IllegalArgumentException if {@code orderExprFunction} is null
*/
SearchStream orderBy(Function super S, ? extends Expression>> orderExprFunction, boolean asc);
/**
* Order results using the {@link Order} list produced by the given {@link Function}.
*
*
* Replaces any existing sort ordering.
*
* @param orderListFunction {@link Function} that produces the sort ordering given an item expression
* @return a new stream with specified ordering
* @throws IllegalArgumentException if {@code orderListFunction} is null
*/
SearchStream orderByMulti(Function super S, ? extends List extends Order>> orderListFunction);
/**
* Order results using the specified property after existing sort.
*
*
* Adds to any existing sort ordering.
*
* @param attribute associated property
* @param asc true for ascending, false for descending
* @return a new stream with specified additional ordering
* @throws IllegalArgumentException if {@code attribute} is null
*/
SearchStream thenOrderBy(SingularAttribute super X, ?> attribute, boolean asc);
/**
* Order results using the specified expression reference after existing sort.
*
*
* Adds to any existing sort ordering.
*
* @param ref previously bound expression reference
* @param asc true for ascending, false for descending
* @return a new stream with specified additional ordering
* @throws IllegalArgumentException if {@code ref} is null
*/
SearchStream thenOrderBy(Ref, ? extends Expression>> ref, boolean asc);
/**
* Order results using the specified {@link Order}s after existing sort.
*
*
* Adds to any existing sort ordering.
*
* @param orders ordering(s), with higher precedence orderings first
* @return a new stream with specified additional ordering(s)
* @throws IllegalArgumentException if {@code orders} is null
*/
SearchStream thenOrderBy(Order... orders);
/**
* Order results using the {@link Expression} produced by the given {@link Function} after existing sort.
*
*
* Adds to any existing sort ordering.
*
* @param orderExprFunction {@link Function} that produces an {@link Expression} to order on given an item expression
* @param asc true for ascending, false for descending
* @return a new stream with specified additional ordering
* @throws IllegalArgumentException if {@code orderExprFunction} is null
*/
SearchStream thenOrderBy(Function super S, ? extends Expression>> orderExprFunction, boolean asc);
/**
* Apply grouping based on an expression reference.
*
*
* Adds to any previously specified groupings.
*
* @param ref previously bound expression reference
* @return a new stream with additional grouping
* @throws IllegalArgumentException if {@code ref} is null
*/
SearchStream groupBy(Ref, ? extends Expression>> ref);
/**
* Apply grouping based on the specified property.
*
*
* Adds to any previously specified groupings.
*
* @param attribute associated property
* @return a new stream with additional grouping
* @throws IllegalArgumentException if {@code attribute} is null
*/
SearchStream groupBy(SingularAttribute super X, ?> attribute);
/**
* Apply grouping based on a single expression.
*
*
* Adds to any previously specified groupings.
*
* @param groupFunction function returning an expression by which to group results
* @return a new stream with additional grouping
* @throws IllegalArgumentException if {@code groupFunction} is null
*/
SearchStream groupBy(Function super S, ? extends Expression>> groupFunction);
/**
* Apply grouping based on a list of expressions.
*
*
* Adds to any previously specified groupings.
*
* @param groupFunction function returning a list of expressions by which to group results
* @return a new instance
* @throws IllegalArgumentException if {@code groupFunction} is null
*/
SearchStream groupByMulti(Function super S, ? extends List>> groupFunction);
/**
* Add a "having" restriction.
*
*
* Adds to any previously specified "having" restrictions.
*
* @param havingFunction function returning a test to apply to grouped results
* @return a new instance
* @throws IllegalArgumentException if {@code havingFunction} is null
*/
SearchStream having(Function super S, ? extends Expression> havingFunction);
// Streamy stuff
/**
* Execute this query and return true if the given property is true for every resulting item.
*
*
* Delegates to {@link TypedQuery#getResultStream} and can throw any exception thrown by that method.
*
* @param attribute boolean property
* @return true if all results have the given property true
*/
boolean allMatch(SingularAttribute super X, Boolean> attribute);
/**
* Execute this query and return true if the predicate returned by the given function is true for every resulting item.
*
*
* Delegates to {@link TypedQuery#getResultStream} and can throw any exception thrown by that method.
*
* @param predicateBuilder function mapping this stream's item to a boolean {@link Expression}
* @return true if all results have the computed expression true
*/
boolean allMatch(Function super S, ? extends Expression> predicateBuilder);
/**
* Execute this query and return true if any results are found for which the given property is true.
*
*
* Delegates to {@link TypedQuery#getResultStream} and can throw any exception thrown by that method.
*
* @param attribute boolean property
* @return true if one or more results have the given property true
*/
boolean anyMatch(SingularAttribute super X, Boolean> attribute);
/**
* Execute this query and return true if any results are found for which the predicate returned by the given function is true.
*
*
* Delegates to {@link TypedQuery#getResultStream} and can throw any exception thrown by that method.
*
* @param predicateBuilder function mapping this stream's item to a boolean {@link Expression}
* @return true if one or more results have the computed expression true
*/
boolean anyMatch(Function super S, ? extends Expression> predicateBuilder);
/**
* Execute this query and return true if no results are found for which the given property is true.
*
*
* Delegates to {@link TypedQuery#getResultStream} and can throw any exception thrown by that method.
*
* @param attribute boolean property
* @return true if no results have the given property true
*/
boolean noneMatch(SingularAttribute super X, Boolean> attribute);
/**
* Execute this query and return true if no result are found for which the predicate returned by the given function is true.
*
*
* Delegates to {@link TypedQuery#getResultStream} and can throw any exception thrown by that method.
*
* @param predicateBuilder function mapping this stream's item to a boolean {@link Expression}
* @return true if no results have the computed expression true
*/
boolean noneMatch(Function super S, ? extends Expression> predicateBuilder);
/**
* Execute this query and return true if no results are found.
*
*
* Note: to perform an "exists" operation in a subquery, use {@link ExprStream#exists}.
*
*
* Delegates to {@link TypedQuery#getResultStream} and can throw any exception thrown by that method.
*
* @return true if no results are found, false if one or more results are found
* @see ExprStream#exists
*/
boolean isEmpty();
/**
* Find any instance in the stream.
*
* @return single-valued stream containg any instance in this stream (or {@code NULL} if this stream is empty)
*/
SearchValue findAny();
/**
* Find the first instance in the stream.
*
* @return single-valued stream containg the first instance in this stream (or {@code NULL} if this stream is empty)
*/
SearchValue findFirst();
// Binding
/**
* Bind an unbound reference to a new query root that will be added to the query.
*
*
* To select the new root in a {@link SearchStream}, use {@link SearchStream#map(Class, Function) SearchStream.map()},
* providing a {@link Function} that returns {@code ref}.
*
*
* Note that this effectively creates an unconstrained (cross product) join with the new root.
* Typically there would be some additional restrictions imposed (e.g., via {@link #filter filter()})
* to relate the new root to the items in the stream.
*
* @param ref unbound reference
* @param type type of the new query root
* @param type of the new query root
* @throws IllegalArgumentException if {@code ref} is already bound
* @throws IllegalArgumentException if {@code type} or {@code ref} is null
* @return new stream that binds {@code ref} to a new query root from {@code type}
*/
SearchStream addRoot(Ref> ref, Class type);
// Mapping
/**
* Map this stream to an associated property.
*
* @param attribute associated property
* @param property type
* @return mapped stream
*/
default PathStream> map(SingularAttribute super X, Y> attribute) {
if (attribute == null)
throw new IllegalArgumentException("null attribute");
QueryStreamImpl.checkOffsetLimit(this, "map()");
return new PathStreamImpl<>(this.getEntityManager(), new SearchType<>(attribute.getJavaType()), (builder, query) -> {
// We always prefer having a From over a Path, because you can continue to join with it.
// If you say path.get() you get a Path, even if you could have said path.join() to get a From.
// So when mapping a SingluarAttribute, path.join() is the same as path.get() but better.
// Of course, the attribute also has to point to something joinable, not e.g. a basic type.
final Path path = (Path)this.configure(builder, query); // cast must be valid if attribute exists
final boolean joinable;
switch (attribute.getPersistentAttributeType()) {
case BASIC:
case EMBEDDED:
joinable = false;
break;
default:
joinable = true;
break;
}
return joinable && path instanceof From ? ((From, X>)path).join(attribute) : path.get(attribute);
}, new QueryInfo());
}
/**
* Map this stream into a stream whose elements are the result of applying the given function.
*
* @param type new item type
* @param exprFunction function mapping this stream's {@link Expression} to a {@link Expression}
* @param mapped expression type
* @return mapped stream
*/
default ExprStream> map(Class type, Function super S, ? extends Expression> exprFunction) {
if (type == null)
throw new IllegalArgumentException("null type");
if (exprFunction == null)
throw new IllegalArgumentException("null exprFunction");
QueryStreamImpl.checkOffsetLimit(this, "map()");
return new ExprStreamImpl<>(this.getEntityManager(), new SearchType(type),
(builder, query) -> exprFunction.apply(this.configure(builder, query)), new QueryInfo());
}
/**
* Map this stream to an associated collection property.
*
* @param attribute associated property
* @param collection element type
* @param collection type
* @return mapped stream
*/
@SuppressWarnings("unchecked")
default > ExprStream> map(PluralAttribute super X, C, E> attribute) {
if (attribute == null)
throw new IllegalArgumentException("null attribute");
QueryStreamImpl.checkOffsetLimit(this, "map()");
// This is necessary due to https://github.com/javaee/jpa-spec/issues/108
final PluralAttribute attribute2 = (PluralAttribute)attribute;
return new ExprStreamImpl<>(this.getEntityManager(), new SearchType<>(attribute.getJavaType()),
(builder, query) -> ((Path)this.configure(builder, query)).get(attribute2), // cast must be valid if attribute exists
new QueryInfo());
}
/**
* Map this stream to an associated map property.
*
* @param attribute associated property
* @param map key type
* @param map value type
* @param map type
* @return mapped stream
*/
@SuppressWarnings("unchecked")
default > ExprStream> map(MapAttribute super X, K, V> attribute) {
if (attribute == null)
throw new IllegalArgumentException("null attribute");
QueryStreamImpl.checkOffsetLimit(this, "map()");
// This is necessary due to https://github.com/javaee/jpa-spec/issues/108
final MapAttribute attribute2 = (MapAttribute)attribute;
return new ExprStreamImpl<>(this.getEntityManager(), new SearchType<>((Class)attribute.getJavaType()),
(builder, query) -> ((Path)this.configure(builder, query)).get(attribute2), // cast must be valid if attribute exists
new QueryInfo());
}
/**
* Map this stream into a stream whose elements are the result of applying the given function.
*
* @param type new item type
* @param pathFunction function mapping this stream's {@link Expression} to a {@link Path}
* @param mapped expresssion type
* @return mapped stream
*/
default PathStream> mapToPath(Class type, Function super S, ? extends Path> pathFunction) {
if (type == null)
throw new IllegalArgumentException("null type");
if (pathFunction == null)
throw new IllegalArgumentException("null pathFunction");
QueryStreamImpl.checkOffsetLimit(this, "mapToPath()");
return new PathStreamImpl<>(this.getEntityManager(), new SearchType(type),
(builder, query) -> pathFunction.apply(this.configure(builder, query)), new QueryInfo());
}
/**
* Map this stream into a stream whose elements are the result of applying the given function.
*
* @param type new item type
* @param fromFunction function mapping this stream's {@link Expression} to a {@link From}
* @param mapped source type
* @param mapped target type
* @return mapped stream
*/
default FromStream> mapToFrom(Class type, Function super S, ? extends From> fromFunction) {
if (type == null)
throw new IllegalArgumentException("null type");
if (fromFunction == null)
throw new IllegalArgumentException("null fromFunction");
QueryStreamImpl.checkOffsetLimit(this, "mapToFrom()");
return new FromStreamImpl<>(this.getEntityManager(), new SearchType(type),
(builder, query) -> fromFunction.apply(this.configure(builder, query)), new QueryInfo());
}
/**
* Map this stream to an associated floating point value.
*
* @param attribute associated numerically-valued property
* @return mapped stream of doubles
*/
default DoubleStream mapToDouble(SingularAttribute super X, ? extends Number> attribute) {
if (attribute == null)
throw new IllegalArgumentException("null attribute");
QueryStreamImpl.checkOffsetLimit(this, "mapToDouble()");
return new DoubleStreamImpl(this.getEntityManager(),
(builder, query) -> builder.toDouble(((Path)this.configure(builder, query)).get(attribute)), // cast must be valid...
new QueryInfo());
}
/**
* Map this stream into a stream of double values that are the result of applying the given function.
*
* @param doubleExprFunction function mapping this stream's {@link Expression} to a numerical {@link Expression}
* @return mapped stream of doubles
*/
default DoubleStream mapToDouble(Function super S, ? extends Expression extends Number>> doubleExprFunction) {
if (doubleExprFunction == null)
throw new IllegalArgumentException("null doubleExprFunction");
QueryStreamImpl.checkOffsetLimit(this, "mapToDouble()");
return new DoubleStreamImpl(this.getEntityManager(),
(builder, query) -> builder.toDouble(doubleExprFunction.apply(this.configure(builder, query))), new QueryInfo());
}
/**
* Map this stream to an associated long value.
*
* @param attribute associated numerically-valued property
* @return mapped stream of longs
*/
default LongStream mapToLong(SingularAttribute super X, ? extends Number> attribute) {
if (attribute == null)
throw new IllegalArgumentException("null attribute");
QueryStreamImpl.checkOffsetLimit(this, "mapToLong()");
return new LongStreamImpl(this.getEntityManager(),
(builder, query) -> builder.toLong(((Path)this.configure(builder, query)).get(attribute)), // cast must be valid...
new QueryInfo());
}
/**
* Map this stream into a stream of long values that are the result of applying the given function.
*
* @param longExprFunction function mapping this stream's {@link Expression} to a numerical {@link Expression}
* @return mapped stream of longs
*/
default LongStream mapToLong(Function super S, ? extends Expression extends Number>> longExprFunction) {
if (longExprFunction == null)
throw new IllegalArgumentException("null longExprFunction");
QueryStreamImpl.checkOffsetLimit(this, "mapToLong()");
return new LongStreamImpl(this.getEntityManager(),
(builder, query) -> builder.toLong(longExprFunction.apply(this.configure(builder, query))), new QueryInfo());
}
/**
* Map this stream to an associated integer value.
*
* @param attribute associated numerically-valued property
* @return mapped stream of integers
*/
default IntStream mapToInt(SingularAttribute super X, ? extends Number> attribute) {
if (attribute == null)
throw new IllegalArgumentException("null attribute");
QueryStreamImpl.checkOffsetLimit(this, "mapToInt()");
return new IntStreamImpl(this.getEntityManager(),
(builder, query) -> builder.toInteger(((Path)this.configure(builder, query)).get(attribute)), // cast must be valid...
new QueryInfo());
}
/**
* Map this stream into a stream of integer values that are the result of applying the given function.
*
* @param intExprFunction function mapping this stream's {@link Expression} to a numerical {@link Expression}
* @return mapped stream of integers
*/
default IntStream mapToInt(Function super S, ? extends Expression extends Number>> intExprFunction) {
if (intExprFunction == null)
throw new IllegalArgumentException("null intExprFunction");
QueryStreamImpl.checkOffsetLimit(this, "mapToInt()");
return new IntStreamImpl(this.getEntityManager(),
(builder, query) -> builder.toInteger(intExprFunction.apply(this.configure(builder, query))), new QueryInfo());
}
/**
* Map this stream into a stream whose elements are the result of applying the given function.
*
*
* This method provides support for multiple selection using
* {@link javax.persistence.criteria.CriteriaBuilder#array CriteriaBuilder.array()},
* {@link javax.persistence.criteria.CriteriaBuilder#construct CriteriaBuilder.construct()}, or
* {@link javax.persistence.criteria.CriteriaBuilder#tuple CriteriaBuilder.tuple()}.
* For normal single selection, typically you would use {@link SearchStream#map SearchStream.map()} instead of this method.
*
* @param type selection type
* @param selectionFunction function to build selection
* @param selection type
* @return mapped stream
*/
default SearchStream> mapToSelection(Class type,
Function super S, ? extends Selection> selectionFunction) {
if (type == null)
throw new IllegalArgumentException("null type");
if (selectionFunction == null)
throw new IllegalArgumentException("null selectionFunction");
QueryStreamImpl.checkOffsetLimit(this, "mapToSelection()");
return new SearchStreamImpl<>(this.getEntityManager(), new SearchType(type),
(builder, query) -> selectionFunction.apply(this.configure(builder, query)), new QueryInfo());
}
// Flat Mapping
/**
* Map this stream to a stream where every item is replaced with the contents of the specified collection.
*
* @param attribute associated collection property
* @param collection element type
* @return mapped stream
*/
default FromStream> flatMap(CollectionAttribute super X, E> attribute) {
QueryStreamImpl.checkOffsetLimit(this, "flatMap()");
return this.join(attribute);
}
/**
* Map this stream to a stream where every item is replaced with the contents of the specified collection.
*
* @param attribute associated collection property
* @param list element type
* @return mapped stream
*/
default FromStream> flatMap(ListAttribute super X, E> attribute) {
QueryStreamImpl.checkOffsetLimit(this, "flatMap()");
return this.join(attribute);
}
/**
* Map this stream to a stream where every item is replaced with the contents of the specified collection.
*
* @param attribute associated collection property
* @param set element type
* @return mapped stream
*/
default FromStream> flatMap(SetAttribute super X, E> attribute) {
QueryStreamImpl.checkOffsetLimit(this, "flatMap()");
return this.join(attribute);
}
/**
* Map this stream to a stream where every item is replaced with the keys of the specified map.
*
* @param attribute associated map property
* @param map key type
* @return mapped stream
*/
default PathStream> flatMapKeys(MapAttribute super X, K, ?> attribute) {
if (attribute == null)
throw new IllegalArgumentException("null attribute");
QueryStreamImpl.checkOffsetLimit(this, "flatMapKeys()");
return new PathStreamImpl<>(this.getEntityManager(), new SearchType<>(attribute.getKeyJavaType()),
(builder, query) -> ((From, X>)this.configure(builder, query)).join(attribute, JoinType.INNER).key(), // valid...
new QueryInfo());
}
/**
* Map this stream to a stream where every item is replaced with the values of the specified map.
*
* @param attribute associated map property
* @param map value type
* @return mapped stream
*/
default PathStream> flatMapValues(MapAttribute super X, ?, V> attribute) {
if (attribute == null)
throw new IllegalArgumentException("null attribute");
QueryStreamImpl.checkOffsetLimit(this, "flatMapValues()");
return new PathStreamImpl<>(this.getEntityManager(), new SearchType<>(attribute.getElementType().getJavaType()),
(builder, query) -> ((From, X>)this.configure(builder, query)).join(attribute, JoinType.INNER).value(), // valid...
new QueryInfo());
}
// Singluar joins
default FromStream> join(SingularAttribute super X, Y> attribute) {
return this.join(attribute, JoinType.INNER);
}
default FromStream> join(SingularAttribute super X, Y> attribute, JoinType joinType) {
if (attribute == null)
throw new IllegalArgumentException("null attribute");
if (!attribute.isAssociation())
throw new IllegalArgumentException("attribute is not an association: " + attribute);
if (joinType == null)
throw new IllegalArgumentException("null joinType");
QueryStreamImpl.checkOffsetLimit(this, "join()");
return new FromStreamImpl<>(this.getEntityManager(), new SearchType<>(attribute.getJavaType()),
(builder, query) -> ((From, X>)this.configure(builder, query)).join(attribute, joinType), // cast must be valid...
new QueryInfo());
}
// Plural Joins
default FromStream> join(CollectionAttribute super X, E> attribute) {
return this.join(attribute, JoinType.INNER);
}
default FromStream> join(CollectionAttribute super X, E> attribute, JoinType joinType) {
if (attribute == null)
throw new IllegalArgumentException("null attribute");
if (!attribute.isAssociation())
throw new IllegalArgumentException("attribute is not an association: " + attribute);
if (joinType == null)
throw new IllegalArgumentException("null joinType");
QueryStreamImpl.checkOffsetLimit(this, "join()");
return new FromStreamImpl<>(this.getEntityManager(), new SearchType<>(attribute.getElementType().getJavaType()),
(builder, query) -> ((From, X>)this.configure(builder, query)).join(attribute, joinType), // cast must be valid...
new QueryInfo());
}
default FromStream> join(ListAttribute super X, E> attribute) {
return this.join(attribute, JoinType.INNER);
}
default FromStream> join(ListAttribute super X, E> attribute, JoinType joinType) {
if (attribute == null)
throw new IllegalArgumentException("null attribute");
if (!attribute.isAssociation())
throw new IllegalArgumentException("attribute is not an association: " + attribute);
if (joinType == null)
throw new IllegalArgumentException("null joinType");
QueryStreamImpl.checkOffsetLimit(this, "join()");
return new FromStreamImpl<>(this.getEntityManager(), new SearchType<>(attribute.getElementType().getJavaType()),
(builder, query) -> ((From, X>)this.configure(builder, query)).join(attribute, joinType), // cast must be valid...
new QueryInfo());
}
default FromStream> join(SetAttribute super X, E> attribute) {
return this.join(attribute, JoinType.INNER);
}
default FromStream> join(SetAttribute super X, E> attribute, JoinType joinType) {
if (attribute == null)
throw new IllegalArgumentException("null attribute");
if (!attribute.isAssociation())
throw new IllegalArgumentException("attribute is not an association: " + attribute);
if (joinType == null)
throw new IllegalArgumentException("null joinType");
QueryStreamImpl.checkOffsetLimit(this, "join()");
return new FromStreamImpl<>(this.getEntityManager(), new SearchType<>(attribute.getElementType().getJavaType()),
(builder, query) -> ((From, X>)this.configure(builder, query)).join(attribute, joinType), // cast must be valid...
new QueryInfo());
}
default FromStream> join(MapAttribute super X, K, V> attribute) {
return this.join(attribute, JoinType.INNER);
}
default FromStream> join(MapAttribute super X, K, V> attribute, JoinType joinType) {
if (attribute == null)
throw new IllegalArgumentException("null attribute");
if (!attribute.isAssociation())
throw new IllegalArgumentException("attribute is not an association: " + attribute);
if (joinType == null)
throw new IllegalArgumentException("null joinType");
QueryStreamImpl.checkOffsetLimit(this, "join()");
return new FromStreamImpl<>(this.getEntityManager(), new SearchType<>(attribute.getElementType().getJavaType()),
(builder, query) -> ((From, X>)this.configure(builder, query)).join(attribute, joinType), // cast must be valid...
new QueryInfo());
}
// Narrowing overrides (QueryStream)
@Override
SearchType getQueryType();
@Override
SearchStream bind(Ref ref);
@Override
SearchStream peek(Consumer super S> peeker);
@Override
> SearchStream bind(Ref ref, Function super S, ? extends S2> refFunction);
@Override
SearchStream filter(SingularAttribute super X, Boolean> attribute);
@Override
SearchStream filter(Function super S, ? extends Expression> predicateBuilder);
@Override
SearchStream limit(int maxSize);
@Override
SearchStream skip(int num);
@Override
SearchStream withFlushMode(FlushModeType flushMode);
@Override
SearchStream withLockMode(LockModeType lockMode);
@Override
SearchStream withHint(String name, Object value);
@Override
SearchStream withHints(Map hints);
@Override
SearchStream withLoadGraph(String name);
@Override
SearchStream withFetchGraph(String name);
}