Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor/data-layer #253

Merged
merged 3 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
.DS_Store
/build
/*/*/build
/*/build
/captures
.externalNativeBuild
.cxx
debug\
release\
/app/debug/
/buildSrc/build/
/sync/build/*
/sync/build/*
.kotlin
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ private fun MarketDetailScreen(
HorizontalDivider()
}
item {
MarketDetail(marketDetailState.marketDetail.marketData)
MarketDetail(marketDetailState.marketDetail?.marketData)
}
}
}
Expand All @@ -136,18 +136,10 @@ fun MarketDetail(marketData: MarketDetail.MarketData?) {
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalAlignment = Alignment.Start,
) {
data.marketCap?.let { marketCap ->
MarketDetailDataBlock("Market Cap", formatNumber(marketCap.usd))
}
data.high24h?.let { high24h ->
MarketDetailDataBlock("High 24h", high24h.usd.toString())
}
data.low24h?.let { low24h ->
MarketDetailDataBlock("Low 24h", low24h.usd.toString())
}
data.marketCapRank?.let { marketCapRank ->
MarketDetailDataBlock("Rank", "#$marketCapRank")
}
MarketDetailDataBlock("Market Cap", formatNumber(data.marketCapUSD))
MarketDetailDataBlock("High 24h", data.high24hUSD.toString())
MarketDetailDataBlock("Low 24h", data.low24hUSD.toString())
MarketDetailDataBlock("Rank", "#${data.marketCapRank}")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package ir.composenews.localdatasource.database

import ir.composenews.db.MarketEntity
import ir.composenews.localdatasource.dto.RemoteMarketDto
import kotlinx.coroutines.flow.Flow

interface MarketDao {
Expand All @@ -12,5 +11,5 @@ interface MarketDao {

suspend fun insertMarket(marketEntity: MarketEntity)

suspend fun upsertMarket(remoteMarketDto: List<RemoteMarketDto>)
suspend fun upsertMarket(marketEntity: List<MarketEntity>)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import app.cash.sqldelight.coroutines.asFlow
import app.cash.sqldelight.coroutines.mapToList
import ir.composenews.db.MarketDatabase
import ir.composenews.db.MarketEntity
import ir.composenews.localdatasource.dto.RemoteMarketDto
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
Expand Down Expand Up @@ -35,8 +34,8 @@ class MarketDaoImpl @Inject constructor(
}
}

override suspend fun upsertMarket(remoteMarketDto: List<RemoteMarketDto>) {
remoteMarketDto.forEach { market ->
override suspend fun upsertMarket(marketEntity: List<MarketEntity>) {
marketEntity.forEach { market ->
market.run {
queries.upsertMarket(
id = id,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,19 +1,7 @@
package ir.composenews.localdatasource.test

import ir.composenews.db.MarketEntity
import ir.composenews.localdatasource.database.FALSE
import ir.composenews.localdatasource.database.TRUE
import ir.composenews.localdatasource.dto.RemoteMarketDto

val marketEntity = MarketEntity(
id = "id",
name = "name",
symbol = "symbol",
currentPrice = 100000.0,
priceChangePercentage24h = 100000.0,
imageUrl = "some_shit_url.png",
isFavorite = FALSE,
)

val favoriteMarketEntity = MarketEntity(
id = "id",
Expand All @@ -24,12 +12,3 @@ val favoriteMarketEntity = MarketEntity(
imageUrl = "some_shit_url.png",
isFavorite = TRUE,
)

val remoteMarketDto = RemoteMarketDto(
id = "id",
name = "name",
symbol = "symbol",
currentPrice = 100000.0,
priceChangePercentage24h = 100000.0,
imageUrl = "some_shit_url.png",
)
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,42 @@ import kotlinx.serialization.Serializable
@Serializable
data class MarketDetailResponse(
@SerialName("id")
val id: String? = null,
val id: String?,
@SerialName("market_cap_rank")
val marketCapRank: Int? = null,
val marketCapRank: Int?,
@SerialName("market_data")
val marketData: MarketData? = null,
val marketData: MarketData?,
@SerialName("name")
val name: String? = null,
val name: String?,
) {

@Serializable
data class MarketData(
@SerialName("high_24h")
val high24h: High24h? = null,
val high24h: High24h?,
@SerialName("low_24h")
val low24h: Low24h? = null,
val low24h: Low24h?,
@SerialName("market_cap")
val marketCap: MarketCap? = null,
val marketCap: MarketCap?,
@SerialName("market_cap_rank")
val marketCapRank: Int? = null,
val marketCapRank: Int?,
) {
@Serializable
data class High24h(
@SerialName("usd")
val usd: Double? = null,
val usd: Double?,
)

@Serializable
data class Low24h(
@SerialName("usd")
val usd: Double? = null,
val usd: Double?,
)

@Serializable
data class MarketCap(
@SerialName("usd")
val usd: Long? = null,
val usd: Long?,
)
}
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,19 @@
package ir.composenews.data.mapper

import ir.composenews.domain.model.MarketDetail
import ir.composenews.domain.model.MarketDetail.MarketData.High24h
import ir.composenews.domain.model.MarketDetail.MarketData.Low24h
import ir.composenews.domain.model.MarketDetail.MarketData.MarketCap
import ir.composenews.remotedatasource.dto.MarketDetailResponse
import ir.composenews.remotedatasource.dto.MarketDetailResponse.MarketData

fun MarketDetailResponse.toDetail(): MarketDetail = MarketDetail(
id = id,
name = name,
fun MarketDetailResponse.toMarketDetail(): MarketDetail = MarketDetail(
id = id ?: "",
name = name ?: "",
marketData = marketData?.toMarketData(),
marketCapRank = marketCapRank,
marketCapRank = marketCapRank ?: 0,
)

fun MarketData.toMarketData(): MarketDetail.MarketData = MarketDetail.MarketData(
high24h = high24h?.toHigh24(),
low24h = low24h?.toLow24(),
marketCap = marketCap?.toMarketCap(),
marketCapRank = marketCapRank,
)

fun MarketData.High24h.toHigh24(): High24h = High24h(
usd = usd,
)

fun MarketData.Low24h.toLow24(): Low24h = Low24h(
usd = usd,
)

fun MarketData.MarketCap.toMarketCap(): MarketCap = MarketCap(
usd = usd,
high24hUSD = high24h?.usd ?: 0.0,
low24hUSD = low24h?.usd ?: 0.0,
marketCapUSD = marketCap?.usd ?: 0,
marketCapRank = marketCapRank ?: 0,
)
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package ir.composenews.data.mapper

import ir.composenews.db.MarketEntity
import ir.composenews.domain.model.Market
import ir.composenews.localdatasource.dto.RemoteMarketDto
import ir.composenews.localdatasource.database.FALSE
import ir.composenews.remotedatasource.dto.MarketResponse

fun MarketResponse.toRemoteMarketDto(): RemoteMarketDto = RemoteMarketDto(
fun MarketResponse.toMarketEntity(): MarketEntity = MarketEntity(
id = id,
name = name,
symbol = symbol,
currentPrice = currentPrice,
priceChangePercentage24h = priceChangePercentage24h,
imageUrl = imageUrl,
isFavorite = FALSE,
)

fun MarketResponse.toMarket(): Market = Market(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ package ir.composenews.data.repository

import android.util.Log
import ir.composenews.data.mapper.toChart
import ir.composenews.data.mapper.toDetail
import ir.composenews.data.mapper.toMarket
import ir.composenews.data.mapper.toMarketDetail
import ir.composenews.data.mapper.toMarketEntity
import ir.composenews.data.mapper.toRemoteMarketDto
import ir.composenews.domain.model.Chart
import ir.composenews.domain.model.Market
import ir.composenews.domain.model.MarketDetail
Expand Down Expand Up @@ -48,10 +47,10 @@ class MarketRepositoryImpl @Inject constructor(
1,
false,
).suspendOnSuccess {
val toRemoteMarketDto = data.map {
it.toRemoteMarketDto()
val marketEntityList = data.map { marketResponse ->
marketResponse.toMarketEntity()
}
dao.upsertMarket(toRemoteMarketDto)
dao.upsertMarket(marketEntityList)
}.onError {
Log.d("debug", message)
}.onException {
Expand Down Expand Up @@ -92,7 +91,7 @@ class MarketRepositoryImpl @Inject constructor(
val detail = api.getMarketDetail(id)
detail.suspendOnSuccess {
suspendMap {
emit(Resource.Success(data.toDetail()))
emit(Resource.Success(data.toMarketDetail()))
}
}.suspendOnError {
suspendMap {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ package ir.composenews.data.repository.mapper
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe
import ir.composenews.data.mapper.toMarket
import ir.composenews.data.mapper.toRemoteMarketDto
import ir.composenews.data.mapper.toMarketEntity
import ir.composenews.db.MarketEntity
import ir.composenews.domain.model.Market
import ir.composenews.localdatasource.dto.RemoteMarketDto
import ir.composenews.remotedatasource.dto.MarketResponse

class MarketDtoMapperTest : StringSpec({

"Given valid market response, When converting to remote market dto, Then returns correct dto" {
"Given valid market response, When converting to market entity, Then returns correct dto" {
val marketResponse = MarketResponse(
id = "bitcoin",
name = "Bitcoin",
Expand All @@ -20,12 +20,12 @@ class MarketDtoMapperTest : StringSpec({
imageUrl = "https://image.url/bitcoin.png",
)

val remoteMarketDto = marketResponse.toRemoteMarketDto()
val marketEntity = marketResponse.toMarketEntity()

remoteMarketDto shouldBeEqual marketResponse
marketEntity shouldBeEqual marketResponse
}

"Given market response with empty strings and zeros, When converting to remote market dto, Then returns correct dto" {
"Given market response with empty strings and zeros, When converting to market entity, Then returns correct dto" {

val marketResponse = MarketResponse(
id = "",
Expand All @@ -36,12 +36,12 @@ class MarketDtoMapperTest : StringSpec({
imageUrl = "",
)

val remoteMarketDto = marketResponse.toRemoteMarketDto()
val marketEntity = marketResponse.toMarketEntity()

remoteMarketDto shouldBeEqual marketResponse
marketEntity shouldBeEqual marketResponse
}

"Given market response with extreme double values, When converting to remote market dto, Then returns correct dto" {
"Given market response with extreme double values, When converting to market entity, Then returns correct dto" {

val marketResponse = MarketResponse(
id = "extreme",
Expand All @@ -52,13 +52,12 @@ class MarketDtoMapperTest : StringSpec({
imageUrl = "https://image.url/extreme.png",
)

val remoteMarketDto = marketResponse.toRemoteMarketDto()
val marketEntity = marketResponse.toMarketEntity()

remoteMarketDto shouldBeEqual marketResponse
marketEntity shouldBeEqual marketResponse
}

"Given market response with negative values, When converting to remote market dto, Then returns correct market with default isFavorite false" {

"Given market response with negative values, When converting to market entity, Then returns correct market with default isFavorite false" {
val marketResponse = MarketResponse(
id = "negative",
name = "Negative Market",
Expand All @@ -68,9 +67,9 @@ class MarketDtoMapperTest : StringSpec({
imageUrl = "https://image.url/negative.png",
)

val remoteMarketDto = marketResponse.toRemoteMarketDto()
val marketEntity = marketResponse.toMarketEntity()

remoteMarketDto shouldBeEqual marketResponse
marketEntity shouldBeEqual marketResponse
}

"Given valid market response, When converting to market, Then returns correct market with default isFavorite false" {
Expand Down Expand Up @@ -136,7 +135,7 @@ class MarketDtoMapperTest : StringSpec({
}
})

private infix fun RemoteMarketDto.shouldBeEqual(expected: MarketResponse) {
private infix fun MarketEntity.shouldBeEqual(expected: MarketResponse) {
id shouldBe expected.id
name shouldBe expected.name
symbol shouldBe expected.symbol
Expand Down
Loading