androidkotlinrepository-patternandroid-architecture-componentsandroid-mvvm

Android: Model mapping in repository pattern


I want to fetch news from remote and map network response to entity class to store in room database in repository layer. i am using separate data class for both remote and database

Here are the data classes that i am using....

How to add mapping logic something like below?

fun NewsRemote.toLocal() = NewsLocal(
       ..............
)

Data class for Network response

data class NewsRemote(
    val articles: List<ArticlesItem?>? = null,
    val status: String? = null,
) {
    data class ArticlesItem(
        val publishedAt: String? = null,
        val author: String? = null,
        val urlToImage: String? = null,
        val description: String? = null,
        val source: Source? = null,
        val title: String? = null,
        val url: String? = null,
        val content: String? = null
    ) {
        data class Source(
            val name: String? = null,
            val id: String? = null
        )
    }
}

Data class for Database

@Entity(tableName = "news")
data class NewsLocal(
    @PrimaryKey
    var id: Int = Random().nextInt(),
    var publishedAt: String? = null,
    var author: String? = null,
    var urlToImage: String? = null,
    var description: String? = null,
    var source: Source? = null,
    var title: String? = null,
    var url: String? = null,
    var content: String? = null
)

Data class External

data class Headlines(
    val status: String? = null,
    val publishedAt: String? = null,
    val author: String? = null,
    val urlToImage: String? = null,
    val description: String? = null,
    val source: NewsSource? = null,
    val title: String? = null,
    val url: String? = null,
    val content: String? = null
)

data class NewsSource(
    val name: String? = null,
    val id: String? = null
)

I am trying to add something like below but not sure how to map exactly

fun NewsRemote.toLocal() = NewsLocal(
       ..............
)

Solution

  • Marks a field of an Entity or POJO to allow nested fields (i.e. fields of the annotated field's class) to be referenced directly in the SQL queries.

    If the container is an Entity, these sub fields will be columns in the Entity's database table.

    Source class new embedded entity.

    Your Entity

    @Entity(tableName = "news")
    data class NewsLocal(
        @PrimaryKey(autoGenerate = true) 
        val id: Int,
        val publishedAt: String?,
        val author: String?,
        val urlToImage: String?,
        val description: String?,
        @Embedded 
        val source: Source?,
        val title: String?,
        val url: String?,
        val content: String?
    )
    
    @Entity(tableName = "source")
    data class Source(
        @PrimaryKey(autoGenerate = true)
        val id: String,
        val name: String
    )
    

    Mapping

    fun NewsRemote.ArticlesItem.toLocalNews(): NewsLocal {
       val sourceObj = Source(
            id = this.source?.id ?: "",
            name = this.source?.name ?: ""
        )
    
        return NewsLocal(
            id = 0,
            publishedAt = this.publishedAt,
            author = this.author,
            urlToImage = this.urlToImage,
            description = this.description,
            source = sourceObj,
            title = this.title,
            url = this.url,
            content = this.content
        )
    }
    
    fun NewsRemote.toLocalNewsList(): List<NewsLocal> {
        
       val newsLocalList: MutableList<NewsLocal> = mutableListOf()
       this.articles?.forEach { articleItem ->
            
            if (articleItem != null) {
                val localNews = articleItem.toLocalNews()
                newsLocalList.add(localNews)
            }
        }
        return newsLocalList
    }