Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package sangria.catseffect.schema

import cats.effect.Async
import sangria.schema.LeafAction
import sangria.schema.{Action, Context, LeafAction}

import scala.concurrent.ExecutionContext
import scala.language.implicitConversions
Expand All @@ -12,6 +12,13 @@ case class AsyncValue[Ctx, Val, F[_]: Async](value: F[Val]) extends LeafAction[C
new AsyncValue(Async[F].map(value)(fn))
}

object AsyncResolver {
implicit def asyncToAction[Ctx, Val, Res, F[_]: Async](
resolver: Context[Ctx, Val] => F[Res]): Context[Ctx, Val] => Action[Ctx, Res] = { context =>
AsyncValue(resolver(context))
}
}

object AsyncValue {
implicit def asyncAction[Ctx, Val, F[_]: Async](value: F[Val]): LeafAction[Ctx, Val] =
AsyncValue(value)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package sangria.catseffect

import cats.effect.IO
import cats.effect.kernel.Async
import cats.effect.unsafe.implicits.global
import io.circe.Json
import org.scalatest.matchers.must.Matchers
import org.scalatest.wordspec.AnyWordSpec
import sangria.execution.Executor
import sangria.catseffect.execution.IOExecutionScheme._
import sangria.execution.Executor
import sangria.macros._
import sangria.marshalling.circe._
import sangria.schema._
Expand All @@ -16,9 +17,11 @@ import sangria.schema._
class IOExecutionSchemeSpec extends AnyWordSpec with Matchers {

import IOExecutionSchemeSpec._

"IOExecutionScheme" must {
"allow using IO effect with pure resolve" in {
val query = gql"""
val query =
gql"""
query q1 {
ids
}
Expand Down Expand Up @@ -56,14 +59,29 @@ class IOExecutionSchemeSpec extends AnyWordSpec with Matchers {
}

object IOExecutionSchemeSpec {
import sangria.catseffect.schema.AsyncValue._

import sangria.catseffect.schema.AsyncResolver._

private def resolve[F[_]: Async](): F[String] = {
import cats.syntax.functor._
Async[F].pure(Option("hello")).map {
case Some(value) => value
case None => throw new Exception("No value")
}
}

private val QueryType: ObjectType[Unit, Unit] = ObjectType(
"Query",
() =>
fields[Unit, Unit](
Field("ids", ListType(IntType), resolve = _ => List(1, 2)),
Field("parent", StringType, resolve = _ => IO("hello"))
))
Field.async(
"parent",
StringType,
resolve = _ => resolve[IO]()
)
)
)

private val schema = Schema(QueryType)
}
41 changes: 34 additions & 7 deletions modules/core/src/main/scala/sangria/schema/Schema.scala
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
package sangria.schema

import sangria.ast.{AstNode, Document}

import language.implicitConversions
import sangria.execution.{FieldTag, SubscriptionField}
import sangria.introspection._
import sangria.marshalling.FromInput.{CoercedScalaResult, InputObjectResult}
import sangria.marshalling._
import sangria.{ast, introspection}
import sangria.validation._
import sangria.introspection._
import sangria.renderer.{QueryRenderer, SchemaFilter, SchemaRenderer}
import sangria.schema.InputObjectType.DefaultInput
import sangria.streaming.SubscriptionStreamLike
import sangria.util.tag._
import sangria.validation._
import sangria.{ast, introspection}

import scala.annotation.{implicitNotFound, tailrec}
import scala.language.implicitConversions
import scala.reflect.ClassTag
import sangria.util.tag._

import scala.util.matching.Regex

sealed trait Type {
Expand Down Expand Up @@ -655,6 +653,35 @@ object Field {
astDirectives,
Vector.empty)

def async[Ctx, Val, Res, Out, F[_]](
name: String,
fieldType: OutputType[Out],
description: Option[String] = None,
arguments: List[Argument[_]] = Nil,
resolve: Context[Ctx, Val] => F[Res],
possibleTypes: => List[PossibleObject[_, _]] = Nil,
tags: List[FieldTag] = Nil,
complexity: Option[(Ctx, Args, Double) => Double] = None,
deprecationReason: Option[String] = None,
astDirectives: Vector[ast.Directive] = Vector.empty
)(implicit
ev: ValidOutType[Res, Out],
asyncToAction: (Context[Ctx, Val] => F[Res]) => Context[Ctx, Val] => Action[Ctx, Res])
: Field[Ctx, Val] =
Field[Ctx, Val](
name,
fieldType,
description,
arguments,
asyncToAction(resolve),
deprecationReason,
tags,
complexity,
() => possibleTypes.map(_.objectType),
astDirectives,
Vector.empty
)

def subs[Ctx, Val, StreamSource, Res, Out](
name: String,
fieldType: OutputType[Out],
Expand Down