Skip to content

Commit

Permalink
make DomainResponse API-aware
Browse files Browse the repository at this point in the history
  • Loading branch information
X1nto committed Dec 28, 2023
1 parent fb61805 commit 5e1a6a2
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOn
import org.koin.core.component.KoinComponent
import org.koin.core.component.get
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.jvm.JvmInline

sealed interface DomainResponse<out T> {
Expand All @@ -24,24 +27,6 @@ sealed interface DomainResponse<out T> {
data object Loading : DomainResponse<Nothing>
}

inline fun <T : ApiResponseBase, R> DomainResponseSource(
crossinline fetch: suspend (ArgosLanguage) -> T,
crossinline transform: (T) -> R,
): DomainResponseSource<R> {
return DomainResponseSource {
try {
val result = fetch(it)
if (result.message == "ok") {
DomainResponse.Success(transform(result))
} else {
DomainResponse.Error(result.errors!!.general[0])
}
} catch (e: Exception) {
DomainResponse.Error(e.message ?: e.stackTraceToString())
}
}
}

inline fun <T1, T2, R> combine(
flow1: Flow<DomainResponse<T1>>,
flow2: Flow<DomainResponse<T2>>,
Expand All @@ -61,22 +46,30 @@ inline fun <T1, T2, R> combine(
}
}

class DomainResponseSource<T>(
private inline val compute: suspend (ArgosLanguage) -> DomainResponse<T>
class DomainResponseSource<T : ApiResponseBase, R>(
private inline val fetch: suspend (ArgosLanguage) -> T,
private inline val transform: (T) -> R,
): KoinComponent {

private val settings: ArgosSettings = get()

private val state = MutableStateFlow<DomainResponse<T>>(DomainResponse.Loading)
private val state = MutableStateFlow<DomainResponse<R>>(DomainResponse.Loading)

fun asFlow(): Flow<DomainResponse<T>> {
fun asFlow(): Flow<DomainResponse<R>> {
return combine(state, settings.observeLanguage()) { state, language ->
return@combine if (state is DomainResponse.Loading) {
compute(language).also {
state.takeUnlessOr(predicate = { it is DomainResponse.Loading }) {
try {
val result = fetch(language)
if (result.message == "ok") {
DomainResponse.Success(transform(result))
} else {
DomainResponse.Error(result.errors!!.general[0])
}
} catch (e: Exception) {
DomainResponse.Error(e.message ?: e.stackTraceToString())
}.also {
this.state.value = it
}
} else {
state
}
}.flowOn(Dispatchers.IO)
}
Expand All @@ -85,5 +78,17 @@ class DomainResponseSource<T>(
state.value = DomainResponse.Loading
}

@OptIn(ExperimentalContracts::class)
private inline fun <T> T.takeUnlessOr(
predicate: (T) -> Boolean,
unless: () -> T
): T {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
callsInPlace(unless, InvocationKind.EXACTLY_ONCE)
}
return if (!predicate(this)) this else unless()
}

suspend operator fun invoke() = asFlow().first()
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class CoursesRepository(
private val argosApi: ArgosApi
) {

fun getCourseSyllabus(courseId: String): DomainResponseSource<DomainCourseSyllabus> {
fun getCourseSyllabus(courseId: String): DomainResponseSource<*, DomainCourseSyllabus> {
return DomainResponseSource(
fetch = {
argosApi.getCourseSyllabus(courseId)
Expand Down Expand Up @@ -45,7 +45,7 @@ class CoursesRepository(
)
}

fun getCourseScores(courseId: String): DomainResponseSource<DomainCourseScores> {
fun getCourseScores(courseId: String): DomainResponseSource<*, DomainCourseScores> {
return DomainResponseSource(
fetch = {
argosApi.getCourseScores(courseId)
Expand All @@ -64,7 +64,7 @@ class CoursesRepository(
)
}

fun getCourseClassmates(courseId: String): DomainResponseSource<List<DomainCourseClassmate>> {
fun getCourseClassmates(courseId: String): DomainResponseSource<*, List<DomainCourseClassmate>> {
return DomainResponseSource(
fetch = {
argosApi.getCourseClassmates(courseId)
Expand All @@ -81,7 +81,7 @@ class CoursesRepository(
)
}

fun getCourseGroups(courseId: String): DomainResponseSource<List<DomainCourseGroup>> {
fun getCourseGroups(courseId: String): DomainResponseSource<*, List<DomainCourseGroup>> {
return DomainResponseSource(
fetch = {
argosApi.getCourseGroups(courseId)
Expand All @@ -103,7 +103,7 @@ class CoursesRepository(
)
}

fun getCourseChosenGroup(courseId: String): DomainResponseSource<DomainCourseChosenGroup> {
fun getCourseChosenGroup(courseId: String): DomainResponseSource<*, DomainCourseChosenGroup> {
return DomainResponseSource(
fetch = {
argosApi.getCourseChosenGroup(courseId)
Expand All @@ -123,7 +123,7 @@ class CoursesRepository(
fun getCourseGroupSchedule(
courseId: String,
groupId: String
): DomainResponseSource<List<DomainCourseGroupSchedule>> {
): DomainResponseSource<*, List<DomainCourseGroupSchedule>> {
return DomainResponseSource(
fetch = {
argosApi.getCourseGroupSchedule(courseId, groupId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class MessagesRepository(
)
}

fun getMessage(id: String, semId: String): DomainResponseSource<DomainMessage> {
fun getMessage(id: String, semId: String): DomainResponseSource<*, DomainMessage> {
return DomainResponseSource(
fetch = {
argosApi.getMessage(id, semId)
Expand Down

0 comments on commit 5e1a6a2

Please sign in to comment.