1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.room;
18 
19 import java.lang.annotation.ElementType;
20 import java.lang.annotation.Retention;
21 import java.lang.annotation.RetentionPolicy;
22 import java.lang.annotation.Target;
23 
24 /**
25  * Marks a method in a {@link Dao} annotated class as a raw query method where you can pass the
26  * query as a {@link androidx.sqlite.db.SupportSQLiteQuery SupportSQLiteQuery}.
27  * <pre>
28  * {@literal @}Dao
29  * interface RawDao {
30  *     {@literal @}RawQuery
31  *     User getUserViaQuery(SupportSQLiteQuery query);
32  * }
33  * SimpleSQLiteQuery query = new SimpleSQLiteQuery("SELECT * FROM User WHERE id = ? LIMIT 1",
34  *         new Object[]{userId});
35  * User user2 = rawDao.getUserViaQuery(query);
36  * </pre>
37  * <p>
38  * Room will generate the code based on the return type of the function and failure to
39  * pass a proper query will result in a runtime failure or an undefined result.
40  * <p>
41  * If you know the query at compile time, you should always prefer {@link Query} since it validates
42  * the query at compile time and also generates more efficient code since Room can compute the
43  * query result at compile time (e.g. it does not need to account for possibly missing columns in
44  * the response).
45  * <p>
46  * On the other hand, {@code RawQuery} serves as an escape hatch where you can build your own
47  * SQL query at runtime but still use Room to convert it into objects.
48  * <p>
49  * {@code RawQuery} methods must return a non-void type. If you want to execute a raw query that
50  * does not return any value, use {@link androidx.room.RoomDatabase#query
51  * RoomDatabase#query} methods.
52  * <p>
53  * RawQuery methods can only be used for read queries. For write queries, use
54  * {@link androidx.room.RoomDatabase#getOpenHelper
55  * RoomDatabase.getOpenHelper().getWritableDatabase()}.
56  * <p>
57  * <b>Observable Queries:</b>
58  * <p>
59  * {@code RawQuery} methods can return observable types but you need to specify which tables are
60  * accessed in the query using the {@link #observedEntities()} field in the annotation.
61  * <pre>
62  * {@literal @}Dao
63  * interface RawDao {
64  *     {@literal @}RawQuery(observedEntities = User.class)
65  *     LiveData&lt;List&lt;User>> getUsers(SupportSQLiteQuery query);
66  * }
67  * LiveData&lt;List&lt;User>> liveUsers = rawDao.getUsers(
68  *     new SimpleSQLiteQuery("SELECT * FROM User ORDER BY name DESC"));
69  * </pre>
70  * <b>Returning Pojos:</b>
71  * <p>
72  * RawQueries can also return plain old java objects, similar to {@link Query} methods.
73  * <pre>
74  * public class NameAndLastName {
75  *     public final String name;
76  *     public final String lastName;
77  *
78  *     public NameAndLastName(String name, String lastName) {
79  *         this.name = name;
80  *         this.lastName = lastName;
81  *     }
82  * }
83  *
84  * {@literal @}Dao
85  * interface RawDao {
86  *     {@literal @}RawQuery
87  *     NameAndLastName getNameAndLastName(SupportSQLiteQuery query);
88  * }
89  * NameAndLastName result = rawDao.getNameAndLastName(
90  *      new SimpleSQLiteQuery("SELECT * FROM User WHERE id = ?", new Object[]{userId}))
91  * // or
92  * NameAndLastName result = rawDao.getNameAndLastName(
93  *      new SimpleSQLiteQuery("SELECT name, lastName FROM User WHERE id = ?",
94  *          new Object[]{userId})))
95  * </pre>
96  * <p>
97  * <b>Pojos with Embedded Fields:</b>
98  * <p>
99  * {@code RawQuery} methods can return pojos that include {@link Embedded} fields as well.
100  * <pre>
101  * public class UserAndPet {
102  *     {@literal @}Embedded
103  *     public User user;
104  *     {@literal @}Embedded
105  *     public Pet pet;
106  * }
107  *
108  * {@literal @}Dao
109  * interface RawDao {
110  *     {@literal @}RawQuery
111  *     UserAndPet getUserAndPet(SupportSQLiteQuery query);
112  * }
113  * UserAndPet received = rawDao.getUserAndPet(
114  *         new SimpleSQLiteQuery("SELECT * FROM User, Pet WHERE User.id = Pet.userId LIMIT 1"))
115  * </pre>
116  *
117  * <b>Relations:</b>
118  * <p>
119  * {@code RawQuery} return types can also be objects with {@link Relation Relations}.
120  * <pre>
121  * public class UserAndAllPets {
122  *     {@literal @}Embedded
123  *     public User user;
124  *     {@literal @}Relation(parentColumn = "id", entityColumn = "userId")
125  *     public List&lt;Pet> pets;
126  * }
127  *
128  * {@literal @}Dao
129  * interface RawDao {
130  *     {@literal @}RawQuery
131  *     List&lt;UserAndAllPets> getUsersAndAllPets(SupportSQLiteQuery query);
132  * }
133  * List&lt;UserAndAllPets> result = rawDao.getUsersAndAllPets(
134  *      new SimpleSQLiteQuery("SELECT * FROM users"));
135  * </pre>
136  */
137 @Target(ElementType.METHOD)
138 @Retention(RetentionPolicy.CLASS)
139 public @interface RawQuery {
140     /**
141      * Denotes the list of entities which are accessed in the provided query and should be observed
142      * for invalidation if the query is observable.
143      * <p>
144      * The listed classes should either be annotated with {@link Entity} or they should reference to
145      * at least 1 Entity (via {@link Embedded} or {@link Relation}).
146      * <p>
147      * Providing this field in a non-observable query has no impact.
148      * <pre>
149      * {@literal @}Dao
150      * interface RawDao {
151      *     {@literal @}RawQuery(observedEntities = User.class)
152      *     LiveData&lt;List&lt;User>> getUsers(String query);
153      * }
154      * LiveData&lt;List&lt;User>> liveUsers = rawDao.getUsers("select * from User ORDER BY name
155      * DESC");
156      * </pre>
157      *
158      * @return List of entities that should invalidate the query if changed.
159      */
observedEntities()160     Class[] observedEntities() default {};
161 }
162