Code Monkey home page Code Monkey logo

Comments (9)

jchyb avatar jchyb commented on July 17, 2024 2

I am taking a look at this right now, and I feel I am close to figuring this out. Slightly delaying implicit resolution in macro seems to make errors consistent between code with import io.circe.generic.auto._ and without it in the first snippet (no idea why yet). It still errors, but at least without the ugly dotc stack trace, just errors with failed implicit resolution. Those suggest that I might need to check what is going on in the sangria.marshalling.circe module. I'll try to prepare a PR with the fixes after figuring out the rest.

from sangria.

PsyfireX avatar PsyfireX commented on July 17, 2024

Additional notes:

The code did compile previously under Scala 2.13

Debugging macros is beyond my current expertise. However, narrowing in closer to the issue, it appears to happen when mixing ObjectType and InputObjectType, where the input is a method-parameter.

When I use an ObjectType inside and ObjectType, or an InputObjectType inside and InputObjectType it seems to compile just fine:

ObjectType inside ObjectType (no errors)

package ai.tagr.graphql.tagr.schema

import sangria.schema.ObjectType
import scala.concurrent.Future
import sangria.schema.InputObjectType

case class Ctx(ctx: String)

object PostSchema {
  import sangria.marshalling.circe._
  import io.circe.generic.auto._
  import sangria.macros.derive._

  case class UpdatePostGql() {
    @GraphQLField
    def text(text: String): Future[TextGql] = ???   // relevant line
  }

  object UpdatePostGql{
    implicit val _ot: ObjectType[Ctx, UpdatePostGql] =
      deriveObjectType[Ctx, UpdatePostGql](
        ObjectTypeName("UpdatePost")
      )
  }

  case class TextGql(text: String)

  object TextGql{
    implicit val _it: ObjectType[Ctx, TextGql] =
      deriveObjectType[Ctx, TextGql](
        ObjectTypeName("Text")
      )
  }
}

InputObjectType inside InputObjectType (no errors)

import sangria.schema.ObjectType
import scala.concurrent.Future
import sangria.schema.InputObjectType

case class Ctx(ctx: String)

object PostSchema {
  import sangria.marshalling.circe._
  import io.circe.generic.auto._
  import sangria.macros.derive._

  case class UpdatePostGql(id: String) {
    @GraphQLField
    def text(text: TextInputGql): Future[String] = ???    // relevant line
  }

  object UpdatePostGql{    // swapped from ObjectType to InputObjectType
    implicit val _it: InputObjectType[UpdatePostGql] =
      deriveInputObjectType[UpdatePostGql](
        InputObjectTypeName("UpdatePost")
      )
  }

  case class TextInputGql(text: String)

  object TextInputGql{
    implicit val _it: InputObjectType[TextInputGql] =
      deriveInputObjectType[TextInputGql](
        InputObjectTypeName("TextInput")
      )
  }
}

from sangria.

PsyfireX avatar PsyfireX commented on July 17, 2024

update:

This code has the same issue, and uses an id with a ScalarAlias[T, Long] for input, and has the same issue.

import scala.concurrent.Future
import scala.util.Try

case class Ctx(ctx: String)

case class SomeId(id: Long)

object SomeSchema {
  import sangria.marshalling.circe._
  import io.circe.generic.auto._
  import sangria.macros.derive._
  import sangria.schema._

  type LongAlias[T] = ScalarAlias[T, Long]

  def longAlias[ID](from: ID=>Long, to: Long=>ID): LongAlias[ID] =
    ScalarAlias(LongType, from, v ⇒ Right(to(v)))
  
  implicit val someIdType: LongAlias[SomeId] = longAlias[SomeId](_.id, SomeId.apply)

  case class SomeOT(id: String) {
    @GraphQLField
    def getSome1(id: SomeId): Future[String] = ???
  }

  object SomeOT{
    implicit val _ot: ObjectType[Ctx, SomeOT] =
      deriveObjectType[Ctx, SomeOT](
        ObjectTypeName("SomeOT")
      )
  }
}

However, I noticed that commenting out:

// import io.circe.generic.auto._

Appears to make the compiler error go away in this very tiny and limited code sample.

Now, I can't do that in my production code. Commenting that line out in my prod code causes a bunch of other errors, and it's apparently being used to support FromInput.

from sangria.

yanns avatar yanns commented on July 17, 2024

I'll have a look at this.
Pinging @jchyb who may have an opinion on what is going on.

from sangria.

yanns avatar yanns commented on July 17, 2024

I can confirm that the first example compiles if I remove import io.circe.generic.auto._ and if I define the FromInput[TextInputGql]:

import sangria.marshalling.FromInput
import sangria.schema.ObjectType

import scala.concurrent.Future
import sangria.schema.InputObjectType

case class Ctx(ctx: String)

object PostSchema {
  import sangria.macros.derive._

