All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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 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 attribute1, boolean asc1, SingularAttribute 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 attribute1, boolean asc1, SingularAttribute attribute2, boolean asc2, SingularAttribute 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> 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> 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> 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 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> 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> 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> 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 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> 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>> 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> 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 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> 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 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> 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 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> 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 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)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> 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 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 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> 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> 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 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> 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 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> 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 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> 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> 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 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 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 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 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)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 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)this.configure(builder, query)).join(attribute, JoinType.INNER).value(), // valid... new QueryInfo()); } // Singluar joins default FromStream> join(SingularAttribute attribute) { return this.join(attribute, JoinType.INNER); } default FromStream> join(SingularAttribute 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)this.configure(builder, query)).join(attribute, joinType), // cast must be valid... new QueryInfo()); } // Plural Joins default FromStream> join(CollectionAttribute attribute) { return this.join(attribute, JoinType.INNER); } default FromStream> join(CollectionAttribute 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)this.configure(builder, query)).join(attribute, joinType), // cast must be valid... new QueryInfo()); } default FromStream> join(ListAttribute attribute) { return this.join(attribute, JoinType.INNER); } default FromStream> join(ListAttribute 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)this.configure(builder, query)).join(attribute, joinType), // cast must be valid... new QueryInfo()); } default FromStream> join(SetAttribute attribute) { return this.join(attribute, JoinType.INNER); } default FromStream> join(SetAttribute 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)this.configure(builder, query)).join(attribute, joinType), // cast must be valid... new QueryInfo()); } default FromStream> join(MapAttribute attribute) { return this.join(attribute, JoinType.INNER); } default FromStream> join(MapAttribute 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)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 peeker); @Override > SearchStream bind(Ref ref, Function refFunction); @Override SearchStream filter(SingularAttribute attribute); @Override SearchStream filter(Function> 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); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy