1 /*
<lambda>null2  * Copyright (C) 2017 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.migration.bundle
18 
19 import androidx.annotation.RestrictTo
20 import androidx.room.migration.bundle.SchemaEqualityUtil.checkSchemaEquality
21 import androidx.room.migration.bundle.SchemaEqualityUtil.filterValuesInstance
22 import kotlinx.serialization.SerialName
23 import kotlinx.serialization.Serializable
24 
25 /** Data class that holds the schema information for a [androidx.room.Database]. */
26 @Serializable
27 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
28 class DatabaseBundle(
29     @SerialName("version") val version: Int,
30     @SerialName("identityHash") val identityHash: String,
31     @SerialName("entities") val entities: List<BaseEntityBundle>,
32     @SerialName("views") val views: List<DatabaseViewBundle> = emptyList(),
33     @SerialName("setupQueries") private val setupQueries: List<String>,
34 ) : SchemaEquality<DatabaseBundle> {
35 
36     val entitiesByTableName: Map<String, BaseEntityBundle> by lazy {
37         entities.associateBy { it.tableName }
38     }
39 
40     val viewsByName: Map<String, DatabaseViewBundle> by lazy { views.associateBy { it.viewName } }
41 
42     /** Builds the list of SQL queries to build this database from scratch. */
43     fun buildCreateQueries(): List<String> {
44         return buildList {
45             entities.sortedWith(FtsEntityCreateComparator()).forEach { entityBundle ->
46                 addAll(entityBundle.buildCreateQueries())
47             }
48             views.forEach { viewBundle -> add(viewBundle.createView()) }
49             addAll(setupQueries)
50         }
51     }
52 
53     override fun isSchemaEqual(other: DatabaseBundle): Boolean {
54         return checkSchemaEquality(
55             entitiesByTableName.filterValuesInstance<String, EntityBundle>(),
56             other.entitiesByTableName.filterValuesInstance<String, EntityBundle>()
57         ) &&
58             checkSchemaEquality(
59                 entitiesByTableName.filterValuesInstance<String, FtsEntityBundle>(),
60                 other.entitiesByTableName.filterValuesInstance<String, FtsEntityBundle>()
61             ) &&
62             checkSchemaEquality(viewsByName, other.viewsByName)
63     }
64 
65     // Comparator to sort FTS entities after their declared external content entity so that the
66     // content entity table gets created first.
67     private class FtsEntityCreateComparator : Comparator<BaseEntityBundle> {
68         override fun compare(a: BaseEntityBundle, b: BaseEntityBundle): Int {
69             if (a is FtsEntityBundle) {
70                 val contentTable = a.ftsOptions.contentTable
71                 if (contentTable == b.tableName) {
72                     return 1
73                 }
74             } else if (b is FtsEntityBundle) {
75                 val contentTable = b.ftsOptions.contentTable
76                 if (contentTable == a.tableName) {
77                     return -1
78                 }
79             }
80             return 0
81         }
82     }
83 }
84