subgraph
subgraph copied to clipboard
Scheme & Proposal Base Interfaces
Current Behavior
Currently, the subgraph schema's solution to adding new types of scheme & proposal types requiring changing the base type (ControllerScheme
& Proposal
). This is because each derived type is added as a nullable field in the base type like so:
type Base {
id: ID!
baseProp: String!
typeName: String!
# Implementations
derivedA: DerivedA
derivedB: DerivedB
}
In order to query all Base
entities, you'd have to form a query like so:
bases {
id
baseProp
typeName
derivedA {
# All derivedA props
someFieldA
}
derivedB {
# All derivedB props
someFieldB
}
}
And in order to know what sub type each entity in the collection is (derivedA
or derivedB
) you have to check the typeName, then access the correct field that corresponds to that entity:
if (res.typeName === "DerivedA") {
res.derivedA.someFieldA
} else if (res.typeName === "DerivedB") {
res.derivedB.someFieldB
}
Opinion
Doing things this way is a "non-standard" way of implementing polymorphism in GraphQL. Here are two ways in which GraphQL supports polymorphic types: https://www.apollographql.com/docs/apollo-server/schema/unions-interfaces/
Unions make sense for when types don't have shared properties. Interfaces make sense for when types have shared "base" properties.
Proposal
Utilize GraphQL interfaces for both Proposal and Scheme types. Here's an example of what this would look like:
interface Base {
id: ID!
baseProp: String!
}
type DerivedA implements Base {
id: ID!
baseProp: String!
someFieldA: String!
}
type DerivedB implements Base {
id: ID!
baseProp: String!
someFieldB: String!
}
// Generate an array of fragments for each known type
const fragments = []
for (const derived of DerivedTypes) {
fragments.push(derived.Fields)
}
query Bases {
bases {
__typename
id
baseProp
# Can be generated from a list of known types
# and appended to the query string, making this code
# open for extension, closed for modification
... on DerivedA {
DerivedAProps
}
... on DerivedB {
DerivedBProps
}
}
}
${fragments}
Then we can instantiate the different types from __typename
:
new DerivedTypes[res.__typename]()
This is currently blocked due to a Graph Node bug. I will follow up with them on that and return to it when possible.
Awesome, thanks so much @ben-kaufman! Out of curiosity, what's the bug?
https://github.com/graphprotocol/graph-cli/pull/477