Query.kt
/*
* 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
/**
* 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](https://www.sqlite.org/c3ref/bind_blob.html) 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 fun findSongsByReleaseYear(year: Int): List<Song>
* ```
*
* 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 fun findByIds(songIds: Array<Long>): List<Song>
* ```
*
* 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](https://www.sqlite.org/limits.html)
*
* 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 [android.database.Cursor] or any query
* result can be wrapped in a [androidx.lifecycle.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<T>` from query methods. This creates a
* `Flow<T>` 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<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 `Flow<List<T>>` 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<T>`, querying an empty table throws a null pointer
* exception.
* * When the return type is `Flow<T?>`, querying an empty table emits a null value.
* * When the return type is `Flow<List<T>>`, querying an empty table emits an empty
* list.
*
* **RxJava2**
*
* If you are using RxJava2, you can also return `Flowable<T>` or
* `Publisher<T>` 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<T[]>] or [Flowable<List<T>>] to workaround this limitation.
*
* Both `Flowable<T>` and `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 `Maybe<T>` or `Single<T>`. If a `Single<T>` query returns `null`,
* Room will throw [androidx.room.EmptyResultSetException].
*
* Additionally if the statement is an INSERT, UPDATE or DELETE then the return types,
* `Single<T>`, `Maybe<T>` 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:
*
* ```
* data class SongDuration (
* val name: String,
* @ColumnInfo(name = "duration")
* val length: String
* )
* ```
*
* You can write a query like this:
*
* ```
* @Query("SELECT name, duration FROM song WHERE id = :songId LIMIT 1")
* public abstract fun findSongDuration(songId: Int): SongDuration
* ```
*
* 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.
*/
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER)
@Retention(AnnotationRetention.BINARY)
public annotation class Query(
/**
* The SQLite query to be run.
* @return The query to be run.
*/
val value: String
)