Merge "Don't key auto-migration added columns by name." into androidx-main
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/util/SchemaDiffer.kt b/room/room-compiler/src/main/kotlin/androidx/room/util/SchemaDiffer.kt
index 234af6d..867bca9 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/util/SchemaDiffer.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/util/SchemaDiffer.kt
@@ -44,7 +44,7 @@
* Contains the changes detected between the two schema versions provided.
*/
data class SchemaDiffResult(
- val addedColumns: LinkedHashMap<String, AutoMigration.AddedColumn>,
+ val addedColumns: List<AutoMigration.AddedColumn>,
val deletedColumns: List<AutoMigration.DeletedColumn>,
val addedTables: Set<AutoMigration.AddedTable>,
val renamedTables: Map<String, String>,
@@ -93,9 +93,9 @@
mutableMapOf<String, AutoMigration.ComplexChangedTable>()
private val deletedTables = deleteTableEntries.map { it.deletedTableName }.toSet()
- // Map of columns that have been added in the database, keyed by the column name, note that
- // the table these columns have been added to will not contain any complex schema changes.
- private val addedColumns = linkedMapOf<String, AutoMigration.AddedColumn>()
+ // Map of columns that have been added in the database, note that the table these columns
+ // have been added to will not contain any complex schema changes.
+ private val addedColumns = mutableListOf<AutoMigration.AddedColumn>()
private val deletedColumns = deleteColumnEntries
/**
@@ -375,8 +375,8 @@
return true
}
// Check if the to table or the from table is an FTS table while the other is not.
- if (fromTable is FtsEntityBundle && !(toTable is FtsEntityBundle) ||
- toTable is FtsEntityBundle && !(fromTable is FtsEntityBundle)
+ if (fromTable is FtsEntityBundle && toTable !is FtsEntityBundle ||
+ toTable is FtsEntityBundle && fromTable !is FtsEntityBundle
) {
return true
}
@@ -557,11 +557,12 @@
// need to account for it as the table will be recreated already with the new
// table.
if (!complexChangedTables.containsKey(fromTable.tableName)) {
- addedColumns[toColumn.columnName] =
+ addedColumns.add(
AutoMigration.AddedColumn(
toTable.tableName,
toColumn
)
+ )
}
}
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
index f30bcb2..290606e 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
@@ -427,11 +427,11 @@
addedColumns.forEach {
val addNewColumnSql = buildString {
append(
- "ALTER TABLE `${it.value.tableName}` ADD COLUMN `${it.key}` " +
- "${it.value.fieldBundle.affinity} "
+ "ALTER TABLE `${it.tableName}` ADD COLUMN `${it.fieldBundle.columnName}` " +
+ "${it.fieldBundle.affinity} "
)
- if (it.value.fieldBundle.isNonNull) {
- append("NOT NULL DEFAULT ${it.value.fieldBundle.defaultValue}")
+ if (it.fieldBundle.isNonNull) {
+ append("NOT NULL DEFAULT ${it.fieldBundle.defaultValue}")
} else {
append("DEFAULT NULL")
}
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/util/SchemaDifferTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/util/SchemaDifferTest.kt
index b5be2a8..bd6a7a3 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/util/SchemaDifferTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/util/SchemaDifferTest.kt
@@ -86,7 +86,7 @@
renameTableEntries = listOf(),
deleteTableEntries = listOf()
).diffSchemas()
- assertThat(schemaDiffResult.addedColumns["artistId"]?.fieldBundle?.columnName)
+ assertThat(schemaDiffResult.addedColumns.single().fieldBundle.columnName)
.isEqualTo("artistId")
}
@@ -101,9 +101,10 @@
renameTableEntries = listOf(),
deleteTableEntries = listOf()
).diffSchemas()
- assertThat(schemaDiffResult.addedColumns["recordLabelId"]?.fieldBundle?.columnName)
+ assertThat(schemaDiffResult.addedColumns).hasSize(2)
+ assertThat(schemaDiffResult.addedColumns[0].fieldBundle.columnName)
.isEqualTo("recordLabelId")
- assertThat(schemaDiffResult.addedColumns["artistId"]?.fieldBundle?.columnName)
+ assertThat(schemaDiffResult.addedColumns[1].fieldBundle.columnName)
.isEqualTo("artistId")
}
@@ -143,6 +144,28 @@
}
@Test
+ fun testColumnsAddedWithSameName() {
+ val schemaDiffResult = SchemaDiffer(
+ fromSchemaBundle = from.database,
+ toSchemaBundle = toColumnsAddedWithSameName.database,
+ className = "MyAutoMigration",
+ renameColumnEntries = listOf(),
+ deleteColumnEntries = listOf(),
+ renameTableEntries = listOf(),
+ deleteTableEntries = listOf()
+ ).diffSchemas()
+ assertThat(schemaDiffResult.addedColumns).hasSize(2)
+ schemaDiffResult.addedColumns[0].let { addedColumn ->
+ assertThat(addedColumn.tableName).isEqualTo("Artist")
+ assertThat(addedColumn.fieldBundle.columnName).isEqualTo("newColumn")
+ }
+ schemaDiffResult.addedColumns[1].let { addedColumn ->
+ assertThat(addedColumn.tableName).isEqualTo("Song")
+ assertThat(addedColumn.fieldBundle.columnName).isEqualTo("newColumn")
+ }
+ }
+
+ @Test
fun testColumnRenamed() {
try {
SchemaDiffer(
@@ -222,7 +245,7 @@
}
}
- val from = SchemaBundle(
+ private val from = SchemaBundle(
1,
DatabaseBundle(
1,
@@ -302,8 +325,9 @@
)
)
- /** Valid "to" Schemas */
- val toTableRenamed = SchemaBundle(
+ //region Valid "to" Schemas
+
+ private val toTableRenamed = SchemaBundle(
2,
DatabaseBundle(
2,
@@ -383,7 +407,7 @@
)
)
- val toTableDeleted = SchemaBundle(
+ private val toTableDeleted = SchemaBundle(
2,
DatabaseBundle(
2,
@@ -429,7 +453,7 @@
)
)
- val toColumnAddedWithColumnInfoDefaultValue = SchemaBundle(
+ private val toColumnAddedWithColumnInfoDefaultValue = SchemaBundle(
2,
DatabaseBundle(
2,
@@ -517,182 +541,9 @@
)
)
- /** Invalid "to" Schemas (These are expected to throw an error.) */
-
- /**
- * The length column is removed from the first version. No other changes made.
- *
- */
- private val toColumnRemoved = SchemaBundle(
- 2,
- DatabaseBundle(
- 2,
- "",
- listOf(
- EntityBundle(
- "Song",
- "CREATE TABLE IF NOT EXISTS `Song` (`id` INTEGER NOT NULL, " +
- "`title` TEXT NOT NULL, PRIMARY KEY(`id`))",
- listOf(
- FieldBundle(
- "id",
- "id",
- "INTEGER",
- true,
- "1"
- ),
- FieldBundle(
- "title",
- "title",
- "TEXT",
- true,
- ""
- ),
- ),
- PrimaryKeyBundle(
- false,
- mutableListOf("id")
- ),
- emptyList(),
- emptyList()
- ),
- EntityBundle(
- "Artist",
- "CREATE TABLE IF NOT EXISTS `Artist` (`id` INTEGER NOT NULL, " +
- "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
- listOf(
- FieldBundle(
- "id",
- "id",
- "INTEGER",
- true,
- "1"
- ),
- FieldBundle(
- "title",
- "title",
- "TEXT",
- true,
- ""
- ),
- FieldBundle(
- "length",
- "length",
- "INTEGER",
- true,
- "1"
- )
- ),
- PrimaryKeyBundle(
- false,
- mutableListOf("id")
- ),
- mutableListOf(),
- mutableListOf()
- )
- ),
- mutableListOf(),
- mutableListOf()
- )
- )
-
- /**
- * If the user declared the default value in the SQL statement and not used a @ColumnInfo,
- * Room will put null for that default value in the exported schema. In this case we
- * can't migrate.
- */
- private val toColumnAddedWithNoDefaultValue = SchemaBundle(
- 2,
- DatabaseBundle(
- 2,
- "",
- listOf(
- EntityBundle(
- "Song",
- "CREATE TABLE IF NOT EXISTS `Song` (`id` INTEGER NOT NULL, " +
- "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, `artistId` " +
- "INTEGER NOT NULL, PRIMARY KEY(`id`))",
- listOf(
- FieldBundle(
- "id",
- "id",
- "INTEGER",
- true,
- "1"
- ),
- FieldBundle(
- "title",
- "title",
- "TEXT",
- true,
- ""
- ),
- FieldBundle(
- "length",
- "length",
- "INTEGER",
- true,
- "1"
- ),
- FieldBundle(
- "artistId",
- "artistId",
- "INTEGER",
- true,
- null
- )
- ),
- PrimaryKeyBundle(
- false,
- mutableListOf("id")
- ),
- emptyList(),
- emptyList()
- ),
- EntityBundle(
- "Artist",
- "CREATE TABLE IF NOT EXISTS `Artist` (`id` INTEGER NOT NULL, " +
- "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
- listOf(
- FieldBundle(
- "id",
- "id",
- "INTEGER",
- true,
- "1"
- ),
- FieldBundle(
- "title",
- "title",
- "TEXT",
- true,
- ""
- ),
- FieldBundle(
- "length",
- "length",
- "INTEGER",
- true,
- "1"
- )
- ),
- PrimaryKeyBundle(
- false,
- mutableListOf("id")
- ),
- mutableListOf(),
- mutableListOf()
- )
- ),
- mutableListOf(),
- mutableListOf()
- )
- )
-
/**
* Adding multiple columns, preserving the order in which they have been added.
*/
-
private val toColumnsAddedInOrder = SchemaBundle(
2,
DatabaseBundle(
@@ -773,7 +624,105 @@
"INTEGER",
true,
"1"
- )
+ ),
+ ),
+ PrimaryKeyBundle(
+ false,
+ mutableListOf("id")
+ ),
+ mutableListOf(),
+ mutableListOf()
+ )
+ ),
+ mutableListOf(),
+ mutableListOf()
+ )
+ )
+
+ /**
+ * Adding multiple columns, preserving the order in which they have been added.
+ */
+ private val toColumnsAddedWithSameName = SchemaBundle(
+ 2,
+ DatabaseBundle(
+ 2,
+ "",
+ listOf(
+ EntityBundle(
+ "Song",
+ "CREATE TABLE IF NOT EXISTS `Song` (`id` INTEGER NOT NULL, " +
+ "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, `artistId` " +
+ "INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ listOf(
+ FieldBundle(
+ "id",
+ "id",
+ "INTEGER",
+ true,
+ "1"
+ ),
+ FieldBundle(
+ "title",
+ "title",
+ "TEXT",
+ true,
+ ""
+ ),
+ FieldBundle(
+ "length",
+ "length",
+ "INTEGER",
+ true,
+ "1"
+ ),
+ FieldBundle(
+ "newColumn",
+ "newColumn",
+ "INTEGER",
+ true,
+ "0"
+ ),
+ ),
+ PrimaryKeyBundle(
+ false,
+ mutableListOf("id")
+ ),
+ emptyList(),
+ emptyList()
+ ),
+ EntityBundle(
+ "Artist",
+ "CREATE TABLE IF NOT EXISTS `Artist` (`id` INTEGER NOT NULL, " +
+ "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ listOf(
+ FieldBundle(
+ "id",
+ "id",
+ "INTEGER",
+ true,
+ "1"
+ ),
+ FieldBundle(
+ "title",
+ "title",
+ "TEXT",
+ true,
+ ""
+ ),
+ FieldBundle(
+ "length",
+ "length",
+ "INTEGER",
+ true,
+ "1"
+ ),
+ FieldBundle(
+ "newColumn",
+ "newColumn",
+ "INTEGER",
+ true,
+ "0"
+ ),
),
PrimaryKeyBundle(
false,
@@ -791,8 +740,6 @@
/**
* Renaming the length column to duration.
*/
- // TODO: We currently do not support column renames as we can't detect rename or deletion
- // yet.
private val toColumnRenamed = SchemaBundle(
2,
DatabaseBundle(
@@ -1322,4 +1269,179 @@
mutableListOf()
)
)
+
+ //endregion
+
+ //region Invalid "to" Schemas (These are expected to throw an error.)
+
+ /**
+ * The length column is removed from the first version. No other changes made.
+ */
+ private val toColumnRemoved = SchemaBundle(
+ 2,
+ DatabaseBundle(
+ 2,
+ "",
+ listOf(
+ EntityBundle(
+ "Song",
+ "CREATE TABLE IF NOT EXISTS `Song` (`id` INTEGER NOT NULL, " +
+ "`title` TEXT NOT NULL, PRIMARY KEY(`id`))",
+ listOf(
+ FieldBundle(
+ "id",
+ "id",
+ "INTEGER",
+ true,
+ "1"
+ ),
+ FieldBundle(
+ "title",
+ "title",
+ "TEXT",
+ true,
+ ""
+ ),
+ ),
+ PrimaryKeyBundle(
+ false,
+ mutableListOf("id")
+ ),
+ emptyList(),
+ emptyList()
+ ),
+ EntityBundle(
+ "Artist",
+ "CREATE TABLE IF NOT EXISTS `Artist` (`id` INTEGER NOT NULL, " +
+ "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ listOf(
+ FieldBundle(
+ "id",
+ "id",
+ "INTEGER",
+ true,
+ "1"
+ ),
+ FieldBundle(
+ "title",
+ "title",
+ "TEXT",
+ true,
+ ""
+ ),
+ FieldBundle(
+ "length",
+ "length",
+ "INTEGER",
+ true,
+ "1"
+ )
+ ),
+ PrimaryKeyBundle(
+ false,
+ mutableListOf("id")
+ ),
+ mutableListOf(),
+ mutableListOf()
+ )
+ ),
+ mutableListOf(),
+ mutableListOf()
+ )
+ )
+
+ /**
+ * If the user declared the default value in the SQL statement and not used a @ColumnInfo,
+ * Room will put null for that default value in the exported schema. In this case we
+ * can't migrate.
+ */
+ private val toColumnAddedWithNoDefaultValue = SchemaBundle(
+ 2,
+ DatabaseBundle(
+ 2,
+ "",
+ listOf(
+ EntityBundle(
+ "Song",
+ "CREATE TABLE IF NOT EXISTS `Song` (`id` INTEGER NOT NULL, " +
+ "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, `artistId` " +
+ "INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ listOf(
+ FieldBundle(
+ "id",
+ "id",
+ "INTEGER",
+ true,
+ "1"
+ ),
+ FieldBundle(
+ "title",
+ "title",
+ "TEXT",
+ true,
+ ""
+ ),
+ FieldBundle(
+ "length",
+ "length",
+ "INTEGER",
+ true,
+ "1"
+ ),
+ FieldBundle(
+ "artistId",
+ "artistId",
+ "INTEGER",
+ true,
+ null
+ )
+ ),
+ PrimaryKeyBundle(
+ false,
+ mutableListOf("id")
+ ),
+ emptyList(),
+ emptyList()
+ ),
+ EntityBundle(
+ "Artist",
+ "CREATE TABLE IF NOT EXISTS `Artist` (`id` INTEGER NOT NULL, " +
+ "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ listOf(
+ FieldBundle(
+ "id",
+ "id",
+ "INTEGER",
+ true,
+ "1"
+ ),
+ FieldBundle(
+ "title",
+ "title",
+ "TEXT",
+ true,
+ ""
+ ),
+ FieldBundle(
+ "length",
+ "length",
+ "INTEGER",
+ true,
+ "1"
+ )
+ ),
+ PrimaryKeyBundle(
+ false,
+ mutableListOf("id")
+ ),
+ mutableListOf(),
+ mutableListOf()
+ )
+ ),
+ mutableListOf(),
+ mutableListOf()
+ )
+ )
+
+ //endregion
}
\ No newline at end of file
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/writer/AutoMigrationWriterTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/writer/AutoMigrationWriterTest.kt
index 0d0afec..28407f2 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/writer/AutoMigrationWriterTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/writer/AutoMigrationWriterTest.kt
@@ -57,18 +57,15 @@
from = 1,
to = 2,
schemaDiff = SchemaDiffResult(
- addedColumns = linkedMapOf(
- Pair(
- "artistId",
- AutoMigration.AddedColumn(
- "Song",
- FieldBundle(
- "artistId",
- "artistId",
- "INTEGER",
- false,
- ""
- )
+ addedColumns = listOf(
+ AutoMigration.AddedColumn(
+ "Song",
+ FieldBundle(
+ "artistId",
+ "artistId",
+ "INTEGER",
+ false,
+ ""
)
)
),
@@ -118,18 +115,15 @@
from = 1,
to = 2,
schemaDiff = SchemaDiffResult(
- addedColumns = linkedMapOf(
- Pair(
- "artistId",
- AutoMigration.AddedColumn(
- "Song",
- FieldBundle(
- "artistId",
- "artistId",
- "INTEGER",
- false,
- ""
- )
+ addedColumns = listOf(
+ AutoMigration.AddedColumn(
+ "Song",
+ FieldBundle(
+ "artistId",
+ "artistId",
+ "INTEGER",
+ false,
+ ""
)
)
),