1efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar/*
2efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * Copyright (C) 2016 The Android Open Source Project
3efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar *
4efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * you may not use this file except in compliance with the License.
6efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * You may obtain a copy of the License at
7efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar *
8efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar *
10efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * Unless required by applicable law or agreed to in writing, software
11efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * See the License for the specific language governing permissions and
14efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * limitations under the License.
15efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar */
16efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar
17ba069d50913c3fb250bb60ec310439db36895337Alan Viverettepackage androidx.room;
1864db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar
192eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Arakiimport android.annotation.SuppressLint;
202eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Arakiimport android.app.ActivityManager;
21059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyarimport android.content.Context;
22efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyarimport android.database.Cursor;
232eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Arakiimport android.os.Build;
24a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyarimport android.util.Log;
25efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar
26ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.annotation.CallSuper;
27ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.annotation.NonNull;
28ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.annotation.Nullable;
29ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.annotation.RequiresApi;
30ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.annotation.RestrictTo;
31ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.annotation.WorkerThread;
32ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.collection.SparseArrayCompat;
33ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.core.app.ActivityManagerCompat;
34ddee2b5170ae257a7b2494f8aaa8459ebed806dcAurimas Liutikasimport androidx.arch.core.executor.ArchTaskExecutor;
35ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.migration.Migration;
36ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.sqlite.db.SimpleSQLiteQuery;
37ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.sqlite.db.SupportSQLiteDatabase;
38ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.sqlite.db.SupportSQLiteOpenHelper;
39ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.sqlite.db.SupportSQLiteQuery;
40ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.sqlite.db.SupportSQLiteStatement;
41ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory;
42ba069d50913c3fb250bb60ec310439db36895337Alan Viverette
43a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyarimport java.util.ArrayList;
44a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyarimport java.util.Collections;
45d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapardimport java.util.HashSet;
46a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyarimport java.util.List;
47d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapardimport java.util.Set;
4864cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Arakiimport java.util.concurrent.Callable;
495843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Arakiimport java.util.concurrent.locks.Lock;
505843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Arakiimport java.util.concurrent.locks.ReentrantLock;
51efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar
52efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar/**
53e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * Base class for all Room databases. All classes that are annotated with {@link Database} must
54e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * extend this class.
55e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * <p>
56e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * RoomDatabase provides direct access to the underlying database implementation but you should
57e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * prefer using {@link Dao} classes.
58e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets *
59e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * @see Database
60efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar */
61e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets//@SuppressWarnings({"unused", "WeakerAccess"})
62937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyarpublic abstract class RoomDatabase {
63059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar    private static final String DB_IMPL_SUFFIX = "_Impl";
646bbf7089c9d4050b04ad48e1a1e5e2c713c48840Yigit Boyar    /**
656bbf7089c9d4050b04ad48e1a1e5e2c713c48840Yigit Boyar     * Unfortunately, we cannot read this value so we are only setting it to the SQLite default.
666bbf7089c9d4050b04ad48e1a1e5e2c713c48840Yigit Boyar     *
676bbf7089c9d4050b04ad48e1a1e5e2c713c48840Yigit Boyar     * @hide
686bbf7089c9d4050b04ad48e1a1e5e2c713c48840Yigit Boyar     */
696bbf7089c9d4050b04ad48e1a1e5e2c713c48840Yigit Boyar    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
706bbf7089c9d4050b04ad48e1a1e5e2c713c48840Yigit Boyar    public static final int MAX_BIND_PARAMETER_CNT = 999;
71fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar    // set by the generated open helper.
72fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar    protected volatile SupportSQLiteDatabase mDatabase;
73059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar    private SupportSQLiteOpenHelper mOpenHelper;
7434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    private final InvalidationTracker mInvalidationTracker;
752e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar    private boolean mAllowMainThreadQueries;
762eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki    boolean mWriteAheadLoggingEnabled;
77efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar
78cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki    @Nullable
79cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki    protected List<Callback> mCallbacks;
80cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki
815843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki    private final ReentrantLock mCloseLock = new ReentrantLock();
825843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki
835843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki    /**
845843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki     * {@link InvalidationTracker} uses this lock to prevent the database from closing while it is
855843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki     * querying database updates.
865843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki     *
875843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki     * @return The lock for {@link #close()}.
885843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki     */
895843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki    Lock getCloseLock() {
905843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki        return mCloseLock;
915843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki    }
925843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki
93d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar    /**
94059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar     * Creates a RoomDatabase.
95059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar     * <p>
96059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar     * You cannot create an instance of a database, instead, you should acquire it via
97059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar     * {@link Room#databaseBuilder(Context, Class, String)} or
98059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar     * {@link Room#inMemoryDatabaseBuilder(Context, Class)}.
99059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar     */
100059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar    public RoomDatabase() {
10134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        mInvalidationTracker = createInvalidationTracker();
102059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar    }
103059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar
104059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar    /**
105059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar     * Called by {@link Room} when it is initialized.
106d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar     *
107059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar     * @param configuration The database configuration.
108d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar     */
109059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar    @CallSuper
110cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets    public void init(@NonNull DatabaseConfiguration configuration) {
111d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar        mOpenHelper = createOpenHelper(configuration);
1122eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        boolean wal = false;
1132eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
1142eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki            wal = configuration.journalMode == JournalMode.WRITE_AHEAD_LOGGING;
1152eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki            mOpenHelper.setWriteAheadLoggingEnabled(wal);
1162eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        }
117cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        mCallbacks = configuration.callbacks;
1182e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar        mAllowMainThreadQueries = configuration.allowMainThreadQueries;
1192eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        mWriteAheadLoggingEnabled = wal;
120d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar    }
121d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar
122d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar    /**
123d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar     * Returns the SQLite open helper used by this database.
124d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar     *
125d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar     * @return The SQLite open helper used by this database.
126d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar     */
127cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets    @NonNull
128d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar    public SupportSQLiteOpenHelper getOpenHelper() {
129d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar        return mOpenHelper;
130efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar    }
131d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar
132d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar    /**
133d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar     * Creates the open helper to access the database. Generated class already implements this
134d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar     * method.
135d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar     * Note that this method is called when the RoomDatabase is initialized.
136d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar     *
137d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar     * @param config The configuration of the Room database.
138d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar     * @return A new SupportSQLiteOpenHelper to be used while connecting to the database.
139d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar     */
140cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets    @NonNull
141d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar    protected abstract SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration config);
142d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar
14334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    /**
14434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * Called when the RoomDatabase is created.
14534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * <p>
14634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * This is already implemented by the generated code.
14734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     *
14834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * @return Creates a new InvalidationTracker.
14934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     */
150cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets    @NonNull
15134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    protected abstract InvalidationTracker createInvalidationTracker();
15234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
153fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar    /**
154fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki     * Deletes all rows from all the tables that are registered to this database as
155fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki     * {@link Database#entities()}.
156fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki     * <p>
157fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki     * This does NOT reset the auto-increment value generated by {@link PrimaryKey#autoGenerate()}.
1587a8b4c9ce824dff0416525ec33302d228901c899Yuichi Araki     * <p>
1597a8b4c9ce824dff0416525ec33302d228901c899Yuichi Araki     * After deleting the rows, Room will set a WAL checkpoint and run VACUUM. This means that the
1607a8b4c9ce824dff0416525ec33302d228901c899Yuichi Araki     * data is completely erased. The space will be reclaimed by the system if the amount surpasses
1617a8b4c9ce824dff0416525ec33302d228901c899Yuichi Araki     * the threshold of database file size.
1627a8b4c9ce824dff0416525ec33302d228901c899Yuichi Araki     *
1637a8b4c9ce824dff0416525ec33302d228901c899Yuichi Araki     * @see <a href="https://www.sqlite.org/fileformat.html">Database File Format</a>
164fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki     */
165fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki    @WorkerThread
166fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki    public abstract void clearAllTables();
167fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki
168fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki    /**
169489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar     * Returns true if database connection is open and initialized.
170fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar     *
171489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar     * @return true if the database connection is open, false otherwise.
172fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar     */
173489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar    public boolean isOpen() {
174489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar        final SupportSQLiteDatabase db = mDatabase;
175489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar        return db != null && db.isOpen();
176489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar    }
177489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar
178489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar    /**
179489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar     * Closes the database if it is already open.
180489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar     */
181489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar    public void close() {
182489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar        if (isOpen()) {
1835843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki            try {
1845843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki                mCloseLock.lock();
1855843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki                mOpenHelper.close();
1865843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki            } finally {
1875843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki                mCloseLock.unlock();
1885843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki            }
189489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar        }
190fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar    }
191fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar
1922e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar    /**
1932e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar     * Asserts that we are not on the main thread.
1942e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar     *
1952e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar     * @hide
1962e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar     */
197e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets    @SuppressWarnings("WeakerAccess")
1982e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
199e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets    // used in generated code
2002e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar    public void assertNotMainThread() {
2012e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar        if (mAllowMainThreadQueries) {
2022e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar            return;
2032e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar        }
204ae36c8b11a64d3cdc9ba6e37d9f3d1d250fdc4a8Yigit Boyar        if (ArchTaskExecutor.getInstance().isMainThread()) {
2052e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar            throw new IllegalStateException("Cannot access database on the main thread since"
20618f17f79daecd759ec66a2d2d7bf551542fcda4aFlorina Muntenescu                    + " it may potentially lock the UI for a long period of time.");
2072e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar        }
2082e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar    }
2092e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar
210937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    // Below, there are wrapper methods for SupportSQLiteDatabase. This helps us track which
211937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    // methods we are using and also helps unit tests to mock this class without mocking
212a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar    // all SQLite database methods.
213059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar
214937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    /**
215e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar     * Convenience method to query the database with arguments.
216937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar     *
217e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar     * @param query The sql query
218e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar     * @param args The bind arguments for the placeholders in the query
219e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar     *
220e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar     * @return A Cursor obtained by running the given query in the Room database.
221937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar     */
222e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar    public Cursor query(String query, @Nullable Object[] args) {
223e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar        return mOpenHelper.getWritableDatabase().query(new SimpleSQLiteQuery(query, args));
224efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar    }
225efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar
226937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    /**
227e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar     * Wrapper for {@link SupportSQLiteDatabase#query(SupportSQLiteQuery)}.
228b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar     *
229a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar     * @param query The Query which includes the SQL and a bind callback for bind arguments.
230b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar     * @return Result of the query.
231b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar     */
232b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    public Cursor query(SupportSQLiteQuery query) {
2332e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar        assertNotMainThread();
234e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar        return mOpenHelper.getWritableDatabase().query(query);
235b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    }
236b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
237b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    /**
238937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar     * Wrapper for {@link SupportSQLiteDatabase#compileStatement(String)}.
239937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar     *
240937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar     * @param sql The query to compile.
241937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar     * @return The compiled query.
242937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar     */
243cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets    public SupportSQLiteStatement compileStatement(@NonNull String sql) {
2442e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar        assertNotMainThread();
245d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar        return mOpenHelper.getWritableDatabase().compileStatement(sql);
246291985054e698c918df1c735d1042b63b9e97219Yigit Boyar    }
247291985054e698c918df1c735d1042b63b9e97219Yigit Boyar
248937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    /**
249937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar     * Wrapper for {@link SupportSQLiteDatabase#beginTransaction()}.
250937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar     */
251291985054e698c918df1c735d1042b63b9e97219Yigit Boyar    public void beginTransaction() {
2522e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar        assertNotMainThread();
253458885cbb4677ae06ce3bd0c4172c86928a7b101Yuichi Araki        SupportSQLiteDatabase database = mOpenHelper.getWritableDatabase();
254458885cbb4677ae06ce3bd0c4172c86928a7b101Yuichi Araki        mInvalidationTracker.syncTriggers(database);
255458885cbb4677ae06ce3bd0c4172c86928a7b101Yuichi Araki        database.beginTransaction();
256291985054e698c918df1c735d1042b63b9e97219Yigit Boyar    }
257291985054e698c918df1c735d1042b63b9e97219Yigit Boyar
258937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    /**
259937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar     * Wrapper for {@link SupportSQLiteDatabase#endTransaction()}.
260937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar     */
261291985054e698c918df1c735d1042b63b9e97219Yigit Boyar    public void endTransaction() {
262d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar        mOpenHelper.getWritableDatabase().endTransaction();
2639610cdd0c0def94a85f4b537d05e4b3226cec3b0Yigit Boyar        if (!inTransaction()) {
2649610cdd0c0def94a85f4b537d05e4b3226cec3b0Yigit Boyar            // enqueue refresh only if we are NOT in a transaction. Otherwise, wait for the last
2659610cdd0c0def94a85f4b537d05e4b3226cec3b0Yigit Boyar            // endTransaction call to do it.
2669610cdd0c0def94a85f4b537d05e4b3226cec3b0Yigit Boyar            mInvalidationTracker.refreshVersionsAsync();
2679610cdd0c0def94a85f4b537d05e4b3226cec3b0Yigit Boyar        }
268291985054e698c918df1c735d1042b63b9e97219Yigit Boyar    }
269291985054e698c918df1c735d1042b63b9e97219Yigit Boyar
270937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    /**
271937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar     * Wrapper for {@link SupportSQLiteDatabase#setTransactionSuccessful()}.
272937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar     */
273291985054e698c918df1c735d1042b63b9e97219Yigit Boyar    public void setTransactionSuccessful() {
274d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar        mOpenHelper.getWritableDatabase().setTransactionSuccessful();
275efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar    }
276059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar
277059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar    /**
27864cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki     * Executes the specified {@link Runnable} in a database transaction. The transaction will be
27964cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki     * marked as successful unless an exception is thrown in the {@link Runnable}.
28064cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki     *
28164cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki     * @param body The piece of code to execute.
28264cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki     */
283cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets    public void runInTransaction(@NonNull Runnable body) {
28464cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki        beginTransaction();
28564cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki        try {
28664cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki            body.run();
28764cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki            setTransactionSuccessful();
28864cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki        } finally {
28964cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki            endTransaction();
29064cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki        }
29164cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki    }
29264cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki
29364cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki    /**
29464cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki     * Executes the specified {@link Callable} in a database transaction. The transaction will be
29564cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki     * marked as successful unless an exception is thrown in the {@link Callable}.
29664cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki     *
29764cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki     * @param body The piece of code to execute.
29864cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki     * @param <V>  The type of the return value.
29964cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki     * @return The value returned from the {@link Callable}.
30064cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki     */
301cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets    public <V> V runInTransaction(@NonNull Callable<V> body) {
30264cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki        beginTransaction();
30364cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki        try {
30464cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki            V result = body.call();
30564cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki            setTransactionSuccessful();
30664cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki            return result;
30764cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki        } catch (RuntimeException e) {
30864cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki            throw e;
30964cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki        } catch (Exception e) {
31064cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki            throw new RuntimeException("Exception in transaction", e);
31164cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki        } finally {
31264cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki            endTransaction();
31364cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki        }
31464cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki    }
31564cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki
31664cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki    /**
31734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * Called by the generated code when database is open.
31834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * <p>
31934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * You should never call this method manually.
32034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     *
32134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * @param db The database instance.
32234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     */
323cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets    protected void internalInitInvalidationTracker(@NonNull SupportSQLiteDatabase db) {
32434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        mInvalidationTracker.internalInit(db);
32534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    }
32634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
32734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    /**
32834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * Returns the invalidation tracker for this database.
32934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * <p>
33034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * You can use the invalidation tracker to get notified when certain tables in the database
33134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * are modified.
33234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     *
33334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * @return The invalidation tracker for the database.
33434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     */
335cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets    @NonNull
33634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    public InvalidationTracker getInvalidationTracker() {
33734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        return mInvalidationTracker;
33834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    }
33934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
34034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    /**
34134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * Returns true if current thread is in a transaction.
34234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     *
34334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * @return True if there is an active transaction in current thread, false otherwise.
34434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * @see SupportSQLiteDatabase#inTransaction()
34534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     */
346e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets    @SuppressWarnings("WeakerAccess")
34734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    public boolean inTransaction() {
34834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        return mOpenHelper.getWritableDatabase().inTransaction();
34934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    }
35034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
35134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    /**
3522eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki     * Journal modes for SQLite database.
3532eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki     *
3542eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki     * @see RoomDatabase.Builder#setJournalMode(JournalMode)
3552eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki     */
3562eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki    public enum JournalMode {
3572eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki
3582eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        /**
3592eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * Let Room choose the journal mode. This is the default value when no explicit value is
3602eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * specified.
3612eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * <p>
3622eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * The actual value will be {@link #TRUNCATE} when the device runs API Level lower than 16
3632eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * or it is a low-RAM device. Otherwise, {@link #WRITE_AHEAD_LOGGING} will be used.
3642eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         */
3652eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        AUTOMATIC,
3662eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki
3672eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        /**
3682eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * Truncate journal mode.
3692eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         */
3702eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        TRUNCATE,
3712eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki
3722eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        /**
3732eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * Write-Ahead Logging mode.
3742eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         */
3752eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
3762eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        WRITE_AHEAD_LOGGING;
3772eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki
3782eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        /**
3792eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * Resolves {@link #AUTOMATIC} to either {@link #TRUNCATE} or
3802eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * {@link #WRITE_AHEAD_LOGGING}.
3812eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         */
3822eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        @SuppressLint("NewApi")
3832eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        JournalMode resolve(Context context) {
3842eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki            if (this != AUTOMATIC) {
3852eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki                return this;
3862eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki            }
3872eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
3882eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki                ActivityManager manager = (ActivityManager)
3892eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki                        context.getSystemService(Context.ACTIVITY_SERVICE);
3902eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki                if (manager != null && !ActivityManagerCompat.isLowRamDevice(manager)) {
3912eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki                    return WRITE_AHEAD_LOGGING;
3922eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki                }
3932eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki            }
3942eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki            return TRUNCATE;
3952eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        }
3962eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki    }
3972eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki
3982eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki    /**
399059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar     * Builder for RoomDatabase.
400059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar     *
401059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar     * @param <T> The type of the abstract database class.
402059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar     */
403059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar    public static class Builder<T extends RoomDatabase> {
404059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar        private final Class<T> mDatabaseClass;
405059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar        private final String mName;
406059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar        private final Context mContext;
407cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        private ArrayList<Callback> mCallbacks;
408059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar
409059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar        private SupportSQLiteOpenHelper.Factory mFactory;
4102e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar        private boolean mAllowMainThreadQueries;
4112eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        private JournalMode mJournalMode;
412234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar        private boolean mRequireMigration;
413a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar        /**
414a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * Migrations, mapped by from-to pairs.
415a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         */
416d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard        private final MigrationContainer mMigrationContainer;
417d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard        private Set<Integer> mMigrationsNotRequiredFrom;
418d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard        /**
419d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * Keeps track of {@link Migration#startVersion}s and {@link Migration#endVersion}s added in
420d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * {@link #addMigrations(Migration...)} for later validation that makes those versions don't
421eed1cacab66988de500612cf4c6af3bcb80402efshepshapard         * match any versions passed to {@link #fallbackToDestructiveMigrationFrom(int...)}.
422d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         */
423d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard        private Set<Integer> mMigrationStartAndEndVersions;
424059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar
425059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar        Builder(@NonNull Context context, @NonNull Class<T> klass, @Nullable String name) {
426059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            mContext = context;
427059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            mDatabaseClass = klass;
428059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            mName = name;
4292eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki            mJournalMode = JournalMode.AUTOMATIC;
430234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar            mRequireMigration = true;
431a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            mMigrationContainer = new MigrationContainer();
432059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar        }
433059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar
434059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar        /**
435059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar         * Sets the database factory. If not set, it defaults to
436059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar         * {@link FrameworkSQLiteOpenHelperFactory}.
437059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar         *
438059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar         * @param factory The factory to use to access the database.
439059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar         * @return this
440059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar         */
441e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets        @NonNull
442e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets        public Builder<T> openHelperFactory(@Nullable SupportSQLiteOpenHelper.Factory factory) {
443059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            mFactory = factory;
444059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            return this;
445059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar        }
446059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar
447059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar        /**
448a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * Adds a migration to the builder.
449a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * <p>
450a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * Each Migration has a start and end versions and Room runs these migrations to bring the
451a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * database to the latest version.
452a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * <p>
453a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * If a migration item is missing between current version and the latest version, Room
454a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * will clear the database and recreate so even if you have no changes between 2 versions,
455a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * you should still provide a Migration object to the builder.
456a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * <p>
457a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * A migration can handle more than 1 version (e.g. if you have a faster path to choose when
458a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * going version 3 to 5 without going to version 4). If Room opens a database at version
459a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * 3 and latest version is &gt;= 5, Room will use the migration object that can migrate from
460a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * 3 to 5 instead of 3 to 4 and 4 to 5.
461a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         *
462a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * @param migrations The migration object that can modify the database and to the necessary
463a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         *                   changes.
464059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar         * @return this
465059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar         */
466e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets        @NonNull
467d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard        public Builder<T> addMigrations(@NonNull  Migration... migrations) {
468d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard            if (mMigrationStartAndEndVersions == null) {
469d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard                mMigrationStartAndEndVersions = new HashSet<>();
470d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard            }
471d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard            for (Migration migration: migrations) {
472d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard                mMigrationStartAndEndVersions.add(migration.startVersion);
473d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard                mMigrationStartAndEndVersions.add(migration.endVersion);
474d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard            }
475d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard
476a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            mMigrationContainer.addMigrations(migrations);
477059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            return this;
478059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar        }
479059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar
480059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar        /**
4812e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar         * Disables the main thread query check for Room.
4822e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar         * <p>
4832e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar         * Room ensures that Database is never accessed on the main thread because it may lock the
4842e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar         * main thread and trigger an ANR. If you need to access the database from the main thread,
4852e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar         * you should always use async alternatives or manually move the call to a background
4862e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar         * thread.
4872e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar         * <p>
4882e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar         * You may want to turn this check off for testing.
4892e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar         *
4902e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar         * @return this
4912e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar         */
492e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets        @NonNull
4932e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar        public Builder<T> allowMainThreadQueries() {
4942e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar            mAllowMainThreadQueries = true;
4952e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar            return this;
4962e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar        }
4972e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar
4982e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar        /**
4992eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * Sets the journal mode for this database.
5002eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         *
5012eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * <p>
5022eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * This value is ignored if the builder is initialized with
5032eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * {@link Room#inMemoryDatabaseBuilder(Context, Class)}.
5042eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * <p>
5052eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * The journal mode should be consistent across multiple instances of
5062eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * {@link RoomDatabase} for a single SQLite database file.
5072eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * <p>
5082eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * The default value is {@link JournalMode#AUTOMATIC}.
5092eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         *
5102eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * @param journalMode The journal mode.
5112eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         * @return this
5122eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki         */
5132eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        @NonNull
5142eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        public Builder<T> setJournalMode(@NonNull JournalMode journalMode) {
5152eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki            mJournalMode = journalMode;
5162eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki            return this;
5172eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        }
5182eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki
5192eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki        /**
520ff860035ea975be71d875a31591c30d8bdcb6a9dshepshapard         * Allows Room to destructively recreate database tables if {@link Migration}s that would
521ff860035ea975be71d875a31591c30d8bdcb6a9dshepshapard         * migrate old database schemas to the latest schema version are not found.
522ff860035ea975be71d875a31591c30d8bdcb6a9dshepshapard         * <p>
523234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar         * When the database version on the device does not match the latest schema version, Room
524234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar         * runs necessary {@link Migration}s on the database.
525234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar         * <p>
526234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar         * If it cannot find the set of {@link Migration}s that will bring the database to the
527234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar         * current version, it will throw an {@link IllegalStateException}.
528234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar         * <p>
529234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar         * You can call this method to change this behavior to re-create the database instead of
530234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar         * crashing.
531234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar         * <p>
532234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar         * Note that this will delete all of the data in the database tables managed by Room.
533234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar         *
534234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar         * @return this
535234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar         */
536e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets        @NonNull
537234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar        public Builder<T> fallbackToDestructiveMigration() {
538234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar            mRequireMigration = false;
539234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar            return this;
540234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar        }
541234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar
542234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar        /**
543d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * Informs Room that it is allowed to destructively recreate database tables from specific
544d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * starting schema versions.
545d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * <p>
546d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * This functionality is the same as that provided by
547d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * {@link #fallbackToDestructiveMigration()}, except that this method allows the
548d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * specification of a set of schema versions for which destructive recreation is allowed.
549d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * <p>
550d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * Using this method is preferable to {@link #fallbackToDestructiveMigration()} if you want
551d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * to allow destructive migrations from some schema versions while still taking advantage
552d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * of exceptions being thrown due to unintentionally missing migrations.
553d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * <p>
554d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * Note: No versions passed to this method may also exist as either starting or ending
555d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * versions in the {@link Migration}s provided to {@link #addMigrations(Migration...)}. If a
556d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * version passed to this method is found as a starting or ending version in a Migration, an
557d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * exception will be thrown.
558d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         *
559d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * @param startVersions The set of schema versions from which Room should use a destructive
560d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         *                      migration.
561d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         * @return this
562d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard         */
563d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard        @NonNull
564eed1cacab66988de500612cf4c6af3bcb80402efshepshapard        public Builder<T> fallbackToDestructiveMigrationFrom(int... startVersions) {
565d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard            if (mMigrationsNotRequiredFrom == null) {
566eed1cacab66988de500612cf4c6af3bcb80402efshepshapard                mMigrationsNotRequiredFrom = new HashSet<>(startVersions.length);
567eed1cacab66988de500612cf4c6af3bcb80402efshepshapard            }
568eed1cacab66988de500612cf4c6af3bcb80402efshepshapard            for (int startVersion : startVersions) {
569eed1cacab66988de500612cf4c6af3bcb80402efshepshapard                mMigrationsNotRequiredFrom.add(startVersion);
570d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard            }
571d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard            return this;
572d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard        }
573d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard
574d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard        /**
575cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki         * Adds a {@link Callback} to this database.
576cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki         *
577cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki         * @param callback The callback.
578cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki         * @return this
579cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki         */
580e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets        @NonNull
581cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        public Builder<T> addCallback(@NonNull Callback callback) {
582cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki            if (mCallbacks == null) {
583cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki                mCallbacks = new ArrayList<>();
584cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki            }
585cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki            mCallbacks.add(callback);
586cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki            return this;
587cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        }
588cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki
589cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        /**
590059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar         * Creates the databases and initializes it.
59134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar         * <p>
59234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar         * By default, all RoomDatabases use in memory storage for TEMP tables and enables recursive
59334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar         * triggers.
59464db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar         *
595059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar         * @return A new database instance.
596059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar         */
597e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets        @NonNull
598059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar        public T build() {
599059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            //noinspection ConstantConditions
600059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            if (mContext == null) {
601059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar                throw new IllegalArgumentException("Cannot provide null context for the database.");
602059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            }
603059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            //noinspection ConstantConditions
604059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            if (mDatabaseClass == null) {
605059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar                throw new IllegalArgumentException("Must provide an abstract class that"
606059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar                        + " extends RoomDatabase");
607059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            }
608d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard
609d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard            if (mMigrationStartAndEndVersions != null && mMigrationsNotRequiredFrom != null) {
610d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard                for (Integer version : mMigrationStartAndEndVersions) {
611d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard                    if (mMigrationsNotRequiredFrom.contains(version)) {
612d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard                        throw new IllegalArgumentException(
613d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard                                "Inconsistency detected. A Migration was supplied to "
614d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard                                        + "addMigration(Migration... migrations) that has a start "
615d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard                                        + "or end version equal to a start version supplied to "
616eed1cacab66988de500612cf4c6af3bcb80402efshepshapard                                        + "fallbackToDestructiveMigrationFrom(int... "
617d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard                                        + "startVersions). Start version: "
618d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard                                        + version);
619d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard                    }
620d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard                }
621d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard            }
622d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard
623059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            if (mFactory == null) {
624059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar                mFactory = new FrameworkSQLiteOpenHelperFactory();
625059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            }
626059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            DatabaseConfiguration configuration =
6272e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar                    new DatabaseConfiguration(mContext, mName, mFactory, mMigrationContainer,
6282eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki                            mCallbacks, mAllowMainThreadQueries,
6292eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki                            mJournalMode.resolve(mContext),
6302eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki                            mRequireMigration, mMigrationsNotRequiredFrom);
631059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            T db = Room.getGeneratedImplementation(mDatabaseClass, DB_IMPL_SUFFIX);
632059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            db.init(configuration);
633059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar            return db;
634059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar        }
635059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar    }
636a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar
637a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar    /**
638a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar     * A container to hold migrations. It also allows querying its contents to find migrations
639a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar     * between two versions.
640a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar     */
641a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar    public static class MigrationContainer {
642a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar        private SparseArrayCompat<SparseArrayCompat<Migration>> mMigrations =
643a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                new SparseArrayCompat<>();
644a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar
645a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar        /**
646a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * Adds the given migrations to the list of available migrations. If 2 migrations have the
647a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * same start-end versions, the latter migration overrides the previous one.
648a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         *
649a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * @param migrations List of available migrations.
650a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         */
651cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets        public void addMigrations(@NonNull Migration... migrations) {
652a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            for (Migration migration : migrations) {
653a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                addMigration(migration);
654a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            }
655a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar        }
656a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar
657a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar        private void addMigration(Migration migration) {
658a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            final int start = migration.startVersion;
659a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            final int end = migration.endVersion;
660a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            SparseArrayCompat<Migration> targetMap = mMigrations.get(start);
661a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            if (targetMap == null) {
662a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                targetMap = new SparseArrayCompat<>();
663a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                mMigrations.put(start, targetMap);
664a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            }
665a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            Migration existing = targetMap.get(end);
666a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            if (existing != null) {
667a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                Log.w(Room.LOG_TAG, "Overriding migration " + existing + " with " + migration);
668a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            }
669a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            targetMap.append(end, migration);
670a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar        }
671a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar
672a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar        /**
673a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * Finds the list of migrations that should be run to move from {@code start} version to
674a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * {@code end} version.
675a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         *
676a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * @param start The current database version
67764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar         * @param end   The target database version
678a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * @return An ordered list of {@link Migration} objects that should be run to migrate
679a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         * between the given versions. If a migration path cannot be found, returns {@code null}.
680a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar         */
681e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets        @SuppressWarnings("WeakerAccess")
682a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar        @Nullable
683a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar        public List<Migration> findMigrationPath(int start, int end) {
684a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            if (start == end) {
685a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                return Collections.emptyList();
686a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            }
687a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            boolean migrateUp = end > start;
688a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            List<Migration> result = new ArrayList<>();
689a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            return findUpMigrationPath(result, migrateUp, start, end);
690a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar        }
691a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar
692a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar        private List<Migration> findUpMigrationPath(List<Migration> result, boolean upgrade,
693a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                int start, int end) {
694a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            final int searchDirection = upgrade ? -1 : 1;
695a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            while (upgrade ? start < end : start > end) {
696a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                SparseArrayCompat<Migration> targetNodes = mMigrations.get(start);
697a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                if (targetNodes == null) {
698a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                    return null;
699a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                }
700a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                // keys are ordered so we can start searching from one end of them.
701a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                final int size = targetNodes.size();
702a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                final int firstIndex;
703a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                final int lastIndex;
704a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar
705a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                if (upgrade) {
706a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                    firstIndex = size - 1;
707a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                    lastIndex = -1;
708a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                } else {
709a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                    firstIndex = 0;
710a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                    lastIndex = size;
711a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                }
712a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                boolean found = false;
713a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                for (int i = firstIndex; i != lastIndex; i += searchDirection) {
714c7d52cda65fa71ff54fca756e8abf73cdd2c7caaYigit Boyar                    final int targetVersion = targetNodes.keyAt(i);
715c7d52cda65fa71ff54fca756e8abf73cdd2c7caaYigit Boyar                    final boolean shouldAddToPath;
716c7d52cda65fa71ff54fca756e8abf73cdd2c7caaYigit Boyar                    if (upgrade) {
717c7d52cda65fa71ff54fca756e8abf73cdd2c7caaYigit Boyar                        shouldAddToPath = targetVersion <= end && targetVersion > start;
718c7d52cda65fa71ff54fca756e8abf73cdd2c7caaYigit Boyar                    } else {
719c7d52cda65fa71ff54fca756e8abf73cdd2c7caaYigit Boyar                        shouldAddToPath = targetVersion >= end && targetVersion < start;
720c7d52cda65fa71ff54fca756e8abf73cdd2c7caaYigit Boyar                    }
721c7d52cda65fa71ff54fca756e8abf73cdd2c7caaYigit Boyar                    if (shouldAddToPath) {
722a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                        result.add(targetNodes.valueAt(i));
723a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                        start = targetVersion;
724a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                        found = true;
725a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                        break;
726a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                    }
727a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                }
728a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                if (!found) {
729a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                    return null;
730a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                }
731a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            }
732a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            return result;
733a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar        }
734a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar    }
735cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki
736cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki    /**
737cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki     * Callback for {@link RoomDatabase}.
738cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki     */
739cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki    public abstract static class Callback {
740cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki
741cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        /**
742cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki         * Called when the database is created for the first time. This is called after all the
743cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki         * tables are created.
744cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki         *
745cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki         * @param db The database.
746cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki         */
747cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        public void onCreate(@NonNull SupportSQLiteDatabase db) {
748cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        }
749cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki
750cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        /**
751cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki         * Called when the database has been opened.
752cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki         *
753cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki         * @param db The database.
754cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki         */
755cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        public void onOpen(@NonNull SupportSQLiteDatabase db) {
756cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        }
757cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki    }
758efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar}
759