public @interface

Query

implements java.lang.annotation.Annotation

 androidx.room.Query

Overview

Marks a method in a Dao annotated class as a query method.

The value of the annotation includes the query that will be run when this method is called. This query is verified at compile time by Room to ensure that it compiles fine against the database.

The arguments of the method will be bound to the bind arguments in the SQL statement. See SQLite's binding documentation for details of bind arguments in SQLite.

Room only supports named bind parameter :name to avoid any confusion between the method parameters and the query bind parameters.

Room will automatically bind the parameters of the method into the bind arguments. This is done by matching the name of the parameters to the name of the bind arguments.

      @Query("SELECT * FROM song WHERE release_year = :year")
     public abstract List<Song> findSongsByReleaseYear(int year);
 

As an extension over SQLite bind arguments, Room supports binding a list of parameters to the query. At runtime, Room will build the correct query to have matching number of bind arguments depending on the number of items in the method parameter.

      @Query("SELECT * FROM song WHERE id IN(:songIds)")
     public abstract List<Song> findByIds(long[] songIds);
 
For the example above, if the songIds is an array of 3 elements, Room will run the query as: SELECT * FROM song WHERE id IN(?, ?, ?) and bind each item in the songIds array into the statement. One caveat of this type of binding is that only 999 items can be bound to the query, this is a limitation of SQLite ( see Section 9 of SQLite Limits).

There are 4 type of statements supported in Query methods: SELECT, INSERT, UPDATE, and DELETE.

For SELECT queries, Room will infer the result contents from the method's return type and generate the code that will automatically convert the query result into the method's return type. For single result queries, the return type can be any data object (also known as POJOs). For queries that return multiple values, you can use java.util.List or Array. In addition to these, any query may return or any query result can be wrapped in a LiveData.

INSERT queries can return void or long. If it is a long, the value is the SQLite rowid of the row inserted by this query. Note that queries which insert multiple rows cannot return more than one rowid, so avoid such statements if returning long.

UPDATE or DELETE queries can return void or int. If it is an int, the value is the number of rows affected by this query.

Flow

If you are using Kotlin, you can also return Flow from query methods. This creates a Flow object that emits the results of the query and re-dispatches the query every time the data in the queried table changes.

Note that querying a table with a return type of Flow always returns the first row in the result set, rather than emitting all of the rows in sequence. To observe changes over multiple rows in a table, use a return type of Flow> instead.

Keep nullability in mind when choosing a return type, as it affects how the query method handles empty tables:

  • When the return type is Flow, querying an empty table throws a null pointer exception.

  • When the return type is Flow, querying an empty table emits a null value.

  • When the return type is Flow>, querying an empty table emits an empty list.

RxJava2

If you are using RxJava2, you can also return Flowable or Publisher from query methods. Since Reactive Streams does not allow null, if the query returns a nullable type, it will not dispatch anything if the value is null (like fetching an Entity row that does not exist). You can return Flowable or Flowable> to workaround this limitation.

Both Flowable and Publisher will observe the database for changes and re-dispatch if data changes. If you want to query the database without observing changes, you can use Maybe or Single. If a Single query returns null, Room will throw EmptyResultSetException.

Additionally if the statement is an INSERT, UPDATE or DELETE then the return types, Single, Maybe and Completable are supported.

You can return arbitrary POJOs from your query methods as long as the fields of the POJO match the column names in the query result.

For example, if you have class:

 class SongDuration {
     String name;
      @ColumnInfo(name = "duration")
     String length;
 }
 
You can write a query like this:
      @Query("SELECT name, duration FROM song WHERE id = :songId LIMIT 1")
     public abstract SongDuration findSongDuration(int songId);
 
And Room will create the correct implementation to convert the query result into a SongDuration object. If there is a mismatch between the query result and the fields of the POJO, and as long as there is at least 1 field match, Room prints a RoomWarnings.CURSOR_MISMATCH warning and sets as many fields as it can.

Summary

Source

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * 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.
 */

