Schema should be able to have cycles.
Schema with cycles generates structs with dependencies on other structs that lead to an error.
I've taken the following example from https://swapi.graph.cool/ to illustrate a cycle.
To be able to perform this query:
query {
allPersons {
name
birthYear
species {
people {
name
birthYear
}
}
}
}
You would need to have this part of the schema:
interface Node {
id: ID!
}
type Person implements Node {
name: String!
birthYear: String
species: [Species!]
}
type Species implements Node {
name: String!
people: [Person!]
}
But that leads to a problem with gengql generating cycling dependency between structs.
Not Null confusion with pointers strikes again! Maybe we remove them everywhere when dealing with structs.
Simple workaround for now should be to drop the ! on the embedded types:
interface Node {
id: ID!
}
type Person implements Node {
name: String!
birthYear: String
species: [Species]
}
type Species implements Node {
name: String!
people: [Person]
}
My friend @steabert and I talked about this and then each of us posted a similar bug report (by misstake), but please also take a look at mine (https://github.com/99designs/gqlgen/issues/586).
Making the field nullable is just a workaround, so if we instead could have some directive in the schema that introduced a pointer in the generated model, it would probably be a better idea.
Sometimes you cannot change the schema and GraphQL allows constructs like this.
Yeah that would be my suggestion, have model-gen always use pointers to other structs. Might cause some issues with non-nullable fields, but the generated code will check the return type and bubble up and error in that case, so maybe not too bad?
That is even better. My initial thought was that the pointer generation could be controlled with a schema directive, but to always have pointers (whenever a reference is introduced to a struct) in combination with a run time check that ensures that nil is never returned, would be a perfect solution for cases like this.
I don't see why it has to do it in this case, though. Both references are slice-of, which introduces an indirection, so it should work from a golang perspective.
馃 What's the problem then? I just tried the schema linked above, and it seems to codegen and run fine (once you add the missing id: ID! fields on the implementors). I don't see a cycle here than gqlgen cannot handle?
Have you tried the schema in my ticket (https://github.com/99designs/gqlgen/issues/586)? It covers the same problem, but was closed in favor of this ticket.
The schema there is dead simple, valid GQL and gives you a model that does not compile.
Yes, #586 is a legitimate reproduction path of the actual failure.
Ah right, yeah maybe I got my wires crossed between these two issues. I'm going to close this issue since I can't seem to reproduce and reopen the other one which has the simpler repro case.
https://github.com/99designs/gqlgen/issues/585 and https://github.com/99designs/gqlgen/issues/586 are now recursive issues
585 and #586 are now recursive issues
How deliciously appropriate!