jakarta.data.repository.Query Maven / Gradle / Ivy
/*
* Copyright (c) 2022,2024 Contributors to the Eclipse Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package jakarta.data.repository;
import jakarta.data.Sort;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotates a repository method as a query method, specifying a query written in Jakarta Data Query Language (JDQL)
* or in Jakarta Persistence Query Language (JPQL). A Jakarta Data provider is not required to support the complete JPQL
* language, which targets relational data stores. However, a given provider might offer features of JPQL which go
* beyond the subset required by JDQL, or might even offer vendor-specific extensions to JDQL which target particular
* capabilities of the target data store technology. Such extensions come with no guarantee of portability between
* providers, nor between databases.
*
* The required {@link #value} member specifies the JDQL or JPQL query as a string.
*
* For {@code select} statements, the return type of the query method must be consistent with the type returned by
* the query. For {@code update} or {@code delete} statements, it must be {@code void}, {@code int} or {@code long}.
*
* Compared to SQL, JDQL allows an abbreviated syntax for {@code select} statements:
*
* - The {@code from} clause is optional in JDQL. When it is missing, the queried entity is determined by the return
* type of the repository method, or, if the return type is not an entity type, by the primary entity type of the
* repository.
* - The {@code select} clause is optional in both JDQL and JPQL. When it is missing, the query returns the queried
* entity.
*
*
* A query might involve:
*
* - named parameters of form {@code :name} where the labels {@code name} are legal Java identifiers, or
* - ordinal parameters of form {@code ?n} where the labels {@code n} are sequential positive integers starting
* from {@code 1}.
*
* A given query must not mix named and ordinal parameters.
*
* Each parameter of an annotated query method must either:
*
* - have exactly the same name (the parameter name in the Java source, or a name assigned by {@link Param @Param})
* and type as a named parameter of the query,
* - have exactly the same type and position within the parameter list of the method as a positional parameter of the
* query, or
* - be of type {@code Limit}, {@code Order}, {@code PageRequest}, or {@code Sort}.
*
*
* The {@link Param} annotation associates a method parameter with a named parameter. The {@code Param} annotation is
* unnecessary when the method parameter name matches the name of a named parameter and the application is compiled with
* the {@code -parameters} compiler option making parameter names available at runtime.
*
* A method parameter is associated with an ordinal parameter by its position in the method parameter list. The first
* parameter of the method is associated with the ordinal parameter {@code ?1}.
*
* For example,
*
*
* @Repository
* public interface People extends CrudRepository<Person, Long> {
*
* // JDQL with positional parameters
* @Query("where firstName = ?1 and lastName = ?2")
* List<Person> byName(String first, String last);
*
* // JDQL with a named parameter
* @Query("where firstName || ' ' || lastName like :pattern")
* List<Person> byName(String pattern);
*
* // JPQL using a positional parameter
* @Query("from Person where extract(year from birthdate) = ?1")
* List<Person> bornIn(int year);
*
* // JPQL using named parameters
* @Query("select distinct name from Person " +
* "where length(name) >= :min and length(name) <= :max")
* Page<String> namesOfLength(@Param("min") int minLength,
* @Param("max") int maxLength,
* PageRequest pageRequest,
* Order<Person> order);
*
* ...
* }
*
*
* A method annotated with {@code @Query} must return one of the following types:
*
* - the query result type {@code R}, when the query returns a single result,
* - {@code Optional
}, when the query returns at most a single result,
* - an array type {@code R[]},
*
- {@code List
},
* - {@code Stream
}, or
* - {@code Page
} or {@code CursoredPage}.
*
* The method returns an object for every query result.
*
* - If the return type of the annotated method is {@code R} or {@code Optional
} and more than one record satisfies
* the query restriction, the method must throw {@link jakarta.data.exceptions.NonUniqueResultException}.
* - If the return type of the annotated method is {@code R} and no record satisfies the query restriction, the method
* must throw {@link jakarta.data.exceptions.EmptyResultException}.
*
*
* Annotations such as {@code @Find}, {@code @Query}, {@code @Insert}, {@code @Update}, {@code @Delete}, and
* {@code @Save} are mutually-exclusive. A given method of a repository interface may have at most one {@code @Find}
* annotation, lifecycle annotation, or query annotation.
*
* @see Param
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Query {
/**
*
Specifies the query executed by the annotated repository method,
* in JDQL or JPQL.
*
* If the annotated repository method accepts other forms of sorting
* (such as a parameter of type {@link Sort}), it is the responsibility
* of the application programmer to compose the query so that an
* {@code ORDER BY} clause can be validly appended to the text of the
* query.
*
* @return the query to be executed when the annotated method is called.
*/
String value();
}