Skip to content

Commit

Permalink
Add a migration to version 2 to include the whole model into de DB
Browse files Browse the repository at this point in the history
Add tests

Fix migration
  • Loading branch information
Serchinastico committed Mar 15, 2019
1 parent 117916a commit 7f465cc
Show file tree
Hide file tree
Showing 8 changed files with 258 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "3298ad790ab4e90668532dfc9d342b54",
"entities": [
{
"tableName": "superheroes",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `photo` TEXT, `isAvenger` INTEGER NOT NULL, `description` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "photo",
"columnName": "photo",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "isAvenger",
"columnName": "isAvenger",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "description",
"columnName": "description",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"3298ad790ab4e90668532dfc9d342b54\")"
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"formatVersion": 1,
"database": {
"version": 2,
"identityHash": "4250c22060f75f31b611cfdc08f9177d",
"entities": [
{
"tableName": "superheroes",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`superhero_id` TEXT NOT NULL, `superhero_name` TEXT NOT NULL, `superhero_photo` TEXT, `superhero_isAvenger` INTEGER NOT NULL, `superhero_description` TEXT NOT NULL, PRIMARY KEY(`superhero_id`))",
"fields": [
{
"fieldPath": "superHero.id",
"columnName": "superhero_id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "superHero.name",
"columnName": "superhero_name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "superHero.photo",
"columnName": "superhero_photo",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "superHero.isAvenger",
"columnName": "superhero_isAvenger",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "superHero.description",
"columnName": "superhero_description",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"superhero_id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"4250c22060f75f31b611cfdc08f9177d\")"
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.karumi.jetpack.superheroes.data.repository.room

import android.support.test.InstrumentationRegistry
import androidx.room.testing.MigrationTestHelper
import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
import com.karumi.jetpack.superheroes.common.Migrations
import com.karumi.jetpack.superheroes.common.SuperHeroesDatabase
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test

class MigrationTest {
companion object {
private const val TEST_DB = "migration-test"
private const val SUPER_HERO_ID = "IronMan"
private const val SUPER_HERO_NAME = "Iron Man"
private val SUPER_HERO_URL: String? = null
private const val SUPER_HERO_IS_AVENGER = true
private const val SUPER_HER_DESCRIPTION = "Iron Man is a super hero"
}

@Rule
@JvmField
val helper: MigrationTestHelper = MigrationTestHelper(
InstrumentationRegistry.getInstrumentation(),
SuperHeroesDatabase::class.java.canonicalName,
FrameworkSQLiteOpenHelperFactory()
)

@Test
fun migrate1To2() = withDb(
fromVersion = 1,
toVersion = 2,
given = { insertSuperHeroInVersion1() },
then = { assertSuperHeroExistsInVersion2(this) }
)

private fun withDb(
fromVersion: Int,
toVersion: Int,
given: SupportSQLiteDatabase.() -> Unit,
then: SupportSQLiteDatabase.() -> Unit
) {
val db = helper.createDatabase(TEST_DB, fromVersion)
given(db)
helper.runMigrationsAndValidate(TEST_DB, toVersion, true, *Migrations.all)
then(db)
helper.closeWhenFinished(db)
}

private fun assertSuperHeroExistsInVersion2(db: SupportSQLiteDatabase) {
val cursor = db.query("SELECT * FROM superheroes")
cursor.moveToFirst()
assertEquals(SUPER_HERO_ID, cursor.getString(0))
assertEquals(SUPER_HERO_NAME, cursor.getString(1))
assertEquals(SUPER_HERO_URL, cursor.getString(2))
assertEquals(SUPER_HERO_IS_AVENGER.toInt(), cursor.getInt(3))
assertEquals(SUPER_HER_DESCRIPTION, cursor.getString(4))
}

private fun SupportSQLiteDatabase.insertSuperHeroInVersion1() {
execSQL(
"""
INSERT INTO superheroes VALUES(
"$SUPER_HERO_ID",
"$SUPER_HERO_NAME",
$SUPER_HERO_URL,
${SUPER_HERO_IS_AVENGER.toInt()},
"$SUPER_HER_DESCRIPTION"
)"""
)
}
}

private fun Boolean.toInt() = if (this) 1 else 0
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.karumi.jetpack.superheroes

import android.app.Application
import android.content.Context
import androidx.room.Room
import com.karumi.jetpack.superheroes.common.SuperHeroesDatabase
import com.karumi.jetpack.superheroes.common.module
import com.karumi.jetpack.superheroes.data.repository.LocalSuperHeroDataSource
Expand Down Expand Up @@ -35,12 +34,7 @@ class SuperHeroesApplication : Application(), KodeinAware {

private fun appDependencies(): Kodein.Module = module {
bind<SuperHeroesDatabase>() with singleton {
Room.databaseBuilder(
this@SuperHeroesApplication,
SuperHeroesDatabase::class.java,
"superheroes-db"
).fallbackToDestructiveMigration()
.build()
SuperHeroesDatabase.build(this@SuperHeroesApplication)
}
bind<SuperHeroDao>() with provider {
val database: SuperHeroesDatabase = instance()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,62 @@
package com.karumi.jetpack.superheroes.common

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.karumi.jetpack.superheroes.data.repository.room.SuperHeroDao
import com.karumi.jetpack.superheroes.data.repository.room.SuperHeroEntity

@Database(entities = [SuperHeroEntity::class], version = 1)
@Database(entities = [SuperHeroEntity::class], version = SuperHeroesDatabase.version)
abstract class SuperHeroesDatabase : RoomDatabase() {
abstract fun superHeroesDao(): SuperHeroDao

companion object {
const val version = 2
fun build(context: Context): SuperHeroesDatabase =
Room.databaseBuilder(context, SuperHeroesDatabase::class.java, "superheroes-db")
.addMigrations(*Migrations.all)
.build()
}
}

object Migrations {
val from1To2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"""
CREATE TABLE `superheroes_temp` (
`superhero_id` TEXT NOT NULL,
`superhero_name` TEXT NOT NULL,
`superhero_photo` TEXT,
`superhero_isAvenger` INTEGER NOT NULL DEFAULT 0,
`superhero_description` TEXT NOT NULL,
PRIMARY KEY(`superhero_id`)
)
"""
)
database.execSQL(
"""
INSERT INTO `superheroes_temp`(
`superhero_id`,
`superhero_name`,
`superhero_photo`,
`superhero_isAvenger`,
`superhero_description`
) SELECT
`id`,
`name`,
`photo`,
`isAvenger`,
`description`
FROM `superheroes`"""
)
database.execSQL("DROP TABLE superheroes")
database.execSQL("ALTER TABLE `superheroes_temp` RENAME TO `superheroes`")
}
}

val all = arrayOf(from1To2)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,11 @@ class LocalSuperHeroDataSource(
}

fun save(superHero: SuperHero): SuperHero {
dao.insertAll(listOf(superHero.toEntity()))
dao.update(superHero.toEntity())
return superHero
}

private fun SuperHeroEntity.toSuperHero(): SuperHero =
SuperHero(id, name, photo, isAvenger, description)
private fun SuperHeroEntity.toSuperHero(): SuperHero = superHero

private fun SuperHero.toEntity(): SuperHeroEntity =
SuperHeroEntity(id, name, photo, isAvenger, description)
private fun SuperHero.toEntity(): SuperHeroEntity = SuperHeroEntity(this)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,22 @@ import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update

@Dao
interface SuperHeroDao {
@Query("SELECT * FROM superheroes ORDER BY id ASC")
@Query("SELECT * FROM superheroes ORDER BY superhero_id ASC")
fun getAll(): List<SuperHeroEntity>

@Query("SELECT * FROM superheroes WHERE id = :id")
@Query("SELECT * FROM superheroes WHERE superhero_id = :id")
fun getById(id: String): SuperHeroEntity?

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(superHeroes: List<SuperHeroEntity>)

@Update
fun update(superHero: SuperHeroEntity)

@Query("DELETE FROM superheroes")
fun deleteAll()
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package com.karumi.jetpack.superheroes.data.repository.room

import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.karumi.jetpack.superheroes.domain.model.SuperHero

@Entity(tableName = "superheroes")
@Entity(tableName = "superheroes", primaryKeys = ["superhero_id"])
data class SuperHeroEntity(
@PrimaryKey val id: String,
val name: String,
val photo: String?,
val isAvenger: Boolean,
val description: String
@Embedded(prefix = "superhero_") val superHero: SuperHero
)

0 comments on commit 7f465cc

Please sign in to comment.