Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subqueries and interfaces, not working at least in one case #467

Open
rpiaggio opened this issue Feb 13, 2023 · 6 comments
Open

Subqueries and interfaces, not working at least in one case #467

rpiaggio opened this issue Feb 13, 2023 · 6 comments

Comments

@rpiaggio
Copy link
Collaborator

In the ODB we have in the schema:

type Gcal implements StepConfig {
  continuum: GcalContinuum
  arcs: [GcalArc!]!
  filter: GcalFilter!
  diffuser: GcalDiffuser!
  shutter: GcalShutter!
  stepType: StepType!
}

If we define a subquery:

@GraphQL
abstract class GcalStepConfigSubquery extends GraphQLSubquery[ObservationDB]("Gcal"):
  override val subquery: String = """
        {
          continuum
          arcs
          filter
          diffuser
          shutter
        }
      """

@GraphQLStub
object GcalStepConfigSubquery

and then query:

query($$obsId: ObservationId!) {
  observation(observationId: $$obsId) {
    execution {
      executionConfig {
        ... on GmosSouthExecutionConfig {
          acquisition {
            nextAtom {
              steps {
                stepConfig {
                  ... on Gcal $GcalStepConfigSubquery
                }
              }
            }
          }
        }
      }
    }
  }
}

This results in:

