Module storm.java

Class QueryBuilderImpl<T extends Data,R,ID>

java.lang.Object
st.orm.template.QueryBuilder<T,R,ID>
st.orm.template.impl.QueryBuilderImpl<T,R,ID>
All Implemented Interfaces:
st.orm.core.template.impl.Subqueryable

public final class QueryBuilderImpl<T extends Data,R,ID> extends QueryBuilder<T,R,ID> implements st.orm.core.template.impl.Subqueryable
QueryBuilderImpl relies on preview features of the Java platform:
  • QueryBuilderImpl refers to one or more preview APIs: StringTemplate.
Programs can only use QueryBuilderImpl when preview features are enabled.
Preview features may be removed in a future release, or upgraded to permanent features of the Java platform.
  • Constructor Details

    • QueryBuilderImpl

      public QueryBuilderImpl(st.orm.core.template.QueryBuilder<T,R,ID> core)
  • Method Details

    • typedId

      public <X> QueryBuilder<T,R,X> typedId(Class<X> pkType)
      Returns a typed query builder for the specified primary key type.
      Specified by:
      typedId in class QueryBuilder<T extends Data,R,ID>
      Type Parameters:
      X - the type of the primary key.
      Parameters:
      pkType - the primary key type.
      Returns:
      the typed query builder.
      Throws:
      PersistenceException - if the pk type is not valid.
      Since:
      1.14
    • narrow

      public <X extends Data> QueryBuilder<X,R,ID> narrow(Class<X> rootType)
      Returns a query builder rooted at the specified type.
      Specified by:
      narrow in class QueryBuilder<T extends Data,R,ID>
      Type Parameters:
      X - the root table type.
      Parameters:
      rootType - the type this query is rooted at.
      Returns:
      the query builder, rooted at rootType.
      Since:
      1.14
    • widen

      public QueryBuilder<Data,R,ID> widen()
      Widens the query as a join does, without joining.
      Specified by:
      widen in class QueryBuilder<T extends Data,R,ID>
      Returns:
      the query builder, accepting paths from any entity in the query.
      Since:
      1.14
    • unsafe

      public QueryBuilder<T,R,ID> unsafe()
      Returns a query builder that allows UPDATE and DELETE queries without a WHERE clause.

      By default, Storm rejects UPDATE and DELETE queries that lack a WHERE clause, throwing a PersistenceException. Call this method to disable that check when you intentionally want to affect all rows in the table.

      Specified by:
      unsafe in class QueryBuilder<T extends Data,R,ID>
      Since:
      1.2
    • distinct

      public QueryBuilder<T,R,ID> distinct()
      Marks the current query as a distinct query.
      Specified by:
      distinct in class QueryBuilder<T extends Data,R,ID>
      Returns:
      the query builder.
    • fetch

      public QueryBuilder<T,R,ID> fetch(List<? extends Navigable<T,? extends Data>> paths)
      Resolves the references at the specified paths as part of this query.
      Specified by:
      fetch in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      paths - the paths of the references to resolve.
      Returns:
      the query builder.
      Since:
      1.13
      See Also:
    • orderBy

      public QueryBuilder<T,R,ID> orderBy(StringTemplatePREVIEW template)
      Adds an ORDER BY clause to the query using a string template. Multiple calls to this method append additional columns to the ORDER BY clause.
      Specified by:
      orderBy in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      template - the template to order by.
      Returns:
      the query builder.
      Since:
      1.2
    • groupBy

      public QueryBuilder<T,R,ID> groupBy(StringTemplatePREVIEW template)
      Adds a GROUP BY clause to the query using a string template. Multiple calls to this method append additional columns to the GROUP BY clause.
      Specified by:
      groupBy in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      template - the template to group by.
      Returns:
      the query builder.
      Since:
      1.2
    • having

      public QueryBuilder<T,R,ID> having(StringTemplatePREVIEW template)
      Adds a HAVING clause to the query using the specified expression. Multiple calls to this method are combined using AND.
      Specified by:
      having in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      template - the expression to add.
      Returns:
      the query builder.
      Since:
      1.2
    • havingExists

      public QueryBuilder<T,R,ID> havingExists(QueryBuilder<?,?,?> subquery)
      Adds a HAVING clause that keeps the groups for which the specified subquery returns at least one row.
      Specified by:
      havingExists in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      subquery - the subquery to test for existence.
      Returns:
      the query builder.
      Since:
      1.13
    • havingNotExists

      public QueryBuilder<T,R,ID> havingNotExists(QueryBuilder<?,?,?> subquery)
      Adds a HAVING clause that keeps the groups for which the specified subquery returns no rows.
      Specified by:
      havingNotExists in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      subquery - the subquery to test for absence.
      Returns:
      the query builder.
      Since:
      1.13
    • hasOrderBy

      protected boolean hasOrderBy()
      Returns true if any ORDER BY columns have been added to this query builder.
      Specified by:
      hasOrderBy in class QueryBuilder<T extends Data,R,ID>
      Returns:
      true if ORDER BY columns are present, false otherwise.
      Since:
      1.9
    • forShare

      public QueryBuilder<T,R,ID> forShare()
      Locks the selected rows for reading.
      Specified by:
      forShare in class QueryBuilder<T extends Data,R,ID>
      Returns:
      the query builder.
      Throws:
      PersistenceException - if the database does not support the specified lock mode, or if the lock mode is not supported for the current query.
      Since:
      1.2
    • forUpdate

      public QueryBuilder<T,R,ID> forUpdate()
      Locks the selected rows for reading.
      Specified by:
      forUpdate in class QueryBuilder<T extends Data,R,ID>
      Returns:
      the query builder.
      Throws:
      PersistenceException - if the database does not support the specified lock mode, or if the lock mode is not supported for the current query.
      Since:
      1.2
    • forLock

      public QueryBuilder<T,R,ID> forLock(StringTemplatePREVIEW template)
      Locks the selected rows using a custom lock mode.

      Note: This method results in non-portable code, as the lock mode is specific to the underlying database.

      Specified by:
      forLock in class QueryBuilder<T extends Data,R,ID>
      Returns:
      the query builder.
      Throws:
      PersistenceException - if the lock mode is not supported for the current query.
      Since:
      1.2
    • hint

      public QueryBuilder<T,R,ID> hint(String hint)
      Adds an optimizer hint to the statement this builder builds.
      Specified by:
      hint in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      hint - the hint text, as the database reads it.
      Returns:
      the query builder.
      Since:
      1.15
    • build

      public Query build()
      Builds the query based on the current state of the query builder.
      Specified by:
      build in class QueryBuilder<T extends Data,R,ID>
      Returns:
      the constructed query.
    • getResultStream

      public Stream<R> getResultStream()
      Executes the query and returns a stream of results.

      The resulting stream is lazily loaded, meaning that the records are only retrieved from the database as they are consumed by the stream. This approach is efficient and minimizes the memory footprint, especially when dealing with large volumes of records.

      Note: Calling this method does trigger the execution of the underlying query, so it should only be invoked when the query is intended to run. Since the stream holds resources open while in use, it must be closed after usage to prevent resource leaks.

      Specified by:
      getResultStream in class QueryBuilder<T extends Data,R,ID>
      Returns:
      a stream of results.
      Throws:
      PersistenceException - if the query operation fails due to underlying database issues, such as connectivity.
    • getResultCount

      public long getResultCount()
      Delegates to the core builder, which executes a dedicated count query derived from the builder's shape.
      Overrides:
      getResultCount in class QueryBuilder<T extends Data,R,ID>
      Returns:
      the total number of results of this query as a long value.
    • getResultList

      public List<R> getResultList()
      Eager terminals delegate to the core builder, which executes them without the fetch-size hint, avoiding transaction wrapping for eagerly consumed results.
      Specified by:
      getResultList in class QueryBuilder<T extends Data,R,ID>
      Returns:
      the list of results.
    • getSingleResult

      public R getSingleResult()
      Description copied from class: QueryBuilder
      Executes the query and returns a single result.
      Specified by:
      getSingleResult in class QueryBuilder<T extends Data,R,ID>
      Returns:
      the single result.
    • getOptionalResult

      public Optional<R> getOptionalResult()
      Description copied from class: QueryBuilder
      Executes the query and returns an optional result.
      Specified by:
      getOptionalResult in class QueryBuilder<T extends Data,R,ID>
      Returns:
      the optional result.
    • getResultGroupedBy

      public <V extends Data> SequencedMap<V,List<R>> getResultGroupedBy(TypedMetamodel<T,V,V> path)
      Description copied from class: QueryBuilder
      Executes the query and returns the results grouped by the record reached via path, typically the parent entity of a foreign key. The SQL is not affected by the grouping; the same select is executed and the results are grouped during hydration.

      The returned map and its lists are unmodifiable and insertion-ordered: groups appear in the order their first result is encountered, and results appear in encounter order within each group. Use orderBy() to control both. Duplicate entities within a result set are guaranteed to share the same instance as long as earlier occurrences remain strongly reachable, and the grouping retains every result and group key while the result set is consumed; each result's reference to its group key is therefore the map key itself.

      This method requires an entity query: the result type must be the table type T so that the path can be resolved against the results. The path must also resolve to a non-null record for every result; paths over nullable foreign keys must be narrowed with a where() clause first.

      The signature requires a path whose component type equals its field type, which is how the generated metamodels type eagerly fetched fields. Paths over Ref fields are typed TypedMetamodel<T, V, Ref<V>> and therefore do not compile; use QueryBuilder.getResultGroupedByRef(Metamodel) for those.

      Specified by:
      getResultGroupedBy in class QueryBuilder<T extends Data,R,ID>
      Type Parameters:
      V - the type of the record to group by.
      Parameters:
      path - the metamodel path from the table type to the record to group by, for example Pet_.owner.
      Returns:
      the results grouped by the record reached via path, in encounter order.
    • getResultGroupedByRef

      public <V extends Data> SequencedMap<Ref<V>,List<R>> getResultGroupedByRef(Metamodel<T,V> path)
      Description copied from class: QueryBuilder
      Executes the query and returns the results grouped by a lightweight ref to the record reached via path, typically the parent entity of a foreign key. The SQL is not affected by the grouping; the same select is executed and the results are grouped during hydration.

      This is the ref-based variant of QueryBuilder.getResultGroupedBy(TypedMetamodel): the map keys are Ref instances, which are compared by primary key, keeping map lookups constant-cost regardless of the size of the group record.

      The behavior of the keys follows how the foreign key is declared on the record:

      • Entity field (for example @FK Owner owner): the referenced record is fetched eagerly, as part of the query's auto-joined graph, and is materialized with each result. The keys are loaded refs wrapping that record: Ref.getOrNull() returns it directly, without touching the database.
      • Ref field (for example @FK Ref<Pet> pet): the referenced record is fetched lazily; the query reads only the foreign key column, without joining or fetching the referenced table. The keys are the unloaded refs produced by the query, carrying just the primary key. When the records are needed, fetch them afterwards in a single query with findAllByRef(map.keySet()).

      The returned map and its lists are unmodifiable and insertion-ordered: groups appear in the order their first result is encountered, and results appear in encounter order within each group. Use orderBy() to control both.

      This method requires an entity query: the result type must be the table type T so that the path can be resolved against the results. The path must also resolve to a non-null value for every result; paths over nullable foreign keys must be narrowed with a where() clause first.

      Specified by:
      getResultGroupedByRef in class QueryBuilder<T extends Data,R,ID>
      Type Parameters:
      V - the type of the record to group by.
      Parameters:
      path - the metamodel path from the table type to the record to group by, for example Pet_.owner.
      Returns:
      the results grouped by a ref to the record reached via path, in encounter order.
    • crossJoin

      public QueryBuilder<Data,R,ID> crossJoin(Class<? extends Data> relation)
      Adds a cross join to the query.
      Specified by:
      crossJoin in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      relation - the relation to join.
      Returns:
      the query builder.
    • innerJoin

      public TypedJoinBuilder<T,R,ID> innerJoin(Class<? extends Data> relation)
      Adds an inner join to the query.
      Specified by:
      innerJoin in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      relation - the relation to join.
      Returns:
      the query builder.
    • leftJoin

      public TypedJoinBuilder<T,R,ID> leftJoin(Class<? extends Data> relation)
      Adds a left join to the query.
      Specified by:
      leftJoin in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      relation - the relation to join.
      Returns:
      the query builder.
    • rightJoin

      public TypedJoinBuilder<T,R,ID> rightJoin(Class<? extends Data> relation)
      Adds a right join to the query.
      Specified by:
      rightJoin in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      relation - the relation to join.
      Returns:
      the query builder.
    • join

      public TypedJoinBuilder<T,R,ID> join(JoinType type, Class<? extends Data> relation, String alias)
      Adds a join of the specified type to the query.
      Specified by:
      join in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      type - the type of the join (e.g., INNER, LEFT, RIGHT).
      relation - the relation to join.
      alias - the alias to use for the joined relation.
      Returns:
      the query builder.
    • crossJoin

      public QueryBuilder<Data,R,ID> crossJoin(StringTemplatePREVIEW template)
      Adds a cross join to the query.
      Specified by:
      crossJoin in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      template - the condition to join.
      Returns:
      the query builder.
    • innerJoin

      public JoinBuilder<T,R,ID> innerJoin(StringTemplatePREVIEW template, String alias)
      Adds an inner join to the query.
      Specified by:
      innerJoin in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      template - the condition to join.
      alias - the alias to use for the joined relation.
      Returns:
      the query builder.
    • leftJoin

      public JoinBuilder<T,R,ID> leftJoin(StringTemplatePREVIEW template, String alias)
      Adds a left join to the query.
      Specified by:
      leftJoin in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      template - the condition to join.
      alias - the alias to use for the joined relation.
      Returns:
      the query builder.
    • rightJoin

      public JoinBuilder<T,R,ID> rightJoin(StringTemplatePREVIEW template, String alias)
      Adds a right join to the query.
      Specified by:
      rightJoin in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      template - the condition to join.
      alias - the alias to use for the joined relation.
      Returns:
      the query builder.
    • join

      public JoinBuilder<T,R,ID> join(JoinType type, StringTemplatePREVIEW template, String alias)
      Adds a join of the specified type to the query using a template.
      Specified by:
      join in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      type - the join type.
      template - the template to join.
      alias - the alias to use for the joined relation.
      Returns:
      the query builder.
    • join

      public JoinBuilder<T,R,ID> join(JoinType type, QueryBuilder<?,?,?> subquery, String alias)
      Adds a join of the specified type to the query using a subquery.
      Specified by:
      join in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      type - the join type.
      subquery - the subquery to join.
      alias - the alias to use for the joined relation.
      Returns:
      the query builder.
    • where

      public QueryBuilder<T,R,ID> where(Function<WhereBuilder<T,R,ID>,PredicateBuilder<T,?,?>> predicate)
      Adds a WHERE clause to the query using a WhereBuilder.
      Specified by:
      where in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      predicate - the predicate to add.
      Returns:
      the query builder.
    • limit

      public QueryBuilder<T,R,ID> limit(int limit)
      Adds a LIMIT clause to the query.
      Specified by:
      limit in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      limit - the maximum number of records to return.
      Returns:
      the query builder.
      Since:
      1.2
    • offset

      public QueryBuilder<T,R,ID> offset(int offset)
      Adds an OFFSET clause to the query.
      Specified by:
      offset in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      offset - the offset.
      Returns:
      the query builder.
      Since:
      1.2
    • scroll

      public Window<R> scroll(Scrollable<T> scrollable)
      Description copied from class: QueryBuilder
      Executes a scroll request and returns a Window: the results in the request's sort order, the flags that say whether rows exist after and before the window, and the tokens that continue from it.

      The request owns the ordering, so the query must not carry an ORDER BY of its own. The sort fields and the key are read from each row alongside the result, so the tokens are there for every result type: the entity, a projection, a ref or a custom select type. A window reached through Window.previous() comes back in the same sort order as every other window.

      Specified by:
      scroll in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      scrollable - the scroll request: ordering, size and position.
      Returns:
      a window containing the results and navigation tokens.
    • windows

      public Stream<Window<R>> windows(int size)
      Description copied from class: QueryBuilder
      Executes the query in windows of size rows ordered by the primary key, each window one closed statement.

      Where QueryBuilder.getResultStream() holds one open statement on the connection for as long as the stream is consumed, a window is fetched by a statement that has returned and closed before the window is handed to the caller. Between windows the connection is free, so the loop over a window may query, fetch references and write, inside a transaction or with a transaction per window. The stream carries no database resource and needs no closing. Each window is its own statement: it runs the query's WHERE clause again from the cursor position, and under READ COMMITTED it sees rows committed since the previous window.

      Windows are keyset windows over the primary key, so the query must not carry an ORDER BY of its own, and the result type must be the entity type the key belongs to: selectRef() and custom select types are refused. A compound primary key is refused too; pass QueryBuilder.windows(Scrollable) a single-column unique key instead. The rows come in ascending key order; pass Scrollable.of(key, size).descending() to QueryBuilder.windows(Scrollable) for descending order.

      
       users.select().where(User_.city, EQUALS, city).windows(1000).forEach(window ->
           users.update(window.content().stream()
               .map(user -> new User(user.id(), user.email().toLowerCase(), user.birthDate(), user.street(), user.postalCode(), user.city()))
               .toList()));
       
      Specified by:
      windows in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      size - the maximum number of rows per window (must be positive).
      Returns:
      a stream of windows; each window's Window.next() resumes the iteration after that window.
    • windows

      public Stream<Window<R>> windows(Scrollable<T> scrollable)
      Description copied from class: QueryBuilder
      Executes the query in windows described by the given scroll request, each window one closed statement.

      This is the form of QueryBuilder.windows(int) that chooses the key, the sort fields, the directions and the starting position: Scrollable.of(key, size) iterates from the start, a Window.next() token or Scrollable.from(String) resumes after an earlier window, and .descending() iterates in descending key order. The same key rules as QueryBuilder.scroll(Scrollable) apply.

      Specified by:
      windows in class QueryBuilder<T extends Data,R,ID>
      Parameters:
      scrollable - the scroll request describing key, sort, size, direction and starting position.
      Returns:
      a stream of windows; each window's Window.next() resumes the iteration after that window.
    • getSubquery

      public st.orm.core.template.TemplateString getSubquery()
      Specified by:
      getSubquery in interface st.orm.core.template.impl.Subqueryable