package androidx.room;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Marks a method in a {@link Dao} annotated class as a query method.
 * <p>
 * The value of the annotation includes the query that will be run when this method is called. This
 * query is <b>verified at compile time</b> by Room to ensure that it compiles fine against the
 * database.
 * <p>
 * The arguments of the method will be bound to the bind arguments in the SQL statement. See
 * <href="https://www.sqlite.org/c3ref/bind_blob.html">SQLite's binding documentation</> for
 * details of bind arguments in SQLite.
 * <p>
 * Room only supports named bind parameter {@code :name} to avoid any confusion between the
 * method parameters and the query bind parameters.
 * <p>
 * Room will automatically bind the parameters of the method into the bind arguments. This is done
 * by matching the name of the parameters to the name of the bind arguments.
 * <pre>
 *     {@literal @}Query("SELECT * FROM song WHERE release_year = :year")
 *     public abstract List&lt;Song&gt; findSongsByReleaseYear(int year);
 * </pre>
 * <p>
 * As an extension over SQLite bind arguments, Room supports binding a list of parameters to the
 * query. At runtime, Room will build the correct query to have matching number of bind arguments
 * depending on the number of items in the method parameter.
 * <pre>
 *     {@literal @}Query("SELECT * FROM song WHERE id IN(:songIds)")
 *     public abstract List&lt;Song&gt; findByIds(long[] songIds);
 * </pre>
 * For the example above, if the {@code songIds} is an array of 3 elements, Room will run the
 * query as: {@code SELECT * FROM song WHERE id IN(?, ?, ?)} and bind each item in the
 * {@code songIds} array into the statement. One caveat of this type of binding is that only 999
 * items can be bound to the query, this is a limitation of SQLite (
 * <href="https://www.sqlite.org/limits.html">see Section 9 of SQLite Limits</>).
 * <p>
 * There are 4 type of statements supported in {@code Query} methods: SELECT, INSERT, UPDATE, and
 * DELETE.
 * <p>
 * For SELECT queries, Room will infer the result contents from the method's return type and
 * generate the code that will automatically convert the query result into the method's return
 * type. For single result queries, the return type can be any data object (also known as POJOs).
 * For queries that return multiple values, you can use {@link java.util.List} or {@code Array}.
 * In addition to these, any query may return {@link android.database.Cursor Cursor} or any query
 * result can be wrapped in a {@link androidx.lifecycle.LiveData LiveData}.
 * <p>
 * INSERT queries can return {@code void} or {@code long}. If it is a {@code long}, the value is the
 * SQLite rowid of the row inserted by this query. Note that queries which insert multiple rows
 * cannot return more than one rowid, so avoid such statements if returning {@code long}.
 * <p>
 * UPDATE or DELETE queries can return {@code void} or {@code int}. If it is an {@code int},
 * the value is the number of rows affected by this query.
 * <p>
 * <b>Flow</b>
 * <p>
 * If you are using Kotlin, you can also return {@code Flow<T>} from query methods. This creates a
 * {@code Flow<T>} object that emits the results of the query and re-dispatches the query every
 * time the data in the queried table changes.
 * <p>
 * Note that querying a table with a return type of {@code Flow<T>} always returns the first row
 * in the result set, rather than emitting all of the rows in sequence. To observe changes over
 * multiple rows in a table, use a return type of {@code Flow<List<T>>} instead.
 * <p>
 * Keep nullability in mind when choosing a return type, as it affects how the query method handles
 * empty tables:
 * <ul>
 * <li> <p>When the return type is {@code Flow<T>}, querying an empty table throws a null pointer
 * exception.
 * <li> <p>When the return type is {@code Flow<T?>}, querying an empty table emits a null value.
 * <li> <p>When the return type is {@code Flow<List<T>>}, querying an empty table emits an empty
 * list. </ul>
 * <p>
 * <b>RxJava2</b>
 * <p>
 * If you are using RxJava2, you can also return {@code Flowable<T>} or
 * {@code Publisher<T>} from query methods. Since Reactive Streams does not allow {@code null}, if
 * the query returns a nullable type, it will not dispatch anything if the value is {@code null}
 * (like fetching an {@link Entity} row that does not exist).
 * You can return {@code Flowable<T[]>} or {@code Flowable<List<T>>} to workaround this limitation.
 * <p>
 * Both {@code Flowable<T>} and {@code Publisher<T>} will observe the database for changes and
 * re-dispatch if data changes. If you want to query the database without observing changes, you can
 * use {@code Maybe<T>} or {@code Single<T>}. If a {@code Single<T>} query returns {@code null},
 * Room will throw {@link androidx.room.EmptyResultSetException EmptyResultSetException}.
 * <p>
 * Additionally if the statement is an INSERT, UPDATE or DELETE then the return types,
 * {@code Single<T>}, {@code Maybe<T>} and {@code Completable} are supported.
 * <p>
 * You can return arbitrary POJOs from your query methods as long as the fields of the POJO match
 * the column names in the query result.
 * <p>
 * For example, if you have class:
 * <pre>
 * class SongDuration {
 *     String name;
 *     {@literal @}ColumnInfo(name = "duration")
 *     String length;
 * }
 * </pre>
 * You can write a query like this:
 * <pre>
 *     {@literal @}Query("SELECT name, duration FROM song WHERE id = :songId LIMIT 1")
 *     public abstract SongDuration findSongDuration(int songId);
 * </pre>
 * And Room will create the correct implementation to convert the query result into a
 * {@code SongDuration} object. If there is a mismatch between the query result and the fields of
 * the POJO, and as long as there is at least 1 field match, Room prints a
 * {@link RoomWarnings#CURSOR_MISMATCH} warning and sets as many fields as it can.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface Query {
    /**
     * The SQLite query to be run.
     * @return The query to be run.
     */
    String value();
}