Scheme & Proposal Base Interfaces
- Dominant language
- TypeScript
- Stars
- 44
- Forks
- 30
- PR merge metrics
- No merged PRs in 30d
Description
# 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:
```graphql
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:
```graphql
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:
```typescript
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:
```graphql
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!
}
```
```typescript
// Generate an array of fragments for each known type
const fragments = []
for (const derived of DerivedTypes) {
fragments.push(derived.Fields)
}
```
```graphql
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`:
```typescript
new DerivedTypes[res.__typename]()
```
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.