[go: nahoru, domu]

blob: 0e1c0b7a2a68fc17835f19a42a70d687292e2ae6 [file] [log] [blame]
Elif Bilgin63ffe602021-02-19 10:46:51 -08001/*
2 * Copyright 2021 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
17package androidx.room.writer
18
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -070019import androidx.room.compiler.codegen.CodeLanguage
20import androidx.room.compiler.codegen.VisibilityModifier
21import androidx.room.compiler.codegen.XCodeBlock
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -070022import androidx.room.compiler.codegen.XFunSpec
23import androidx.room.compiler.codegen.XFunSpec.Builder.Companion.addStatement
elifbilginf748a172023-03-02 10:27:43 -080024import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -070025import androidx.room.compiler.codegen.XTypeSpec
Daniel Santiago Rivera885c9eb2022-09-29 21:49:35 -040026import androidx.room.compiler.codegen.XTypeSpec.Builder.Companion.addOriginatingElement
Daniel Santiago Rivera8b793f82022-09-28 13:23:51 -040027import androidx.room.compiler.codegen.XTypeSpec.Builder.Companion.addProperty
Daniel Santiago Rivera051c4a5e2021-09-02 10:21:25 -070028import androidx.room.compiler.processing.XTypeElement
Elif Bilgin63ffe602021-02-19 10:46:51 -080029import androidx.room.ext.RoomTypeNames
Elif Bilgin63ffe602021-02-19 10:46:51 -080030import androidx.room.ext.SupportDbTypeNames
Elif Bilgin26e3f9d2021-03-29 05:57:30 -070031import androidx.room.migration.bundle.EntityBundle
Elif Bilgin7a55b712021-04-06 09:24:33 -070032import androidx.room.migration.bundle.FtsEntityBundle
Elif Bilgin51f4b352021-04-20 16:02:55 -070033import androidx.room.vo.AutoMigration
Elif Bilgin63ffe602021-02-19 10:46:51 -080034
35/**
36 * Writes the implementation of migrations that were annotated with @AutoMigration.
37 */
38class AutoMigrationWriter(
Daniel Santiago Rivera051c4a5e2021-09-02 10:21:25 -070039 private val dbElement: XTypeElement,
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -070040 val autoMigration: AutoMigration,
Daniel Santiago Riverafe98c702022-09-22 22:58:50 -040041 codeLanguage: CodeLanguage
42) : TypeWriter(codeLanguage) {
Elif Bilgin51f4b352021-04-20 16:02:55 -070043 private val addedColumns = autoMigration.schemaDiff.addedColumns
44 private val addedTables = autoMigration.schemaDiff.addedTables
45 private val renamedTables = autoMigration.schemaDiff.renamedTables
46 private val complexChangedTables = autoMigration.schemaDiff.complexChangedTables
47 private val deletedTables = autoMigration.schemaDiff.deletedTables
Elif Bilgin63ffe602021-02-19 10:46:51 -080048
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -070049 override fun createTypeSpecBuilder(): XTypeSpec.Builder {
50 val builder = XTypeSpec.classBuilder(
51 codeLanguage,
Daniel Santiago Rivera587c02192022-09-17 12:55:48 -070052 autoMigration.getImplTypeName(dbElement.asClassName())
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -070053 )
Elif Bilgin63ffe602021-02-19 10:46:51 -080054 builder.apply {
55 addOriginatingElement(dbElement)
Daniel Santiago Rivera7e7bb0b2022-11-07 10:54:49 -050056 superclass(RoomTypeNames.MIGRATION)
Daniel Santiago Rivera63239ab2022-12-21 16:36:29 -050057 // Class is package-protected in Java (no visibility modifier) and internal in Kotlin
58 if (language == CodeLanguage.KOTLIN) {
59 setVisibility(VisibilityModifier.INTERNAL)
60 }
Elif Bilgin51f4b352021-04-20 16:02:55 -070061 if (autoMigration.specClassName != null) {
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -070062 builder.addProperty(
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -070063 name = "callback",
Daniel Santiago Rivera7e7bb0b2022-11-07 10:54:49 -050064 typeName = RoomTypeNames.AUTO_MIGRATION_SPEC,
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -070065 visibility = VisibilityModifier.PRIVATE,
66 initExpr = if (!autoMigration.isSpecProvided) {
Daniel Santiago Rivera9b412152022-09-23 22:26:42 -040067 XCodeBlock.ofNewInstance(
68 codeLanguage,
Daniel Santiago Rivera7e7bb0b2022-11-07 10:54:49 -050069 autoMigration.specClassName
Daniel Santiago Rivera9b412152022-09-23 22:26:42 -040070 )
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -070071 } else {
72 null
Elif Bilgine6f17b42021-04-20 15:32:25 -070073 }
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -070074 )
Elif Bilginc6db95e2021-04-07 11:57:50 -070075 }
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -070076 addFunction(createConstructor())
77 addFunction(createMigrateMethod())
Elif Bilgin63ffe602021-02-19 10:46:51 -080078 }
79 return builder
80 }
81
Elif Bilginfba75de2021-03-09 04:44:10 -080082 /**
83 * Builds the constructor of the generated AutoMigration.
84 *
85 * @return The constructor of the generated AutoMigration
86 */
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -070087 private fun createConstructor(): XFunSpec {
88 return XFunSpec.constructorBuilder(codeLanguage, VisibilityModifier.PUBLIC).apply {
89 callSuperConstructor(
90 XCodeBlock.of(codeLanguage, "%L", autoMigration.from),
91 XCodeBlock.of(codeLanguage, "%L", autoMigration.to),
Elif Bilgin51f4b352021-04-20 16:02:55 -070092 )
93 if (autoMigration.isSpecProvided) {
Elif Bilgine6f17b42021-04-20 15:32:25 -070094 addParameter(
Daniel Santiago Rivera7e7bb0b2022-11-07 10:54:49 -050095 typeName = RoomTypeNames.AUTO_MIGRATION_SPEC,
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -070096 name = "callback",
Elif Bilgine6f17b42021-04-20 15:32:25 -070097 )
98 addStatement("this.callback = callback")
99 }
Elif Bilginfba75de2021-03-09 04:44:10 -0800100 }.build()
101 }
102
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700103 private fun createMigrateMethod(): XFunSpec {
104 val migrateFunctionBuilder: XFunSpec.Builder = XFunSpec.builder(
105 language = codeLanguage,
106 name = "migrate",
107 visibility = VisibilityModifier.PUBLIC,
Daniel Santiago Rivera76bf2562022-10-16 12:31:34 -0400108 isOverride = true,
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700109 ).apply {
Daniel Santiago Rivera7e7bb0b2022-11-07 10:54:49 -0500110 addParameter(
111 typeName = SupportDbTypeNames.DB,
elifbilgind62dc352023-02-03 11:22:25 -0800112 name = "db",
Daniel Santiago Rivera7e7bb0b2022-11-07 10:54:49 -0500113 )
114 addMigrationStatements(this)
115 if (autoMigration.specClassName != null) {
elifbilgind62dc352023-02-03 11:22:25 -0800116 addStatement("callback.onPostMigrate(db)")
Elif Bilgin63ffe602021-02-19 10:46:51 -0800117 }
Daniel Santiago Rivera7e7bb0b2022-11-07 10:54:49 -0500118 }
Elif Bilgin63ffe602021-02-19 10:46:51 -0800119 return migrateFunctionBuilder.build()
120 }
121
122 /**
123 * Takes the changes provided in the {@link AutoMigrationResult} which are differences detected
124 * between the two versions of the same database, and converts them to the appropriate
125 * sequence of SQL statements that migrate the database from one version to the other.
126 *
Elif Bilginfba75de2021-03-09 04:44:10 -0800127 * @param migrateBuilder Builder for the migrate() function to be generated
Elif Bilgin63ffe602021-02-19 10:46:51 -0800128 */
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700129 private fun addMigrationStatements(migrateBuilder: XFunSpec.Builder) {
Elif Bilgin51f4b352021-04-20 16:02:55 -0700130 addDropViewStatements(migrateBuilder)
Elif Bilginfba75de2021-03-09 04:44:10 -0800131 addSimpleChangeStatements(migrateBuilder)
Elif Bilgin7a55b712021-04-06 09:24:33 -0700132 addComplexChangeStatements(migrateBuilder)
Elif Bilgin51f4b352021-04-20 16:02:55 -0700133 addRecreateViewStatements(migrateBuilder)
134 }
135
136 /**
137 * Adds SQL statements to drop all views of the database in the 'from' version.
138 *
139 * @param migrateBuilder Builder for the migrate() function to be generated
140 */
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700141 private fun addDropViewStatements(migrateBuilder: XFunSpec.Builder) {
Elif Bilgin51f4b352021-04-20 16:02:55 -0700142 autoMigration.schemaDiff.fromViews.forEach { view ->
143 addDatabaseExecuteSqlStatement(migrateBuilder, "DROP VIEW ${view.viewName}")
144 }
145 }
146
147 /**
148 * Adds SQL statements to create all views of the database in the 'to' version.
149 *
150 * @param migrateBuilder Builder for the migrate() function to be generated
151 */
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700152 private fun addRecreateViewStatements(migrateBuilder: XFunSpec.Builder) {
Elif Bilgin51f4b352021-04-20 16:02:55 -0700153 autoMigration.schemaDiff.toViews.forEach { view ->
154 addDatabaseExecuteSqlStatement(migrateBuilder, view.createView())
155 }
Elif Bilginfba75de2021-03-09 04:44:10 -0800156 }
157
158 /**
159 * Adds SQL statements performing schema altering commands that are not directly supported by
160 * SQLite (e.g. foreign key changes). These changes are referred to as "complex" changes.
161 *
162 * @param migrateBuilder Builder for the migrate() function to be generated
163 */
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700164 private fun addComplexChangeStatements(migrateBuilder: XFunSpec.Builder) {
Elif Bilgin7a55b712021-04-06 09:24:33 -0700165 // Create a collection that is sorted such that FTS bundles are handled after the normal
166 // tables have been processed
167 complexChangedTables.values.sortedBy {
168 it.newVersionEntityBundle is FtsEntityBundle
169 }.forEach {
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700170 (
171 _,
172 tableNameWithNewPrefix,
173 oldEntityBundle,
174 newEntityBundle,
175 renamedColumnsMap
176 ) ->
177
Elif Bilgin7a55b712021-04-06 09:24:33 -0700178 if (oldEntityBundle is FtsEntityBundle &&
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700179 oldEntityBundle.ftsOptions.contentTable.isNotBlank()
Elif Bilgin7a55b712021-04-06 09:24:33 -0700180 ) {
181 addStatementsToMigrateFtsTable(
182 migrateBuilder,
183 oldEntityBundle,
184 newEntityBundle,
185 renamedColumnsMap
186 )
187 } else {
188 addStatementsToCreateNewTable(newEntityBundle, migrateBuilder)
189 addStatementsToContentTransfer(
190 oldEntityBundle.tableName,
191 tableNameWithNewPrefix,
192 oldEntityBundle,
193 newEntityBundle,
194 renamedColumnsMap,
195 migrateBuilder
196 )
197 addStatementsToDropTableAndRenameTempTable(
198 oldEntityBundle.tableName,
199 newEntityBundle.tableName,
200 tableNameWithNewPrefix,
201 migrateBuilder
202 )
203 addStatementsToRecreateIndexes(newEntityBundle, migrateBuilder)
204 if (newEntityBundle.foreignKeys.isNotEmpty()) {
205 addStatementsToCheckForeignKeyConstraint(
206 newEntityBundle.tableName,
207 migrateBuilder
208 )
209 }
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700210 }
Elif Bilgin63ffe602021-02-19 10:46:51 -0800211 }
212 }
213
Elif Bilgin7a55b712021-04-06 09:24:33 -0700214 private fun addStatementsToMigrateFtsTable(
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700215 migrateBuilder: XFunSpec.Builder,
Elif Bilgin7a55b712021-04-06 09:24:33 -0700216 oldTable: EntityBundle,
217 newTable: EntityBundle,
218 renamedColumnsMap: MutableMap<String, String>
219 ) {
220 addDatabaseExecuteSqlStatement(migrateBuilder, "DROP TABLE `${oldTable.tableName}`")
221 addDatabaseExecuteSqlStatement(migrateBuilder, newTable.createTable())
222
223 // Transfer contents of the FTS table, using the content table if available.
224 val newColumnSequence = oldTable.fieldsByColumnName.keys.filter {
225 oldTable.fieldsByColumnName.keys.contains(it) ||
226 renamedColumnsMap.containsKey(it)
227 }.toMutableList()
228 val oldColumnSequence = mutableListOf<String>()
229 newColumnSequence.forEach { column ->
230 oldColumnSequence.add(renamedColumnsMap[column] ?: column)
231 }
232 if (oldTable is FtsEntityBundle) {
233 oldColumnSequence.add("rowid")
234 newColumnSequence.add("docid")
235 }
236 val contentTable = (newTable as FtsEntityBundle).ftsOptions.contentTable
237 val selectFromTable = if (contentTable.isEmpty()) {
238 oldTable.tableName
239 } else {
240 contentTable
241 }
242 addDatabaseExecuteSqlStatement(
243 migrateBuilder,
244 buildString {
245 append(
Elif Bilgin10279982021-10-26 16:59:42 -0700246 "INSERT INTO `${newTable.tableName}` " +
247 "(${newColumnSequence.joinToString(",") { "`$it`" }})" +
248 " SELECT ${oldColumnSequence.joinToString(",") { "`$it`" }} " +
249 "FROM `$selectFromTable`",
Elif Bilgin7a55b712021-04-06 09:24:33 -0700250 )
251 }
252 )
253 }
254
Elif Bilgin63ffe602021-02-19 10:46:51 -0800255 /**
Elif Bilginfba75de2021-03-09 04:44:10 -0800256 * Adds SQL statements performing schema altering commands directly supported by SQLite
257 * (adding tables/columns, renaming tables/columns, dropping tables/columns). These changes
258 * are referred to as "simple" changes.
Elif Bilgin63ffe602021-02-19 10:46:51 -0800259 *
Elif Bilginfba75de2021-03-09 04:44:10 -0800260 * @param migrateBuilder Builder for the migrate() function to be generated
Elif Bilgin63ffe602021-02-19 10:46:51 -0800261 */
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700262 private fun addSimpleChangeStatements(migrateBuilder: XFunSpec.Builder) {
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700263 addDeleteTableStatements(migrateBuilder)
264 addRenameTableStatements(migrateBuilder)
265 addNewColumnStatements(migrateBuilder)
266 addNewTableStatements(migrateBuilder)
Elif Bilginfba75de2021-03-09 04:44:10 -0800267 }
268
269 /**
270 * Adds the SQL statements for creating a new table in the desired revised format of table.
271 *
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700272 * @param newTable Schema of the new table to be created
Elif Bilginfba75de2021-03-09 04:44:10 -0800273 * @param migrateBuilder Builder for the migrate() function to be generated
274 */
275 private fun addStatementsToCreateNewTable(
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700276 newTable: EntityBundle,
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700277 migrateBuilder: XFunSpec.Builder
Elif Bilginfba75de2021-03-09 04:44:10 -0800278 ) {
279 addDatabaseExecuteSqlStatement(
280 migrateBuilder,
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700281 newTable.createNewTable()
Elif Bilginfba75de2021-03-09 04:44:10 -0800282 )
283 }
284
285 /**
286 * Adds the SQL statements for transferring the contents of the old table to the new version.
287 *
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700288 * @param oldTableName Name of the table in the old version of the database
289 * @param tableNameWithNewPrefix Name of the table with the '_new_' prefix added
290 * @param oldEntityBundle Entity bundle of the table in the old version of the database
291 * @param newEntityBundle Entity bundle of the table in the new version of the database
292 * @param renamedColumnsMap Map of the renamed columns of the table (new name -> old name)
Elif Bilginfba75de2021-03-09 04:44:10 -0800293 * @param migrateBuilder Builder for the migrate() function to be generated
294 */
295 private fun addStatementsToContentTransfer(
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700296 oldTableName: String,
297 tableNameWithNewPrefix: String,
298 oldEntityBundle: EntityBundle,
299 newEntityBundle: EntityBundle,
300 renamedColumnsMap: MutableMap<String, String>,
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700301 migrateBuilder: XFunSpec.Builder
Elif Bilginfba75de2021-03-09 04:44:10 -0800302 ) {
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700303 val newColumnSequence = newEntityBundle.fieldsByColumnName.keys.filter {
304 oldEntityBundle.fieldsByColumnName.keys.contains(it) ||
305 renamedColumnsMap.containsKey(it)
Elif Bilgin7a55b712021-04-06 09:24:33 -0700306 }.toMutableList()
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700307 val oldColumnSequence = mutableListOf<String>()
308 newColumnSequence.forEach { column ->
309 oldColumnSequence.add(renamedColumnsMap[column] ?: column)
310 }
Elif Bilginfba75de2021-03-09 04:44:10 -0800311
312 addDatabaseExecuteSqlStatement(
313 migrateBuilder,
314 buildString {
Elif Bilgin63ffe602021-02-19 10:46:51 -0800315 append(
Elif Bilgin7a55b712021-04-06 09:24:33 -0700316 "INSERT INTO `$tableNameWithNewPrefix` " +
Elif Bilgin10279982021-10-26 16:59:42 -0700317 "(${newColumnSequence.joinToString(",") { "`$it`" }})" +
318 " SELECT ${oldColumnSequence.joinToString(",") { "`$it`" }} FROM " +
Elif Bilgin7a55b712021-04-06 09:24:33 -0700319 "`$oldTableName`",
Elif Bilgin63ffe602021-02-19 10:46:51 -0800320 )
Elif Bilgin63ffe602021-02-19 10:46:51 -0800321 }
Elif Bilginfba75de2021-03-09 04:44:10 -0800322 )
Elif Bilgin63ffe602021-02-19 10:46:51 -0800323 }
324
325 /**
Elif Bilginfba75de2021-03-09 04:44:10 -0800326 * Adds the SQL statements for dropping the table at the old version and renaming the
327 * temporary table to the name of the original table.
Elif Bilginf2f87f52021-02-24 09:12:24 -0800328 *
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700329 * @param oldTableName Name of the table in the old version of the database
330 * @param newTableName Name of the table in the new version of the database
331 * @param tableNameWithNewPrefix Name of the table with the '_new_' prefix added
Elif Bilginfba75de2021-03-09 04:44:10 -0800332 * @param migrateBuilder Builder for the migrate() function to be generated
Elif Bilginf2f87f52021-02-24 09:12:24 -0800333 */
Elif Bilginfba75de2021-03-09 04:44:10 -0800334 private fun addStatementsToDropTableAndRenameTempTable(
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700335 oldTableName: String,
336 newTableName: String,
337 tableNameWithNewPrefix: String,
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700338 migrateBuilder: XFunSpec.Builder
Elif Bilginfba75de2021-03-09 04:44:10 -0800339 ) {
340 addDatabaseExecuteSqlStatement(
341 migrateBuilder,
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700342 "DROP TABLE `$oldTableName`"
Elif Bilginfba75de2021-03-09 04:44:10 -0800343 )
344 addDatabaseExecuteSqlStatement(
345 migrateBuilder,
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700346 "ALTER TABLE `$tableNameWithNewPrefix` RENAME TO `$newTableName`"
Elif Bilginfba75de2021-03-09 04:44:10 -0800347 )
348 }
349
350 /**
351 * Adds the SQL statements for recreating indexes.
352 *
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700353 * @param table The table the indexes of which will be recreated
Elif Bilginfba75de2021-03-09 04:44:10 -0800354 * @param migrateBuilder Builder for the migrate() function to be generated
355 */
356 private fun addStatementsToRecreateIndexes(
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700357 table: EntityBundle,
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700358 migrateBuilder: XFunSpec.Builder
Elif Bilginfba75de2021-03-09 04:44:10 -0800359 ) {
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700360 table.indices.forEach { index ->
Elif Bilginfba75de2021-03-09 04:44:10 -0800361 addDatabaseExecuteSqlStatement(
362 migrateBuilder,
363 index.getCreateSql(table.tableName)
Elif Bilginf2f87f52021-02-24 09:12:24 -0800364 )
365 }
366 }
367
368 /**
Elif Bilginfba75de2021-03-09 04:44:10 -0800369 * Adds the SQL statement for checking the foreign key constraints.
Elif Bilgin63ffe602021-02-19 10:46:51 -0800370 *
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700371 * @param tableName Name of the table
Elif Bilginfba75de2021-03-09 04:44:10 -0800372 * @param migrateBuilder Builder for the migrate() function to be generated
Elif Bilgin63ffe602021-02-19 10:46:51 -0800373 */
Elif Bilginfba75de2021-03-09 04:44:10 -0800374 private fun addStatementsToCheckForeignKeyConstraint(
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700375 tableName: String,
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700376 migrateBuilder: XFunSpec.Builder
Elif Bilginfba75de2021-03-09 04:44:10 -0800377 ) {
Elif Bilgin7917c782021-06-07 13:58:31 -0700378 migrateBuilder.addStatement(
elifbilginf748a172023-03-02 10:27:43 -0800379 "%M(db, %S)",
380 RoomTypeNames.DB_UTIL.packageMember("foreignKeyCheck"),
Elif Bilgin7917c782021-06-07 13:58:31 -0700381 tableName
Elif Bilginfba75de2021-03-09 04:44:10 -0800382 )
383 }
384
385 /**
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700386 * Adds the SQL statements for removing a table.
387 *
388 * @param migrateBuilder Builder for the migrate() function to be generated
389 */
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700390 private fun addDeleteTableStatements(migrateBuilder: XFunSpec.Builder) {
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700391 deletedTables.forEach { tableName ->
392 val deleteTableSql = buildString {
393 append(
394 "DROP TABLE `$tableName`"
395 )
396 }
397 addDatabaseExecuteSqlStatement(
398 migrateBuilder,
399 deleteTableSql
400 )
401 }
402 }
403
404 /**
405 * Adds the SQL statements for renaming a table.
406 *
407 * @param migrateBuilder Builder for the migrate() function to be generated
408 */
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700409 private fun addRenameTableStatements(migrateBuilder: XFunSpec.Builder) {
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700410 renamedTables.forEach { (oldName, newName) ->
411 val renameTableSql = buildString {
412 append(
413 "ALTER TABLE `$oldName` RENAME TO `$newName`"
414 )
415 }
416 addDatabaseExecuteSqlStatement(
417 migrateBuilder,
418 renameTableSql
419 )
420 }
421 }
422
423 /**
Elif Bilginfba75de2021-03-09 04:44:10 -0800424 * Adds the SQL statements for adding new columns to a table.
425 *
426 * @param migrateBuilder Builder for the migrate() function to be generated
427 */
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700428 private fun addNewColumnStatements(migrateBuilder: XFunSpec.Builder) {
Elif Bilginfba75de2021-03-09 04:44:10 -0800429 addedColumns.forEach {
430 val addNewColumnSql = buildString {
431 append(
Daniel Santiago Riverabfa17ff2021-09-23 12:10:59 -0700432 "ALTER TABLE `${it.tableName}` ADD COLUMN `${it.fieldBundle.columnName}` " +
Elif Bilgin87c1e432021-07-19 10:05:33 -0700433 "${it.fieldBundle.affinity}"
Elif Bilginfba75de2021-03-09 04:44:10 -0800434 )
Daniel Santiago Riverabfa17ff2021-09-23 12:10:59 -0700435 if (it.fieldBundle.isNonNull) {
Elif Bilgin87c1e432021-07-19 10:05:33 -0700436 append(" NOT NULL")
437 }
438 if (it.fieldBundle.defaultValue?.isNotEmpty() == true) {
439 append(" DEFAULT ${it.fieldBundle.defaultValue}")
Elif Bilginfba75de2021-03-09 04:44:10 -0800440 } else {
Elif Bilgin87c1e432021-07-19 10:05:33 -0700441 check(
442 !it.fieldBundle.isNonNull
443 ) { "A Non-Null field should always have a default value." }
444 append(" DEFAULT NULL")
Elif Bilginfba75de2021-03-09 04:44:10 -0800445 }
446 }
447 addDatabaseExecuteSqlStatement(
448 migrateBuilder,
449 addNewColumnSql
450 )
451 }
452 }
453
454 /**
455 * Adds the SQL statements for adding new tables to a database.
456 *
457 * @param migrateBuilder Builder for the migrate() function to be generated
458 */
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700459 private fun addNewTableStatements(migrateBuilder: XFunSpec.Builder) {
Elif Bilginfba75de2021-03-09 04:44:10 -0800460 addedTables.forEach { addedTable ->
461 addDatabaseExecuteSqlStatement(
462 migrateBuilder,
463 addedTable.entityBundle.createTable()
464 )
Elif Bilginbc4d0b02021-06-06 12:02:05 -0700465 addStatementsToRecreateIndexes(addedTable.entityBundle, migrateBuilder)
Elif Bilginfba75de2021-03-09 04:44:10 -0800466 }
467 }
468
469 /**
470 * Adds the given SQL statements into the generated migrate() function to be executed by the
471 * database.
472 *
473 * @param migrateBuilder Builder for the migrate() function to be generated
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700474 * @param sql The SQL statement to be executed by the database
Elif Bilginfba75de2021-03-09 04:44:10 -0800475 */
476 private fun addDatabaseExecuteSqlStatement(
Daniel Santiago Riverab604ea32022-08-10 10:06:19 -0700477 migrateBuilder: XFunSpec.Builder,
Elif Bilginfba75de2021-03-09 04:44:10 -0800478 sql: String
479 ) {
480 migrateBuilder.addStatement(
elifbilgind62dc352023-02-03 11:22:25 -0800481 "db.execSQL(%S)",
Elif Bilgin26e3f9d2021-03-29 05:57:30 -0700482 sql
Elif Bilginfba75de2021-03-09 04:44:10 -0800483 )
Elif Bilgin63ffe602021-02-19 10:46:51 -0800484 }
485}