Hi, I created a Compose app with a room database a...
# compose
p
Hi, I created a Compose app with a room database and flows, which is loading data from an assets database. Then I add favorites and more stuff. It works and stores favorites until I close the app and reopen it. Then, all favorites are lost and the database seems to be the same as the assets database. Any idea about what I'm doing wrong? I'm attaching some code on a thread here:
Copy code
@Database(entities = [Airport::class, Favorite::class], version = 1)
abstract class FlightsDatabase : RoomDatabase() {
    abstract fun flightsDao(): FlightsDao

    companion object {
        @Volatile
        private var Instance: FlightsDatabase? = null

        fun getDatabase(context: Context): FlightsDatabase {
            return Instance ?: synchronized(this) {
                Room.databaseBuilder(
                    context,
                    FlightsDatabase::class.java,
                    "app_database"
                )
                    .createFromAsset("database/flight_search.db")
                    .fallbackToDestructiveMigration()
                    .build()
                    .also { Instance = it}
            }
        }
    }
}
👀 1
Copy code
class DefaultAppContainer(private val context: Context) : AppContainer {
    override val flightRepository: FlightsRepository by lazy {
        OfflineFlightsRepository(FlightsDatabase.getDatabase(context).flightsDao())
    }
    override val userPreferencesRepository = UserPreferencesRepository(context.dataStore)
}
Copy code
interface FlightsRepository {
    fun getAllAirports(): Flow<List<Airport>>
    fun getAirportsByIatOrName(text: String): Flow<List<Airport>>
    fun getAllDifferentAirports(id: Int): Flow<List<Airport>>
    fun getFavorites(): Flow<List<Favorite>>
    suspend fun insertFavorite(favorite: Favorite)
}

class OfflineFlightsRepository(private val flightsDao: FlightsDao) : FlightsRepository {
    override fun getAllAirports(): Flow<List<Airport>> {
        return flightsDao.getAllAirports()
    }

    override fun getAirportsByIatOrName(text: String): Flow<List<Airport>> {
        return flightsDao.getAirportsByIatOrName(text)
    }

    override fun getAllDifferentAirports(id: Int): Flow<List<Airport>> {
        return flightsDao.getAllDifferentAirports(id)
    }

    override fun getFavorites(): Flow<List<Favorite>> {
        return flightsDao.getFavorites()
    }

    override suspend fun insertFavorite(favorite: Favorite) {
        val foundFavorite = flightsDao.getFavoriteByIATAS(favorite.departureCode, favorite.destinationCode)

        if (foundFavorite != null && foundFavorite.first() != null) {
            val favorite = foundFavorite.first()
            flightsDao.deleteFavorite(favorite)
        } else {
            flightsDao.insertFavorite(favorite)
        }
    }
}
Copy code
@Dao
interface FlightsDao {
    @Query("SELECT * FROM airport ORDER BY passengers DESC")
    fun getAllAirports(): Flow<List<Airport>>

    @Query("SELECT * FROM airport WHERE iata_code LIKE '%'||:text||'%' OR name LIKE '%'||:text||'%' ORDER BY passengers DESC")
    fun getAirportsByIatOrName(text: String): Flow<List<Airport>>

    @Query("SELECT * FROM airport WHERE id NOT LIKE :id ORDER BY passengers DESC")
    fun getAllDifferentAirports(id: Int): Flow<List<Airport>>

    @Query("SELECT * FROM favorite")
    fun getFavorites(): Flow<List<Favorite>>

    @Query("SELECT EXISTS(SELECT * FROM favorite WHERE departure_code = :departureCode AND destination_code = :destinationCode)")
    suspend fun checkIfFavoriteExists(departureCode: String, destinationCode: String): Boolean

    @Query("SELECT * FROM favorite WHERE departure_code = :departureCode AND destination_code = :destinationCode")
    fun getFavoriteByIATAS(departureCode: String, destinationCode: String): Flow<Favorite>?

    @Insert
    suspend fun insertFavorite(favorite: Favorite)

    @Delete
    suspend fun deleteFavorite(favorite: Favorite)
}
c
Try #room
âž• 2
k
Basically, The issue is related to createFromAssests. You haven't define any logic for that. If the dbfile doesn't exist then builder should create from assests. Here is the modified code:
Copy code
fun getDatabase(context: Context): FlightsDatabase {
    return Instance ?: synchronized(this) {
        val dbFile = context.getDatabasePath("app_database")
        val builder = Room.databaseBuilder(
            context,
            FlightsDatabase::class.java,
            "app_database"
        )

        if (!dbFile.exists()) {
            builder.createFromAsset("database/flight_search.db")
        }

        builder
            .fallbackToDestructiveMigration()
            .build()
            .also { Instance = it }
    }
}
p
thank you khubaib, it worked, can't believe google didn't wrote that in the documentation, they just wrote that you must use createFromAsset bug don't tell that you can check if previous db exists (and how to do it) and call it only if not exist. I assumed that room automatically checked that. They should improve the documentation.
🙌 1
k
Happy to Help you mate. Basically, Google didn't provide any information related to existing databases. It's better to have a condition of checking the database to ensure that it works correctly.