[error] scalafix.internal.v1.FileException: unexpected error processing file /Users/rpiaggio/gemini/explore/common-graphql/src/main/scala/queries/common/GeneratedSequenceSQL.scala
[error] Caused by: java.lang.Exception: Could not resolve type for field [subquery10] - Is this a valid field present in the schema?
[error]         at clue.gen.QueryGen.$anonfun$resolveData$9(QueryGen.scala:270)
[error]         at scala.Option.fold(Option.scala:263)
[error]         at clue.gen.QueryGen.clue$gen$QueryGen$$go$1(QueryGen.scala:272)
[error]         at clue.gen.QueryGen$$anonfun$$nestedInanonfun$resolveData$19$1.applyOrElse(QueryGen.scala:327)
[error]         at clue.gen.QueryGen$$anonfun$$nestedInanonfun$resolveData$19$1.applyOrElse(QueryGen.scala:326)
[error]         at scala.collection.immutable.List.collect(List.scala:267)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$19(QueryGen.scala:326)
[error]         at scala.collection.immutable.List.map(List.scala:250)
[error]         at clue.gen.QueryGen.clue$gen$QueryGen$$go$1(QueryGen.scala:323)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$11(QueryGen.scala:274)
[error]         at scala.Option.map(Option.scala:242)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$10(QueryGen.scala:274)
[error]         at scala.Option.fold(Option.scala:263)
[error]         at clue.gen.QueryGen.clue$gen$QueryGen$$go$1(QueryGen.scala:272)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$20(QueryGen.scala:331)
[error]         at scala.collection.immutable.List.map(List.scala:250)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$19(QueryGen.scala:331)
[error]         at scala.collection.immutable.List.map(List.scala:246)
[error]         at clue.gen.QueryGen.clue$gen$QueryGen$$go$1(QueryGen.scala:323)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$11(QueryGen.scala:274)
[error]         at scala.Option.map(Option.scala:242)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$10(QueryGen.scala:274)
[error]         at scala.Option.fold(Option.scala:263)
[error]         at clue.gen.QueryGen.clue$gen$QueryGen$$go$1(QueryGen.scala:272)
[error]         at clue.gen.QueryGen$$anonfun$$nestedInanonfun$resolveData$19$1.applyOrElse(QueryGen.scala:327)
[error]         at clue.gen.QueryGen$$anonfun$$nestedInanonfun$resolveData$19$1.applyOrElse(QueryGen.scala:326)
[error]         at scala.collection.immutable.List.collect(List.scala:275)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$19(QueryGen.scala:326)
[error]         at scala.collection.immutable.List.map(List.scala:246)
[error]         at clue.gen.QueryGen.clue$gen$QueryGen$$go$1(QueryGen.scala:323)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$11(QueryGen.scala:274)
[error]         at scala.Option.map(Option.scala:242)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$10(QueryGen.scala:274)
[error]         at scala.Option.fold(Option.scala:263)
[error]         at clue.gen.QueryGen.clue$gen$QueryGen$$go$1(QueryGen.scala:272)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$20(QueryGen.scala:331)
[error]         at scala.collection.immutable.List.map(List.scala:246)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$19(QueryGen.scala:331)
[error]         at scala.collection.immutable.List.map(List.scala:246)
[error]         at clue.gen.QueryGen.clue$gen$QueryGen$$go$1(QueryGen.scala:323)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$11(QueryGen.scala:274)
[error]         at scala.Option.map(Option.scala:242)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$10(QueryGen.scala:274)
[error]         at scala.Option.fold(Option.scala:263)
[error]         at clue.gen.QueryGen.clue$gen$QueryGen$$go$1(QueryGen.scala:272)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$20(QueryGen.scala:331)
[error]         at scala.collection.immutable.List.map(List.scala:250)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$19(QueryGen.scala:331)
[error]         at scala.collection.immutable.List.map(List.scala:246)
[error]         at clue.gen.QueryGen.clue$gen$QueryGen$$go$1(QueryGen.scala:323)
[error]         at clue.gen.QueryGen$$anonfun$$nestedInanonfun$resolveData$19$1.applyOrElse(QueryGen.scala:327)
[error]         at clue.gen.QueryGen$$anonfun$$nestedInanonfun$resolveData$19$1.applyOrElse(QueryGen.scala:326)
[error]         at scala.collection.immutable.List.collect(List.scala:267)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$19(QueryGen.scala:326)
[error]         at scala.collection.immutable.List.map(List.scala:250)
[error]         at clue.gen.QueryGen.clue$gen$QueryGen$$go$1(QueryGen.scala:323)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$11(QueryGen.scala:274)
[error]         at scala.Option.map(Option.scala:242)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$10(QueryGen.scala:274)
[error]         at scala.Option.fold(Option.scala:263)
[error]         at clue.gen.QueryGen.clue$gen$QueryGen$$go$1(QueryGen.scala:272)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$11(QueryGen.scala:274)
[error]         at scala.Option.map(Option.scala:242)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$10(QueryGen.scala:274)
[error]         at scala.Option.fold(Option.scala:263)
[error]         at clue.gen.QueryGen.clue$gen$QueryGen$$go$1(QueryGen.scala:272)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$11(QueryGen.scala:274)
[error]         at scala.Option.map(Option.scala:242)
[error]         at clue.gen.QueryGen.$anonfun$resolveData$10(QueryGen.scala:274)
[error]         at scala.Option.fold(Option.scala:263)
[error]         at clue.gen.QueryGen.clue$gen$QueryGen$$go$1(QueryGen.scala:272)
[error]         at clue.gen.QueryGen.resolveData(QueryGen.scala:376)
[error]         at clue.gen.QueryGen.resolveData$(QueryGen.scala:220)
[error]         at clue.gen.GraphQLGen.resolveData(GraphQLGen.scala:15)
[error]         at clue.gen.QueryGen.$anonfun$addData$1(QueryGen.scala:416)
[error]         at scala.Function$.$anonfun$chain$2(Function.scala:23)
[error]         at scala.collection.LinearSeqOps.foldLeft(LinearSeq.scala:183)
[error]         at scala.collection.LinearSeqOps.foldLeft$(LinearSeq.scala:179)
[error]         at scala.collection.immutable.List.foldLeft(List.scala:79)
[error]         at scala.Function$.$anonfun$chain$1(Function.scala:23)
[error]         at clue.gen.GraphQLGen$$anonfun$2.$anonfun$applyOrElse$8(GraphQLGen.scala:138)
[error]         at apply @ clue.gen.GraphQLGen$$anonfun$2.$anonfun$applyOrElse$7(GraphQLGen.scala:115)
[error]         at >> @ clue.gen.GraphQLGenConfig.$anonfun$retrieveSchema$11(GraphQLGenConfig.scala:70)
[error]         at complete @ clue.gen.GraphQLGenConfig.$anonfun$getSchema$3(GraphQLGenConfig.scala:84)
[error]         at >> @ clue.gen.GraphQLGenConfig.$anonfun$retrieveSchema$11(GraphQLGenConfig.scala:70)
[error]         at apply @ clue.gen.GraphQLGenConfig.$anonfun$retrieveSchema$9(GraphQLGenConfig.scala:56)
[error]         at flatten @ clue.gen.GraphQLGenConfig.$anonfun$getSchema$1(GraphQLGenConfig.scala:87)
[error]         at flatTap @ clue.gen.GraphQLGenConfig.$anonfun$getSchema$2(GraphQLGenConfig.scala:84)
[error] (graphql / Compile / scalafix) scalafix.sbt.ScalafixFailed: UnexpectedError
@armanbilge
Copy link
Contributor

