org.mattshoe.shoebox.kernl.runtime.ext.DataResultExtensions.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Kernl.Runtime Show documentation
Show all versions of Kernl.Runtime Show documentation
Kernl: A Kotlin Symbol Processing (KSP) library for automatic repository generation.
The newest version!
package org.mattshoe.shoebox.kernl.runtime.ext
import kotlinx.coroutines.flow.*
import org.mattshoe.shoebox.kernl.runtime.DataResult
import org.mattshoe.shoebox.kernl.runtime.error.InvalidationException
import org.mattshoe.shoebox.kernl.runtime.DataResult.Success
import org.mattshoe.shoebox.kernl.runtime.DataResult.Error
import org.mattshoe.shoebox.kernl.runtime.DataResult.Invalidated
import org.mattshoe.shoebox.kernl.runtime.ValidDataResult
/**
* ### Returns the encapsulated [data][DataResult.Success.data] if this [DataResult] is [Success], and `null` otherwise.
*
* @return The encapsulated data of a successful data retrieval operation, or `null` if the result is an error or invalidated.
* @sample sampleValueOrNull
* @see DataResult.unwrap
*/
fun DataResult.valueOrNull(): T? {
return unwrap { }
}
/**
* ### Unwraps the data from this [DataResult], and throws an exception if the result is not [DataResult.Success].
*
* @throws Throwable if the result is [Error], propagating the encountered error.
* @throws InvalidationException if the result is [Invalidated], indicating that the data is no longer valid.
* @return The encapsulated data of a successful data retrieval operation.
* @sample sampleUnwrap
* @see DataResult.Error
* @see DataResult.Invalidated
*/
fun DataResult.unwrap(): T {
return when (this) {
is Success -> this.data
is Error -> throw this.error
is Invalidated -> throw invalidationException()
}
}
/**
* ### Unwraps the data from this [DataResult], or invokes [onError] if the result is not [DataResult.Success].
*
* This function provides a way to handle errors gracefully by passing the error to the [onError] callback,
* and returns `null` instead of throwing an exception.
*
* @param onError A function that takes a [Throwable] and handles it, typically logging or other error processing.
* @return The encapsulated data of a successful data retrieval operation, or `null` if an error occurs.
* @receiver The [DataResult] instance on which this function is called.
* @sample sampleUnwrapWithErrorHandling
* @see DataResult.Error
* @see DataResult.Invalidated
*/
fun DataResult.unwrap(onError: (Throwable) -> Unit): T? {
return try {
unwrap()
} catch (e: Throwable) {
onError(e)
null
}
}
/**
* ### Unwraps the data from this [DataResult], and returns the default value provided by [default] if the result is not [DataResult.Success].
*
* This function is useful when a default value should be provided in the event of an error or invalidation,
* allowing the caller to supply a fallback value.
*
* @param default A function that takes a [Throwable] and returns a default value of type [T].
* @return The encapsulated data of a successful data retrieval operation, or the default value if an error occurs.
* @receiver The [DataResult] instance on which this function is called.
* @sample sampleOrElse
* @see DataResult.Error
* @see DataResult.Invalidated
*/
fun DataResult.orElse(default: (Throwable) -> T): T {
return try {
unwrap()
} catch (e: Throwable) {
default(e)
}
}
/**
* ### Converts this [Throwable] to a [DataResult].
*
* This function wraps this [Throwable] in [DataResult.Error].
*
* @return A [DataResult.Error] containing this [Throwable].
*
* @sample sampleThrowableAsDataResult
*/
fun Throwable.asDataResult(): ValidDataResult {
return Error(this)
}
/**
* ### Converts a value of type [T] to a [DataResult].
*
* This function wraps the value in a [DataResult.Success].
*
* @return A [DataResult.Success] containing the value.
*
* @sample sampleObjectAsDataResult
*/
fun T.asDataResult(): ValidDataResult {
return Success(this)
}
/**
* ### Performs an action on each [DataResult.Success] emitted by the [Flow].
*
* This function allows you to perform a specified action on the data contained in each [DataResult.Success].
* The action is only performed for successful data results, not for errors or invalidations.
*
* @param action The action to perform on the data of each [DataResult.Success].
* @return A [Flow] of [DataResult].
*
* @sample sampleOnSuccess
*/
fun Flow>.onSuccess(action: suspend (T) -> Unit): Flow> {
return onEach {
if (it is Success) {
action(it.data)
}
}
}
/**
* ### Catches [DataResult.Error] and [DataResult.Invalidated] emissions and performs an action on them.
*
* This function allows you to perform a specified action when an error or invalidation is encountered in the flow.
* The action is only performed for [DataResult.Error] and [DataResult.Invalidated], while [DataResult.Success]
* emissions are passed through with their data.
*
* This operator essentially "unwraps" the underlying data, and only emits the result of [Success] operations
* downstream.
*
* @param action The action to perform when an error or invalidation is encountered. The action receives the
* cause of the error or a custom invalidation exception.
* @return A [Flow] of data of type [T].
*
* @sample sampleCatchDataResult
*/
fun Flow>.catchDataResult(
action: suspend FlowCollector.(cause: Throwable) -> Unit
): Flow {
return transform {
when (it) {
is Success -> emit(it.data)
is Error -> action(it.error)
is Invalidated -> action(invalidationException())
}
}
}
/**
* ### Catches [DataResult.Error] emissions and performs an action on them.
*
* This function allows you to perform a specified action when an error is encountered in the flow. The action is only
* performed for [DataResult.Error], while [DataResult.Success] emissions are passed through with their data.
*
* This operator essentially "unwraps" the underlying data, and only emits the result of [Success] operations
* downstream.
*
* @param action The action to perform when an error or invalidation is encountered. The action receives the
* cause of the error or a custom invalidation exception.
* @return A [Flow] of data of type [T].
*
* @sample sampleOnError
*/
fun Flow>.onError(
action: suspend FlowCollector.(cause: Throwable) -> Unit
): Flow {
return transform {
when (it) {
is Success -> emit(it.data)
is Error -> action(it.error)
}
}.catch {
action(it)
}
}
/**
* ### Performs an action when a [DataResult.Invalidated] is emitted by the [Flow].
*
* This operator allows you to perform a specified action when an invalidation is encountered in the flow.
* The action is only performed for [DataResult.Invalidated] emissions.
*
* This operator essentially filters out [Invalidated] emissions such that only [Success] and [Error] events are
* emitted downstream.
*
* @param action The action to perform when an invalidation is encountered.
* @return A [Flow] of [ValidDataResult].
*
* @sample sampleOnInvalidation
*/
fun Flow>.onInvalidation(
action: suspend FlowCollector>.() -> Unit
): Flow> {
return transform {
when (it) {
is Success -> emit(it)
is Error -> emit(it)
else -> action()
}
}
}
private fun invalidationException() = InvalidationException("Attempted to unwrap an Invalidated data result.")
© 2015 - 2025 Weber Informatics LLC | Privacy Policy