  case class UpdatePostGql() {
    @GraphQLField
    def text(text: TextInputGql): Future[String] = ???
  }

  object UpdatePostGql {
    implicit val _ot: ObjectType[Ctx, UpdatePostGql] =
      deriveObjectType[Ctx, UpdatePostGql](
        ObjectTypeName("UpdatePost")
      )
  }

  case class TextInputGql(text: String)

  object TextInputGql {
    implicit val fi: FromInput[TextInputGql] = ???
    implicit val _it: InputObjectType[TextInputGql] =
      deriveInputObjectType[TextInputGql](
        InputObjectTypeName("TextInput")
      )
  }
}

So it seems that issue is coming from a different resolution of implicits.

from sangria.

yanns avatar yanns commented on July 17, 2024

I'm trying to check with semi-automatic derivation to better control which implicits are created:

import io.circe.Decoder
import sangria.schema.{InputObjectType, ObjectType}

import scala.concurrent.Future

case class Ctx(ctx: String)

object PostSchema {
  import sangria.marshalling.circe._
  import io.circe.generic.semiauto._
  import sangria.macros.derive._

  case class UpdatePostGql() {
    @GraphQLField
    def text(text: TextInputGql): Future[String] = ???
  }

  object UpdatePostGql {
    implicit val _ot: ObjectType[Ctx, UpdatePostGql] =
      deriveObjectType[Ctx, UpdatePostGql](
        ObjectTypeName("UpdatePost")
      )
  }

  case class TextInputGql(
      @GraphQLInputType(sangria.schema.StringType)
      text: String)

  object TextInputGql {
    implicit val decoder: Decoder[TextInputGql] = deriveDecoder[TextInputGql]
    implicit val _it: InputObjectType[TextInputGql] =
      deriveInputObjectType[TextInputGql](
        InputObjectTypeName("TextInput")
      )
  }
}

It leads to the compilation error:

[error] 20 |      deriveObjectType[Ctx, UpdatePostGql](
[error]    |      ^
[error]    |GraphQlOutputType not found: scala.Function1[java.lang.String, sangria.schema.Action[Ctx, java.lang.String]]
[error] 21 |        ObjectTypeName("UpdatePost")
[error] 22 |      )
[error] one error found

I've pushed the changes to https://github.com/sangria-graphql/sangria/tree/issue-905 if someone wants to re-use that.

from sangria.

PsyfireX avatar PsyfireX commented on July 17, 2024

Thank you for starting the investigation! @yanns

I might not be very useful in fixing the bug itself with code-changes (due to no macro experience), however I also encountered what appears to be the exact same issue in both my top-level Query and Mutation types, using deriveContextObject, producing an almost identical MatchError, and similarly pointing to another InputObjectType

      val objectType: ObjectType[Ctx, Unit] =
        deriveContextObjectType[Ctx, AllQueries, Unit](_ctx => new AllQueries {
          override val ctx: Ctx = _ctx
        })
        

Since you are already started looking at the issue, I'll see if I can also extract this code into a reproducible, isolated, code-sample.

from sangria.

PsyfireX avatar PsyfireX commented on July 17, 2024

Here is the second code sample, revolving around deriveContextObject

package ai.tagr.graphql.tagr.schema

import scala.concurrent.Future
import scala.util.Try

case class Ctx(ctx: String)

case class SomeId(id: Long)

object SomeSchema {
  import sangria.marshalling.circe._
  // commenting out the import below eliminates one error around `getSome1`.  However, it causes  `getSome2` breaks, because it needs a `FromInput[SomeInput,InputObjectResult]`
  // import io.circe.generic.auto._ 
  import sangria.macros.derive._
  import sangria.schema._

  type LongAlias[T] = ScalarAlias[T, Long]

  def longAlias[ID](from: ID=>Long, to: Long=>ID): LongAlias[ID] =
    ScalarAlias(LongType, from, v ⇒ Right(to(v)))
  
  implicit val someIdType: LongAlias[SomeId] = longAlias[SomeId](_.id, SomeId.apply)

  case class SomeInput(text: String)
  object SomeInput{
    implicit val _it: InputObjectType[SomeInput] = deriveInputObjectType[SomeInput](
      InputObjectTypeName("SomeInput")
    )
  }

  trait QueryRoot {
    def ctx: Ctx

    @GraphQLField
    def getSome1(id: SomeId): Future[String] = ???

    @GraphQLField
    def getSome2(in: SomeInput): Future[String] = ???
  }

  object QueryRoot {
    implicit val _ot: ObjectType[Ctx, Unit] = 
      deriveContextObjectType[Ctx,QueryRoot,Unit](
        _ctx => new QueryRoot{  override def ctx: Ctx = _ctx}
      )
  }
}

from sangria.

PsyfireX avatar PsyfireX commented on July 17, 2024

@jchyb Thank you! I believe this is the very last piece in order for me to finish converting my entire project over to Scala 3.

from sangria.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.