Transaction.kt

/*
 * Copyright (C) 2017 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] class as a transaction method.
 *
 * When used on a non-abstract method of an abstract [Dao] class,
 * the derived implementation of the method will execute the super method in a database transaction.
 * All the parameters and return types are preserved. The transaction will be marked as successful
 * unless an exception is thrown in the method body.
 *
 * Example:
 *
 * ```
 * @Dao
 * abstract class SongDao {
 *     @Insert
 *     abstract fun insert(song: Song)
 *     @Delete
 *     abstract fun delete(song: Song)
 *     @Transaction
 *     fun insertAndDeleteInTransaction(newSong: Song, oldSong: Song) {
 *         // Anything inside this method runs in a single transaction.
 *         insert(newSong)
 *         delete(oldSong)
 *     }
 * }
 * ```
 *
 * When used on a [Query] method that has a `SELECT` statement, the generated code for
 * the [Query] will be run in a transaction. There are 2 main cases where you may want to do that:
 *
 * * If the result of the query is fairly big, it is better to run it inside a transaction
 * to receive a consistent result. Otherwise, if the query result does not fit into a single
 * [android.database.CursorWindow], the query result may be corrupted due to changes in the database
 * in between cursor window swaps.
 *
 * * If the result of the query is a POJO with {@link Relation} fields, these fields are
 * queried separately. To receive consistent results between these queries, you also want
 * to run them in a single transaction.
 *
 * Example:
 *
 * ```
 * data class AlbumWithSongs : Album (
 *     @Relation(parentColumn = "albumId", entityColumn = "songId")
 *     val songs: List<Song>
 * )
 *
 * @Dao
 * public interface AlbumDao {
 *     @Transaction
 *     @Query("SELECT * FROM album")
 *     fun loadAll(): List<AlbumWithSongs>
 * }
 * ```
 *
 * If the query is asynchronous (e.g. returns a [androidx.lifecycle.LiveData]
 * or RxJava [Flowable]), the transaction is properly handled when the query is run, not when
 * the method is called.
 *
 * Putting this annotation on an [Insert], [Update] or [Delete] method has no
 * impact because those methods are always run inside a transaction. Similarly, if a method is
 * annotated with [Query] but runs an INSERT, UPDATE or DELETE statement, it is automatically
 * wrapped in a transaction and this annotation has no effect. Room will only perform at most one
 * transaction at a time, additional transactions are queued
 * and executed on a first come, first serve order.
 */
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
public annotation class Transaction