Skip to content

Commit

Permalink
Issue #31: Create Room Database. (#35)
Browse files Browse the repository at this point in the history
Issue #33: Save Characters from the service to the Database.

- Initial setup for room library.
- Added entity, DAO and implementation to get Characters from the database if they are already cached from the service.

Signed-off-by: Diego Recalde <diego.recalde@globant.com>
  • Loading branch information
recaldev authored and jamacado committed Dec 31, 2019
1 parent 4d100ec commit 920735e
Show file tree
Hide file tree
Showing 33 changed files with 248 additions and 97 deletions.
3 changes: 3 additions & 0 deletions buildSrc/src/main/java/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ object Versions {
internal const val fabricTools = "1.31.2"
internal const val materialVersion = "1.0.0"
internal const val cardView = "28.0.0"
internal const val roomVersion = "2.2.3"
}

object GradleDependencies {
Expand Down Expand Up @@ -73,4 +74,6 @@ object LibsDependencies {
const val glide = "com.github.bumptech.glide:glide:${Versions.glide}"
const val glideAnnotation = "com.github.bumptech.glide:compiler:${Versions.glide}"
const val httpLoggingInterceptor = "com.squareup.okhttp3:logging-interceptor:${Versions.httpLoggingInterceptorVersion}"
const val room = "androidx.room:room-runtime:${Versions.roomVersion}"
const val roomCompiler = "androidx.room:room-compiler:${Versions.roomVersion}"
}
11 changes: 11 additions & 0 deletions data/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply from: "$rootDir/detekt.gradle"

def apiPropertiesFile = rootProject.file("api.properties")
Expand All @@ -20,6 +21,12 @@ android {
buildConfigField("String", "MARVEL_PRIVATE_KEY", apiProperties['MARVEL_PRIVATE_KEY'])
buildConfigField("String", "MARVEL_PUBLIC_KEY", apiProperties['MARVEL_PUBLIC_KEY'])
buildConfigField("String", "TIME_STAMP", apiProperties['TIME_STAMP'])

javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.incremental":"true"]
}
}
}

