Skip to content

Commit

Permalink
feat: go back to Present/Absent
Browse files Browse the repository at this point in the history
  • Loading branch information
alvr committed May 25, 2024
1 parent fbb9e3d commit 608b071
Show file tree
Hide file tree
Showing 15 changed files with 148 additions and 162 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ internal class KatanaKoverPlugin : Plugin<Project> {
"*.data.type",

// UI
"*.generated.resources",
"*.resources",
"*.shared.navigation",
"*.shared.resources",
"*.shared.strings",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ internal class KatanaMultiplatformDataRemotePlugin : Plugin<Project> {
decapitalizeFields = true
generateAsInternal = true
generateMethods = listOf("equalsHashCode")
generateOptionalOperationVariables = false
packageName = fullPackageName
warnOnDeprecatedUsages = true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import dev.alvr.katana.common.user.data.UserIdQuery
import dev.alvr.katana.common.user.data.mappers.responses.invoke
import dev.alvr.katana.common.user.domain.failures.UserFailure
import dev.alvr.katana.core.common.catchUnit
import dev.alvr.katana.core.remote.executeOrThrow
import dev.alvr.katana.core.remote.toFailure

internal class UserIdRemoteSourceImpl(
Expand Down Expand Up @@ -36,6 +37,6 @@ internal class UserIdRemoteSourceImpl(
private suspend fun userIdHandler(policy: FetchPolicy) = client
.query(UserIdQuery())
.fetchPolicy(policy)
.execute()
.executeOrThrow()
.dataAssertNoErrors()
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.apollographql.apollo3.cache.normalized.store
import com.apollographql.apollo3.testing.QueueTestNetworkTransport
import com.apollographql.apollo3.testing.enqueueTestResponse
import dev.alvr.katana.common.user.data.UserIdQuery
import dev.alvr.katana.core.remote.executeOrThrow
import dev.alvr.katana.core.remote.type.buildUser
import io.kotest.core.spec.style.FreeSpec
import io.kotest.matchers.booleans.shouldBeFalse
Expand All @@ -31,7 +32,7 @@ internal class ApolloUserIdManagerTest : FreeSpec() {
}

client.enqueueTestResponse(UserIdQuery(), query)
client.query(UserIdQuery()).execute()
client.query(UserIdQuery()).executeOrThrow()
.also { res -> res.isFromCache.shouldBeFalse() }
.data.shouldNotBeNull()
.viewer.shouldNotBeNull() shouldBeEqual query.viewer.shouldNotBeNull()
Expand All @@ -45,8 +46,8 @@ internal class ApolloUserIdManagerTest : FreeSpec() {
}

client.enqueueTestResponse(UserIdQuery(), query)
client.query(UserIdQuery()).execute() // Simulate HTTP request
client.query(UserIdQuery()).execute() // Next request is from cache
client.query(UserIdQuery()).executeOrThrow() // Simulate HTTP request
client.query(UserIdQuery()).executeOrThrow() // Next request is from cache
.also { res -> res.isFromCache.shouldBeTrue() }
.data.shouldNotBeNull()
.viewer.shouldNotBeNull() shouldBeEqual query.viewer.shouldNotBeNull()
Expand All @@ -61,15 +62,15 @@ internal class ApolloUserIdManagerTest : FreeSpec() {
}

client.enqueueTestResponse(UserIdQuery(), query)
client.query(UserIdQuery()).execute() // Simulate HTTP request
client.query(UserIdQuery()).execute() // Next request is from cache
client.query(UserIdQuery()).executeOrThrow() // Simulate HTTP request
client.query(UserIdQuery()).executeOrThrow() // Next request is from cache
.also { res -> res.isFromCache.shouldBeTrue() }
.data.shouldNotBeNull()
.viewer.shouldNotBeNull() shouldBeEqual query.viewer.shouldNotBeNull()

store.clearAll()

client.query(UserIdQuery()).execute() // No cache, HTTP request
client.query(UserIdQuery()).executeOrThrow() // No cache, HTTP request
.also { res -> res.isFromCache.shouldBeFalse() }
.data.shouldNotBeNull()
.viewer.shouldNotBeNull() shouldBeEqual query.viewer.shouldNotBeNull()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.annotations.ApolloExperimental
import com.apollographql.apollo3.exception.JsonDataException
import com.apollographql.apollo3.testing.QueueTestNetworkTransport
import com.apollographql.apollo3.testing.enqueueTestNetworkError
import com.apollographql.apollo3.testing.enqueueTestResponse
import dev.alvr.katana.common.user.data.UserIdQuery
import dev.alvr.katana.common.user.domain.models.UserId
Expand Down Expand Up @@ -47,6 +48,11 @@ internal class UserIdRemoteSourceTest : FreeSpec() {
client.enqueueTestResponse(UserIdQuery(), query)
source.saveUserId().shouldBeRight()
}

"is error" {
client.enqueueTestNetworkError()
source.saveUserId().shouldBeLeft()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import com.apollographql.apollo3.cache.normalized.FetchPolicy
import com.apollographql.apollo3.cache.normalized.api.CacheKey
import com.apollographql.apollo3.cache.normalized.api.CacheKeyGenerator
import com.apollographql.apollo3.cache.normalized.api.CacheKeyGeneratorContext
import com.apollographql.apollo3.cache.normalized.api.MemoryCacheFactory
import com.apollographql.apollo3.cache.normalized.api.NormalizedCacheFactory
import com.apollographql.apollo3.cache.normalized.fetchPolicy
import com.apollographql.apollo3.cache.normalized.normalizedCache
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package dev.alvr.katana.core.remote

import arrow.core.Either
import arrow.core.Option
import com.apollographql.apollo3.ApolloCall
import com.apollographql.apollo3.api.Operation
import com.apollographql.apollo3.api.Optional
import com.apollographql.apollo3.exception.ApolloHttpException
import com.apollographql.apollo3.exception.ApolloNetworkException
Expand All @@ -12,8 +15,6 @@ import com.apollographql.apollo3.exception.JsonEncodingException
import com.apollographql.apollo3.exception.NoDataException
import dev.alvr.katana.core.domain.failures.Failure

fun <A, B> Either<A, B>.optional() = Optional.presentIfNotNull(getOrNull())

fun Throwable.toFailure(
network: Failure = Failure.Unknown,
response: Failure = Failure.Unknown,
Expand All @@ -23,10 +24,25 @@ fun Throwable.toFailure(
is ApolloHttpException,
is ApolloNetworkException,
is DefaultApolloException -> network

is CacheMissException,
is HttpCacheMissException -> cache

is JsonDataException,
is JsonEncodingException,
is NoDataException -> response

else -> unknown
}

suspend fun <D : Operation.Data> ApolloCall<D>.executeOrThrow() = execute().also { response ->
response.exception?.let { throw it }
}

val <V> V?.optional get(): Optional<V?> = Optional.presentIfNotNull(this)

val <V> V.present get(): Optional<V?> = Optional.present(this)

val <V> Either<*, V>.optional get(): Optional<V?> = Optional.presentIfNotNull(getOrNull())

val <V> Option<V>.optional get(): Optional<V?> = Optional.presentIfNotNull(getOrNull())
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
package dev.alvr.katana.features.lists.data.mappers.requests

import com.apollographql.apollo3.api.Optional
import dev.alvr.katana.core.remote.present
import dev.alvr.katana.core.remote.type.FuzzyDateInput
import korlibs.time.Date

internal fun Date?.toFuzzyDate() = FuzzyDateInput(
year = Optional.presentIfNotNull(this?.year),
month = Optional.presentIfNotNull(this?.month1),
day = Optional.presentIfNotNull(this?.day),
internal fun Date.toFuzzyDate() = FuzzyDateInput(
year = year.present,
month = month1.present,
day = day.present,
)

internal fun FuzzyDateInput.takeIfValid() = takeIf {
year !is Optional.Absent && month !is Optional.Absent && day !is Optional.Absent
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package dev.alvr.katana.features.lists.data.mappers.requests

import dev.alvr.katana.core.remote.optional
import dev.alvr.katana.features.lists.data.MediaListEntriesMutation
import dev.alvr.katana.features.lists.domain.models.lists.MediaList

internal fun MediaList.toMutation() = MediaListEntriesMutation(
id = id,
score = score,
progress = progress,
progressVolumes = progressVolumes,
repeat = repeat,
private = private,
notes = notes,
hiddenFromStatusLists = hiddenFromStatusLists,
startedAt = startedAt.toFuzzyDate().takeIfValid(),
completedAt = completedAt.toFuzzyDate().takeIfValid(),
score = score.optional,
progress = progress.optional,
progressVolumes = progressVolumes.optional,
repeat = repeat.optional,
private = private.optional,
notes = notes.optional,
hiddenFromStatusLists = hiddenFromStatusLists.optional,
startedAt = startedAt?.toFuzzyDate().optional,
completedAt = completedAt?.toFuzzyDate().optional,
)
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import com.apollographql.apollo3.exception.CacheMissException
import com.apollographql.apollo3.interceptor.ApolloInterceptor
import dev.alvr.katana.common.user.domain.managers.UserIdManager
import dev.alvr.katana.core.common.catchUnit
import dev.alvr.katana.core.remote.executeOrThrow
import dev.alvr.katana.core.remote.optional
import dev.alvr.katana.core.remote.toFailure
import dev.alvr.katana.core.remote.type.MediaType
import dev.alvr.katana.features.lists.data.MediaListCollectionQuery
Expand All @@ -33,7 +35,7 @@ internal class CommonListsRemoteSourceImpl(
private val reloadInterceptor: ApolloInterceptor,
) : CommonListsRemoteSource {
override suspend fun updateList(entry: MediaList) = Either.catchUnit {
client.mutation(entry.toMutation()).execute()
client.mutation(entry.toMutation()).executeOrThrow()
}.mapLeft { error ->
Logger.e(error) { "There was an error updating the entry" }

Expand All @@ -45,7 +47,7 @@ internal class CommonListsRemoteSourceImpl(

override fun <T : MediaEntry> getMediaCollection(type: MediaType) = flow {
val response = client
.query(MediaListCollectionQuery(userId.getId().getOrNull(), type))
.query(MediaListCollectionQuery(userId.getId().optional, type))
.fetchPolicyInterceptor(reloadInterceptor)
.watch()
.filterNot { it.exception is CacheMissException }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,64 +6,31 @@ import io.kotest.core.spec.style.FreeSpec
import io.kotest.matchers.equals.shouldBeEqual
import io.kotest.matchers.nulls.shouldBeNull
import io.kotest.matchers.nulls.shouldNotBeNull
import io.kotest.property.Arb
import io.kotest.property.arbitrary.int
import io.kotest.property.arbitrary.next
import korlibs.time.Date

internal class FuzzyDateMapperTest : FreeSpec() {
private val possibleValues = listOf(
Optional.Present(Arb.int(min = 1, max = 12).next()),
Optional.Absent,
)
internal class FuzzyDateMapperTest : FreeSpec({
"a null Date" {
val date: Date? = null

init {
"a null Date" {
val date: Date? = null

date.toFuzzyDate() shouldBeEqual FuzzyDateInput(
year = Optional.Absent,
month = Optional.Absent,
day = Optional.Absent,
)
}

@Suppress("RedundantNullableReturnType")
"a nullable Date with value" {
val date: Date? = Date(2022, 7, 20)

date.toFuzzyDate() shouldBeEqual FuzzyDateInput(
year = Optional.Present(2022),
month = Optional.Present(7),
day = Optional.Present(20),
)
}

"a valid Date" {
Date(2022, 7, 20).toFuzzyDate() shouldBeEqual FuzzyDateInput(
year = Optional.Present(2022),
month = Optional.Present(7),
day = Optional.Present(20),
)
}

(possibleValues * possibleValues * possibleValues).forEach { (dayMonth, year) ->
val (day, month) = dayMonth
val (dayValue, monthValue, yearValue) = Triple(day.getOrNull(), month.getOrNull(), year.getOrNull())
date?.toFuzzyDate().shouldBeNull()
}

"date $dayValue/$monthValue/$yearValue with optional values" {
val date = FuzzyDateInput(year, month, day)
@Suppress("RedundantNullableReturnType")
"a nullable Date with value" {
val date: Date? = Date(2022, 7, 20)

if (date.day is Optional.Present && date.month is Optional.Present && date.year is Optional.Present) {
date.takeIfValid().shouldNotBeNull()
} else {
date.takeIfValid().shouldBeNull()
}
}
}
date?.toFuzzyDate().shouldNotBeNull() shouldBeEqual FuzzyDateInput(
year = Optional.Present(2022),
month = Optional.Present(7),
day = Optional.Present(20),
)
}

private operator fun <S, T> List<S>.times(other: List<T>) = flatMap { list ->
List(other.size) { list }.zip(other)
"a valid Date" {
Date(2022, 7, 20).toFuzzyDate().shouldNotBeNull() shouldBeEqual FuzzyDateInput(
year = Optional.Present(2022),
month = Optional.Present(7),
day = Optional.Present(20),
)
}
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package dev.alvr.katana.features.lists.data.mappers.requests
import com.apollographql.apollo3.api.Optional
import dev.alvr.katana.core.common.empty
import dev.alvr.katana.core.common.zero
import dev.alvr.katana.core.remote.optional
import dev.alvr.katana.core.remote.type.FuzzyDateInput
import dev.alvr.katana.features.lists.data.MediaListEntriesMutation
import dev.alvr.katana.features.lists.domain.models.lists.MediaList
Expand All @@ -27,23 +28,23 @@ internal class MediaListMapperTest : FreeSpec({
updatedAt = DateTimeTz.nowLocal(),
).toMutation() shouldBeEqual MediaListEntriesMutation(
id = Int.zero,
score = Double.zero,
progress = Int.zero,
progressVolumes = Int.zero,
repeat = Int.zero,
private = false,
notes = String.empty,
hiddenFromStatusLists = false,
score = Double.zero.optional,
progress = Int.zero.optional,
progressVolumes = Int.zero.optional,
repeat = Int.zero.optional,
private = false.optional,
notes = String.empty.optional,
hiddenFromStatusLists = false.optional,
startedAt = FuzzyDateInput(
year = Optional.Present(2022),
month = Optional.Present(7),
day = Optional.Present(20),
),
).optional,
completedAt = FuzzyDateInput(
year = Optional.Present(2022),
month = Optional.Present(7),
day = Optional.Present(20),
),
).optional,
)
}

Expand All @@ -62,15 +63,15 @@ internal class MediaListMapperTest : FreeSpec({
updatedAt = null,
).toMutation() shouldBeEqual MediaListEntriesMutation(
id = Int.zero,
score = Double.zero,
progress = Int.zero,
progressVolumes = null,
repeat = Int.zero,
private = false,
notes = String.empty,
hiddenFromStatusLists = false,
startedAt = null,
completedAt = null,
score = Double.zero.optional,
progress = Int.zero.optional,
progressVolumes = null.optional,
repeat = Int.zero.optional,
private = false.optional,
notes = String.empty.optional,
hiddenFromStatusLists = false.optional,
startedAt = null.optional,
completedAt = null.optional,
)
}
})
Loading

0 comments on commit 608b071

Please sign in to comment.