Kev
02/17/2024, 3:29 AMgetQuestionById
to call getNodeById
with a given lambda which can do the cast. However, the lambda that will be past in requires a context of type Raise<NonEmptyList<StructuralError>>
and getByNodeId
has the context Raise<JourneyError>
context(JourneyErrors)
suspend fun <T : Node> getNodeById(
id: StructuralNodeId,
transformer: (StructuralNode) -> EitherNel<StructuralError, T>,
): Pair<StructuralNodeId, T> {
val node = repository.getStructuralNodeById(id)
val transformed = transformer(node).mapLeft { errors ->
val message = errors.joinToString { error -> "${error.message}\n" }
JourneyError.Fatal(message).also {
logger.error("Failed to getNodeById: $message")
}
}.bind()
return Pair(id, transformed)
}
context(JourneyErrors)
suspend fun getQuestionById(id: StructuralNodeId): Pair<StructuralNodeId, Question> =
getNodeById(id) {
// Complaining about no context for Raise<NonEmptyList<StructuralError>>
Question(it.attributes)
}
I tried doing something with the transformation parameter definition to be something like transformer: context(NonEmptyList<StructuralError>) (StructuralNode> -> EitherNel<StructuralError, T>
which just ends up with the transformer
method invocation requiring 2 parameters (NonEmptyList<StructuralError>, node).
How can I apply a context receiver on a lambda method parameter?Kev
02/17/2024, 3:49 AMcontext(JourneyErrors)
suspend fun <T : Node> getNodeById(
id: StructuralNodeId,
transformer: (StructuralNode) -> EitherNel<StructuralError, T>,
): Pair<StructuralNodeId, T> =
transformer(repository.getStructuralNodeById(id))
.map { Pair(id, it) }
.mapLeft { errors -> JourneyError.Fatal("$errors") }
.bind()
context(JourneyErrors)
suspend fun getQuestionById(id: StructuralNodeId): Pair<StructuralNodeId, Question> = getNodeById(id) {
either { Question(it.attributes) }
}
Youssef Shoaib [MOD]
02/17/2024, 4:42 AMEitherNel
. What you instead want is something using withError
. Code to follow shortly...Youssef Shoaib [MOD]
02/17/2024, 4:50 AMcontext(JourneyErrors)
suspend fun <T : Node> getNodeById(
id: StructuralNodeId,
transformer: context(Raise<Nel<StructuralError>>) (StructuralNode) -> T,
): Pair<StructuralNodeId, T> {
val node = repository.getStructuralNodeById(id)
return withError(Nel<StructuralError>::toJourneyError) {
id to transformer(node)
}
}
fun Nel<StructuralError>.toJourneyError(): JourneyError {
val message = errors.joinToString { error -> "${error.message}\n" }
return JourneyError.Fatal(message).also {
logger.error("Failed to getNodeById: $message")
}
}
context(JourneyErrors)
suspend fun getQuestionById(id: StructuralNodeId): Pair<StructuralNodeId, Question> =
getNodeById(id) {
Question(it.attributes)
}
Unrelated, but I think returning a Pair
here is unnecessary since you can recover the id
from the call itself, but I'm guessing the code is more complicated