Looks like for some reason this case is not matching, and it's proceeding to the next one, where it crashes.

case Select(name, _, Select(fieldName, _, _)) if fieldName.startsWith("subquery") =>

@armanbilge
Copy link
Contributor

So I've been staring at this one, and actually I am not sure if it's supposed to work—at least not in general. I think the issue is this bit:

... on Gcal $GcalStepConfigSubquery

I have a recollection that we discussed at one point, how fragments and subqueries actually do not mix. Because in the general case fragments are actually defining a new result type (that would not match the subquery's type).

e.g. in this example, fragments are creating a new result type that includes name. If on Droid or on Human was a subquery, it would not include name and thus those datatypes cannot be used.

query HeroForEpisode($ep: Episode!) {
  hero(episode: $ep) {
    name
    ... on Droid {
      primaryFunction
    }
    ... on Human {
      height
    }
  }
}

If my analysis is correct, then I think we should consider:

  1. arguably this is a special case, since you are only expanding a single fragment with no other fields. So should it get special treatment?
  2. otherwise this probably deserves a nicer error message :)

Thoughts?

@rpiaggio
Copy link
Collaborator Author

You are totally right. Interface queries don't necessarily materialize into an instance. We should extract a subquery on the actual instantiated type (hero in your example).

We could still define reusable blocks for these cases (ie: special case), and I think it would be just a string with the subquery (no output type or decoder), only that we would have to resolve the interpolation at compile time, like we do for actual subqueries. I wonder if this is worthwhile, thoughts? Do you think this it's straightforward or that I'm missing something?

@armanbilge
Copy link
Contributor

armanbilge commented Feb 23, 2023

We could still define reusable blocks for these cases (ie: special case), and I think it would be just a string with the subquery (no output type or decoder), only that we would have to resolve the interpolation at compile time, like we do for actual subqueries.

Oh, I see! So in this case, we just want to interpolate the string part of the query, and not share/reuse data classes? Did I understand correctly?

@rpiaggio
Copy link
Collaborator Author

Oh, I see! So in this case, we just want to interpolate the string part of the query, and not share/reuse data classes? Did I understand correctly?

Yes, that's what I mean. In other words, compile-time concatenation. It might be useful too when there are common fields but not a common interface. WDYT?

@armanbilge
Copy link
Contributor

Yes, I do think that would be useful! I actually attempted that when I first started working on subqueries, because I assumed it would be helpful. It turned out to be difficult and not strictly needed 😂

I still have the branch lying around, I can give it another shot :) the strategy I was trying to use there, was that the Scala compiler will automatically concatenate final val strings at compile time. So I was hoping we could tap into that somehow.
https://github.com/gemini-hlsw/clue/commits/pr/final-val-document

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants