Political Preparedness

Political Preparedness

Part 2 :Database

Download the Political Preparedness Project Starter Code

Inside the database package you have the following files:

  • Converters.kt
  • ElectionDao.kt
  • ElectionDatabase.kt

  • ElectionsLocalRepository.kt

Converters.kt

A converter as per Cambridge English dictionary is a machine or device that changes something into a different form.

In android, room doesn't allow for object references between entities . In this app we need to store a custom data type in a single database column. We support custom types by providing type converters, which are methods that tell Room how to convert custom types to and from known types that Room can persist.

Read more on Referencing complex data using Room

import androidx.room.TypeConverter
import java.util.*

class Converters {
    @TypeConverter
    fun fromTimestamp(value: Long?): Date? {
        return value?.let { Date(it) }
    }

    @TypeConverter
    fun dateToTimestamp(date: Date?): Long? {
        return date?.time?.toLong()
    }
}

Check out Converters.kt code on GitHub

ElectionDatabase.kt

You add the @ TypeConverters annotation to the AppDatabase class so that Room knows about the converter class that you have defined:

 @Database(entities = arrayOf(User::class), version = 1)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
   abstract val electionDao: ElectionDao
}

Check out ElectionDatabase.kt code on GitHub

ElectionDao.kt

When you use the Room persistence library to store your app's data, you interact with the stored data by defining data access objects (DAOs). Each DAO includes methods that offer abstract access to your app's database.

You can define each DAO as either an interface or an abstract class- always annotate your DAOs with @ Dao

The DAO methods that define database interactions are divided into two:

  • Convenience methods that let you insert, update, and delete rows in your database without writing any SQL code.

  • Query methods that let you write your own SQL query to interact with the database.

Read more on accessing data using Room DAOs

import androidx.lifecycle.LiveData
import androidx.room.*
import com.example.android.politicalpreparedness.network.models.Election

@Dao
interface ElectionDao {



    //inserting all eletions
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun allElectionsInserted(vararg elections: Election)


    // Add select all election query

    @Query("SELECT * from election_table" )
   fun getElections(): LiveData<List<Election>>

    @Query("SELECT * FROM election_table WHERE id in (SELECT id FROM elections_followed_table) ORDER BY electionDay DESC")
    fun getElectionsFollowed(): LiveData<List<Election>>

    @Query("SELECT CASE id WHEN NULL THEN 0 ELSE 1 END FROM elections_followed_table WHERE id = :electionSavedId")
    fun isElectionSaved(electionSavedId: Int): LiveData<Int>

    @Query("INSERT INTO elections_followed_table (id) VALUES(:electionFollowedId)")
    suspend fun electionFollowed(electionFollowedId: Int)
    suspend fun electionFollowed(election: Election){
        electionFollowed(election.id)
    }


    @Query("DELETE FROM elections_followed_table WHERE id = :electionUnFollowId")
    suspend fun electionUnFollow(electionUnFollowId: Int)
    suspend fun electionUnFollow(election: Election){
        electionUnFollow(election.id)
    }

}

Check out ElectionDao.kt code on GitHub

Live Data

An observable data holder class that is lifecycle aware.

Live Data.png

LiveData allows UI controller observers to subscribe to updates. When the data held by the LiveData object changes, the UI automatically updates in response.

Live Data.jpg

Lifecycle - Awareness to LiveData.jpg

The Room persistence library supports observable queries, which return LiveData objects. Observable queries are written as part of a Database Access Object (DAO).

Learn more on LiveData

ElectionsLocalRepository.kt

Repository modules handle data operations. They provide a clean API so that the rest of the app can retrieve this data easily. They know where to get the data from and what API calls to make when data is updated. They can be considered to be mediators between different data sources, such as persistent models, web services, and caches.

import android.content.ContentValues
import android.util.Log
import androidx.lifecycle.LiveData
import com.example.android.politicalpreparedness.network.CivicsApi
import com.example.android.politicalpreparedness.network.models.Election
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

class ElectionsLocalRepository(private val electionDatabase: ElectionDatabase
){

    //list of elections tha has been saved
    val elections:LiveData<List<Election>> =electionDatabase.electionDao.getElections()

    // The list of  elections that has been followed.
    // The list of followed elections.
    val electionsFollowed: LiveData<List<Election>> = electionDatabase.electionDao.getElectionsFollowed()



    suspend fun electionsRefreshed() {
        withContext(Dispatchers.IO) {
            try {
                // Get String Json response via Retrofit
                val electionsResponse = CivicsApi.retrofitService.electionResponse()
                val result = electionsResponse.elections

                // Push the results to the database
               electionDatabase.electionDao.allElectionsInserted(*result.toTypedArray())

                Log.d(ContentValues.TAG, result.toString())
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

}

Check out ElectionsLocalRepository.kt code on GitHub

Read more on Guide to app architecture

Many thanks for reading see you in part 3