DOCS: improve graphql inheritance docs

This commit is contained in:
Aaron Carlino 2021-06-30 19:38:11 +12:00
parent 0537e769fc
commit 29320841c9
2 changed files with 57 additions and 70 deletions

47
.idea/workspace.xml generated
View File

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="49c2db15-d223-4efe-b1e8-2d4ecfdaa74a" name="Default Changelist" comment="">
<change beforePath="$PROJECT_DIR$/docs/en/00_Getting_Started/index.md" beforeDir="false" afterPath="$PROJECT_DIR$/docs/en/00_Getting_Started/index.md" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="ComposerSettings" synchronizationState="SYNCHRONIZE">
<pharConfigPath>$PROJECT_DIR$/composer.json</pharConfigPath>
<execution />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="ProjectId" id="1ueqw0dJJFnqPFjpLOJN1mIgTXB" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
<property name="vue.rearranger.settings.migration" value="true" />
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="49c2db15-d223-4efe-b1e8-2d4ecfdaa74a" name="Default Changelist" comment="" />
<created>1625036637006</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1625036637006</updated>
<workItem from="1625036638810" duration="456000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
</project>

View File

@ -73,8 +73,8 @@ But what about when we want more than `title` and `content`? In some cases, we'l
query {
readPages {
nodes {
title
content
title # Common field
content # Common field
... on HomePage {
heroImage {
url
@ -98,22 +98,23 @@ that only appear on some types, we need to be explicit.
But let's take this a step further. What if there's another class in between? Imagine this ancestry:
```
Page:
EventPage:
ConferencePage
WebinarPage
Page
-> EventPage
-> ConferencePage
-> WebinarPage
```
We can use the intermediary interface `EventPageInterface` to consolidate fields that are unique to
`ConferencePage` and `WebinarPage`.
```
```graphql
query {
readPages {
nodes {
title
content
title # Common to all types
content # Common to all types
... on EventPageInterface {
# Common fields for WebinarPage, ConferencePage, EventPage
numberOfTickets
featuredSpeaker {
firstName
@ -147,10 +148,12 @@ which is usually the parent class with the "Interface" suffix.
### Inheritance: A deep dive
There are two components to the way inheritance is handled at build time:
There are several ways inheritance is handled at build time:
* Implicit field / type exposure
* Interface generation and assignment to types
* Interface generation
* Assignment of generated interfaces to types
* Assignment of generated interfaces to queries
We'll look at each of these in detail.
@ -180,7 +183,7 @@ GalleryPage:
This results in these two types being exposed with the fields as shown, but also results in a `Page` type:
```
```graphql
type Page {
id: ID! # always exposed
title: String
@ -189,7 +192,7 @@ type Page {
}
```
#### Interface generation and assignment to types
#### Interface generation
Any type that's part of an inheritance chain will generate interfaces. Each applicable ancestral interface is added
to the type. Like the type inheritance pattern shown above, interfaces duplicate fields from their ancestors as well.
@ -202,16 +205,16 @@ All of this is serviced by: `SilverStripe\GraphQL\Schema\DataObject\InterfaceBui
##### Example
```
Page:
BlogPage extends Page
EventsPage extends Page
ConferencePage extends EventsPage
WebinarPage extends EventsPage
Page
-> BlogPage extends Page
-> EventsPage extends Page
-> ConferencePage extends EventsPage
-> WebinarPage extends EventsPage
```
This will create the following interfaces:
```
```graphql
interface PageInterface {
title: String
content: String
@ -249,9 +252,11 @@ interface WebinarPageInterface {
}
```
Types then get these interfaces applied, like so:
#### Interface assignment to types
```
The generated interfaces then get applied to the appropriate types, like so:
```graphql
type Page implements PageInterface {}
type BlogPage implements BlogPageInterface & PageInterface {}
type EventsPage implements EventsPageInterface & PageInterface {}
@ -261,17 +266,46 @@ type WebinarPage implements WebinarPageInterface & EventsPageInterface & PageInt
Lastly, for good measure, we create a `DataObjectInterface` that applies to everything.
```
```graphql
interface DataObjectInterface {
id: ID!
# Any other fields you've explicitly exposed in config.modelConfig.DataObject.base_fields
}
```
```
```graphql
type Page implements PageInterface & DataObjectInterface {}
```
#### Interface assignment to queries
Queries, both at the root, and nested as fields on types, will have their types
updated if they refer to a type that has had any generated interfaces added to it.
```graphql
type Query {
readPages: [Page]
}
type BlogPage {
download: File
}
```
Becomes:
```graphql
type Query {
readPages: [PageInterface]
}
type BlogPage {
download: FileInterface
}
```
All of this is serviced by: `SilverStripe\GraphQL\Schema\DataObject\InterfaceBuilder`
#### Elemental
Almost by definition, content blocks are always abstractions. You're never going to query for a `BaseElement` type