Class QueryStream.Builder

java.lang.Object
org.dellroad.querystream.jpa.util.ForwardingCriteriaBuilder
org.dellroad.querystream.jpa.QueryStream.Builder
All Implemented Interfaces:
CriteriaBuilder
Enclosing interface:
QueryStream<X,S extends Selection<X>,C extends CommonAbstractCriteria,C2 extends C,Q extends Query>

public static final class QueryStream.Builder extends ForwardingCriteriaBuilder
Builder for QueryStreams, DeleteStreams, and UpdateStreams.

New instances of this class are created via QueryStream.newBuilder().

For convenience, this class also implements CriteriaBuilder.

The primary stream creation methods are:

The following methods create SearchStreams for use in correlated subqueries:

See substream(Root) for an example of using substreams.

The following methods provide "convenience" access to objects that are not always readily available:

  • Method Details

    • getEntityManager

      public EntityManager getEntityManager()
      Get the EntityManager associated with this instance.
      Returns:
      associated EntityManager
    • getCriteriaBuilder

      public CriteriaBuilder getCriteriaBuilder()
      Get the CriteriaBuilder associated with this instance.
      Specified by:
      getCriteriaBuilder in class ForwardingCriteriaBuilder
      Returns:
      CriteriaBuilder created from this instance's EntityManager
    • stream

      public <X> RootStream<X> stream(Class<X> type)
      Create a SearchStream for search queries.
      Type Parameters:
      X - stream result type
      Parameters:
      type - stream result type
      Returns:
      new search stream
      Throws:
      IllegalArgumentException - if type is null
    • substream

      public <X> RootStream<X> substream(Root<X> root)
      Create a SearchStream for use as a subquery, using the specified correlated Root.

      The returned RootStream cannot be materialized directly via toQuery() or toCriteriaQuery(); instead, it can only be used indirectly as a correlated subquery.

      Here's an example that returns the names of teachers who have one or more newly enrolled students:

        List<String> names = qb.stream(Teacher.class)
          .filter(teacher ->
             qb.substream(teacher)
               .map(Teacher_.students)
               .filter(Student_.newlyEnrolled)
               .exists()))
          .map(Teacher_.name)
          .getResultList();
       
      Type Parameters:
      X - stream result type
      Parameters:
      root - correlated root for subquery
      Returns:
      new subquery search stream
      Throws:
      IllegalArgumentException - if root is null
    • substream

      public <X, Y> FromStream<Y,? extends From<X,Y>> substream(From<X,Y> from)
      Create a SearchStream for use as a subquery, using the specified From.

      This method inspects the type of from and then delegates to the substream() variant corresponding to whether from is really a Root, SetJoin, MapJoin, etc. You can use this method when you don't have more specific type information about from.

      Type Parameters:
      X - source type
      Y - target type
      Parameters:
      from - correlated join object for subquery
      Returns:
      new subquery search stream
      Throws:
      IllegalArgumentException - if join is null
      See Also:
    • substream

      public <X, E> FromStream<E,CollectionJoin<X,E>> substream(CollectionJoin<X,E> join)
      Create a SearchStream for use as a subquery, using the specified join.
      Type Parameters:
      X - join origin type
      E - collection element type
      Parameters:
      join - correlated join object for subquery
      Returns:
      new subquery search stream
      Throws:
      IllegalArgumentException - if join is null
      See Also:
    • substream

      public <X, E> FromStream<E,ListJoin<X,E>> substream(ListJoin<X,E> join)
      Create a SearchStream for use as a subquery, using the specified join.
      Type Parameters:
      X - join origin type
      E - list element type
      Parameters:
      join - correlated join object for subquery
      Returns:
      new subquery search stream
      Throws:
      IllegalArgumentException - if join is null
      See Also:
    • substream

      public <X, K, V> FromStream<V,MapJoin<X,K,V>> substream(MapJoin<X,K,V> join)
      Create a SearchStream for use as a subquery, using the specified join.
      Type Parameters:
      X - join origin type
      K - map key type
      V - map value type
      Parameters:
      join - correlated join object for subquery
      Returns:
      new subquery search stream
      Throws:
      IllegalArgumentException - if join is null
      See Also:
    • substream

      public <X, E> FromStream<E,SetJoin<X,E>> substream(SetJoin<X,E> join)
      Create a SearchStream for use as a subquery, using the specified join.
      Type Parameters:
      X - join origin type
      E - set element type
      Parameters:
      join - correlated join object for subquery
      Returns:
      new subquery search stream
      Throws:
      IllegalArgumentException - if join is null
      See Also:
    • substream

      public <X, E> FromStream<E,Join<X,E>> substream(Join<X,E> join)
      Create a SearchStream for use as a subquery, using the specified join.
      Type Parameters:
      X - join origin type
      E - collection element type
      Parameters:
      join - correlated join object for subquery
      Returns:
      new subquery search stream
      Throws:
      IllegalArgumentException - if join is null
      See Also:
    • deleteStream

      public <X> DeleteStream<X> deleteStream(Class<X> type)
      Create a DeleteStream for bulk delete queries.
      Type Parameters:
      X - stream target type
      Parameters:
      type - stream target type
      Returns:
      new bulk delete stream
      Throws:
      IllegalArgumentException - if type is null
    • updateStream

      public <X> UpdateStream<X> updateStream(Class<X> type)
      Create a UpdateStream for bulk update queries.
      Type Parameters:
      X - stream target type
      Parameters:
      type - stream target type
      Returns:
      new bulk update stream
      Throws:
      IllegalArgumentException - if type is null
    • currentQuery

      public CommonAbstractCriteria currentQuery()
      Access the current Criteria API query under construction.

      This method provides a way to access the current CriteriaQuery, CriteriaUpdate, CriteriaDelete, or Subquery currently being constructed.

      This is useful (for example) when implementing a QueryStream.filter(Function) function using the traditional JPA Criteria API and you need to create a Subquery:

        List<String> names = qb.stream(Teacher.class)
          .filter(teacher -> {
             Subquery<Student> subquery = qb.currentQuery().subquery(Student.class);
             // configure Student subquery...
             return qb.exists(subquery);
          })
          .map(Teacher_.name)
          .getResultList();         // note: the query is actually constructed here
       

      This method does not work outside of the context of a query being constructed.

      In the case of nested substream(s), then the inner-most query is returned:

        List<String> names = qb.stream(Teacher.class)
          .filter(teacher -> {
             // here qb.currentQuery() would return CriteriaQuery<Teacher>
             return qb.substream(teacher)
               .map(Teacher_.students)
               .filter(student -> {
                 // here qb.currentQuery() returns CriteriaQuery<Student>
                 Subquery<Test> subquery = qb.currentQuery().subquery(Test.class);
                 // configure Test subquery...
                 return qb.exists(subquery);
               })
               .exists();
          })
          .map(Teacher_.name)
          .getResultList();
        // here qb.currentQuery() will throw IllegalStateException
        qb.currentQuery();      // this will throw IllegalStateException
       

      The returned query object should not be modified.

      Returns:
      the current Criteria API query under construction
      Throws:
      IllegalStateException - if invoked outside of Criteria API query construction
    • bindParam

      public void bindParam(ParamBinding<?> binding)
      Register a parameter binding with the current Query that is under construction.

      This method addresses an inconvenience in the JPA Criteria API, which is that parameters are (a) used (i.e., within some Criteria API expression) and (b) bound (i.e., assigned a value) at two separate stages of query construction: parameters are used in the context of building a Criteria API Predicate, but the value of the parameter can only be bound once the overall Query has been constructed. Often these two steps are implemented at different places in the code.

      This method allows the value of the parameter to be bound at the same time it is used. It simply remembers the parameter value until later when the Query is created and the value can then be actually assigned. However, this method only works for Querys created via QueryStream API query execution methods, e.g., QueryStream.toQuery(), SearchStream.getResultList(), DeleteStream.delete(), SearchValue.value(), etc.

      This example shows how parameters would usually be handled:

        // Create parameter and get parameterized value
        Date startDateCutoff = ...;
        Parameter<Date> startDateParam = qb.parameter(Date.class);
      
        // Build Query
        Query query = qb.stream(Employee.class)
          .filter(e -> qb.greaterThan(e.get(Employee_.startDate), startDateParam))   // parameter used here
          .map(Employee_.name)
          .toQuery();
      
        // Bind parameter value
        query.setParameter(paramRef.get(), startDateCutoff, TemporalType.DATE);      // parameter bound here
      
        // Execute query
        return query.getResultStream();
       
      This example, which is functionally equivalent to the above, shows how bindParam() allows performing all of the parameter handling in one place:
        return qb.stream(Employee.class)
          .filter(e -> {
             Date startDateCutoff = ...;
             Parameter<Date> startDateParam = qb.parameter(Date.class);
             qb.bindParam(new DateParamBinding(startDateParam, startDateCutoff, TemporalType.DATE));
             return qb.greaterThan(e.get(Employee_.startDate), param);
          })
          .map(Employee_.name)
          .getResultStream();               // note: the Query is actually constructed here
       

      If this method is invoked outside of the context of Query construction, an IllegalStateException is thrown.

      Parameters:
      binding - parameter binding
      Throws:
      IllegalStateException - if invoked outside of QueryStream.toQuery() or other query execution method
      IllegalArgumentException - if binding is null