Skip to content

Commit

Permalink
Merge pull request #78 from RajashekarRaju/implement-caching-mechanism
Browse files Browse the repository at this point in the history
Implement simple cache mechanism with LruCache
  • Loading branch information
RajashekarRaju authored Jan 9, 2025
2 parents f26bb5f + 003dc41 commit 0f707ad
Show file tree
Hide file tree
Showing 17 changed files with 239 additions and 43 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@
.externalNativeBuild
.cxx
local.properties
/misc.xml
/.idea/appInsightsSettings.xml
/.idea/deploymentTargetSelector.xml
/.idea/runConfigurations.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.developersbreach.composeactors.core.cache

object CacheKey {
fun forPerson(id: Int): String = "${PERSON}_$id"
fun forMovie(id: String): String = "${MOVIE}_$id"

private const val PERSON = "person_"
private const val MOVIE = "movie_"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.developersbreach.composeactors.core.cache

import android.util.LruCache
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class CacheManager @Inject constructor(
cacheSize: Int = 100
) {
private val cache = object : LruCache<String, Any>(cacheSize) {
override fun sizeOf(key: String, value: Any): Int {
return 1
}
}

@Synchronized
fun <T> get(key: String): T? {
return cache[key] as? T
}

@Synchronized
fun <T> put(key: String, value: T) {
cache.put(key, value)
}

@Synchronized
fun remove(key: String) {
cache.remove(key)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@ import androidx.room.Database
import androidx.room.RoomDatabase
import com.developersbreach.composeactors.core.database.dao.FavoritePersonsDao
import com.developersbreach.composeactors.core.database.dao.FavoriteMoviesDao
import com.developersbreach.composeactors.core.database.dao.PersonDetailsDao
import com.developersbreach.composeactors.core.database.entity.FavoritePersonsEntity
import com.developersbreach.composeactors.core.database.entity.FavoriteMoviesEntity
import com.developersbreach.composeactors.core.database.entity.PersonDetailEntity


@Database(
entities = [FavoritePersonsEntity::class, FavoriteMoviesEntity::class],
version = 4,
entities = [FavoritePersonsEntity::class, FavoriteMoviesEntity::class, PersonDetailEntity::class],
version = 5,
exportSchema = false,
)
abstract class AppDatabase : RoomDatabase() {
abstract val favoritePersonsDao: FavoritePersonsDao
abstract val personDetailsDao: PersonDetailsDao
abstract val favoriteMoviesDao: FavoriteMoviesDao
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.developersbreach.composeactors.core.database.dao

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.developersbreach.composeactors.core.database.entity.PersonDetailEntity

@Dao
interface PersonDetailsDao {

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertPersonDetail(personDetail: PersonDetailEntity)

@Query("SELECT * FROM person_detail_table WHERE column_person_detail_id = :personId")
suspend fun getPersonDetail(personId: Int): PersonDetailEntity?
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.compose.runtime.Stable
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.developersbreach.composeactors.data.movie.model.Movie

@Entity(tableName = "favorite_movies_table")
data class FavoriteMoviesEntity(
Expand All @@ -22,3 +23,14 @@ data class FavoriteMoviesEntity(
@ColumnInfo(name = "column_movie_banner")
val movieBanner: String?
)

fun List<FavoriteMoviesEntity>.movieAsDomainModel(): List<Movie> {
return map {
Movie(
movieId = it.movieId,
movieName = it.movieName,
posterPath = it.moviePosterUrl,
backdropPath = it.movieBanner
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.compose.runtime.Stable
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.developersbreach.composeactors.data.person.model.FavoritePerson

@Entity(tableName = "favorite_persons_table")
data class FavoritePersonsEntity(
Expand All @@ -22,3 +23,14 @@ data class FavoritePersonsEntity(
@ColumnInfo(name = "column_person_placeOfBirth")
val personPlaceOfBirth: String?
)

fun List<FavoritePersonsEntity>.toFavoritePersons(): List<FavoritePerson> {
return map {
FavoritePerson(
personId = it.personId,
personName = it.personName,
profileUrl = it.personProfileUrl,
placeOfBirth = it.personPlaceOfBirth
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.developersbreach.composeactors.core.database.entity

import androidx.compose.runtime.Stable
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.developersbreach.composeactors.data.person.model.PersonDetail

@Entity(tableName = "person_detail_table")
data class PersonDetailEntity(

@Stable
@PrimaryKey
@ColumnInfo(name = "column_person_detail_id")
val personId: Int,

@ColumnInfo(name = "column_person_detail_name")
val personName: String,

@ColumnInfo(name = "column_person_detail_profile_path")
val profilePath: String?,

@ColumnInfo(name = "column_person_detail_biography")
val biography: String,

@ColumnInfo(name = "column_person_detail_date_of_birth")
val dateOfBirth: String?,

@ColumnInfo(name = "column_person_detail_place_of_birth")
val placeOfBirth: String?,

@ColumnInfo(name = "column_person_detail_popularity")
val popularity: Double
)

fun PersonDetailEntity.toPersonDetail(): PersonDetail {
return PersonDetail(
personId = personId,
personName = personName,
profilePath = profilePath,
biography = biography,
dateOfBirth = dateOfBirth,
placeOfBirth = placeOfBirth,
popularity = popularity
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ package com.developersbreach.composeactors.data.datasource.database

import androidx.lifecycle.LiveData
import androidx.lifecycle.map
import arrow.core.Either
import com.developersbreach.composeactors.core.database.AppDatabase
import com.developersbreach.composeactors.core.database.entity.PersonDetailEntity
import com.developersbreach.composeactors.core.database.entity.movieAsDomainModel
import com.developersbreach.composeactors.core.database.entity.toFavoritePersons
import com.developersbreach.composeactors.data.person.model.FavoritePerson
import com.developersbreach.composeactors.data.movie.model.Movie
import com.developersbreach.composeactors.data.person.model.personAsDatabaseModel
import com.developersbreach.composeactors.data.person.model.personAsDomainModel
import com.developersbreach.composeactors.data.person.model.FavoritePersonsEntity
import com.developersbreach.composeactors.data.movie.model.movieAsDatabaseModel
import com.developersbreach.composeactors.data.movie.model.movieAsDomainModel
import com.developersbreach.composeactors.data.person.model.PersonDetail
import com.developersbreach.composeactors.data.person.model.toEntity
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.Dispatchers
Expand All @@ -29,7 +33,7 @@ class DatabaseDataSource @Inject constructor(
fun getAllFavoritePersons(): LiveData<List<FavoritePerson>> {
val allFavoritePersons = database.favoritePersonsDao.getAllFavoritePersons()
return allFavoritePersons.map { favEntityList ->
favEntityList.personAsDomainModel()
favEntityList.toFavoritePersons()
}
}

Expand All @@ -52,7 +56,7 @@ class DatabaseDataSource @Inject constructor(
suspend fun addPersonToFavorites(
favoritePerson: FavoritePerson
) = withContext(Dispatchers.IO) {
with(favoritePerson.personAsDatabaseModel()) {
with(favoritePerson.FavoritePersonsEntity()) {
database.favoritePersonsDao.addPersonToFavorites(favoritePersonsEntity = this)
}
}
Expand All @@ -68,8 +72,22 @@ class DatabaseDataSource @Inject constructor(
suspend fun deleteSelectedFavoritePerson(
favoritePerson: FavoritePerson
) = withContext(Dispatchers.IO) {
with(favoritePerson.personAsDatabaseModel()) {
with(favoritePerson.FavoritePersonsEntity()) {
database.favoritePersonsDao.deleteSelectedFavoritePerson(favoritePersonsEntity = this)
}
}

suspend fun addPersonDetail(
personDetail: PersonDetail
) {
database.personDetailsDao.insertPersonDetail(personDetail.toEntity())
}

suspend fun getPersonDetail(
personId: Int
): Either<Throwable, PersonDetailEntity?> {
return Either.catch {
database.personDetailsDao.getPersonDetail(personId)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,4 @@ fun Movie.movieAsDatabaseModel(): FavoriteMoviesEntity {
moviePosterUrl = this.posterPathUrl,
movieBanner = this.bannerUrl
)
}

fun List<FavoriteMoviesEntity>.movieAsDomainModel(): List<Movie> {
return map {
Movie(
movieId = it.movieId,
movieName = it.movieName,
posterPath = it.moviePosterUrl,
backdropPath = it.movieBanner
)
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
package com.developersbreach.composeactors.data.person.model

import androidx.compose.runtime.Stable
import com.developersbreach.composeactors.core.database.entity.FavoritePersonsEntity

data class FavoritePerson(
@Stable val personId: Int,
val personName: String,
val profileUrl: String,
val placeOfBirth: String?
)
)

fun FavoritePerson.FavoritePersonsEntity(): FavoritePersonsEntity {
return FavoritePersonsEntity(
personId = this.personId,
personName = this.personName,
personProfileUrl = this.profileUrl,
personPlaceOfBirth = this.placeOfBirth
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.developersbreach.composeactors.data.person.model

import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import com.developersbreach.composeactors.core.database.entity.FavoritePersonsEntity
import com.developersbreach.composeactors.core.database.entity.PersonDetailEntity
import com.developersbreach.composeactors.core.network.HIGH_RES_IMAGE
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
Expand All @@ -28,22 +28,14 @@ fun PersonDetail.toFavoritePerson() = FavoritePerson(
placeOfBirth = this.placeOfBirth
)

fun FavoritePerson.personAsDatabaseModel(): FavoritePersonsEntity {
return FavoritePersonsEntity(
personId = this.personId,
personName = this.personName,
personProfileUrl = this.profileUrl,
personPlaceOfBirth = this.placeOfBirth
fun PersonDetail.toEntity(): PersonDetailEntity {
return PersonDetailEntity(
personId = personId,
personName = personName,
profilePath = profileUrl,
biography = biography,
dateOfBirth = dateOfBirth,
placeOfBirth = placeOfBirth,
popularity = popularity
)
}

fun List<FavoritePersonsEntity>.personAsDomainModel(): List<FavoritePerson> {
return map {
FavoritePerson(
personId = it.personId,
personName = it.personName,
profileUrl = it.personProfileUrl,
placeOfBirth = it.personPlaceOfBirth
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package com.developersbreach.composeactors.data.person.repository

import androidx.lifecycle.LiveData
import arrow.core.Either
import com.developersbreach.composeactors.core.cache.CacheKey
import com.developersbreach.composeactors.core.cache.CacheManager
import com.developersbreach.composeactors.core.database.entity.toPersonDetail
import com.developersbreach.composeactors.data.datasource.database.DatabaseDataSource
import com.developersbreach.composeactors.data.person.model.Person
import com.developersbreach.composeactors.data.person.model.PersonDetail
Expand All @@ -16,7 +19,8 @@ import kotlinx.coroutines.withContext
@Singleton
class PersonRepositoryImpl @Inject constructor(
private val personApi: PersonApi,
private val databaseDataSource: DatabaseDataSource
private val databaseDataSource: DatabaseDataSource,
private val cacheManager: CacheManager,
) : PersonRepository {

override suspend fun getPopularPersons(): Either<Throwable, List<Person>> = withContext(Dispatchers.IO) {
Expand All @@ -34,7 +38,25 @@ class PersonRepositoryImpl @Inject constructor(
override suspend fun getPersonDetails(
personId: Int
): Either<Throwable, PersonDetail> = withContext(Dispatchers.IO) {
personApi.getPersonDetails(personId)
val cacheKey = CacheKey.forPerson(personId)
val cachedData = cacheManager.get<PersonDetail>(cacheKey)
if (cachedData != null) {
return@withContext Either.Right(cachedData)
}

val dbData = databaseDataSource.getPersonDetail(personId)
dbData.map {
if (it != null) {
cacheManager.put(cacheKey, it.toPersonDetail())
return@withContext Either.Right(it.toPersonDetail())
}
}

personApi.getPersonDetails(personId).map {
cacheManager.put(cacheKey, it)
databaseDataSource.addPersonDetail(it)
it
}
}

override suspend fun getCastDetails(
Expand Down
Loading

0 comments on commit 0f707ad

Please sign in to comment.