buildTypes {
Expand All @@ -39,13 +46,17 @@ dependencies {
implementation SupportDependencies.appCompat
implementation SupportDependencies.coreKtx

implementation LibsDependencies.room
kapt LibsDependencies.roomCompiler

api LibsDependencies.retrofit2
api LibsDependencies.retrofitGson
api LibsDependencies.httpLoggingInterceptor

testImplementation TestDependencies.junit
testImplementation TestDependencies.robolectric
testImplementation TestDependencies.coroutinesTest

androidTestImplementation TestDependencies.testJunit
androidTestImplementation TestDependencies.espressoCore
}
20 changes: 20 additions & 0 deletions data/src/main/java/com/architect/coders/mu8/data/DataApp.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.architect.coders.mu8.data

import android.app.Application
import androidx.room.Room
import com.architect.coders.mu8.data.database.MU8Database

open class DataApp : Application() {

lateinit var database: MU8Database
private set

override fun onCreate() {
super.onCreate()
database = Room.databaseBuilder(
this,
MU8Database::class.java,
"MU8-db"
).build()
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.architect.coders.mu8.data.local.categories
package com.architect.coders.mu8.data.categories

import com.architect.codes.mu8.CHARACTERS
import com.architect.codes.mu8.COMICS
import com.architect.codes.mu8.EVENTS
import com.architect.codes.mu8.utils.CHARACTERS
import com.architect.codes.mu8.utils.COMICS
import com.architect.codes.mu8.utils.EVENTS
import com.architect.codes.mu8.categories.Category

class CategoriesRepository {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.architect.coders.mu8.data.characters

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy.IGNORE
import androidx.room.Query

@Dao
interface CharactersDAO {

@Query("SELECT * FROM CharactersEntity")
fun getAllCharacters(): List<CharactersEntity>

@Query("SELECT COUNT(id) FROM CharactersEntity")
fun charactersCount(): Int

@Insert(onConflict = IGNORE)
fun insertCharacters(characters: List<CharactersEntity>)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.architect.coders.mu8.data.characters

import androidx.room.Entity
import androidx.room.PrimaryKey
import com.architect.coders.mu8.data.response.common.ThumbnailEntity
import com.architect.coders.mu8.data.response.common.UrlsEntity
import com.architect.codes.mu8.utils.EMPTY_STRING

@Entity
data class CharactersEntity(
@PrimaryKey(autoGenerate = false) val id: Long = 0L,
val name: String = EMPTY_STRING,
val description: String = EMPTY_STRING,
val thumbnail: ThumbnailEntity,
val urls: List<UrlsEntity>
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import com.architect.coders.mu8.data.mapper.common.UrlsMapper
import com.architect.coders.mu8.data.utils.replaceHttps
import com.architect.codes.mu8.characters.Character

class CharactersMapper(private val urlsMapper: UrlsMapper) : BaseResponseMapper<CharactersResponse, Character>() {
class CharactersMapper(
private val urlsMapper: UrlsMapper
) : BaseResponseMapper<CharactersEntity, Character>() {

override fun transform(input: CharactersResponse): Character {
override fun transform(input: CharactersEntity): Character {
return Character(
input.id,
input.name,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,40 @@
package com.architect.coders.mu8.data.characters

import com.architect.coders.mu8.data.service.MarvelServiceManager
import com.architect.coders.mu8.data.DataApp
import com.architect.coders.mu8.data.service.MarvelServiceManager.hashcode
import com.architect.coders.mu8.data.service.MarvelServiceManager.service
import com.architect.coders.mu8.data.utils.DEFAULT_OFFSET
import com.architect.coders.mu8.data.utils.LIMIT
import com.architect.coders.mu8.data.utils.MARVEL_PUBLIC_KEY
import com.architect.coders.mu8.data.utils.TIME_STAMP
import com.architect.codes.mu8.characters.Character
import com.architect.codes.mu8.characters.CharactersRepository
import com.architect.codes.mu8.common.Scope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

class CharactersRepositoryImpl(
private val mapper: CharactersMapper
) : CharactersRepository, Scope by Scope.Implementation() {
private val mapper: CharactersMapper,
application: DataApp
) : CharactersRepository {

init {
initScope()
}
private val database = application.database

override suspend fun invoke(): List<Character> {
val response = MarvelServiceManager.service.getAllCharacters(TIME_STAMP, MARVEL_PUBLIC_KEY, hashcode)
override suspend fun invoke(): List<Character> = withContext(Dispatchers.IO) {
with(database.getCharactersDao()) {
if (charactersCount() <= 0) {
val response = service.getAllCharacters(
TIME_STAMP,
MARVEL_PUBLIC_KEY,
hashcode,
DEFAULT_OFFSET,
LIMIT
)

val characters = mutableListOf<Character>()
if (response.isSuccessful) {
response.body()?.data?.results?.forEach {
characters.add(mapper.transform(it))
if (response.isSuccessful) {
response.body()?.data?.results?.run { insertCharacters(this) }
}
}
return@withContext getAllCharacters().map { mapper.transform(it) }
}
return characters
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.architect.coders.mu8.data.comics.model
package com.architect.coders.mu8.data.comics

import com.architect.coders.mu8.data.response.common.ThumbnailResponse
import com.architect.coders.mu8.data.response.common.ThumbnailEntity
import com.google.gson.annotations.SerializedName

data class ComicResponse(
Expand All @@ -17,5 +17,5 @@ data class ComicResponse(
val format: String,

@SerializedName("thumbnail")
val thumbnail: ThumbnailResponse
val thumbnail: ThumbnailEntity
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.architect.coders.mu8.data.comics

import com.architect.coders.mu8.data.comics.model.ComicResponse
import com.architect.coders.mu8.data.mapper.BaseResponseMapper
import com.architect.coders.mu8.data.utils.replaceHttps
import com.architect.codes.mu8.comics.Comic
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.architect.coders.mu8.data.database

import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import com.architect.coders.mu8.data.characters.CharactersDAO
import com.architect.coders.mu8.data.characters.CharactersEntity
import com.architect.coders.mu8.data.database.converter.ThumbnailTypeConverters
import com.architect.coders.mu8.data.database.converter.UrlsTypeConverters

private const val DATABASE_VERSION = 1

@Database(entities = [CharactersEntity::class], version = DATABASE_VERSION)
@TypeConverters(UrlsTypeConverters::class, ThumbnailTypeConverters::class)
abstract class MU8Database : RoomDatabase() {
abstract fun getCharactersDao(): CharactersDAO
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.architect.coders.mu8.data.database.converter

import androidx.room.TypeConverter
import com.architect.coders.mu8.data.response.common.ThumbnailEntity
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken

class ThumbnailTypeConverters {

private val gson = Gson()

@TypeConverter
fun stringToThumbnail(data: String?): ThumbnailEntity {
if (data == null) {
return ThumbnailEntity()
}
val type = object : TypeToken<ThumbnailEntity>() {}.type
return gson.fromJson(data, type)
}

@TypeConverter
fun thumbnailToString(thumbnail: ThumbnailEntity?): String {
if (thumbnail == null) {
return gson.toJson(ThumbnailEntity())
}
return gson.toJson(thumbnail)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.architect.coders.mu8.data.database.converter

import androidx.room.TypeConverter
import com.architect.coders.mu8.data.response.common.UrlsEntity
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken

class UrlsTypeConverters {

private val gson = Gson()

@TypeConverter
fun stringToUrls(data: String?): List<UrlsEntity> {
if (data == null) {
return emptyList()
}
val type = object : TypeToken<List<UrlsEntity>>() {}.type
return gson.fromJson(data, type)
}

@TypeConverter
fun urlsToString(urls: List<UrlsEntity>?): String {
if (urls.isNullOrEmpty()) {
gson.toJson(emptyList<UrlsEntity>())
}
return gson.toJson(urls)
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package com.architect.coders.mu8.data.mapper.common

import com.architect.coders.mu8.data.mapper.BaseResponseMapper
import com.architect.coders.mu8.data.response.common.UrlsResponse
import com.architect.coders.mu8.data.response.common.UrlsEntity
import com.architect.codes.mu8.common.Urls

class UrlsMapper : BaseResponseMapper<UrlsResponse, Urls>() {
class UrlsMapper : BaseResponseMapper<UrlsEntity, Urls>() {

override fun transform(input: UrlsResponse): Urls {
override fun transform(input: UrlsEntity): Urls {
return Urls(input.type, input.url)
}

fun transform(input: List<UrlsResponse>): List<Urls> {
fun transform(input: List<UrlsEntity>): List<Urls> {
val output = mutableListOf<Urls>()
input.forEach { output.add(transform(it)) }
return output
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.architect.coders.mu8.data.response.common

import com.architect.codes.mu8.utils.EMPTY_STRING

data class ThumbnailEntity(val path: String = EMPTY_STRING, val extension: String = EMPTY_STRING)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.architect.coders.mu8.data.response.common

data class UrlsEntity(val type: String, val url: String)

This file was deleted.

Loading

0 comments on commit 920735e

Please sign in to comment.