Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
toxicafunk
@toxicafunk
@milessabin This can be very useful when you want to avoid an N+1 problem. (https://sangria-graphql.org/learn/#deferred-value-resolution)
its DeferredResolver actually
Miles Sabin
@milessabin
That seems much lower-level than eg. DataLoader. Is Sangria's Fetcher closer to DataLoader?
toxicafunk
@toxicafunk
sorry, never used DataLoader so I wouldn't know
Richard van Heest
@rvanheest
one of the subsections of 'deferred value resolution' is https://sangria-graphql.org/learn/#high-level-fetch-api
probably you're looking for that, @milessabin
Miles Sabin
@milessabin
Right. Would you say that it plays a similar role to DataLoader implementations?
Richard van Heest
@rvanheest
I assume you mean https://github.com/graphql/dataloader? I'm not familiar with it, but from looking through its README it looks like it serves the same purpose.
Miguel Carmona
@mkarmona
If anyone would mind giving some help with this. So, having defined
def getTargets(ids: Seq[String]): Future[IndexedSeq[Option[Target]]] = ??? as I cannot promise having an entity per id passed through param seq ids
So, not sure how to define hasId when you could have missing data
  implicit val targetHasId = HasId[Target, String](_.id)
  implicit val optTargetHasId = HasId[Option[Target], String](_.get.id)

  val targetsFetcher = Fetcher(
    config = FetcherConfig.maxBatchSize(256),
    fetch = (ctx: Backend, ids: Seq[String]) => {
      ctx.getTargets(ids)
    })
Miguel Carmona
@mkarmona
Perhaps, I would expect something else more like
implicit val optTargetHasId = HasId[Option[Target], Option[String]](_.map(_.id))?
Richard van Heest
@rvanheest

as I cannot promise having an entity per id passed through param seq ids

that's the whole idea of the Fetcher. If you're not certain about whether the requested value exists, you can use targetsFetcher.deferOpt instead of .defer.
With that you can implement def getTargets(ids: Seq[String]): Future[Seq[Target]] = ??? and call that from the Fetcher. With that you only need a HasId[Target, String]

Miguel Carmona
@mkarmona

@rvanheest first, thanks for your time. As you said that is as I had in the past but I cannot promise having an entity per passed id. I guess when you use

      Field("targets", ListType(targetImp),
        description = Some("Return a Target"),
        arguments = ensemblIds :: Nil,
        resolve = ctx => targetsFetcher.deferSeqOpt(ctx.arg(ensemblIds)))

and some of the ensemblIds you ask for are missing, the length of the results won't correspond to the list passed as argument at getTargets

Richard van Heest
@rvanheest
@toxicafunk can you elaborate on your suggestion about "maybe you need a Transformer here or a Reader Monad"? Not sure what you mean with the Transformer. Do you have any references? I'm familiar with the Reader Monad, but not sure how that applies in my case.
Miguel Carmona
@mkarmona
@rvanheest if you ask for getTargets(Seq("1", "2", "3")) you could have as a result just two objects but not 3. So, is the fetcher keeping track of the missing elements from the returned seq?
Richard van Heest
@rvanheest

the length of the results won't correspond to the list passed as argument

that's no problem. The fetcher keeps track of that; that's also (probably, I'm not familiar with the inner workings of Sangria) why you need the HasId

Miguel Carmona
@mkarmona
@rvanheest then I dont need to match the same number of rreturned elements wrapped with options indeed. I do rather change back to my previous implementation and I will follow your suggestion. hasId is needed in order to know the field that maps to the id to keep the biyective funcion working
@rvanheest thanks a lot!
it could be me I didnt understand this corner case from the sabgria documentaiton. I will give it another go and check it again.
toxicafunk
@toxicafunk
@rvanheest I haven't tried them out with Sangria, but generally speaking, let's say you have a function that returns Future[A] and another one that returns an Option[A] and you need to combine them into a Future[Option[A]], then you need a monad transformer as explained here: https://blog.buildo.io/monad-transformers-for-the-working-programmer-aa7e981190e7
now, this is NOT your case since you don't change F[_] (the monad part, but the type A and B, i.e. Person and Work
BUT both are DAOs so maybe you can make define your DAO as an F[_] and use a DAOTransformer
the idea with the Reader (again, I haven't tried it) is that you define your Ctx as a Reader so you can provide it with a PersonStore AND with a WorkStore that way yor Ctx should have access to both stores everywhere in your code
toxicafunk
@toxicafunk
if you know understand about type constructorsthen the Transformer options should be easy to try out
you would probably need to define DAO[Person] and DAO[Work], of course, I don't have a base to test this idea
Richard van Heest
@rvanheest
@mkarmona it's not just you... I've been working with Sangria for a couple months now and also had those Future[Seq[(Key, Option[Value])]] types. Only yesterday I understood why there is such a thing as deferOpt and all the other variants! It was a great joy simplifying all the types today ;-)
Miguel Carmona
@mkarmona
@rvanheest great I find it a bit confusing or not clear enough about these corner cases where real examples are missing data. Although, the doc about macros and case classes are quite comprehensive and in combination with json-play transformers I can map wild json bodies into something more structured
is it worth opening an issue in order to suggest some minor doc additions ?
Robert D. Blanchet Jr.
@blanchet4forte
yea documentation is very underwhelming with this library. but I think that's been my experience with every single Scala library I've ever used. Seems to be a systemic Scala community problem
Richard van Heest
@rvanheest
@toxicafunk I don't think that's the solution I'm looking for. Probably I didn't explain my problem well enough... I put my code up at https://github.com/Dans-labs/GraphQL-Sangria-Demo. Here you can find the Dao interfaces and 'demo implementations' in here.
Fetchers are implemented in the resolvers package. Here you can find WorkResolver.authorIdsOfWork and PersonResolver.personsById.
The aim is to implement this field using these fetchers. However, since DeferredValue is only a Functor and not a Monad, I can't flatten nested DeferredValue instances.
I've also tried implementing this via Fetcher.rel, using the Dao interfaces and ignoring the existing fetchers. However, also there the types don't line up.
Personally I still have a feeling that the library's intended way to go is to use Fetcher.rel, but it's not clear to me how to pull that off for my case.
toxicafunk
@toxicafunk
@rvanheest 2 quick and dirty solutions:
on GraphQLWork
@GraphQLField
  @GraphQLDescription("List all authors of this work.")
  def authors()(implicit ctx: Context[DataContext, GraphQLWork]): DeferredValue[DataContext, Seq[GraphQLPerson]] = {
    val pIds: Seq[PersonId] = ctx.ctx.repo.workDao.getPersonsByWork(ctx.value.id).get
    val persons: DeferredValue[DataContext, Seq[Person]] =  PersonResolver.personsById(pIds)
    val gqlPs: DeferredValue[DataContext, Seq[GraphQLPerson]] = persons.map(_.map(GraphQLPerson(_)))
    gqlPs
  }
or on WorkResolver
def authorsByWorkId(workId: WorkId)(implicit ctx: DataContext): DeferredValue[DataContext, Option[Seq[GraphQLPerson]]] = {
    DeferredValue(authorWorkIdFetcher.deferOpt(workId))
      .map(_.map { case (_, personIds) => ctx.repo.personDao.find(personIds).map(GraphQLPerson(_)) })
  }
Richard van Heest
@rvanheest
@toxicafunk thanks for the insights. May I conclude from these examples that it's not possible with Sangria to merge 2 fetchers to have efficient data resolution from both sources? It apparently is a choice between which DAO is least efficient and do batching/caching of the requests on that one.
Feels like someone might want to look into implementing flatMap on DeferredValue (or it's super types)
toxicafunk
@toxicafunk
It seems that way, you'd need to implement either zip or flatMap if you want to bind resolvers. The other option is to implement a repo that combines the DAOs si that you just call it from a resolver.
Travis Brown
@travisbrown
I've set up MiMa to check binary compatibility for most of the Scala 2.13 PRs for Sangria modules, and I've listed the ones I know are ready here: sangria-graphql/sangria#453
Sebastian Bruckner
@Sebruck

HI :wave:

What is the best way to pass additional arguments to Fetcher.caching and ´Fetcher.relCaching`?

Erik
@ErikHedblom

@Slakah

I don't suppose anyone has looked into a middleware for apollo-federation https://www.apollographql.com/docs/apollo-server/federation/federation-spec/ ? I have a quick gist which shows how it might be achieved. I'm by no means a Sangria/Apollo Federation expert, so any pointers would be greatly appreciated!
Gist: https://gist.github.com/Slakah/74d392da9ecc4b7f604c80e2c92309fc
It feels like this could be expanded into a library at some point, but was just interested if anyone was tackling a similar problem.

I’m also interested in this, have you done any further investigation?

I have played around with this a little bit and the main problem I’m facing is that I cannot figure out how to add the federation directives (@external,@requires,@provides and @key) to an ObjectType or Field. It seems like the only way of doing this is to define the schema using SDL. I would like to find a solution that works with Macro-Based GraphQL Type Derivation. Ideas?

Robert D. Blanchet Jr.
@blanchet4forte
the original author of sangria has their own repo and one of them is a sangria gateway which seems to be somewhat inspired by Apollo Federation. Its incomplete and doesn't follow the Apollo spec. However, their implementation would serve as a great example of how to add custom directives like those required by the federation spec.
Erik
@ErikHedblom

@blanchet4forte Thanks for the response. I might have been unclear, I'm interested in using the Apollo Federation project together with a sangria server. I can define the directives but actually adding them to a Type or Field is the problem.

I figured out yesterday that I can add sangria.ast.Directive to ObjectType or Field instead of trying to use sangria.schema.Directive. However, they are not very ergonomic to use as noted by @paulpdaniels

Andrii Zarichnyi
@azarichnyi
Hello, Community! 

Seems that one of my colleagues found solution for Overlapping Fields Can Be Merged validation performance issue (sangria-graphql/sangria#296) - we would like to hear you constructive critic and feedback in general. Medium post: https://tech.xing.com/graphql-overlapping-fields-can-be-merged-fast-ea6e92e0a01 
Still very sad that we could not discuss it with Oleg Ilyenko (a.k.a. @easyangel) anymore :( 
Thanks in advance!
Regards,

Andrii
carloscaldas
@carloscaldas
Hello guys. I can see there are many PRs in the repository and it is not updated since 2008. I read the unfortunate issue with the repo maintainer. Since there are 157 forks which one you guys are using as "official" ?
Andrii Zarichnyi
@azarichnyi
@carloscaldas please see discussion in this issuesangria-graphql/sangria#446 - people working to take over original repo and continue there. p.s. I think you mean 2018 not 2008 :)
carloscaldas
@carloscaldas
thx. Yes, I meant 2018
Travis Brown
@travisbrown
@carloscaldas There's a list of branches / PRs here specifically related to 2.13 support: sangria-graphql/sangria#453
carloscaldas
@carloscaldas
I saw in the comments yanns contacted github at May and looks like still does not have any answer. In your opinions is 4 months expected delay or probable github just ignored the message?
Travis Brown
@travisbrown
@carloscaldas I don't know the latest details, but last week we were able to get in touch with some new contacts at GitHub, and it sounds like the process is moving forward again.
carloscaldas
@carloscaldas
cool! thx for the updates