Initial commit
Some checks failed
CI / build (push) Has been cancelled

This commit is contained in:
2026-06-11 11:03:01 +02:00
commit d1ff0e30ba
138 changed files with 5658 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
plugins {
alias(libs.plugins.architecture.domain.module)
}

View File

@@ -0,0 +1,29 @@
package com.example.architecture.core.domain
/**
* Errors raised by the data layer. [Network] for remote calls, [Local] for on-device storage.
* A repository that merges multiple sources can expose the [DataError] supertype.
*/
sealed interface DataError : Error {
enum class Network : DataError {
BAD_REQUEST,
REQUEST_TIMEOUT,
UNAUTHORIZED,
FORBIDDEN,
NOT_FOUND,
CONFLICT,
TOO_MANY_REQUESTS,
NO_INTERNET,
PAYLOAD_TOO_LARGE,
SERVER_ERROR,
SERVICE_UNAVAILABLE,
SERIALIZATION,
UNKNOWN,
}
enum class Local : DataError {
DISK_FULL,
NOT_FOUND,
UNKNOWN,
}
}

View File

@@ -0,0 +1,7 @@
package com.example.architecture.core.domain
/**
* Marker for every typed error in the app. Each layer/feature defines its own [Error]
* implementations (e.g. [DataError], or a feature validation enum) and pairs them with [Result].
*/
interface Error

View File

@@ -0,0 +1,46 @@
package com.example.architecture.core.domain
/**
* Typed result usable across every layer (data, domain, presentation, validation). Carries either
* success [data] or a typed [Error]. Prefer this over throwing for expected failures.
*/
sealed interface Result<out D, out E : Error> {
data class Success<out D>(val data: D) : Result<D, Nothing>
// The bound is fully qualified because inside this scope `Error` would resolve to this class.
data class Error<out E : com.example.architecture.core.domain.Error>(
val error: E,
) : Result<Nothing, E>
}
/** A [Result] that carries no success payload - for operations that either succeed or fail. */
typealias EmptyResult<E> = Result<Unit, E>
inline fun <T, E : Error, R> Result<T, E>.map(map: (T) -> R): Result<R, E> {
return when (this) {
is Result.Error -> Result.Error(error)
is Result.Success -> Result.Success(map(data))
}
}
inline fun <T, E : Error> Result<T, E>.onSuccess(action: (T) -> Unit): Result<T, E> {
return when (this) {
is Result.Error -> this
is Result.Success -> {
action(data)
this
}
}
}
inline fun <T, E : Error> Result<T, E>.onFailure(action: (E) -> Unit): Result<T, E> {
return when (this) {
is Result.Error -> {
action(error)
this
}
is Result.Success -> this
}
}
fun <T, E : Error> Result<T, E>.asEmptyResult(): EmptyResult<E> = map { }